Re-organize sources
authorMichael Jeanson <mjeanson@efficios.com>
Mon, 10 Jun 2019 21:44:09 +0000 (17:44 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Wed, 12 Jun 2019 21:55:59 +0000 (17:55 -0400)
 * Create a top-level 'src' directory.
 * Move all private headers from the public include directory to the
   'src' directory.
 * Rename all those private headers to remove the 'internal' notation.
 * Use double quotes in `#include` directives when including a private
   header so that we can easily know.

Change-Id: I05fbb81d969b3735aaf303ec2c222be7142c19ab
Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1413
Tested-by: jenkins
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
847 files changed:
.gitignore
CONTRIBUTING.adoc
LICENSE
Makefile.am
babeltrace2-ctf-writer.pc.in [deleted file]
babeltrace2.pc.in [deleted file]
bindings/Makefile.am [deleted file]
bindings/python/Makefile.am [deleted file]
bindings/python/bt2/.gitignore [deleted file]
bindings/python/bt2/Makefile.am [deleted file]
bindings/python/bt2/bt2/__init__.py.in [deleted file]
bindings/python/bt2/bt2/clock_class.py [deleted file]
bindings/python/bt2/bt2/clock_snapshot.py [deleted file]
bindings/python/bt2/bt2/component.py [deleted file]
bindings/python/bt2/bt2/connection.py [deleted file]
bindings/python/bt2/bt2/event.py [deleted file]
bindings/python/bt2/bt2/event_class.py [deleted file]
bindings/python/bt2/bt2/field.py [deleted file]
bindings/python/bt2/bt2/field_class.py [deleted file]
bindings/python/bt2/bt2/field_path.py [deleted file]
bindings/python/bt2/bt2/graph.py [deleted file]
bindings/python/bt2/bt2/logging.c [deleted file]
bindings/python/bt2/bt2/logging.h [deleted file]
bindings/python/bt2/bt2/logging.py [deleted file]
bindings/python/bt2/bt2/message.py [deleted file]
bindings/python/bt2/bt2/message_iterator.py [deleted file]
bindings/python/bt2/bt2/native_bt.i [deleted file]
bindings/python/bt2/bt2/native_bt_clock_class.i [deleted file]
bindings/python/bt2/bt2/native_bt_clock_snapshot.i [deleted file]
bindings/python/bt2/bt2/native_bt_component.i [deleted file]
bindings/python/bt2/bt2/native_bt_component_class.i [deleted file]
bindings/python/bt2/bt2/native_bt_connection.i [deleted file]
bindings/python/bt2/bt2/native_bt_event.i [deleted file]
bindings/python/bt2/bt2/native_bt_event_class.i [deleted file]
bindings/python/bt2/bt2/native_bt_field.i [deleted file]
bindings/python/bt2/bt2/native_bt_field_class.i [deleted file]
bindings/python/bt2/bt2/native_bt_field_path.i [deleted file]
bindings/python/bt2/bt2/native_bt_graph.i [deleted file]
bindings/python/bt2/bt2/native_bt_logging.i [deleted file]
bindings/python/bt2/bt2/native_bt_message.i [deleted file]
bindings/python/bt2/bt2/native_bt_notifier.i [deleted file]
bindings/python/bt2/bt2/native_bt_packet.i [deleted file]
bindings/python/bt2/bt2/native_bt_plugin.i [deleted file]
bindings/python/bt2/bt2/native_bt_port.i [deleted file]
bindings/python/bt2/bt2/native_bt_query_exec.i [deleted file]
bindings/python/bt2/bt2/native_bt_stream.i [deleted file]
bindings/python/bt2/bt2/native_bt_stream_class.i [deleted file]
bindings/python/bt2/bt2/native_bt_trace.i [deleted file]
bindings/python/bt2/bt2/native_bt_trace_class.i [deleted file]
bindings/python/bt2/bt2/native_bt_value.i [deleted file]
bindings/python/bt2/bt2/native_bt_version.i [deleted file]
bindings/python/bt2/bt2/object.py [deleted file]
bindings/python/bt2/bt2/packet.py [deleted file]
bindings/python/bt2/bt2/plugin.py [deleted file]
bindings/python/bt2/bt2/port.py [deleted file]
bindings/python/bt2/bt2/py_plugin.py [deleted file]
bindings/python/bt2/bt2/query_executor.py [deleted file]
bindings/python/bt2/bt2/stream.py [deleted file]
bindings/python/bt2/bt2/stream_class.py [deleted file]
bindings/python/bt2/bt2/trace.py [deleted file]
bindings/python/bt2/bt2/trace_class.py [deleted file]
bindings/python/bt2/bt2/trace_collection_message_iterator.py [deleted file]
bindings/python/bt2/bt2/utils.py [deleted file]
bindings/python/bt2/bt2/value.py [deleted file]
bindings/python/bt2/setup.py.in [deleted file]
cli/Makefile.am [deleted file]
cli/babeltrace2-cfg-cli-args-connect.c [deleted file]
cli/babeltrace2-cfg-cli-args-connect.h [deleted file]
cli/babeltrace2-cfg-cli-args-default.c [deleted file]
cli/babeltrace2-cfg-cli-args-default.h [deleted file]
cli/babeltrace2-cfg-cli-args.c [deleted file]
cli/babeltrace2-cfg-cli-args.h [deleted file]
cli/babeltrace2-cfg.c [deleted file]
cli/babeltrace2-cfg.h [deleted file]
cli/babeltrace2-log.c [deleted file]
cli/babeltrace2.c [deleted file]
cli/logging.c [deleted file]
cli/logging.h [deleted file]
common/Makefile.am [deleted file]
common/assert.c [deleted file]
common/common.c [deleted file]
common/logging.c [deleted file]
common/logging.h [deleted file]
compat/Makefile.am [deleted file]
compat/compat_mman.c [deleted file]
compat/compat_uuid.c [deleted file]
compat/logging.c [deleted file]
compat/logging.h [deleted file]
configure.ac
ctf-writer/Makefile.am [deleted file]
ctf-writer/attributes.c [deleted file]
ctf-writer/clock-class.c [deleted file]
ctf-writer/clock.c [deleted file]
ctf-writer/event-class.c [deleted file]
ctf-writer/event.c [deleted file]
ctf-writer/field-path.c [deleted file]
ctf-writer/field-types.c [deleted file]
ctf-writer/field-wrapper.c [deleted file]
ctf-writer/fields.c [deleted file]
ctf-writer/functor.c [deleted file]
ctf-writer/logging.c [deleted file]
ctf-writer/logging.h [deleted file]
ctf-writer/object-pool.c [deleted file]
ctf-writer/object.c [deleted file]
ctf-writer/resolve.c [deleted file]
ctf-writer/stream-class.c [deleted file]
ctf-writer/stream.c [deleted file]
ctf-writer/trace.c [deleted file]
ctf-writer/utils.c [deleted file]
ctf-writer/validation.c [deleted file]
ctf-writer/values.c [deleted file]
ctf-writer/visitor.c [deleted file]
ctf-writer/writer.c [deleted file]
ctfser/Makefile.am [deleted file]
ctfser/ctfser.c [deleted file]
ctfser/logging.c [deleted file]
ctfser/logging.h [deleted file]
doc/api/Doxyfile.in
doc/bindings/python/Makefile.am
fd-cache/Makefile.am [deleted file]
fd-cache/fd-cache.c [deleted file]
fd-cache/logging.c [deleted file]
fd-cache/logging.h [deleted file]
include/Makefile.am
include/babeltrace2/align-internal.h [deleted file]
include/babeltrace2/assert-internal.h [deleted file]
include/babeltrace2/assert-pre-internal.h [deleted file]
include/babeltrace2/babeltrace-internal.h [deleted file]
include/babeltrace2/bitfield-internal.h [deleted file]
include/babeltrace2/common-internal.h [deleted file]
include/babeltrace2/compat/fcntl-internal.h [deleted file]
include/babeltrace2/compat/glib-internal.h [deleted file]
include/babeltrace2/compat/limits-internal.h [deleted file]
include/babeltrace2/compat/memstream-internal.h [deleted file]
include/babeltrace2/compat/mman-internal.h [deleted file]
include/babeltrace2/compat/socket-internal.h [deleted file]
include/babeltrace2/compat/stdio-internal.h [deleted file]
include/babeltrace2/compat/stdlib-internal.h [deleted file]
include/babeltrace2/compat/string-internal.h [deleted file]
include/babeltrace2/compat/time-internal.h [deleted file]
include/babeltrace2/compat/unistd-internal.h [deleted file]
include/babeltrace2/compat/utc-internal.h [deleted file]
include/babeltrace2/compat/uuid-internal.h [deleted file]
include/babeltrace2/compiler-internal.h [deleted file]
include/babeltrace2/ctf-writer/assert-pre-internal.h [deleted file]
include/babeltrace2/ctf-writer/attributes-internal.h [deleted file]
include/babeltrace2/ctf-writer/clock-class-internal.h [deleted file]
include/babeltrace2/ctf-writer/clock-internal.h [deleted file]
include/babeltrace2/ctf-writer/event-class-internal.h [deleted file]
include/babeltrace2/ctf-writer/event-internal.h [deleted file]
include/babeltrace2/ctf-writer/field-path-internal.h [deleted file]
include/babeltrace2/ctf-writer/field-types-internal.h [deleted file]
include/babeltrace2/ctf-writer/field-wrapper-internal.h [deleted file]
include/babeltrace2/ctf-writer/fields-internal.h [deleted file]
include/babeltrace2/ctf-writer/functor-internal.h [deleted file]
include/babeltrace2/ctf-writer/object-internal.h [deleted file]
include/babeltrace2/ctf-writer/object-pool-internal.h [deleted file]
include/babeltrace2/ctf-writer/resolve-internal.h [deleted file]
include/babeltrace2/ctf-writer/stream-class-internal.h [deleted file]
include/babeltrace2/ctf-writer/stream-internal.h [deleted file]
include/babeltrace2/ctf-writer/trace-internal.h [deleted file]
include/babeltrace2/ctf-writer/utils-internal.h [deleted file]
include/babeltrace2/ctf-writer/validation-internal.h [deleted file]
include/babeltrace2/ctf-writer/values-internal.h [deleted file]
include/babeltrace2/ctf-writer/visitor-internal.h [deleted file]
include/babeltrace2/ctf-writer/writer-internal.h [deleted file]
include/babeltrace2/ctfser-internal.h [deleted file]
include/babeltrace2/endian-internal.h [deleted file]
include/babeltrace2/fd-cache-internal.h [deleted file]
include/babeltrace2/graph/component-class-internal.h [deleted file]
include/babeltrace2/graph/component-class-sink-colander-internal.h [deleted file]
include/babeltrace2/graph/component-filter-internal.h [deleted file]
include/babeltrace2/graph/component-internal.h [deleted file]
include/babeltrace2/graph/component-sink-internal.h [deleted file]
include/babeltrace2/graph/component-source-internal.h [deleted file]
include/babeltrace2/graph/connection-internal.h [deleted file]
include/babeltrace2/graph/graph-internal.h [deleted file]
include/babeltrace2/graph/message-discarded-items-internal.h [deleted file]
include/babeltrace2/graph/message-event-internal.h [deleted file]
include/babeltrace2/graph/message-internal.h [deleted file]
include/babeltrace2/graph/message-iterator-internal.h [deleted file]
include/babeltrace2/graph/message-message-iterator-inactivity-internal.h [deleted file]
include/babeltrace2/graph/message-packet-internal.h [deleted file]
include/babeltrace2/graph/message-stream-activity-internal.h [deleted file]
include/babeltrace2/graph/message-stream-internal.h [deleted file]
include/babeltrace2/graph/port-internal.h [deleted file]
include/babeltrace2/graph/query-executor-internal.h [deleted file]
include/babeltrace2/lib-logging-internal.h [deleted file]
include/babeltrace2/list-internal.h [deleted file]
include/babeltrace2/logging-internal.h [deleted file]
include/babeltrace2/mmap-align-internal.h [deleted file]
include/babeltrace2/object-internal.h [deleted file]
include/babeltrace2/object-pool-internal.h [deleted file]
include/babeltrace2/plugin/plugin-internal.h [deleted file]
include/babeltrace2/plugin/plugin-so-internal.h [deleted file]
include/babeltrace2/plugin/python-plugin-provider-internal.h [deleted file]
include/babeltrace2/prio-heap-internal.h [deleted file]
include/babeltrace2/property-internal.h [deleted file]
include/babeltrace2/trace-ir/attributes-internal.h [deleted file]
include/babeltrace2/trace-ir/clock-class-internal.h [deleted file]
include/babeltrace2/trace-ir/clock-snapshot-internal.h [deleted file]
include/babeltrace2/trace-ir/clock-snapshot-set-internal.h [deleted file]
include/babeltrace2/trace-ir/event-class-internal.h [deleted file]
include/babeltrace2/trace-ir/event-internal.h [deleted file]
include/babeltrace2/trace-ir/field-class-internal.h [deleted file]
include/babeltrace2/trace-ir/field-internal.h [deleted file]
include/babeltrace2/trace-ir/field-path-internal.h [deleted file]
include/babeltrace2/trace-ir/field-wrapper-internal.h [deleted file]
include/babeltrace2/trace-ir/packet-internal.h [deleted file]
include/babeltrace2/trace-ir/resolve-field-path-internal.h [deleted file]
include/babeltrace2/trace-ir/stream-class-internal.h [deleted file]
include/babeltrace2/trace-ir/stream-internal.h [deleted file]
include/babeltrace2/trace-ir/trace-class-internal.h [deleted file]
include/babeltrace2/trace-ir/trace-internal.h [deleted file]
include/babeltrace2/trace-ir/utils-internal.h [deleted file]
include/babeltrace2/value-internal.h [deleted file]
include/version.h [deleted file]
lib/Makefile.am [deleted file]
lib/babeltrace2.c [deleted file]
lib/graph/Makefile.am [deleted file]
lib/graph/component-class-sink-colander.c [deleted file]
lib/graph/component-class.c [deleted file]
lib/graph/component-filter.c [deleted file]
lib/graph/component-sink.c [deleted file]
lib/graph/component-source.c [deleted file]
lib/graph/component.c [deleted file]
lib/graph/connection.c [deleted file]
lib/graph/graph.c [deleted file]
lib/graph/iterator.c [deleted file]
lib/graph/message/Makefile.am [deleted file]
lib/graph/message/discarded-items.c [deleted file]
lib/graph/message/event.c [deleted file]
lib/graph/message/message-iterator-inactivity.c [deleted file]
lib/graph/message/message.c [deleted file]
lib/graph/message/packet.c [deleted file]
lib/graph/message/stream-activity.c [deleted file]
lib/graph/message/stream.c [deleted file]
lib/graph/port.c [deleted file]
lib/graph/query-executor.c [deleted file]
lib/lib-logging.c [deleted file]
lib/logging.c [deleted file]
lib/object-pool.c [deleted file]
lib/plugin/Makefile.am [deleted file]
lib/plugin/plugin-so.c [deleted file]
lib/plugin/plugin.c [deleted file]
lib/prio_heap/Makefile.am [deleted file]
lib/prio_heap/prio_heap.c [deleted file]
lib/trace-ir/Makefile.am [deleted file]
lib/trace-ir/attributes.c [deleted file]
lib/trace-ir/clock-class.c [deleted file]
lib/trace-ir/clock-snapshot.c [deleted file]
lib/trace-ir/event-class.c [deleted file]
lib/trace-ir/event.c [deleted file]
lib/trace-ir/field-class.c [deleted file]
lib/trace-ir/field-path.c [deleted file]
lib/trace-ir/field-wrapper.c [deleted file]
lib/trace-ir/field.c [deleted file]
lib/trace-ir/packet-context-field.c [deleted file]
lib/trace-ir/packet.c [deleted file]
lib/trace-ir/resolve-field-path.c [deleted file]
lib/trace-ir/stream-class.c [deleted file]
lib/trace-ir/stream.c [deleted file]
lib/trace-ir/trace-class.c [deleted file]
lib/trace-ir/trace.c [deleted file]
lib/trace-ir/utils.c [deleted file]
lib/util.c [deleted file]
lib/value.c [deleted file]
logging/LICENSE [deleted file]
logging/Makefile.am [deleted file]
logging/log.c [deleted file]
plugins/Makefile.am [deleted file]
plugins/ctf/Makefile.am [deleted file]
plugins/ctf/common/Makefile.am [deleted file]
plugins/ctf/common/bfcr/Makefile.am [deleted file]
plugins/ctf/common/bfcr/bfcr.c [deleted file]
plugins/ctf/common/bfcr/bfcr.h [deleted file]
plugins/ctf/common/bfcr/btr.gdb [deleted file]
plugins/ctf/common/bfcr/logging.c [deleted file]
plugins/ctf/common/bfcr/logging.h [deleted file]
plugins/ctf/common/metadata/Makefile.am [deleted file]
plugins/ctf/common/metadata/ast.h [deleted file]
plugins/ctf/common/metadata/ctf-meta-resolve.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-translate.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-update-in-ir.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-update-meanings.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-validate.c [deleted file]
plugins/ctf/common/metadata/ctf-meta-visitors.h [deleted file]
plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.c [deleted file]
plugins/ctf/common/metadata/ctf-meta.h [deleted file]
plugins/ctf/common/metadata/decoder.c [deleted file]
plugins/ctf/common/metadata/decoder.h [deleted file]
plugins/ctf/common/metadata/lexer.l [deleted file]
plugins/ctf/common/metadata/logging.c [deleted file]
plugins/ctf/common/metadata/logging.h [deleted file]
plugins/ctf/common/metadata/objstack.c [deleted file]
plugins/ctf/common/metadata/objstack.h [deleted file]
plugins/ctf/common/metadata/parser.y [deleted file]
plugins/ctf/common/metadata/scanner-symbols.h [deleted file]
plugins/ctf/common/metadata/scanner.h [deleted file]
plugins/ctf/common/metadata/visitor-generate-ir.c [deleted file]
plugins/ctf/common/metadata/visitor-parent-links.c [deleted file]
plugins/ctf/common/metadata/visitor-semantic-validator.c [deleted file]
plugins/ctf/common/msg-iter/Makefile.am [deleted file]
plugins/ctf/common/msg-iter/logging.c [deleted file]
plugins/ctf/common/msg-iter/logging.h [deleted file]
plugins/ctf/common/msg-iter/msg-iter.c [deleted file]
plugins/ctf/common/msg-iter/msg-iter.h [deleted file]
plugins/ctf/common/print.h [deleted file]
plugins/ctf/common/utils/Makefile.am [deleted file]
plugins/ctf/common/utils/logging.c [deleted file]
plugins/ctf/common/utils/logging.h [deleted file]
plugins/ctf/common/utils/utils.c [deleted file]
plugins/ctf/common/utils/utils.h [deleted file]
plugins/ctf/fs-sink/Makefile.am [deleted file]
plugins/ctf/fs-sink/fs-sink-ctf-meta.h [deleted file]
plugins/ctf/fs-sink/fs-sink-stream.c [deleted file]
plugins/ctf/fs-sink/fs-sink-stream.h [deleted file]
plugins/ctf/fs-sink/fs-sink-trace.c [deleted file]
plugins/ctf/fs-sink/fs-sink-trace.h [deleted file]
plugins/ctf/fs-sink/fs-sink.c [deleted file]
plugins/ctf/fs-sink/fs-sink.h [deleted file]
plugins/ctf/fs-sink/logging.c [deleted file]
plugins/ctf/fs-sink/logging.h [deleted file]
plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c [deleted file]
plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.h [deleted file]
plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c [deleted file]
plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.h [deleted file]
plugins/ctf/fs-src/Makefile.am [deleted file]
plugins/ctf/fs-src/data-stream-file.c [deleted file]
plugins/ctf/fs-src/data-stream-file.h [deleted file]
plugins/ctf/fs-src/file.c [deleted file]
plugins/ctf/fs-src/file.h [deleted file]
plugins/ctf/fs-src/fs.c [deleted file]
plugins/ctf/fs-src/fs.h [deleted file]
plugins/ctf/fs-src/logging.c [deleted file]
plugins/ctf/fs-src/logging.h [deleted file]
plugins/ctf/fs-src/lttng-index.h [deleted file]
plugins/ctf/fs-src/metadata.c [deleted file]
plugins/ctf/fs-src/metadata.h [deleted file]
plugins/ctf/fs-src/query.c [deleted file]
plugins/ctf/fs-src/query.h [deleted file]
plugins/ctf/lttng-live/Makefile.am [deleted file]
plugins/ctf/lttng-live/data-stream.c [deleted file]
plugins/ctf/lttng-live/data-stream.h [deleted file]
plugins/ctf/lttng-live/logging.c [deleted file]
plugins/ctf/lttng-live/logging.h [deleted file]
plugins/ctf/lttng-live/lttng-live.c [deleted file]
plugins/ctf/lttng-live/lttng-live.h [deleted file]
plugins/ctf/lttng-live/lttng-viewer-abi.h [deleted file]
plugins/ctf/lttng-live/metadata.c [deleted file]
plugins/ctf/lttng-live/metadata.h [deleted file]
plugins/ctf/lttng-live/viewer-connection.c [deleted file]
plugins/ctf/lttng-live/viewer-connection.h [deleted file]
plugins/ctf/plugin.c [deleted file]
plugins/ctf/print.h [deleted file]
plugins/lttng-utils/Makefile.am [deleted file]
plugins/lttng-utils/debug-info/Makefile.am [deleted file]
plugins/lttng-utils/debug-info/bin-info.c [deleted file]
plugins/lttng-utils/debug-info/bin-info.h [deleted file]
plugins/lttng-utils/debug-info/crc32.c [deleted file]
plugins/lttng-utils/debug-info/crc32.h [deleted file]
plugins/lttng-utils/debug-info/debug-info.c [deleted file]
plugins/lttng-utils/debug-info/debug-info.h [deleted file]
plugins/lttng-utils/debug-info/dwarf.c [deleted file]
plugins/lttng-utils/debug-info/dwarf.h [deleted file]
plugins/lttng-utils/debug-info/logging.c [deleted file]
plugins/lttng-utils/debug-info/logging.h [deleted file]
plugins/lttng-utils/debug-info/trace-ir-data-copy.c [deleted file]
plugins/lttng-utils/debug-info/trace-ir-data-copy.h [deleted file]
plugins/lttng-utils/debug-info/trace-ir-mapping.c [deleted file]
plugins/lttng-utils/debug-info/trace-ir-mapping.h [deleted file]
plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c [deleted file]
plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h [deleted file]
plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c [deleted file]
plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h [deleted file]
plugins/lttng-utils/debug-info/utils.c [deleted file]
plugins/lttng-utils/debug-info/utils.h [deleted file]
plugins/lttng-utils/plugin.c [deleted file]
plugins/plugins-common.h [deleted file]
plugins/text/Makefile.am [deleted file]
plugins/text/dmesg/Makefile.am [deleted file]
plugins/text/dmesg/dmesg.c [deleted file]
plugins/text/dmesg/dmesg.h [deleted file]
plugins/text/dmesg/logging.c [deleted file]
plugins/text/dmesg/logging.h [deleted file]
plugins/text/plugin.c [deleted file]
plugins/text/pretty/Makefile.am [deleted file]
plugins/text/pretty/logging.c [deleted file]
plugins/text/pretty/logging.h [deleted file]
plugins/text/pretty/pretty.c [deleted file]
plugins/text/pretty/pretty.h [deleted file]
plugins/text/pretty/print.c [deleted file]
plugins/utils/Makefile.am [deleted file]
plugins/utils/counter/Makefile.am [deleted file]
plugins/utils/counter/counter.c [deleted file]
plugins/utils/counter/counter.h [deleted file]
plugins/utils/counter/logging.c [deleted file]
plugins/utils/counter/logging.h [deleted file]
plugins/utils/dummy/Makefile.am [deleted file]
plugins/utils/dummy/dummy.c [deleted file]
plugins/utils/dummy/dummy.h [deleted file]
plugins/utils/muxer/Makefile.am [deleted file]
plugins/utils/muxer/logging.c [deleted file]
plugins/utils/muxer/logging.h [deleted file]
plugins/utils/muxer/muxer.c [deleted file]
plugins/utils/muxer/muxer.h [deleted file]
plugins/utils/plugin.c [deleted file]
plugins/utils/trimmer/Makefile.am [deleted file]
plugins/utils/trimmer/logging.c [deleted file]
plugins/utils/trimmer/logging.h [deleted file]
plugins/utils/trimmer/trimmer.c [deleted file]
plugins/utils/trimmer/trimmer.h [deleted file]
python-plugin-provider/Makefile.am [deleted file]
python-plugin-provider/python-plugin-provider.c [deleted file]
src/Makefile.am [new file with mode: 0644]
src/babeltrace2-ctf-writer.pc.in [new file with mode: 0644]
src/babeltrace2.pc.in [new file with mode: 0644]
src/bindings/Makefile.am [new file with mode: 0644]
src/bindings/python/Makefile.am [new file with mode: 0644]
src/bindings/python/bt2/.gitignore [new file with mode: 0644]
src/bindings/python/bt2/Makefile.am [new file with mode: 0644]
src/bindings/python/bt2/bt2/__init__.py.in [new file with mode: 0644]
src/bindings/python/bt2/bt2/clock_class.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/clock_snapshot.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/component.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/connection.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/event.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/event_class.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/field.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/field_class.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/field_path.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/graph.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/logging.c [new file with mode: 0644]
src/bindings/python/bt2/bt2/logging.h [new file with mode: 0644]
src/bindings/python/bt2/bt2/logging.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/message.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/message_iterator.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_clock_class.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_clock_snapshot.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_component.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_component_class.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_connection.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_event.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_event_class.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_field.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_field_class.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_field_path.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_graph.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_logging.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_message.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_notifier.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_packet.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_plugin.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_port.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_query_exec.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_stream.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_stream_class.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_trace.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_trace_class.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_value.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/native_bt_version.i [new file with mode: 0644]
src/bindings/python/bt2/bt2/object.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/packet.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/plugin.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/port.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/py_plugin.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/query_executor.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/stream.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/stream_class.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/trace.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/trace_class.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/trace_collection_message_iterator.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/utils.py [new file with mode: 0644]
src/bindings/python/bt2/bt2/value.py [new file with mode: 0644]
src/bindings/python/bt2/setup.py.in [new file with mode: 0644]
src/cli/Makefile.am [new file with mode: 0644]
src/cli/babeltrace2-cfg-cli-args-connect.c [new file with mode: 0644]
src/cli/babeltrace2-cfg-cli-args-connect.h [new file with mode: 0644]
src/cli/babeltrace2-cfg-cli-args-default.c [new file with mode: 0644]
src/cli/babeltrace2-cfg-cli-args-default.h [new file with mode: 0644]
src/cli/babeltrace2-cfg-cli-args.c [new file with mode: 0644]
src/cli/babeltrace2-cfg-cli-args.h [new file with mode: 0644]
src/cli/babeltrace2-cfg.c [new file with mode: 0644]
src/cli/babeltrace2-cfg.h [new file with mode: 0644]
src/cli/babeltrace2-log.c [new file with mode: 0644]
src/cli/babeltrace2.c [new file with mode: 0644]
src/cli/logging.c [new file with mode: 0644]
src/cli/logging.h [new file with mode: 0644]
src/common/Makefile.am [new file with mode: 0644]
src/common/align.h [new file with mode: 0644]
src/common/assert.c [new file with mode: 0644]
src/common/assert.h [new file with mode: 0644]
src/common/babeltrace.h [new file with mode: 0644]
src/common/common.c [new file with mode: 0644]
src/common/common.h [new file with mode: 0644]
src/common/list.h [new file with mode: 0644]
src/common/logging.c [new file with mode: 0644]
src/common/logging.h [new file with mode: 0644]
src/common/mmap-align.h [new file with mode: 0644]
src/common/version.h [new file with mode: 0644]
src/compat/Makefile.am [new file with mode: 0644]
src/compat/bitfield.h [new file with mode: 0644]
src/compat/compiler.h [new file with mode: 0644]
src/compat/endian.h [new file with mode: 0644]
src/compat/fcntl.h [new file with mode: 0644]
src/compat/glib.h [new file with mode: 0644]
src/compat/limits.h [new file with mode: 0644]
src/compat/logging.c [new file with mode: 0644]
src/compat/logging.h [new file with mode: 0644]
src/compat/memstream.h [new file with mode: 0644]
src/compat/mman.c [new file with mode: 0644]
src/compat/mman.h [new file with mode: 0644]
src/compat/socket.h [new file with mode: 0644]
src/compat/stdio.h [new file with mode: 0644]
src/compat/stdlib.h [new file with mode: 0644]
src/compat/string.h [new file with mode: 0644]
src/compat/time.h [new file with mode: 0644]
src/compat/unistd.h [new file with mode: 0644]
src/compat/utc.h [new file with mode: 0644]
src/compat/uuid.c [new file with mode: 0644]
src/compat/uuid.h [new file with mode: 0644]
src/ctf-writer/Makefile.am [new file with mode: 0644]
src/ctf-writer/assert-pre.h [new file with mode: 0644]
src/ctf-writer/attributes.c [new file with mode: 0644]
src/ctf-writer/attributes.h [new file with mode: 0644]
src/ctf-writer/clock-class.c [new file with mode: 0644]
src/ctf-writer/clock-class.h [new file with mode: 0644]
src/ctf-writer/clock.c [new file with mode: 0644]
src/ctf-writer/clock.h [new file with mode: 0644]
src/ctf-writer/event-class.c [new file with mode: 0644]
src/ctf-writer/event-class.h [new file with mode: 0644]
src/ctf-writer/event.c [new file with mode: 0644]
src/ctf-writer/event.h [new file with mode: 0644]
src/ctf-writer/field-path.c [new file with mode: 0644]
src/ctf-writer/field-path.h [new file with mode: 0644]
src/ctf-writer/field-types.c [new file with mode: 0644]
src/ctf-writer/field-types.h [new file with mode: 0644]
src/ctf-writer/field-wrapper.c [new file with mode: 0644]
src/ctf-writer/field-wrapper.h [new file with mode: 0644]
src/ctf-writer/fields.c [new file with mode: 0644]
src/ctf-writer/fields.h [new file with mode: 0644]
src/ctf-writer/functor.c [new file with mode: 0644]
src/ctf-writer/functor.h [new file with mode: 0644]
src/ctf-writer/logging.c [new file with mode: 0644]
src/ctf-writer/logging.h [new file with mode: 0644]
src/ctf-writer/object-pool.c [new file with mode: 0644]
src/ctf-writer/object-pool.h [new file with mode: 0644]
src/ctf-writer/object.c [new file with mode: 0644]
src/ctf-writer/object.h [new file with mode: 0644]
src/ctf-writer/resolve.c [new file with mode: 0644]
src/ctf-writer/resolve.h [new file with mode: 0644]
src/ctf-writer/stream-class.c [new file with mode: 0644]
src/ctf-writer/stream-class.h [new file with mode: 0644]
src/ctf-writer/stream.c [new file with mode: 0644]
src/ctf-writer/stream.h [new file with mode: 0644]
src/ctf-writer/trace.c [new file with mode: 0644]
src/ctf-writer/trace.h [new file with mode: 0644]
src/ctf-writer/utils.c [new file with mode: 0644]
src/ctf-writer/utils.h [new file with mode: 0644]
src/ctf-writer/validation.c [new file with mode: 0644]
src/ctf-writer/validation.h [new file with mode: 0644]
src/ctf-writer/values.c [new file with mode: 0644]
src/ctf-writer/values.h [new file with mode: 0644]
src/ctf-writer/visitor.c [new file with mode: 0644]
src/ctf-writer/visitor.h [new file with mode: 0644]
src/ctf-writer/writer.c [new file with mode: 0644]
src/ctf-writer/writer.h [new file with mode: 0644]
src/ctfser/Makefile.am [new file with mode: 0644]
src/ctfser/ctfser.c [new file with mode: 0644]
src/ctfser/ctfser.h [new file with mode: 0644]
src/ctfser/logging.c [new file with mode: 0644]
src/ctfser/logging.h [new file with mode: 0644]
src/fd-cache/Makefile.am [new file with mode: 0644]
src/fd-cache/fd-cache.c [new file with mode: 0644]
src/fd-cache/fd-cache.h [new file with mode: 0644]
src/fd-cache/logging.c [new file with mode: 0644]
src/fd-cache/logging.h [new file with mode: 0644]
src/lib/Makefile.am [new file with mode: 0644]
src/lib/assert-pre.h [new file with mode: 0644]
src/lib/babeltrace2.c [new file with mode: 0644]
src/lib/graph/Makefile.am [new file with mode: 0644]
src/lib/graph/component-class-sink-colander.c [new file with mode: 0644]
src/lib/graph/component-class-sink-colander.h [new file with mode: 0644]
src/lib/graph/component-class.c [new file with mode: 0644]
src/lib/graph/component-class.h [new file with mode: 0644]
src/lib/graph/component-filter.c [new file with mode: 0644]
src/lib/graph/component-filter.h [new file with mode: 0644]
src/lib/graph/component-sink.c [new file with mode: 0644]
src/lib/graph/component-sink.h [new file with mode: 0644]
src/lib/graph/component-source.c [new file with mode: 0644]
src/lib/graph/component-source.h [new file with mode: 0644]
src/lib/graph/component.c [new file with mode: 0644]
src/lib/graph/component.h [new file with mode: 0644]
src/lib/graph/connection.c [new file with mode: 0644]
src/lib/graph/connection.h [new file with mode: 0644]
src/lib/graph/graph.c [new file with mode: 0644]
src/lib/graph/graph.h [new file with mode: 0644]
src/lib/graph/iterator.c [new file with mode: 0644]
src/lib/graph/message/Makefile.am [new file with mode: 0644]
src/lib/graph/message/discarded-items.c [new file with mode: 0644]
src/lib/graph/message/discarded-items.h [new file with mode: 0644]
src/lib/graph/message/event.c [new file with mode: 0644]
src/lib/graph/message/event.h [new file with mode: 0644]
src/lib/graph/message/iterator.h [new file with mode: 0644]
src/lib/graph/message/message-iterator-inactivity.c [new file with mode: 0644]
src/lib/graph/message/message-iterator-inactivity.h [new file with mode: 0644]
src/lib/graph/message/message.c [new file with mode: 0644]
src/lib/graph/message/message.h [new file with mode: 0644]
src/lib/graph/message/packet.c [new file with mode: 0644]
src/lib/graph/message/packet.h [new file with mode: 0644]
src/lib/graph/message/stream-activity.c [new file with mode: 0644]
src/lib/graph/message/stream-activity.h [new file with mode: 0644]
src/lib/graph/message/stream.c [new file with mode: 0644]
src/lib/graph/message/stream.h [new file with mode: 0644]
src/lib/graph/port.c [new file with mode: 0644]
src/lib/graph/port.h [new file with mode: 0644]
src/lib/graph/query-executor.c [new file with mode: 0644]
src/lib/graph/query-executor.h [new file with mode: 0644]
src/lib/lib-logging.c [new file with mode: 0644]
src/lib/lib-logging.h [new file with mode: 0644]
src/lib/logging.c [new file with mode: 0644]
src/lib/object-pool.c [new file with mode: 0644]
src/lib/object-pool.h [new file with mode: 0644]
src/lib/object.h [new file with mode: 0644]
src/lib/plugin/Makefile.am [new file with mode: 0644]
src/lib/plugin/plugin-so.c [new file with mode: 0644]
src/lib/plugin/plugin-so.h [new file with mode: 0644]
src/lib/plugin/plugin.c [new file with mode: 0644]
src/lib/plugin/plugin.h [new file with mode: 0644]
src/lib/prio-heap/Makefile.am [new file with mode: 0644]
src/lib/prio-heap/prio-heap.c [new file with mode: 0644]
src/lib/prio-heap/prio-heap.h [new file with mode: 0644]
src/lib/property.h [new file with mode: 0644]
src/lib/trace-ir/Makefile.am [new file with mode: 0644]
src/lib/trace-ir/attributes.c [new file with mode: 0644]
src/lib/trace-ir/attributes.h [new file with mode: 0644]
src/lib/trace-ir/clock-class.c [new file with mode: 0644]
src/lib/trace-ir/clock-class.h [new file with mode: 0644]
src/lib/trace-ir/clock-snapshot-set.h [new file with mode: 0644]
src/lib/trace-ir/clock-snapshot.c [new file with mode: 0644]
src/lib/trace-ir/clock-snapshot.h [new file with mode: 0644]
src/lib/trace-ir/event-class.c [new file with mode: 0644]
src/lib/trace-ir/event-class.h [new file with mode: 0644]
src/lib/trace-ir/event.c [new file with mode: 0644]
src/lib/trace-ir/event.h [new file with mode: 0644]
src/lib/trace-ir/field-class.c [new file with mode: 0644]
src/lib/trace-ir/field-class.h [new file with mode: 0644]
src/lib/trace-ir/field-path.c [new file with mode: 0644]
src/lib/trace-ir/field-path.h [new file with mode: 0644]
src/lib/trace-ir/field-wrapper.c [new file with mode: 0644]
src/lib/trace-ir/field-wrapper.h [new file with mode: 0644]
src/lib/trace-ir/field.c [new file with mode: 0644]
src/lib/trace-ir/field.h [new file with mode: 0644]
src/lib/trace-ir/packet-context-field.c [new file with mode: 0644]
src/lib/trace-ir/packet.c [new file with mode: 0644]
src/lib/trace-ir/packet.h [new file with mode: 0644]
src/lib/trace-ir/resolve-field-path.c [new file with mode: 0644]
src/lib/trace-ir/resolve-field-path.h [new file with mode: 0644]
src/lib/trace-ir/stream-class.c [new file with mode: 0644]
src/lib/trace-ir/stream-class.h [new file with mode: 0644]
src/lib/trace-ir/stream.c [new file with mode: 0644]
src/lib/trace-ir/stream.h [new file with mode: 0644]
src/lib/trace-ir/trace-class.c [new file with mode: 0644]
src/lib/trace-ir/trace-class.h [new file with mode: 0644]
src/lib/trace-ir/trace.c [new file with mode: 0644]
src/lib/trace-ir/trace.h [new file with mode: 0644]
src/lib/trace-ir/utils.c [new file with mode: 0644]
src/lib/trace-ir/utils.h [new file with mode: 0644]
src/lib/util.c [new file with mode: 0644]
src/lib/value.c [new file with mode: 0644]
src/lib/value.h [new file with mode: 0644]
src/logging/LICENSE [new file with mode: 0644]
src/logging/Makefile.am [new file with mode: 0644]
src/logging/log.c [new file with mode: 0644]
src/logging/log.h [new file with mode: 0644]
src/plugins/Makefile.am [new file with mode: 0644]
src/plugins/ctf/Makefile.am [new file with mode: 0644]
src/plugins/ctf/common/Makefile.am [new file with mode: 0644]
src/plugins/ctf/common/bfcr/Makefile.am [new file with mode: 0644]
src/plugins/ctf/common/bfcr/bfcr.c [new file with mode: 0644]
src/plugins/ctf/common/bfcr/bfcr.h [new file with mode: 0644]
src/plugins/ctf/common/bfcr/btr.gdb [new file with mode: 0644]
src/plugins/ctf/common/bfcr/logging.c [new file with mode: 0644]
src/plugins/ctf/common/bfcr/logging.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/Makefile.am [new file with mode: 0644]
src/plugins/ctf/common/metadata/ast.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-resolve.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-translate.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-update-meanings.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-validate.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-visitors.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/ctf-meta.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/decoder.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/decoder.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/lexer.l [new file with mode: 0644]
src/plugins/ctf/common/metadata/logging.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/logging.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/objstack.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/objstack.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/parser.y [new file with mode: 0644]
src/plugins/ctf/common/metadata/scanner-symbols.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/scanner.h [new file with mode: 0644]
src/plugins/ctf/common/metadata/visitor-generate-ir.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/visitor-parent-links.c [new file with mode: 0644]
src/plugins/ctf/common/metadata/visitor-semantic-validator.c [new file with mode: 0644]
src/plugins/ctf/common/msg-iter/Makefile.am [new file with mode: 0644]
src/plugins/ctf/common/msg-iter/logging.c [new file with mode: 0644]
src/plugins/ctf/common/msg-iter/logging.h [new file with mode: 0644]
src/plugins/ctf/common/msg-iter/msg-iter.c [new file with mode: 0644]
src/plugins/ctf/common/msg-iter/msg-iter.h [new file with mode: 0644]
src/plugins/ctf/common/print.h [new file with mode: 0644]
src/plugins/ctf/common/utils/Makefile.am [new file with mode: 0644]
src/plugins/ctf/common/utils/logging.c [new file with mode: 0644]
src/plugins/ctf/common/utils/logging.h [new file with mode: 0644]
src/plugins/ctf/common/utils/utils.c [new file with mode: 0644]
src/plugins/ctf/common/utils/utils.h [new file with mode: 0644]
src/plugins/ctf/fs-sink/Makefile.am [new file with mode: 0644]
src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h [new file with mode: 0644]
src/plugins/ctf/fs-sink/fs-sink-stream.c [new file with mode: 0644]
src/plugins/ctf/fs-sink/fs-sink-stream.h [new file with mode: 0644]
src/plugins/ctf/fs-sink/fs-sink-trace.c [new file with mode: 0644]
src/plugins/ctf/fs-sink/fs-sink-trace.h [new file with mode: 0644]
src/plugins/ctf/fs-sink/fs-sink.c [new file with mode: 0644]
src/plugins/ctf/fs-sink/fs-sink.h [new file with mode: 0644]
src/plugins/ctf/fs-sink/logging.c [new file with mode: 0644]
src/plugins/ctf/fs-sink/logging.h [new file with mode: 0644]
src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c [new file with mode: 0644]
src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.h [new file with mode: 0644]
src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c [new file with mode: 0644]
src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.h [new file with mode: 0644]
src/plugins/ctf/fs-src/Makefile.am [new file with mode: 0644]
src/plugins/ctf/fs-src/data-stream-file.c [new file with mode: 0644]
src/plugins/ctf/fs-src/data-stream-file.h [new file with mode: 0644]
src/plugins/ctf/fs-src/file.c [new file with mode: 0644]
src/plugins/ctf/fs-src/file.h [new file with mode: 0644]
src/plugins/ctf/fs-src/fs.c [new file with mode: 0644]
src/plugins/ctf/fs-src/fs.h [new file with mode: 0644]
src/plugins/ctf/fs-src/logging.c [new file with mode: 0644]
src/plugins/ctf/fs-src/logging.h [new file with mode: 0644]
src/plugins/ctf/fs-src/lttng-index.h [new file with mode: 0644]
src/plugins/ctf/fs-src/metadata.c [new file with mode: 0644]
src/plugins/ctf/fs-src/metadata.h [new file with mode: 0644]
src/plugins/ctf/fs-src/query.c [new file with mode: 0644]
src/plugins/ctf/fs-src/query.h [new file with mode: 0644]
src/plugins/ctf/lttng-live/Makefile.am [new file with mode: 0644]
src/plugins/ctf/lttng-live/data-stream.c [new file with mode: 0644]
src/plugins/ctf/lttng-live/data-stream.h [new file with mode: 0644]
src/plugins/ctf/lttng-live/logging.c [new file with mode: 0644]
src/plugins/ctf/lttng-live/logging.h [new file with mode: 0644]
src/plugins/ctf/lttng-live/lttng-live.c [new file with mode: 0644]
src/plugins/ctf/lttng-live/lttng-live.h [new file with mode: 0644]
src/plugins/ctf/lttng-live/lttng-viewer-abi.h [new file with mode: 0644]
src/plugins/ctf/lttng-live/metadata.c [new file with mode: 0644]
src/plugins/ctf/lttng-live/metadata.h [new file with mode: 0644]
src/plugins/ctf/lttng-live/viewer-connection.c [new file with mode: 0644]
src/plugins/ctf/lttng-live/viewer-connection.h [new file with mode: 0644]
src/plugins/ctf/plugin.c [new file with mode: 0644]
src/plugins/ctf/print.h [new file with mode: 0644]
src/plugins/lttng-utils/Makefile.am [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/Makefile.am [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/bin-info.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/bin-info.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/crc32.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/crc32.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/debug-info.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/debug-info.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/dwarf.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/dwarf.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/logging.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/logging.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/trace-ir-data-copy.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/trace-ir-mapping.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/trace-ir-mapping.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/utils.c [new file with mode: 0644]
src/plugins/lttng-utils/debug-info/utils.h [new file with mode: 0644]
src/plugins/lttng-utils/plugin.c [new file with mode: 0644]
src/plugins/plugins-common.h [new file with mode: 0644]
src/plugins/text/Makefile.am [new file with mode: 0644]
src/plugins/text/dmesg/Makefile.am [new file with mode: 0644]
src/plugins/text/dmesg/dmesg.c [new file with mode: 0644]
src/plugins/text/dmesg/dmesg.h [new file with mode: 0644]
src/plugins/text/dmesg/logging.c [new file with mode: 0644]
src/plugins/text/dmesg/logging.h [new file with mode: 0644]
src/plugins/text/plugin.c [new file with mode: 0644]
src/plugins/text/pretty/Makefile.am [new file with mode: 0644]
src/plugins/text/pretty/logging.c [new file with mode: 0644]
src/plugins/text/pretty/logging.h [new file with mode: 0644]
src/plugins/text/pretty/pretty.c [new file with mode: 0644]
src/plugins/text/pretty/pretty.h [new file with mode: 0644]
src/plugins/text/pretty/print.c [new file with mode: 0644]
src/plugins/utils/Makefile.am [new file with mode: 0644]
src/plugins/utils/counter/Makefile.am [new file with mode: 0644]
src/plugins/utils/counter/counter.c [new file with mode: 0644]
src/plugins/utils/counter/counter.h [new file with mode: 0644]
src/plugins/utils/counter/logging.c [new file with mode: 0644]
src/plugins/utils/counter/logging.h [new file with mode: 0644]
src/plugins/utils/dummy/Makefile.am [new file with mode: 0644]
src/plugins/utils/dummy/dummy.c [new file with mode: 0644]
src/plugins/utils/dummy/dummy.h [new file with mode: 0644]
src/plugins/utils/muxer/Makefile.am [new file with mode: 0644]
src/plugins/utils/muxer/logging.c [new file with mode: 0644]
src/plugins/utils/muxer/logging.h [new file with mode: 0644]
src/plugins/utils/muxer/muxer.c [new file with mode: 0644]
src/plugins/utils/muxer/muxer.h [new file with mode: 0644]
src/plugins/utils/plugin.c [new file with mode: 0644]
src/plugins/utils/trimmer/Makefile.am [new file with mode: 0644]
src/plugins/utils/trimmer/logging.c [new file with mode: 0644]
src/plugins/utils/trimmer/logging.h [new file with mode: 0644]
src/plugins/utils/trimmer/trimmer.c [new file with mode: 0644]
src/plugins/utils/trimmer/trimmer.h [new file with mode: 0644]
src/python-plugin-provider/Makefile.am [new file with mode: 0644]
src/python-plugin-provider/python-plugin-provider.c [new file with mode: 0644]
src/python-plugin-provider/python-plugin-provider.h [new file with mode: 0644]
tests/bindings/python/bt2/test_python_bt2.in
tests/lib/Makefile.am
tests/lib/test-plugin-plugins/Makefile.am
tests/lib/test-plugin-plugins/sfs.c
tests/lib/test_bitfield.c
tests/lib/test_bt_values.c
tests/lib/test_ctf_writer.c
tests/lib/test_graph_topo.c
tests/lib/test_plugin.c
tests/lib/test_trace_ir_ref.c
tests/lib/trace-ir/test_trace_ir.in
tests/plugins/Makefile.am
tests/plugins/test_bin_info.c
tests/plugins/test_lttng_utils_debug_info.in
tests/python-plugin-provider/test_python_plugin_provider.in
tests/python-plugin-provider/test_python_plugin_provider_env.in
tests/utils/common.sh.in
tests/utils/test_python_bt2_env.in

index 9c71bb9d64ee4ba9ccf3845846516a90effb2b8e..b460d1118b72886644b49db2dc0ad326807b65df 100644 (file)
@@ -58,18 +58,18 @@ ctf-lexer.c
 ctf-parser.c
 ctf-parser.h
 ctf-parser-test
 ctf-parser.c
 ctf-parser.h
 ctf-parser-test
-plugins/ctf/common/metadata/lexer.c
-plugins/ctf/common/metadata/parser.c
-plugins/ctf/common/metadata/parser.h
-plugins/ctf/common/metadata/parser.output
-/cli/babeltrace2
-/cli/babeltrace2.bin
-/cli/babeltrace2-log
-/cli/babeltrace2-log.bin
-/include/config.h
-/include/config.h.in
-/include/version.i
-/include/version.i.tmp
+/src/plugins/ctf/common/metadata/lexer.c
+/src/plugins/ctf/common/metadata/parser.c
+/src/plugins/ctf/common/metadata/parser.h
+/src/plugins/ctf/common/metadata/parser.output
+/src/cli/babeltrace2
+/src/cli/babeltrace2.bin
+/src/cli/babeltrace2-log
+/src/cli/babeltrace2-log.bin
+/src/common/config.h
+/src/common/config.h.in
+/src/common/version.i
+/src/common/version.i.tmp
 /config.status
 *.log
 aclocal.m4
 /config.status
 *.log
 aclocal.m4
@@ -87,8 +87,8 @@ config/
 core
 stamp-h1
 __pycache__
 core
 stamp-h1
 __pycache__
-/babeltrace2.pc
-/babeltrace2-ctf-writer.pc
+/src/babeltrace2.pc
+/src/babeltrace2-ctf-writer.pc
 TAGS
 cscope*
 doc/api/Doxyfile
 TAGS
 cscope*
 doc/api/Doxyfile
index 32fd796343b5b669aadf69ca9bd37686cd1f89f4..3489e0e1f5b32e472a3b9e24ce6e4792b2a5a573 100644 (file)
@@ -284,18 +284,18 @@ The logging API headers are:
     Public header which a library user can use to control and read
     libbabeltrace2's current log level.
 
     Public header which a library user can use to control and read
     libbabeltrace2's current log level.
 
-`<babeltrace2/logging-internal.h>`::
+`<logging/log.h>`::
     Internal, generic logging API which you can use in any Babeltrace
     subproject. This is the translation of `zf_log.h`.
 
     Internal, generic logging API which you can use in any Babeltrace
     subproject. This is the translation of `zf_log.h`.
 
-`<babeltrace2/lib-logging-internal.h>`::
+`<lib/lib-logging.h>`::
     Specific internal header to use within the library. This header
     defines `BT_LOG_OUTPUT_LEVEL` to a custom, library-wide hidden
     symbol which is the library's current log level before including
     Specific internal header to use within the library. This header
     defines `BT_LOG_OUTPUT_LEVEL` to a custom, library-wide hidden
     symbol which is the library's current log level before including
-    `<babeltrace2/logging-internal.h>`.
+    `<logging/log.h>`.
 
 
-Do not include `<babeltrace2/logging-internal.h>` or
-`<babeltrace2/lib-logging-internal.h>` in a header which contains logging
+Do not include `<logging/log.h>` or
+`<lib/lib-logging.h>` in a header which contains logging
 statements: this header could be included in source files which define a
 different <<choose-a-tag,tag>>, for example. See
 <<logging-instrument-header, Instrument a C header file>>.
 statements: this header could be included in source files which define a
 different <<choose-a-tag,tag>>, for example. See
 <<logging-instrument-header, Instrument a C header file>>.
@@ -355,10 +355,10 @@ get the configured minimal log level.
 `_bt_log_global_output_lvl` symbol. In practice, we never use this
 symbol, and always make sure that `BT_LOG_OUTPUT_LEVEL` is defined to a
 module-wise or subproject-wise hidden symbol before including
 `_bt_log_global_output_lvl` symbol. In practice, we never use this
 symbol, and always make sure that `BT_LOG_OUTPUT_LEVEL` is defined to a
 module-wise or subproject-wise hidden symbol before including
-`<babeltrace2/logging-internal.h>`. In the library,
-`<babeltrace2/lib-logging-internal.h>` does this job: just include this
+`<logging/log.h>`. In the library,
+`<lib/lib-logging.h>` does this job: just include this
 header which defines `BT_LOG_OUTPUT_LEVEL` to the appropriate symbol
 header which defines `BT_LOG_OUTPUT_LEVEL` to the appropriate symbol
-before it includes `<babeltrace2/logging-internal.h>`. In plugins, for
+before it includes `<logging/log.h>`. In plugins, for
 example, there is one log level per component class, which makes log
 filtering easier during execution.
 +
 example, there is one log level per component class, which makes log
 filtering easier during execution.
 +
@@ -593,7 +593,7 @@ Follow those steps to make your module loggable:
  */
 
 #define BT_LOG_OUTPUT_LEVEL my_module_log_level
  */
 
 #define BT_LOG_OUTPUT_LEVEL my_module_log_level
-#include <babeltrace2/logging-internal.h>
+#include "logging/log.h"
 
 BT_LOG_INIT_LOG_LEVEL(my_module_log_level, "BABELTRACE_MY_MODULE_LOG_LEVEL");
 ----
 
 BT_LOG_INIT_LOG_LEVEL(my_module_log_level, "BABELTRACE_MY_MODULE_LOG_LEVEL");
 ----
@@ -639,7 +639,7 @@ the environment variable and sets the log level symbol accordingly.
  */
 
 #define BT_LOG_OUTPUT_LEVEL my_module_log_level
  */
 
 #define BT_LOG_OUTPUT_LEVEL my_module_log_level
-#include <babeltrace2/logging-internal.h>
+#include "logging/log.h"
 
 BT_LOG_LEVEL_EXTERN_SYMBOL(my_module_log_level);
 
 
 BT_LOG_LEVEL_EXTERN_SYMBOL(my_module_log_level);
 
diff --git a/LICENSE b/LICENSE
index 76475d5f6577f19c115886b8b0583e1202dd2f8c..dae5d84d677f6639befc37af80f5f4b6d3b38ef0 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -16,7 +16,7 @@ per-file license. See gpl-2.0.txt for details.
 
 * LGPLv2.1
 
 
 * LGPLv2.1
 
-The file include/babeltrace/list-internal.h is licensed under LGPLv2.1. It only
+The file src/bt-list.h is licensed under LGPLv2.1. It only
 contains trivial static inline functions and macros, and, therefore,
 including it does not make babeltrace a derivative work on this header.
 Please refer to the LGPLv2.1 license for details.
 contains trivial static inline functions and macros, and, therefore,
 including it does not make babeltrace a derivative work on this header.
 Please refer to the LGPLv2.1 license for details.
index 938dc75bbcdf23b7bdf868dfcfc9d0e5d0c2aaf5..745ff31e1cac9d32169c20f941a893222d9d9bba 100644 (file)
@@ -1,18 +1,9 @@
 ACLOCAL_AMFLAGS = -I m4
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = include              \
-       common                  \
-       ctfser                  \
-       fd-cache                \
-       compat                  \
-       logging                 \
-       lib                     \
-       python-plugin-provider  \
-       ctf-writer              \
-       plugins                 \
-       cli                     \
-       bindings                \
-       doc                     \
+SUBDIRS = \
+       include \
+       src \
+       doc \
        tests
 
 # Directories added to EXTRA_DIST will be recursively copied to the distribution.
        tests
 
 # Directories added to EXTRA_DIST will be recursively copied to the distribution.
@@ -24,9 +15,6 @@ dist_doc_DATA = ChangeLog LICENSE mit-license.txt gpl-2.0.txt \
 
 dist_noinst_DATA = CodingStyle
 
 
 dist_noinst_DATA = CodingStyle
 
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = babeltrace2.pc babeltrace2-ctf-writer.pc
-
 # This is a convenience target, it's not part of the build process.
 CONTRIBUTING.html: CONTRIBUTING.adoc
        $(ASCIIDOC) --verbose -a source-highlighter=pygments $<
 # This is a convenience target, it's not part of the build process.
 CONTRIBUTING.html: CONTRIBUTING.adoc
        $(ASCIIDOC) --verbose -a source-highlighter=pygments $<
diff --git a/babeltrace2-ctf-writer.pc.in b/babeltrace2-ctf-writer.pc.in
deleted file mode 100644 (file)
index 504d859..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Babeltrace CTF parser
-Description: libbabeltrace2-ctf provides the specific bits necessary to write a Common Trace Format (CTF) trace.
-Version: @PACKAGE_VERSION@
-Requires:
-Requires.private: uuid popt
-Libs: -L${libdir} -lbabeltrace2-ctf-writer
-Cflags: -I${includedir}
-
diff --git a/babeltrace2.pc.in b/babeltrace2.pc.in
deleted file mode 100644 (file)
index 646aeb4..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Babeltrace
-Description: libbabeltrace2 provides a reader for trace files, reading mainly the
-Common Trace Format (CTF).
-Version: @PACKAGE_VERSION@
-Requires:
-Requires.private: uuid popt
-Libs: -L${libdir} -lbabeltrace2
-Cflags: -I${includedir}
-
diff --git a/bindings/Makefile.am b/bindings/Makefile.am
deleted file mode 100644 (file)
index 773e43a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-if ENABLE_PYTHON_BINDINGS
-SUBDIRS = python
-endif
diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am
deleted file mode 100644 (file)
index f3cec07..0000000
+++ /dev/null
@@ -1 +0,0 @@
-SUBDIRS = bt2
diff --git a/bindings/python/bt2/.gitignore b/bindings/python/bt2/.gitignore
deleted file mode 100644 (file)
index b893bce..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-bt2/__init__.py
-bt2/native_bt.py
-bt2/native_bt_wrap.c
-build
-build-python-bindings.stamp
-installed_files.txt
-setup.py
diff --git a/bindings/python/bt2/Makefile.am b/bindings/python/bt2/Makefile.am
deleted file mode 100644 (file)
index 31d9e17..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-# Since the shared object used by the python bindings is not built with
-# libtool, we need to add the directory containing libbabeltrace2 to the
-# linker path.
-AM_LDFLAGS=-L$(top_builddir)/lib/.libs
-
-INSTALLED_FILES=$(builddir)/installed_files.txt
-
-STATIC_BINDINGS_DEPS =                                 \
-       bt2/logging.c                                   \
-       bt2/logging.h                                   \
-       bt2/native_bt_clock_class.i                     \
-       bt2/native_bt_clock_snapshot.i                  \
-       bt2/native_bt_component_class.i                 \
-       bt2/native_bt_component.i                       \
-       bt2/native_bt_connection.i                      \
-       bt2/native_bt_event_class.i                     \
-       bt2/native_bt_event.i                           \
-       bt2/native_bt_field_class.i                     \
-       bt2/native_bt_field_path.i                      \
-       bt2/native_bt_field.i                           \
-       bt2/native_bt_graph.i                           \
-       bt2/native_bt.i                                 \
-       bt2/native_bt_logging.i                         \
-       bt2/native_bt_message.i                         \
-       bt2/native_bt_notifier.i                        \
-       bt2/native_bt_packet.i                          \
-       bt2/native_bt_plugin.i                          \
-       bt2/native_bt_port.i                            \
-       bt2/native_bt_query_exec.i                      \
-       bt2/native_bt_stream_class.i                    \
-       bt2/native_bt_stream.i                          \
-       bt2/native_bt_trace_class.i                     \
-       bt2/native_bt_trace.i                           \
-       bt2/native_bt_value.i                           \
-       bt2/native_bt_version.i                         \
-       bt2/clock_class.py                              \
-       bt2/clock_snapshot.py                           \
-       bt2/component.py                                \
-       bt2/connection.py                               \
-       bt2/event_class.py                              \
-       bt2/event.py                                    \
-       bt2/field.py                                    \
-       bt2/field_class.py                              \
-       bt2/field_path.py                               \
-       bt2/graph.py                                    \
-       bt2/logging.py                                  \
-       bt2/message_iterator.py                         \
-       bt2/message.py                                  \
-       bt2/object.py                                   \
-       bt2/packet.py                                   \
-       bt2/plugin.py                                   \
-       bt2/port.py                                     \
-       bt2/py_plugin.py                                \
-       bt2/query_executor.py                           \
-       bt2/stream_class.py                             \
-       bt2/stream.py                                   \
-       bt2/trace.py                                    \
-       bt2/trace_class.py                              \
-       bt2/trace_collection_message_iterator.py        \
-       bt2/utils.py                                    \
-       bt2/value.py
-
-GENERATED_BINDINGS_DEPS =      \
-       bt2/__init__.py         \
-       setup.py
-
-BUILD_FLAGS=CC="$(CC)" \
-               CFLAGS="$(GLIB_CFLAGS) $(AM_CFLAGS) $(CFLAGS)" \
-               CPPFLAGS="$(AM_CPPFLAGS) $(CPPFLAGS)" \
-               LDFLAGS="$(AM_LDFLAGS) $(LDFLAGS) $(GLIB_LIBS) $(LIBS)"
-
-all-local: build-python-bindings.stamp
-
-copy-static-deps.stamp: $(addprefix $(srcdir)/, $(STATIC_BINDINGS_DEPS))
-       @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
-               for file in $(STATIC_BINDINGS_DEPS); do \
-                       cp -f $(srcdir)/$$file $(builddir)/$$file; \
-               done; \
-       fi
-       touch $@
-
-build-python-bindings.stamp: copy-static-deps.stamp $(GENERATED_BINDINGS_DEPS)
-       $(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build_ext --force --swig "$(SWIG)"
-       $(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build --force
-       touch $@
-
-install-exec-local: build-python-bindings.stamp
-       @opts="--prefix=$(prefix) --record $(INSTALLED_FILES) --verbose --no-compile $(DISTSETUPOPTS)"; \
-       if [ "$(DESTDIR)" != "" ]; then \
-               opts="$$opts --root=$(DESTDIR)"; \
-       fi; \
-       $(PYTHON) $(builddir)/setup.py install $$opts;
-
-clean-local:
-       rm -rf $(builddir)/build
-       @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
-               for file in $(STATIC_BINDINGS_DEPS); do \
-                       rm -f $(builddir)/$$file; \
-               done; \
-       fi
-
-# Distutils' setup.py does not include an uninstall target, we thus need to do
-# it manually. We save the path of the files that were installed during the install target
-# and delete them during the uninstallation.
-uninstall-local:
-       if [ "$(DESTDIR)" != "" ]; then \
-               $(SED) -i "s|^|$(DESTDIR)/|g" $(INSTALLED_FILES); \
-       fi
-       cat $(INSTALLED_FILES) | xargs rm -rf || true
-       $(GREP) "__init__.py" $(INSTALLED_FILES) | xargs dirname | xargs rm -rf || true
-       rm -f $(INSTALLED_FILES)
-
-# distribute: extra Python modules and SWIG interface files
-EXTRA_DIST = $(STATIC_BINDINGS_DEPS)
-
-# clean: generated C and Python files (by SWIG)
-CLEANFILES = bt2/native_bt.py bt2/native_bt_wrap.c build-python-bindings.stamp copy-static-deps.stamp
diff --git a/bindings/python/bt2/bt2/__init__.py.in b/bindings/python/bt2/bt2/__init__.py.in
deleted file mode 100644 (file)
index f80cf65..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-__version__ = '@PACKAGE_VERSION@'
-
-
-from bt2.clock_class import *
-from bt2.clock_snapshot import *
-from bt2.component import *
-from bt2.component import _FilterComponent
-from bt2.component import _GenericFilterComponentClass
-from bt2.component import _GenericSinkComponentClass
-from bt2.component import _GenericSourceComponentClass
-from bt2.component import _SinkComponent
-from bt2.component import _SourceComponent
-from bt2.component import _UserFilterComponent
-from bt2.component import _UserSinkComponent
-from bt2.component import _UserSourceComponent
-from bt2.connection import *
-from bt2.connection import _Connection
-from bt2.event import _Event
-from bt2.event_class import *
-from bt2.field_class import *
-from bt2.field_path import *
-from bt2.field import *
-from bt2.graph import *
-from bt2.logging import *
-from bt2.message import *
-from bt2.message import _DiscardedEventsMessage
-from bt2.message import _DiscardedPacketsMessage
-from bt2.message_iterator import *
-from bt2.message_iterator import _UserMessageIterator
-from bt2.packet import _Packet
-from bt2.plugin import *
-from bt2.port import *
-from bt2.py_plugin import *
-from bt2.query_executor import *
-from bt2.stream import _Stream
-from bt2.stream_class import *
-from bt2.trace import *
-from bt2.trace_class import *
-from bt2.trace_collection_message_iterator import *
-from bt2.value import *
-from bt2.value import _Value
-from bt2.value import _IntegerValue
-
-
-class Error(Exception):
-    pass
-
-
-class CreationError(Error):
-    '''Raised when object creation fails due to memory issues.'''
-
-
-class InvalidQueryObject(Error):
-    pass
-
-
-class InvalidQueryParams(Error):
-    pass
-
-
-class TryAgain(Exception):
-    pass
-
-
-class Stop(StopIteration):
-    pass
-
-
-class PortConnectionRefused(Exception):
-    pass
-
-
-class IncompleteUserClass(Error):
-    pass
-
-
-class GraphCanceled(Exception):
-    pass
-
-
-class QueryExecutorCanceled(Exception):
-    pass
-
-
-class NonexistentClockSnapshot(Error):
-    pass
-
-
-class _ListenerHandle:
-    def __init__(self, listener_id, obj):
-        self._listener_id = listener_id
-        self._obj = obj
-
-
-def _init_and_register_exit():
-    import bt2.native_bt as _native_bt
-    import atexit
-
-    atexit.register(_native_bt.py3_cc_exit_handler)
-    version = (_native_bt.version_get_major(), _native_bt.version_get_minor(),
-               _native_bt.version_get_patch(), _native_bt.version_get_extra())
-    _native_bt.py3_cc_init_from_bt2()
-
-
-_init_and_register_exit()
-
-
-try:
-    del native_bt
-except:
-    pass
diff --git a/bindings/python/bt2/bt2/clock_class.py b/bindings/python/bt2/bt2/clock_class.py
deleted file mode 100644 (file)
index 59a93cd..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2
-import uuid as uuidp
-
-
-class ClockClassOffset:
-    def __init__(self, seconds=0, cycles=0):
-        utils._check_int64(seconds)
-        utils._check_int64(cycles)
-        self._seconds = seconds
-        self._cycles = cycles
-
-    @property
-    def seconds(self):
-        return self._seconds
-
-    @property
-    def cycles(self):
-        return self._cycles
-
-    def __eq__(self, other):
-        if not isinstance(other, self.__class__):
-            # not comparing apples to apples
-            return False
-
-        return (self.seconds, self.cycles) == (other.seconds, other.cycles)
-
-
-class _ClockClass(object._SharedObject):
-    _get_ref = staticmethod(native_bt.clock_class_get_ref)
-    _put_ref = staticmethod(native_bt.clock_class_put_ref)
-
-    @property
-    def name(self):
-        return native_bt.clock_class_get_name(self._ptr)
-
-    def _name(self, name):
-        utils._check_str(name)
-        ret = native_bt.clock_class_set_name(self._ptr, name)
-        utils._handle_ret(ret, "cannot set clock class object's name")
-
-    _name = property(fset=_name)
-
-    @property
-    def description(self):
-        return native_bt.clock_class_get_description(self._ptr)
-
-    def _description(self, description):
-        utils._check_str(description)
-        ret = native_bt.clock_class_set_description(self._ptr, description)
-        utils._handle_ret(ret, "cannot set clock class object's description")
-
-    _description = property(fset=_description)
-
-    @property
-    def frequency(self):
-        return native_bt.clock_class_get_frequency(self._ptr)
-
-    def _frequency(self, frequency):
-        utils._check_uint64(frequency)
-        native_bt.clock_class_set_frequency(self._ptr, frequency)
-
-    _frequency = property(fset=_frequency)
-
-    @property
-    def precision(self):
-        precision = native_bt.clock_class_get_precision(self._ptr)
-        return precision
-
-    def _precision(self, precision):
-        utils._check_uint64(precision)
-        native_bt.clock_class_set_precision(self._ptr, precision)
-
-    _precision = property(fset=_precision)
-
-    @property
-    def offset(self):
-        offset_s, offset_cycles = native_bt.clock_class_get_offset(self._ptr)
-        return ClockClassOffset(offset_s, offset_cycles)
-
-    def _offset(self, offset):
-        utils._check_type(offset, ClockClassOffset)
-        native_bt.clock_class_set_offset(self._ptr, offset.seconds, offset.cycles)
-
-    _offset = property(fset=_offset)
-
-    @property
-    def origin_is_unix_epoch(self):
-        return native_bt.clock_class_origin_is_unix_epoch(self._ptr)
-
-    def _origin_is_unix_epoch(self, origin_is_unix_epoch):
-        utils._check_bool(origin_is_unix_epoch)
-        native_bt.clock_class_set_origin_is_unix_epoch(self._ptr, int(origin_is_unix_epoch))
-
-    _origin_is_unix_epoch = property(fset=_origin_is_unix_epoch)
-
-    @property
-    def uuid(self):
-        uuid_bytes = native_bt.clock_class_get_uuid(self._ptr)
-
-        if uuid_bytes is None:
-            return
-
-        return uuidp.UUID(bytes=uuid_bytes)
-
-    def _uuid(self, uuid):
-        utils._check_type(uuid, uuidp.UUID)
-        native_bt.clock_class_set_uuid(self._ptr, uuid.bytes)
-
-    _uuid = property(fset=_uuid)
-
-    def cycles_to_ns_from_origin(self, cycles):
-        utils._check_uint64(cycles)
-        ret, ns = native_bt.clock_class_cycles_to_ns_from_origin(self._ptr, cycles)
-
-        error_msg = "cannot convert clock value to nanoseconds from origin for given clock class"
-
-        if ret == native_bt.CLOCK_CLASS_STATUS_OVERFLOW:
-            raise OverflowError(error_msg)
-
-        utils._handle_ret(ret, error_msg)
-        return ns
diff --git a/bindings/python/bt2/bt2/clock_snapshot.py b/bindings/python/bt2/bt2/clock_snapshot.py
deleted file mode 100644 (file)
index 4bf37d6..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import numbers
-import bt2
-import functools
-
-
-class _BaseClockSnapshot(object._UniqueObject):
-    @property
-    def clock_class(self):
-        cc_ptr = native_bt.clock_snapshot_borrow_clock_class_const(self._ptr)
-        assert cc_ptr is not None
-        return bt2.clock_class._ClockClass._create_from_ptr_and_get_ref(cc_ptr)
-
-
-@functools.total_ordering
-class _ClockSnapshot(_BaseClockSnapshot):
-    @property
-    def value(self):
-        return native_bt.clock_snapshot_get_value(self._ptr)
-
-    @property
-    def ns_from_origin(self):
-        ret, ns = native_bt.clock_snapshot_get_ns_from_origin(self._ptr)
-
-        if ret == native_bt.CLOCK_SNAPSHOT_STATUS_OVERFLOW:
-            raise OverflowError("cannot get clock snapshot's nanoseconds from origin")
-
-        return ns
-
-    def __eq__(self, other):
-        if not isinstance(other, numbers.Integral):
-            return NotImplemented
-
-        return self.value == int(other)
-
-    def __lt__(self, other):
-        if not isinstance(other, numbers.Integral):
-            return NotImplemented
-
-        return self.value < int(other)
-
-
-class _UnknownClockSnapshot(_BaseClockSnapshot):
-    pass
-
-
-class _InfiniteClockSnapshot(_BaseClockSnapshot):
-    pass
diff --git a/bindings/python/bt2/bt2/component.py b/bindings/python/bt2/bt2/component.py
deleted file mode 100644 (file)
index 3480f65..0000000
+++ /dev/null
@@ -1,785 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.message_iterator
-import collections.abc
-import bt2.value
-import traceback
-import bt2.port
-import sys
-import bt2
-import os
-
-
-_env_var = os.environ.get('BABELTRACE_PYTHON_BT2_NO_TRACEBACK')
-_NO_PRINT_TRACEBACK = _env_var == '1'
-
-
-# This class wraps a component class pointer. This component class could
-# have been created by Python code, but since we only have the pointer,
-# we can only wrap it in a generic way and lose the original Python
-# class.
-#
-# Subclasses must implement some methods that this base class uses:
-#
-#   - _as_component_class_ptr: static method, convert the passed component class
-#     pointer to a 'bt_component_class *'.
-
-class _GenericComponentClass(object._SharedObject):
-    @property
-    def name(self):
-        ptr = self._as_component_class_ptr(self._ptr)
-        name = native_bt.component_class_get_name(ptr)
-        assert name is not None
-        return name
-
-    @property
-    def description(self):
-        ptr = self._as_component_class_ptr(self._ptr)
-        return native_bt.component_class_get_description(ptr)
-
-    @property
-    def help(self):
-        ptr = self._as_component_class_ptr(self._ptr)
-        return native_bt.component_class_get_help(ptr)
-
-    def _component_class_ptr(self):
-        return self._as_component_class_ptr(self._ptr)
-
-    def __eq__(self, other):
-        if not isinstance(other, _GenericComponentClass):
-            try:
-                if not issubclass(other, _UserComponent):
-                    return False
-            except TypeError:
-                return False
-
-        return self.addr == other.addr
-
-
-class _GenericSourceComponentClass(_GenericComponentClass):
-    _get_ref = staticmethod(native_bt.component_class_source_get_ref)
-    _put_ref = staticmethod(native_bt.component_class_source_put_ref)
-    _as_component_class_ptr = staticmethod(native_bt.component_class_source_as_component_class)
-
-
-class _GenericFilterComponentClass(_GenericComponentClass):
-    _get_ref = staticmethod(native_bt.component_class_filter_get_ref)
-    _put_ref = staticmethod(native_bt.component_class_filter_put_ref)
-    _as_component_class_ptr = staticmethod(native_bt.component_class_filter_as_component_class)
-
-
-class _GenericSinkComponentClass(_GenericComponentClass):
-    _get_ref = staticmethod(native_bt.component_class_sink_get_ref)
-    _put_ref = staticmethod(native_bt.component_class_sink_put_ref)
-    _as_component_class_ptr = staticmethod(native_bt.component_class_sink_as_component_class)
-
-
-def _handle_component_status(status, gen_error_msg):
-    if status == native_bt.SELF_COMPONENT_STATUS_END:
-        raise bt2.Stop
-    elif status == native_bt.SELF_COMPONENT_STATUS_AGAIN:
-        raise bt2.TryAgain
-    elif status == native_bt.SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION:
-        raise bt2.PortConnectionRefused
-    elif status < 0:
-        raise bt2.Error(gen_error_msg)
-
-
-class _PortIterator(collections.abc.Iterator):
-    def __init__(self, comp_ports):
-        self._comp_ports = comp_ports
-        self._at = 0
-
-    def __next__(self):
-        if self._at == len(self._comp_ports):
-            raise StopIteration
-
-        comp_ports = self._comp_ports
-        comp_ptr = comp_ports._component_ptr
-
-        port_ptr = comp_ports._borrow_port_ptr_at_index(comp_ptr, self._at)
-        assert port_ptr is not None
-
-        name = native_bt.port_get_name(comp_ports._port_pycls._as_port_ptr(port_ptr))
-        assert name is not None
-
-        self._at += 1
-        return name
-
-
-class _ComponentPorts(collections.abc.Mapping):
-
-    # component_ptr is a bt_component_source *, bt_component_filter * or
-    # bt_component_sink *.  Its type must match the type expected by the
-    # functions passed as arguments.
-
-    def __init__(self, component_ptr,
-                 borrow_port_ptr_by_name,
-                 borrow_port_ptr_at_index,
-                 get_port_count,
-                 port_pycls):
-        self._component_ptr = component_ptr
-        self._borrow_port_ptr_by_name = borrow_port_ptr_by_name
-        self._borrow_port_ptr_at_index = borrow_port_ptr_at_index
-        self._get_port_count = get_port_count
-        self._port_pycls = port_pycls
-
-    def __getitem__(self, key):
-        utils._check_str(key)
-        port_ptr = self._borrow_port_ptr_by_name(self._component_ptr, key)
-
-        if port_ptr is None:
-            raise KeyError(key)
-
-        return self._port_pycls._create_from_ptr_and_get_ref(port_ptr)
-
-    def __len__(self):
-        count = self._get_port_count(self._component_ptr)
-        assert count >= 0
-        return count
-
-    def __iter__(self):
-        return _PortIterator(self)
-
-
-# This class holds the methods which are common to both generic
-# component objects and Python user component objects.
-#
-# Subclasses must provide these methods or property:
-#
-#   - _borrow_component_class_ptr: static method, must return a pointer to the
-#     specialized component class (e.g. 'bt_component_class_sink *') of the
-#     passed specialized component pointer (e.g. 'bt_component_sink *').
-#   - _comp_cls_type: property, one of the native_bt.COMPONENT_CLASS_TYPE_*
-#     constants.
-#   - _as_component_ptr: static method, must return the passed specialized
-#     component pointer (e.g. 'bt_component_sink *') as a 'bt_component *'.
-
-class _Component:
-    @property
-    def name(self):
-        ptr = self._as_component_ptr(self._ptr)
-        name = native_bt.component_get_name(ptr)
-        assert name is not None
-        return name
-
-    @property
-    def cls(self):
-        cc_ptr = self._borrow_component_class_ptr(self._ptr)
-        assert cc_ptr is not None
-        return _create_component_class_from_ptr_and_get_ref(cc_ptr, self._comp_cls_type)
-
-    def __eq__(self, other):
-        if not hasattr(other, 'addr'):
-            return False
-
-        return self.addr == other.addr
-
-
-class _SourceComponent(_Component):
-    _borrow_component_class_ptr = staticmethod(native_bt.component_source_borrow_class_const)
-    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE
-    _as_component_class_ptr = staticmethod(native_bt.component_class_source_as_component_class)
-    _as_component_ptr = staticmethod(native_bt.component_source_as_component_const)
-
-
-class _FilterComponent(_Component):
-    _borrow_component_class_ptr = staticmethod(native_bt.component_filter_borrow_class_const)
-    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_FILTER
-    _as_component_class_ptr = staticmethod(native_bt.component_class_filter_as_component_class)
-    _as_component_ptr = staticmethod(native_bt.component_filter_as_component_const)
-
-
-class _SinkComponent(_Component):
-    _borrow_component_class_ptr = staticmethod(native_bt.component_sink_borrow_class_const)
-    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_SINK
-    _as_component_class_ptr = staticmethod(native_bt.component_class_sink_as_component_class)
-    _as_component_ptr = staticmethod(native_bt.component_sink_as_component_const)
-
-
-# This is analogous to _GenericSourceComponentClass, but for source
-# component objects.
-class _GenericSourceComponent(object._SharedObject, _SourceComponent):
-    _get_ref = staticmethod(native_bt.component_source_get_ref)
-    _put_ref = staticmethod(native_bt.component_source_put_ref)
-
-    @property
-    def output_ports(self):
-        return _ComponentPorts(self._ptr,
-                               native_bt.component_source_borrow_output_port_by_name_const,
-                               native_bt.component_source_borrow_output_port_by_index_const,
-                               native_bt.component_source_get_output_port_count,
-                               bt2.port._OutputPort)
-
-
-# This is analogous to _GenericFilterComponentClass, but for filter
-# component objects.
-class _GenericFilterComponent(object._SharedObject, _FilterComponent):
-    _get_ref = staticmethod(native_bt.component_filter_get_ref)
-    _put_ref = staticmethod(native_bt.component_filter_put_ref)
-
-    @property
-    def output_ports(self):
-        return _ComponentPorts(self._ptr,
-                               native_bt.component_filter_borrow_output_port_by_name_const,
-                               native_bt.component_filter_borrow_output_port_by_index_const,
-                               native_bt.component_filter_get_output_port_count,
-                               bt2.port._OutputPort)
-
-    @property
-    def input_ports(self):
-        return _ComponentPorts(self._ptr,
-                               native_bt.component_filter_borrow_input_port_by_name_const,
-                               native_bt.component_filter_borrow_input_port_by_index_const,
-                               native_bt.component_filter_get_input_port_count,
-                               bt2.port._InputPort)
-
-
-# This is analogous to _GenericSinkComponentClass, but for sink
-# component objects.
-class _GenericSinkComponent(object._SharedObject, _SinkComponent):
-    _get_ref = staticmethod(native_bt.component_sink_get_ref)
-    _put_ref = staticmethod(native_bt.component_sink_put_ref)
-
-    @property
-    def input_ports(self):
-        return _ComponentPorts(self._ptr,
-                               native_bt.component_sink_borrow_input_port_by_name_const,
-                               native_bt.component_sink_borrow_input_port_by_index_const,
-                               native_bt.component_sink_get_input_port_count,
-                               bt2.port._InputPort)
-
-
-_COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS = {
-    native_bt.COMPONENT_CLASS_TYPE_SOURCE: _GenericSourceComponent,
-    native_bt.COMPONENT_CLASS_TYPE_FILTER: _GenericFilterComponent,
-    native_bt.COMPONENT_CLASS_TYPE_SINK: _GenericSinkComponent,
-}
-
-
-_COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS = {
-    native_bt.COMPONENT_CLASS_TYPE_SOURCE: _GenericSourceComponentClass,
-    native_bt.COMPONENT_CLASS_TYPE_FILTER: _GenericFilterComponentClass,
-    native_bt.COMPONENT_CLASS_TYPE_SINK: _GenericSinkComponentClass,
-}
-
-
-# Create a component Python object of type _GenericSourceComponent,
-# _GenericFilterComponent or _GenericSinkComponent, depending on
-# comp_cls_type.
-#
-#    Steals the reference to ptr from the caller.
-
-def _create_component_from_ptr(ptr, comp_cls_type):
-    return _COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS[comp_cls_type]._create_from_ptr(ptr)
-
-
-# Same as the above, but acquire a new reference instead of stealing the
-# reference from the caller.
-
-def _create_component_from_ptr_and_get_ref(ptr, comp_cls_type):
-    return _COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS[comp_cls_type]._create_from_ptr_and_get_ref(ptr)
-
-
-# Create a component class Python object of type
-# _GenericSourceComponentClass, _GenericFilterComponentClass or
-# _GenericSinkComponentClass, depending on comp_cls_type.
-#
-# Acquires a new reference to ptr.
-
-def _create_component_class_from_ptr_and_get_ref(ptr, comp_cls_type):
-    return _COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS[comp_cls_type]._create_from_ptr_and_get_ref(ptr)
-
-
-def _trim_docstring(docstring):
-    lines = docstring.expandtabs().splitlines()
-    indent = sys.maxsize
-
-    for line in lines[1:]:
-        stripped = line.lstrip()
-
-        if stripped:
-            indent = min(indent, len(line) - len(stripped))
-
-    trimmed = [lines[0].strip()]
-
-    if indent < sys.maxsize:
-        for line in lines[1:]:
-            trimmed.append(line[indent:].rstrip())
-
-    while trimmed and not trimmed[-1]:
-        trimmed.pop()
-
-    while trimmed and not trimmed[0]:
-        trimmed.pop(0)
-
-    return '\n'.join(trimmed)
-
-
-# Metaclass for component classes defined by Python code.
-#
-# The Python user can create a standard Python class which inherits one
-# of the three base classes (_UserSourceComponent, _UserFilterComponent,
-# or _UserSinkComponent). Those base classes set this class
-# (_UserComponentType) as their metaclass.
-#
-# Once the body of a user-defined component class is executed, this
-# metaclass is used to create and initialize the class. The metaclass
-# creates a native BT component class of the corresponding type and
-# associates it with this user-defined class. The metaclass also defines
-# class methods like the `name` and `description` properties to match
-# the _GenericComponentClass interface.
-#
-# The component class name which is used is either:
-#
-# * The `name` parameter of the class:
-#
-#       class MySink(bt2.SinkComponent, name='my-custom-sink'):
-#           ...
-#
-# * If the `name` class parameter is not used: the name of the class
-#   itself (`MySink` in the example above).
-#
-# The component class description which is used is the user-defined
-# class's docstring:
-#
-#     class MySink(bt2.SinkComponent):
-#         'Description goes here'
-#         ...
-#
-# A user-defined Python component class can have an __init__() method
-# which must at least accept the `params` and `name` arguments:
-#
-#     def __init__(self, params, name, something_else):
-#         ...
-#
-# The user-defined component class can also have a _finalize() method
-# (do NOT use __del__()) to be notified when the component object is
-# finalized.
-#
-# User-defined source and filter component classes must use the
-# `message_iterator_class` class parameter to specify the
-# message iterator class to use for this component class:
-#
-#     class MyMessageIterator(bt2._UserMessageIterator):
-#         ...
-#
-#     class MySource(bt2._UserSourceComponent,
-#                    message_iterator_class=MyMessageIterator):
-#         ...
-#
-# This message iterator class must inherit
-# bt2._UserMessageIterator, and it must define the _get() and
-# _next() methods. The message iterator class can also define an
-# __init__() method: this method has access to the original Python
-# component object which was used to create it as the `component`
-# property. The message iterator class can also define a
-# _finalize() method (again, do NOT use __del__()): this is called when
-# the message iterator is (really) destroyed.
-#
-# When the user-defined class is destroyed, this metaclass's __del__()
-# method is called: the native BT component class pointer is put (not
-# needed anymore, at least not by any Python code since all references
-# are dropped for __del__() to be called).
-class _UserComponentType(type):
-    # __new__() is used to catch custom class parameters
-    def __new__(meta_cls, class_name, bases, attrs, **kwargs):
-        return super().__new__(meta_cls, class_name, bases, attrs)
-
-    def __init__(cls, class_name, bases, namespace, **kwargs):
-        super().__init__(class_name, bases, namespace)
-
-        # skip our own bases; they are never directly instantiated by the user
-        own_bases = (
-            '_UserComponent',
-            '_UserFilterSinkComponent',
-            '_UserSourceComponent',
-            '_UserFilterComponent',
-            '_UserSinkComponent',
-        )
-
-        if class_name in own_bases:
-            return
-
-        comp_cls_name = kwargs.get('name', class_name)
-        utils._check_str(comp_cls_name)
-        comp_cls_descr = None
-        comp_cls_help = None
-
-        if hasattr(cls, '__doc__') and cls.__doc__ is not None:
-            utils._check_str(cls.__doc__)
-            docstring = _trim_docstring(cls.__doc__)
-            lines = docstring.splitlines()
-
-            if len(lines) >= 1:
-                comp_cls_descr = lines[0]
-
-            if len(lines) >= 3:
-                comp_cls_help = '\n'.join(lines[2:])
-
-        iter_cls = kwargs.get('message_iterator_class')
-
-        if _UserSourceComponent in bases:
-            _UserComponentType._set_iterator_class(cls, iter_cls)
-            cc_ptr = native_bt.py3_component_class_source_create(cls,
-                                                                 comp_cls_name,
-                                                                 comp_cls_descr,
-                                                                 comp_cls_help)
-        elif _UserFilterComponent in bases:
-            _UserComponentType._set_iterator_class(cls, iter_cls)
-            cc_ptr = native_bt.py3_component_class_filter_create(cls,
-                                                                 comp_cls_name,
-                                                                 comp_cls_descr,
-                                                                 comp_cls_help)
-        elif _UserSinkComponent in bases:
-            if not hasattr(cls, '_consume'):
-                raise bt2.IncompleteUserClass("cannot create component class '{}': missing a _consume() method".format(class_name))
-
-            cc_ptr = native_bt.py3_component_class_sink_create(cls,
-                                                               comp_cls_name,
-                                                               comp_cls_descr,
-                                                               comp_cls_help)
-        else:
-            raise bt2.IncompleteUserClass("cannot find a known component class base in the bases of '{}'".format(class_name))
-
-        if cc_ptr is None:
-            raise bt2.CreationError("cannot create component class '{}'".format(class_name))
-
-        cls._cc_ptr = cc_ptr
-
-    def _init_from_native(cls, comp_ptr, params_ptr):
-        # create instance, not user-initialized yet
-        self = cls.__new__(cls)
-
-        # pointer to native self component object (weak/borrowed)
-        self._ptr = comp_ptr
-
-        # call user's __init__() method
-        if params_ptr is not None:
-            params = bt2.value._create_from_ptr_and_get_ref(params_ptr)
-        else:
-            params = None
-
-        self.__init__(params)
-        return self
-
-    def __call__(cls, *args, **kwargs):
-        raise bt2.Error('cannot directly instantiate a user component from a Python module')
-
-    @staticmethod
-    def _set_iterator_class(cls, iter_cls):
-        if iter_cls is None:
-            raise bt2.IncompleteUserClass("cannot create component class '{}': missing message iterator class".format(cls.__name__))
-
-        if not issubclass(iter_cls, bt2.message_iterator._UserMessageIterator):
-            raise bt2.IncompleteUserClass("cannot create component class '{}': message iterator class does not inherit bt2._UserMessageIterator".format(cls.__name__))
-
-        if not hasattr(iter_cls, '__next__'):
-            raise bt2.IncompleteUserClass("cannot create component class '{}': message iterator class is missing a __next__() method".format(cls.__name__))
-
-        cls._iter_cls = iter_cls
-
-    @property
-    def name(cls):
-        ptr = cls._as_component_class_ptr(cls._cc_ptr)
-        return native_bt.component_class_get_name(ptr)
-
-    @property
-    def description(cls):
-        ptr = cls._as_component_class_ptr(cls._cc_ptr)
-        return native_bt.component_class_get_description(ptr)
-
-    @property
-    def help(cls):
-        ptr = cls._as_component_class_ptr(cls._cc_ptr)
-        return native_bt.component_class_get_help(ptr)
-
-    @property
-    def addr(cls):
-        return int(cls._cc_ptr)
-
-    def _query_from_native(cls, query_exec_ptr, obj, params_ptr):
-        # this can raise, in which case the native call to
-        # bt_component_class_query() returns NULL
-        if params_ptr is not None:
-            params = bt2.value._create_from_ptr_and_get_ref(params_ptr)
-        else:
-            params = None
-
-        query_exec = bt2.QueryExecutor._create_from_ptr_and_get_ref(
-            query_exec_ptr)
-
-        # this can raise, but the native side checks the exception
-        results = cls._query(query_exec, obj, params)
-
-        # this can raise, but the native side checks the exception
-        results = bt2.create_value(results)
-
-        if results is None:
-            results_addr = int(native_bt.value_null)
-        else:
-            # return new reference
-            results_addr = int(results._release())
-
-        return results_addr
-
-    def _query(cls, query_executor, obj, params):
-        raise NotImplementedError
-
-    def _component_class_ptr(self):
-        return self._as_component_class_ptr(self._cc_ptr)
-
-    def __del__(cls):
-        if hasattr(cls, '_cc_ptr'):
-            cc_ptr = cls._as_component_class_ptr(cls._cc_ptr)
-            native_bt.component_class_put_ref(cc_ptr)
-
-# Subclasses must provide these methods or property:
-#
-#   - _as_not_self_specific_component_ptr: static method, must return the passed
-#     specialized self component pointer (e.g. 'bt_self_component_sink *') as a
-#     specialized non-self pointer (e.g. 'bt_component_sink *').
-#   - _borrow_component_class_ptr: static method, must return a pointer to the
-#     specialized component class (e.g. 'bt_component_class_sink *') of the
-#     passed specialized component pointer (e.g. 'bt_component_sink *').
-#   - _comp_cls_type: property, one of the native_bt.COMPONENT_CLASS_TYPE_*
-#     constants.
-
-class _UserComponent(metaclass=_UserComponentType):
-    @property
-    def name(self):
-        ptr = self._as_not_self_specific_component_ptr(self._ptr)
-        ptr = self._as_component_ptr(ptr)
-        name = native_bt.component_get_name(ptr)
-        assert name is not None
-        return name
-
-    @property
-    def cls(self):
-        comp_ptr = self._as_not_self_specific_component_ptr(self._ptr)
-        cc_ptr = self._borrow_component_class_ptr(comp_ptr)
-        return _create_component_class_from_ptr_and_get_ref(cc_ptr, self._comp_cls_type)
-
-    @property
-    def addr(self):
-        return int(self._ptr)
-
-    def __init__(self, params=None):
-        pass
-
-    def _finalize(self):
-        pass
-
-    def _accept_port_connection(self, port, other_port):
-        return True
-
-    def _accept_port_connection_from_native(self, self_port_ptr, self_port_type, other_port_ptr):
-        port = bt2.port._create_self_from_ptr_and_get_ref(
-            self_port_ptr, self_port_type)
-
-        if self_port_type == native_bt.PORT_TYPE_OUTPUT:
-            other_port_type = native_bt.PORT_TYPE_INPUT
-        else:
-            other_port_type = native_bt.PORT_TYPE_OUTPUT
-
-        other_port = bt2.port._create_from_ptr_and_get_ref(
-            other_port_ptr, other_port_type)
-        res = self._accept_port_connection(port, other_port_ptr)
-
-        if type(res) is not bool:
-            raise TypeError("'{}' is not a 'bool' object")
-
-        return res
-
-    def _port_connected(self, port, other_port):
-        pass
-
-    def _port_connected_from_native(self, self_port_ptr, self_port_type, other_port_ptr):
-        port = bt2.port._create_self_from_ptr_and_get_ref(
-            self_port_ptr, self_port_type)
-
-        if self_port_type == native_bt.PORT_TYPE_OUTPUT:
-            other_port_type = native_bt.PORT_TYPE_INPUT
-        else:
-            other_port_type = native_bt.PORT_TYPE_OUTPUT
-
-        other_port = bt2.port._create_from_ptr_and_get_ref(
-            other_port_ptr, other_port_type)
-        self._port_connected(port, other_port)
-
-    def _graph_is_configured_from_native(self):
-        self._graph_is_configured()
-
-    def _create_trace_class(self, env=None, uuid=None,
-                            assigns_automatic_stream_class_id=True):
-        ptr = self._as_self_component_ptr(self._ptr)
-        tc_ptr = native_bt.trace_class_create(ptr)
-
-        if tc_ptr is None:
-            raise bt2.CreationError('could not create trace class')
-
-        tc = bt2._TraceClass._create_from_ptr(tc_ptr)
-
-        if env is not None:
-            for key, value in env.items():
-                tc.env[key] = value
-
-        if uuid is not None:
-            tc._uuid = uuid
-
-        tc._assigns_automatic_stream_class_id = assigns_automatic_stream_class_id
-
-        return tc
-
-    def _create_clock_class(self, frequency=None, name=None, description=None,
-                            precision=None, offset=None, origin_is_unix_epoch=True,
-                            uuid=None):
-        ptr = self._as_self_component_ptr(self._ptr)
-        cc_ptr = native_bt.clock_class_create(ptr)
-
-        if cc_ptr is None:
-            raise bt2.CreationError('could not create clock class')
-
-        cc = bt2.clock_class._ClockClass._create_from_ptr(cc_ptr)
-
-        if frequency is not None:
-            cc._frequency = frequency
-
-        if name is not None:
-            cc._name = name
-
-        if description is not None:
-            cc._description = description
-
-        if precision is not None:
-            cc._precision = precision
-
-        if offset is not None:
-            cc._offset = offset
-
-        cc._origin_is_unix_epoch = origin_is_unix_epoch
-
-        if uuid is not None:
-            cc._uuid = uuid
-
-        return cc
-
-
-class _UserSourceComponent(_UserComponent, _SourceComponent):
-    _as_not_self_specific_component_ptr = staticmethod(native_bt.self_component_source_as_component_source)
-    _as_self_component_ptr = staticmethod(native_bt.self_component_source_as_self_component)
-
-    @property
-    def _output_ports(self):
-        def get_output_port_count(self_ptr):
-            ptr = self._as_not_self_specific_component_ptr(self_ptr)
-            return native_bt.component_source_get_output_port_count(ptr)
-
-        return _ComponentPorts(self._ptr,
-                               native_bt.self_component_source_borrow_output_port_by_name,
-                               native_bt.self_component_source_borrow_output_port_by_index,
-                               get_output_port_count,
-                               bt2.port._UserComponentOutputPort)
-
-    def _add_output_port(self, name, user_data=None):
-        utils._check_str(name)
-        fn = native_bt.self_component_source_add_output_port
-        comp_status, self_port_ptr = fn(self._ptr, name, user_data)
-        _handle_component_status(comp_status,
-                                 'cannot add output port to source component object')
-        assert self_port_ptr is not None
-        return bt2.port._UserComponentOutputPort._create_from_ptr(self_port_ptr)
-
-
-class _UserFilterComponent(_UserComponent, _FilterComponent):
-    _as_not_self_specific_component_ptr = staticmethod(native_bt.self_component_filter_as_component_filter)
-    _as_self_component_ptr = staticmethod(native_bt.self_component_filter_as_self_component)
-
-    @property
-    def _output_ports(self):
-        def get_output_port_count(self_ptr):
-            ptr = self._as_not_self_specific_component_ptr(self_ptr)
-            return native_bt.component_filter_get_output_port_count(ptr)
-
-        return _ComponentPorts(self._ptr,
-                               native_bt.self_component_filter_borrow_output_port_by_name,
-                               native_bt.self_component_filter_borrow_output_port_by_index,
-                               get_output_port_count,
-                               bt2.port._UserComponentOutputPort)
-
-    @property
-    def _input_ports(self):
-        def get_input_port_count(self_ptr):
-            ptr = self._as_not_self_specific_component_ptr(self_ptr)
-            return native_bt.component_filter_get_input_port_count(ptr)
-
-        return _ComponentPorts(self._ptr,
-                               native_bt.self_component_filter_borrow_input_port_by_name,
-                               native_bt.self_component_filter_borrow_input_port_by_index,
-                               get_input_port_count,
-                               bt2.port._UserComponentInputPort)
-
-    def _add_output_port(self, name, user_data=None):
-        utils._check_str(name)
-        fn = native_bt.self_component_filter_add_output_port
-        comp_status, self_port_ptr = fn(self._ptr, name, user_data)
-        _handle_component_status(comp_status,
-                                 'cannot add output port to filter component object')
-        assert self_port_ptr
-        return bt2.port._UserComponentOutputPort._create_from_ptr(self_port_ptr)
-
-    def _add_input_port(self, name, user_data=None):
-        utils._check_str(name)
-        fn = native_bt.self_component_filter_add_input_port
-        comp_status, self_port_ptr = fn(self._ptr, name, user_data)
-        _handle_component_status(comp_status,
-                                 'cannot add input port to filter component object')
-        assert self_port_ptr
-        return bt2.port._UserComponentInputPort._create_from_ptr(self_port_ptr)
-
-
-class _UserSinkComponent(_UserComponent, _SinkComponent):
-    _as_not_self_specific_component_ptr = staticmethod(native_bt.self_component_sink_as_component_sink)
-    _as_self_component_ptr = staticmethod(native_bt.self_component_sink_as_self_component)
-
-    @property
-    def _input_ports(self):
-        def get_input_port_count(self_ptr):
-            ptr = self._as_not_self_specific_component_ptr(self_ptr)
-            return native_bt.component_sink_get_input_port_count(ptr)
-
-        return _ComponentPorts(self._ptr,
-                               native_bt.self_component_sink_borrow_input_port_by_name,
-                               native_bt.self_component_sink_borrow_input_port_by_index,
-                               get_input_port_count,
-                               bt2.port._UserComponentInputPort)
-
-    def _add_input_port(self, name, user_data=None):
-        utils._check_str(name)
-        fn = native_bt.self_component_sink_add_input_port
-        comp_status, self_port_ptr = fn(self._ptr, name, user_data)
-        _handle_component_status(comp_status,
-                                 'cannot add input port to sink component object')
-        assert self_port_ptr
-        return bt2.port._UserComponentInputPort._create_from_ptr(self_port_ptr)
diff --git a/bindings/python/bt2/bt2/connection.py b/bindings/python/bt2/bt2/connection.py
deleted file mode 100644 (file)
index 4c52a77..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, utils
-import bt2.message_iterator
-import bt2.port
-import bt2
-
-
-class _Connection(bt2.object._SharedObject):
-    _get_ref = staticmethod(native_bt.connection_get_ref)
-    _put_ref = staticmethod(native_bt.connection_put_ref)
-
-    @property
-    def downstream_port(self):
-        port_ptr = native_bt.connection_borrow_downstream_port_const(self._ptr)
-        utils._handle_ptr(port_ptr, "cannot get connection object's downstream port object")
-        return bt2.port._create_from_ptr_and_get_ref(port_ptr, native_bt.PORT_TYPE_INPUT)
-
-    @property
-    def upstream_port(self):
-        port_ptr = native_bt.connection_borrow_upstream_port_const(self._ptr)
-        utils._handle_ptr(port_ptr, "cannot get connection object's upstream port object")
-        return bt2.port._create_from_ptr_and_get_ref(port_ptr, native_bt.PORT_TYPE_OUTPUT)
diff --git a/bindings/python/bt2/bt2/event.py b/bindings/python/bt2/bt2/event.py
deleted file mode 100644 (file)
index 4ff398b..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.clock_class
-import bt2.event_class
-import bt2.packet
-import bt2.stream
-import bt2.field
-import bt2.clock_snapshot
-import bt2
-
-
-class _Event(object._UniqueObject):
-    @property
-    def cls(self):
-        event_class_ptr = native_bt.event_borrow_class(self._ptr)
-        assert event_class_ptr is not None
-        return bt2.event_class._EventClass._create_from_ptr_and_get_ref(event_class_ptr)
-
-    @property
-    def name(self):
-        return self.cls.name
-
-    @property
-    def id(self):
-        return self.cls.id
-
-    @property
-    def packet(self):
-        packet_ptr = native_bt.event_borrow_packet(self._ptr)
-        assert packet_ptr is not None
-        return bt2.packet._Packet._create_from_ptr_and_get_ref(packet_ptr)
-
-    @property
-    def stream(self):
-        stream_ptr = native_bt.event_borrow_stream(self._ptr)
-        assert stream_ptr is not None
-        return bt2._Stream._create_from_ptr_and_get_ref(stream_ptr)
-
-    @property
-    def common_context_field(self):
-        field_ptr = native_bt.event_borrow_common_context_field(self._ptr)
-
-        if field_ptr is None:
-            return
-
-        return bt2.field._create_field_from_ptr(field_ptr, self._owner_ptr,
-                                                self._owner_get_ref,
-                                                self._owner_put_ref)
-
-    @property
-    def specific_context_field(self):
-        field_ptr = native_bt.event_borrow_specific_context_field(self._ptr)
-
-        if field_ptr is None:
-            return
-
-        return bt2.field._create_field_from_ptr(field_ptr, self._owner_ptr,
-                                                self._owner_get_ref,
-                                                self._owner_put_ref)
-
-    @property
-    def payload_field(self):
-        field_ptr = native_bt.event_borrow_payload_field(self._ptr)
-
-        if field_ptr is None:
-            return
-
-        return bt2.field._create_field_from_ptr(field_ptr, self._owner_ptr,
-                                                self._owner_get_ref,
-                                                self._owner_put_ref)
-
-    def __getitem__(self, key):
-        utils._check_str(key)
-        payload_field = self.payload_field
-
-        if payload_field is not None and key in payload_field:
-            return payload_field[key]
-
-        specific_context_field = self.specific_context_field
-
-        if specific_context_field is not None and key in specific_context_field:
-            return specific_context_field[key]
-
-        common_context_field = self.common_context_field
-
-        if common_context_field is not None and key in common_context_field:
-            return common_context_field[key]
-
-        packet_context_field = self.packet.context_field
-
-        if packet_context_field is not None and key in packet_context_field:
-            return packet_context_field[key]
-
-        raise KeyError(key)
diff --git a/bindings/python/bt2/bt2/event_class.py b/bindings/python/bt2/bt2/event_class.py
deleted file mode 100644 (file)
index d3141b8..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.field_class
-import bt2.value
-import bt2.event
-import bt2
-
-
-class EventClassLogLevel:
-    EMERGENCY = native_bt.EVENT_CLASS_LOG_LEVEL_EMERGENCY
-    ALERT = native_bt.EVENT_CLASS_LOG_LEVEL_ALERT
-    CRITICAL = native_bt.EVENT_CLASS_LOG_LEVEL_CRITICAL
-    ERROR = native_bt.EVENT_CLASS_LOG_LEVEL_ERROR
-    WARNING = native_bt.EVENT_CLASS_LOG_LEVEL_WARNING
-    NOTICE = native_bt.EVENT_CLASS_LOG_LEVEL_NOTICE
-    INFO = native_bt.EVENT_CLASS_LOG_LEVEL_INFO
-    DEBUG_SYSTEM = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM
-    DEBUG_PROGRAM = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM
-    DEBUG_PROCESS = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS
-    DEBUG_MODULE = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE
-    DEBUG_UNIT = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT
-    DEBUG_FUNCTION = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION
-    DEBUG_LINE = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_LINE
-    DEBUG = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG
-
-
-class _EventClass(object._SharedObject):
-    _get_ref = staticmethod(native_bt.event_class_get_ref)
-    _put_ref = staticmethod(native_bt.event_class_put_ref)
-
-    @property
-    def stream_class(self):
-        sc_ptr = native_bt.event_class_borrow_stream_class(self._ptr)
-
-        if sc_ptr is not None:
-            return bt2.stream_class._StreamClass._create_from_ptr_and_get_ref(sc_ptr)
-
-    @property
-    def name(self):
-        return native_bt.event_class_get_name(self._ptr)
-
-    def _name(self, name):
-        utils._check_str(name)
-        return native_bt.event_class_set_name(self._ptr, name)
-
-    _name = property(fset=_name)
-
-    @property
-    def id(self):
-        id = native_bt.event_class_get_id(self._ptr)
-        return id if id >= 0 else None
-
-    @property
-    def log_level(self):
-        is_available, log_level = native_bt.event_class_get_log_level(self._ptr)
-
-        if is_available != native_bt.PROPERTY_AVAILABILITY_AVAILABLE:
-            return None
-
-        return _EVENT_CLASS_LOG_LEVEL_TO_OBJ[log_level]
-
-    def _log_level(self, log_level):
-        log_levels = (
-            EventClassLogLevel.EMERGENCY,
-            EventClassLogLevel.ALERT,
-            EventClassLogLevel.CRITICAL,
-            EventClassLogLevel.ERROR,
-            EventClassLogLevel.WARNING,
-            EventClassLogLevel.NOTICE,
-            EventClassLogLevel.INFO,
-            EventClassLogLevel.DEBUG_SYSTEM,
-            EventClassLogLevel.DEBUG_PROGRAM,
-            EventClassLogLevel.DEBUG_PROCESS,
-            EventClassLogLevel.DEBUG_MODULE,
-            EventClassLogLevel.DEBUG_UNIT,
-            EventClassLogLevel.DEBUG_FUNCTION,
-            EventClassLogLevel.DEBUG_LINE,
-            EventClassLogLevel.DEBUG,
-        )
-
-        if log_level not in log_levels:
-            raise ValueError("'{}' is not a valid log level".format(log_level))
-
-        native_bt.event_class_set_log_level(self._ptr, log_level)
-
-    _log_level = property(fset=_log_level)
-
-    @property
-    def emf_uri(self):
-        return native_bt.event_class_get_emf_uri(self._ptr)
-
-    def _emf_uri(self, emf_uri):
-        utils._check_str(emf_uri)
-        ret = native_bt.event_class_set_emf_uri(self._ptr, emf_uri)
-        utils._handle_ret(ret, "cannot set event class object's EMF URI")
-
-    _emf_uri = property(fset=_emf_uri)
-
-    @property
-    def specific_context_field_class(self):
-        fc_ptr = native_bt.event_class_borrow_specific_context_field_class_const(self._ptr)
-
-        if fc_ptr is None:
-            return
-
-        return bt2.field_class._create_field_class_from_ptr_and_get_ref(fc_ptr)
-
-    def _specific_context_field_class(self, context_field_class):
-        if context_field_class is not None:
-            utils._check_type(context_field_class, bt2.field_class._StructureFieldClass)
-            ret = native_bt.event_class_set_specific_context_field_class(self._ptr, context_field_class._ptr)
-            utils._handle_ret(ret, "cannot set event class object's context field class")
-
-    _specific_context_field_class = property(fset=_specific_context_field_class)
-
-    @property
-    def payload_field_class(self):
-        fc_ptr = native_bt.event_class_borrow_payload_field_class_const(self._ptr)
-
-        if fc_ptr is None:
-            return
-
-        return bt2.field_class._create_field_class_from_ptr_and_get_ref(fc_ptr)
-
-    def _payload_field_class(self, payload_field_class):
-        if payload_field_class is not None:
-            utils._check_type(payload_field_class, bt2.field_class._StructureFieldClass)
-            ret = native_bt.event_class_set_payload_field_class(self._ptr, payload_field_class._ptr)
-            utils._handle_ret(ret, "cannot set event class object's payload field class")
-
-    _payload_field_class = property(fset=_payload_field_class)
-
-
-_EVENT_CLASS_LOG_LEVEL_TO_OBJ = {
-    native_bt.EVENT_CLASS_LOG_LEVEL_EMERGENCY: EventClassLogLevel.EMERGENCY,
-    native_bt.EVENT_CLASS_LOG_LEVEL_ALERT: EventClassLogLevel.ALERT,
-    native_bt.EVENT_CLASS_LOG_LEVEL_CRITICAL: EventClassLogLevel.CRITICAL,
-    native_bt.EVENT_CLASS_LOG_LEVEL_ERROR: EventClassLogLevel.ERROR,
-    native_bt.EVENT_CLASS_LOG_LEVEL_WARNING: EventClassLogLevel.WARNING,
-    native_bt.EVENT_CLASS_LOG_LEVEL_NOTICE: EventClassLogLevel.NOTICE,
-    native_bt.EVENT_CLASS_LOG_LEVEL_INFO: EventClassLogLevel.INFO,
-    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM: EventClassLogLevel.DEBUG_SYSTEM,
-    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM: EventClassLogLevel.DEBUG_PROGRAM,
-    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS: EventClassLogLevel.DEBUG_PROCESS,
-    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE: EventClassLogLevel.DEBUG_MODULE,
-    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT: EventClassLogLevel.DEBUG_UNIT,
-    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION: EventClassLogLevel.DEBUG_FUNCTION,
-    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_LINE: EventClassLogLevel.DEBUG_LINE,
-    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG: EventClassLogLevel.DEBUG,
-}
diff --git a/bindings/python/bt2/bt2/field.py b/bindings/python/bt2/bt2/field.py
deleted file mode 100644 (file)
index 62dac5f..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.field_class
-import collections.abc
-import functools
-import numbers
-import math
-import bt2
-
-
-def _create_field_from_ptr(ptr, owner_ptr, owner_get_ref, owner_put_ref):
-    field_class_ptr = native_bt.field_borrow_class_const(ptr)
-    utils._handle_ptr(field_class_ptr, "cannot get field object's class")
-    typeid = native_bt.field_class_get_type(field_class_ptr)
-    field = _TYPE_ID_TO_OBJ[typeid]._create_from_ptr_and_get_ref(
-        ptr, owner_ptr, owner_get_ref, owner_put_ref)
-    return field
-
-
-# Get the "effective" field of `field`.  If `field` is a variant, return the
-# currently selected field.  If `field` is of any other type, return `field`
-# directly.
-
-def _get_leaf_field(field):
-    if not isinstance(field, _VariantField):
-        return field
-
-    return _get_leaf_field(field.selected_option)
-
-
-class _Field(object._UniqueObject):
-    def __eq__(self, other):
-        other = _get_leaf_field(other)
-        return self._spec_eq(other)
-
-    @property
-    def field_class(self):
-        field_class_ptr = native_bt.field_borrow_class_const(self._ptr)
-        assert field_class_ptr is not None
-        return bt2.field_class._create_field_class_from_ptr_and_get_ref(field_class_ptr)
-
-    def _repr(self):
-        raise NotImplementedError
-
-    def __repr__(self):
-        return self._repr()
-
-
-@functools.total_ordering
-class _NumericField(_Field):
-    @staticmethod
-    def _extract_value(other):
-        if other is True or other is False:
-            return other
-
-        if isinstance(other, numbers.Integral):
-            return int(other)
-
-        if isinstance(other, numbers.Real):
-            return float(other)
-
-        if isinstance(other, numbers.Complex):
-            return complex(other)
-
-        raise TypeError("'{}' object is not a number object".format(other.__class__.__name__))
-
-    def __int__(self):
-        return int(self._value)
-
-    def __float__(self):
-        return float(self._value)
-
-    def _repr(self):
-        return repr(self._value)
-
-    def __lt__(self, other):
-        if not isinstance(other, numbers.Number):
-            raise TypeError('unorderable types: {}() < {}()'.format(self.__class__.__name__,
-                                                                    other.__class__.__name__))
-
-        return self._value < float(other)
-
-    def __le__(self, other):
-        if not isinstance(other, numbers.Number):
-            raise TypeError('unorderable types: {}() <= {}()'.format(self.__class__.__name__,
-                                                                     other.__class__.__name__))
-
-        return self._value <= float(other)
-
-    def _spec_eq(self, other):
-        if not isinstance(other, numbers.Number):
-            return NotImplemented
-
-        return self._value == complex(other)
-
-    def __rmod__(self, other):
-        return self._extract_value(other) % self._value
-
-    def __mod__(self, other):
-        return self._value % self._extract_value(other)
-
-    def __rfloordiv__(self, other):
-        return self._extract_value(other) // self._value
-
-    def __floordiv__(self, other):
-        return self._value // self._extract_value(other)
-
-    def __round__(self, ndigits=None):
-        if ndigits is None:
-            return round(self._value)
-        else:
-            return round(self._value, ndigits)
-
-    def __ceil__(self):
-        return math.ceil(self._value)
-
-    def __floor__(self):
-        return math.floor(self._value)
-
-    def __trunc__(self):
-        return int(self._value)
-
-    def __abs__(self):
-        return abs(self._value)
-
-    def __add__(self, other):
-        return self._value + self._extract_value(other)
-
-    def __radd__(self, other):
-        return self.__add__(other)
-
-    def __neg__(self):
-        return -self._value
-
-    def __pos__(self):
-        return +self._value
-
-    def __mul__(self, other):
-        return self._value * self._extract_value(other)
-
-    def __rmul__(self, other):
-        return self.__mul__(other)
-
-    def __truediv__(self, other):
-        return self._value / self._extract_value(other)
-
-    def __rtruediv__(self, other):
-        return self._extract_value(other) / self._value
-
-    def __pow__(self, exponent):
-        return self._value ** self._extract_value(exponent)
-
-    def __rpow__(self, base):
-        return self._extract_value(base) ** self._value
-
-    def __iadd__(self, other):
-        self.value = self + other
-        return self
-
-    def __isub__(self, other):
-        self.value = self - other
-        return self
-
-    def __imul__(self, other):
-        self.value = self * other
-        return self
-
-    def __itruediv__(self, other):
-        self.value = self / other
-        return self
-
-    def __ifloordiv__(self, other):
-        self.value = self // other
-        return self
-
-    def __imod__(self, other):
-        self.value = self % other
-        return self
-
-    def __ipow__(self, other):
-        self.value = self ** other
-        return self
-
-
-class _IntegralField(_NumericField, numbers.Integral):
-    def __lshift__(self, other):
-        return self._value << self._extract_value(other)
-
-    def __rlshift__(self, other):
-        return self._extract_value(other) << self._value
-
-    def __rshift__(self, other):
-        return self._value >> self._extract_value(other)
-
-    def __rrshift__(self, other):
-        return self._extract_value(other) >> self._value
-
-    def __and__(self, other):
-        return self._value & self._extract_value(other)
-
-    def __rand__(self, other):
-        return self._extract_value(other) & self._value
-
-    def __xor__(self, other):
-        return self._value ^ self._extract_value(other)
-
-    def __rxor__(self, other):
-        return self._extract_value(other) ^ self._value
-
-    def __or__(self, other):
-        return self._value | self._extract_value(other)
-
-    def __ror__(self, other):
-        return self._extract_value(other) | self._value
-
-    def __invert__(self):
-        return ~self._value
-
-    def __ilshift__(self, other):
-        self.value = self << other
-        return self
-
-    def __irshift__(self, other):
-        self.value = self >> other
-        return self
-
-    def __iand__(self, other):
-        self.value = self & other
-        return self
-
-    def __ixor__(self, other):
-        self.value = self ^ other
-        return self
-
-    def __ior__(self, other):
-        self.value = self | other
-        return self
-
-
-class _IntegerField(_IntegralField, _Field):
-    pass
-
-
-class _UnsignedIntegerField(_IntegerField, _Field):
-    _NAME = 'Unsigned integer'
-
-    def _value_to_int(self, value):
-        if not isinstance(value, numbers.Real):
-            raise TypeError('expecting a real number object')
-
-        value = int(value)
-        utils._check_uint64(value)
-
-        return value
-
-    @property
-    def _value(self):
-        return native_bt.field_unsigned_integer_get_value(self._ptr)
-
-    def _set_value(self, value):
-        value = self._value_to_int(value)
-        native_bt.field_unsigned_integer_set_value(self._ptr, value)
-
-    value = property(fset=_set_value)
-
-
-class _SignedIntegerField(_IntegerField, _Field):
-    _NAME = 'Signed integer'
-
-    def _value_to_int(self, value):
-        if not isinstance(value, numbers.Real):
-            raise TypeError('expecting a real number object')
-
-        value = int(value)
-        utils._check_int64(value)
-
-        return value
-
-    @property
-    def _value(self):
-        return native_bt.field_signed_integer_get_value(self._ptr)
-
-    def _set_value(self, value):
-        value = self._value_to_int(value)
-        native_bt.field_signed_integer_set_value(self._ptr, value)
-
-    value = property(fset=_set_value)
-
-
-class _RealField(_NumericField, numbers.Real):
-    _NAME = 'Real'
-
-    def _value_to_float(self, value):
-        if not isinstance(value, numbers.Real):
-            raise TypeError("expecting a real number object")
-
-        return float(value)
-
-    @property
-    def _value(self):
-        return native_bt.field_real_get_value(self._ptr)
-
-    def _set_value(self, value):
-        value = self._value_to_float(value)
-        native_bt.field_real_set_value(self._ptr, value)
-
-    value = property(fset=_set_value)
-
-
-class _EnumerationField(_IntegerField):
-    def _repr(self):
-        return '{} ({})'.format(self._value, ', '.join(self.labels))
-
-    @property
-    def labels(self):
-        ret, labels = self._get_mapping_labels(self._ptr)
-        utils._handle_ret(ret, "cannot get label for enumeration field")
-
-        assert labels is not None
-        return labels
-
-
-class _UnsignedEnumerationField(_EnumerationField, _UnsignedIntegerField):
-    _NAME = 'Unsigned Enumeration'
-    _get_mapping_labels = staticmethod(native_bt.field_unsigned_enumeration_get_mapping_labels)
-
-
-class _SignedEnumerationField(_EnumerationField, _SignedIntegerField):
-    _NAME = 'Signed Enumeration'
-    _get_mapping_labels = staticmethod(native_bt.field_signed_enumeration_get_mapping_labels)
-
-
-@functools.total_ordering
-class _StringField(_Field):
-    _NAME = 'String'
-
-    def _value_to_str(self, value):
-        if isinstance(value, self.__class__):
-            value = value._value
-
-        if not isinstance(value, str):
-            raise TypeError("expecting a 'str' object")
-
-        return value
-
-    @property
-    def _value(self):
-        return native_bt.field_string_get_value(self._ptr)
-
-    def _set_value(self, value):
-        value = self._value_to_str(value)
-        native_bt.field_string_set_value(self._ptr, value)
-
-    value = property(fset=_set_value)
-
-    def _spec_eq(self, other):
-        try:
-            other = self._value_to_str(other)
-        except Exception:
-            return False
-
-        return self._value == other
-
-    def __le__(self, other):
-        return self._value <= self._value_to_str(other)
-
-    def __lt__(self, other):
-        return self._value < self._value_to_str(other)
-
-    def __bool__(self):
-        return bool(self._value)
-
-    def _repr(self):
-        return repr(self._value)
-
-    def __str__(self):
-        return str(self._value)
-
-    def __getitem__(self, index):
-        return self._value[index]
-
-    def __len__(self):
-        return native_bt.field_string_get_length(self._ptr)
-
-    def __iadd__(self, value):
-        value = self._value_to_str(value)
-        ret = native_bt.field_string_append(self._ptr, value)
-        utils._handle_ret(ret, "cannot append to string field object's value")
-        return self
-
-
-class _ContainerField(_Field):
-    def __bool__(self):
-        return len(self) != 0
-
-    def __len__(self):
-        count = self._count()
-        assert count >= 0
-        return count
-
-    def __delitem__(self, index):
-        raise NotImplementedError
-
-
-class _StructureField(_ContainerField, collections.abc.MutableMapping):
-    _NAME = 'Structure'
-
-    def _count(self):
-        return len(self.field_class)
-
-    def __setitem__(self, key, value):
-        # raises if key is somehow invalid
-        field = self[key]
-
-        # the field's property does the appropriate conversion or raises
-        # the appropriate exception
-        field.value = value
-
-    def __iter__(self):
-        # same name iterator
-        return iter(self.field_class)
-
-    def _spec_eq(self, other):
-        try:
-            if len(self) != len(other):
-                return False
-
-            for self_key, self_value in self.items():
-                if self_key not in other:
-                    return False
-
-                other_value = other[self_key]
-
-                if self_value != other_value:
-                    return False
-
-            return True
-        except Exception:
-            return False
-
-    def _set_value(self, values):
-        try:
-            for key, value in values.items():
-                self[key].value = value
-        except Exception:
-            raise
-
-    value = property(fset=_set_value)
-
-    def _repr(self):
-        items = ['{}: {}'.format(repr(k), repr(v)) for k, v in self.items()]
-        return '{{{}}}'.format(', '.join(items))
-
-    def __getitem__(self, key):
-        utils._check_str(key)
-        field_ptr = native_bt.field_structure_borrow_member_field_by_name(self._ptr, key)
-
-        if field_ptr is None:
-            raise KeyError(key)
-
-        return _create_field_from_ptr(field_ptr, self._owner_ptr,
-                                      self._owner_get_ref,
-                                      self._owner_put_ref)
-
-    def member_at_index(self, index):
-        utils._check_uint64(index)
-
-        if index >= len(self):
-            raise IndexError
-
-        field_ptr = native_bt.field_structure_borrow_member_field_by_index(self._ptr, index)
-        assert field_ptr is not None
-        return _create_field_from_ptr(field_ptr, self._owner_ptr,
-                                      self._owner_get_ref,
-                                      self._owner_put_ref)
-
-
-class _VariantField(_ContainerField, _Field):
-    _NAME = 'Variant'
-
-    @property
-    def selected_option_index(self):
-        return native_bt.field_variant_get_selected_option_field_index(self._ptr)
-
-    @selected_option_index.setter
-    def selected_option_index(self, index):
-        native_bt.field_variant_select_option_field(self._ptr, index)
-
-    @property
-    def selected_option(self):
-        field_ptr = native_bt.field_variant_borrow_selected_option_field(self._ptr)
-        utils._handle_ptr(field_ptr, "cannot get variant field's selected option")
-
-        return _create_field_from_ptr(field_ptr, self._owner_ptr,
-                                      self._owner_get_ref,
-                                      self._owner_put_ref)
-
-    def _spec_eq(self, other):
-        new_self = _get_leaf_field(self)
-        return new_self == other
-
-    def __bool__(self):
-        raise NotImplementedError
-
-    def __str__(self):
-        return str(self.selected_option)
-
-    def _repr(self):
-        return repr(self.selected_option)
-
-    def _set_value(self, value):
-        self.selected_option.value = value
-
-    value = property(fset=_set_value)
-
-
-class _ArrayField(_ContainerField, _Field):
-
-    def _get_length(self):
-        return native_bt.field_array_get_length(self._ptr)
-
-    length = property(fget=_get_length)
-
-    def __getitem__(self, index):
-        if not isinstance(index, numbers.Integral):
-            raise TypeError("'{}' is not an integral number object: invalid index".format(index.__class__.__name__))
-
-        index = int(index)
-
-        if index < 0 or index >= len(self):
-            raise IndexError('{} field object index is out of range'.format(self._NAME))
-
-        field_ptr = native_bt.field_array_borrow_element_field_by_index(self._ptr, index)
-        assert(field_ptr)
-        return _create_field_from_ptr(field_ptr, self._owner_ptr,
-                                      self._owner_get_ref,
-                                      self._owner_put_ref)
-
-    def __setitem__(self, index, value):
-        # we can only set numbers and strings
-        if not isinstance(value, (numbers.Number, _StringField, str)):
-            raise TypeError('expecting number or string object')
-
-        # raises if index is somehow invalid
-        field = self[index]
-
-        if not isinstance(field, (_NumericField, _StringField)):
-            raise TypeError('can only set the value of a number or string field')
-
-        # the field's property does the appropriate conversion or raises
-        # the appropriate exception
-        field.value = value
-
-    def insert(self, index, value):
-        raise NotImplementedError
-
-    def _spec_eq(self, other):
-        try:
-            if len(self) != len(other):
-                return False
-
-            for self_field, other_field in zip(self, other):
-                if self_field != other_field:
-                    return False
-
-            return True
-        except Exception:
-            return False
-
-    def _repr(self):
-        return '[{}]'.format(', '.join([repr(v) for v in self]))
-
-
-class _StaticArrayField(_ArrayField, _Field):
-    _NAME = 'Static array'
-
-    def _count(self):
-        return native_bt.field_array_get_length(self._ptr)
-
-    def _set_value(self, values):
-        if len(self) != len(values):
-            raise ValueError(
-                'expected length of value and array field to match')
-
-        for index, value in enumerate(values):
-            if value is not None:
-                self[index].value = value
-
-    value = property(fset=_set_value)
-
-
-class _DynamicArrayField(_ArrayField, _Field):
-    _NAME = 'Dynamic array'
-
-    def _count(self):
-        return self.length
-
-    def _set_length(self, length):
-        utils._check_uint64(length)
-        ret = native_bt.field_dynamic_array_set_length(self._ptr, length)
-        utils._handle_ret(ret, "cannot set dynamic array length")
-
-    length = property(fget=_ArrayField._get_length, fset=_set_length)
-
-    def _set_value(self, values):
-        if len(values) != self.length:
-            self.length = len(values)
-
-        for index, value in enumerate(values):
-            if value is not None:
-                self[index].value = value
-
-    value = property(fset=_set_value)
-
-
-_TYPE_ID_TO_OBJ = {
-    native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerField,
-    native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerField,
-    native_bt.FIELD_CLASS_TYPE_REAL: _RealField,
-    native_bt.FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: _UnsignedEnumerationField,
-    native_bt.FIELD_CLASS_TYPE_SIGNED_ENUMERATION: _SignedEnumerationField,
-    native_bt.FIELD_CLASS_TYPE_STRING: _StringField,
-    native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureField,
-    native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayField,
-    native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY: _DynamicArrayField,
-    native_bt.FIELD_CLASS_TYPE_VARIANT: _VariantField,
-}
diff --git a/bindings/python/bt2/bt2/field_class.py b/bindings/python/bt2/bt2/field_class.py
deleted file mode 100644 (file)
index 27a37d9..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import collections.abc
-import bt2.field
-import bt2.field_path
-import bt2
-
-
-def _create_field_class_from_ptr_and_get_ref(ptr):
-    typeid = native_bt.field_class_get_type(ptr)
-    return _FIELD_CLASS_TYPE_TO_OBJ[typeid]._create_from_ptr_and_get_ref(ptr)
-
-
-class IntegerDisplayBase:
-    BINARY = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
-    OCTAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
-    DECIMAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
-    HEXADECIMAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
-
-
-class _FieldClass(object._SharedObject):
-    _get_ref = staticmethod(native_bt.field_class_get_ref)
-    _put_ref = staticmethod(native_bt.field_class_put_ref)
-
-    def _check_create_status(self, ptr):
-        if ptr is None:
-            raise bt2.CreationError('cannot create {} field class object'.format(self._NAME.lower()))
-
-
-class _IntegerFieldClass(_FieldClass):
-    @property
-    def field_value_range(self):
-        size = native_bt.field_class_integer_get_field_value_range(self._ptr)
-        assert(size >= 1)
-        return size
-
-    def _field_value_range(self, size):
-        if size < 1 or size > 64:
-            raise ValueError("Value is outside valid range [1, 64] ({})".format(size))
-        native_bt.field_class_integer_set_field_value_range(self._ptr, size)
-
-    _field_value_range = property(fset=_field_value_range)
-
-    @property
-    def preferred_display_base(self):
-        base = native_bt.field_class_integer_get_preferred_display_base(
-            self._ptr)
-        assert(base >= 0)
-        return base
-
-    def _preferred_display_base(self, base):
-        utils._check_uint64(base)
-
-        if base not in (IntegerDisplayBase.BINARY,
-                        IntegerDisplayBase.OCTAL,
-                        IntegerDisplayBase.DECIMAL,
-                        IntegerDisplayBase.HEXADECIMAL):
-            raise ValueError("Display base is not a valid IntegerDisplayBase value")
-
-        native_bt.field_class_integer_set_preferred_display_base(
-            self._ptr, base)
-
-    _preferred_display_base = property(fset=_preferred_display_base)
-
-
-class _UnsignedIntegerFieldClass(_IntegerFieldClass):
-    _NAME = 'Unsigned integer'
-
-
-class _SignedIntegerFieldClass(_IntegerFieldClass):
-    _NAME = 'Signed integer'
-
-
-class _RealFieldClass(_FieldClass):
-    _NAME = 'Real'
-
-    @property
-    def is_single_precision(self):
-        return native_bt.field_class_real_is_single_precision(self._ptr)
-
-    def _is_single_precision(self, is_single_precision):
-        utils._check_bool(is_single_precision)
-        native_bt.field_class_real_set_is_single_precision(
-            self._ptr, is_single_precision)
-
-    _is_single_precision = property(fset=_is_single_precision)
-
-
-class _EnumerationFieldClassMappingRange:
-    def __init__(self, lower, upper):
-        self._lower = lower
-        self._upper = upper
-
-    @property
-    def lower(self):
-        return self._lower
-
-    @property
-    def upper(self):
-        return self._upper
-
-    def __eq__(self, other):
-        return self.lower == other.lower and self.upper == other.upper
-
-
-class _EnumerationFieldClassMapping(collections.abc.Set):
-    def __init__(self, mapping_ptr):
-        self._mapping_ptr = mapping_ptr
-
-    @property
-    def label(self):
-        mapping_ptr = self._as_enumeration_field_class_mapping_ptr(self._mapping_ptr)
-        label = native_bt.field_class_enumeration_mapping_get_label(mapping_ptr)
-        assert label is not None
-        return label
-
-    def __len__(self):
-        mapping_ptr = self._as_enumeration_field_class_mapping_ptr(self._mapping_ptr)
-        return native_bt.field_class_enumeration_mapping_get_range_count(mapping_ptr)
-
-    def __contains__(self, other_range):
-        for curr_range in self:
-            if curr_range == other_range:
-                return True
-        return False
-
-    def __iter__(self):
-        for idx in range(len(self)):
-            lower, upper = self._get_range_by_index(self._mapping_ptr, idx)
-            yield _EnumerationFieldClassMappingRange(lower, upper)
-
-
-class _UnsignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping):
-    _as_enumeration_field_class_mapping_ptr = staticmethod(native_bt.field_class_unsigned_enumeration_mapping_as_mapping_const)
-    _get_range_by_index = staticmethod(native_bt.field_class_unsigned_enumeration_mapping_get_range_by_index)
-
-
-class _SignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping):
-    _as_enumeration_field_class_mapping_ptr = staticmethod(native_bt.field_class_signed_enumeration_mapping_as_mapping_const)
-    _get_range_by_index = staticmethod(native_bt.field_class_signed_enumeration_mapping_get_range_by_index)
-
-
-class _EnumerationFieldClass(_IntegerFieldClass, collections.abc.Mapping):
-    def __len__(self):
-        count = native_bt.field_class_enumeration_get_mapping_count(self._ptr)
-        assert(count >= 0)
-        return count
-
-    def map_range(self, label, lower, upper=None):
-        utils._check_str(label)
-
-        if upper is None:
-            upper = lower
-
-        ret = self._map_range(self._ptr, label, lower, upper)
-        utils._handle_ret(ret, "cannot add mapping to enumeration field class object")
-
-    def labels_by_value(self, value):
-        ret, labels = self._get_mapping_labels_by_value(self._ptr, value)
-        utils._handle_ret(ret, "cannot get mapping labels")
-        return labels
-
-    def __iter__(self):
-        for idx in range(len(self)):
-            mapping = self._get_mapping_by_index(self._ptr, idx)
-            yield mapping.label
-
-    def __getitem__(self, key):
-        utils._check_str(key)
-        for idx in range(len(self)):
-            mapping = self._get_mapping_by_index(self._ptr, idx)
-            if mapping.label == key:
-                return mapping
-
-        raise KeyError(key)
-
-    def __iadd__(self, mappings):
-        for mapping in mappings.values():
-            for range in mapping:
-                self.map_range(mapping.label, range.lower, range.upper)
-
-        return self
-
-
-class _UnsignedEnumerationFieldClass(_EnumerationFieldClass, _UnsignedIntegerFieldClass):
-    _NAME = 'Unsigned enumeration'
-
-    @staticmethod
-    def _get_mapping_by_index(enum_ptr, index):
-        mapping_ptr = native_bt.field_class_unsigned_enumeration_borrow_mapping_by_index_const(enum_ptr, index)
-        assert mapping_ptr is not None
-        return _UnsignedEnumerationFieldClassMapping(mapping_ptr)
-
-    @staticmethod
-    def _map_range(enum_ptr, label, lower, upper):
-        utils._check_uint64(lower)
-        utils._check_uint64(upper)
-        return native_bt.field_class_unsigned_enumeration_map_range(enum_ptr, label, lower, upper)
-
-    @staticmethod
-    def _get_mapping_labels_by_value(enum_ptr, value):
-        utils._check_uint64(value)
-        return native_bt.field_class_unsigned_enumeration_get_mapping_labels_by_value(enum_ptr, value)
-
-
-class _SignedEnumerationFieldClass(_EnumerationFieldClass, _SignedIntegerFieldClass):
-    _NAME = 'Signed enumeration'
-
-    @staticmethod
-    def _get_mapping_by_index(enum_ptr, index):
-        mapping_ptr = native_bt.field_class_signed_enumeration_borrow_mapping_by_index_const(enum_ptr, index)
-        assert mapping_ptr is not None
-        return _SignedEnumerationFieldClassMapping(mapping_ptr)
-
-    @staticmethod
-    def _map_range(enum_ptr, label, lower, upper):
-        utils._check_int64(lower)
-        utils._check_int64(upper)
-        return native_bt.field_class_signed_enumeration_map_range(enum_ptr, label, lower, upper)
-
-    @staticmethod
-    def _get_mapping_labels_by_value(enum_ptr, value):
-        utils._check_int64(value)
-        return native_bt.field_class_signed_enumeration_get_mapping_labels_by_value(enum_ptr, value)
-
-
-class _StringFieldClass(_FieldClass):
-    _NAME = 'String'
-
-
-class _FieldContainer(collections.abc.Mapping):
-    def __len__(self):
-        count = self._get_element_count(self._ptr)
-        assert count >= 0
-        return count
-
-    def __getitem__(self, key):
-        if not isinstance(key, str):
-            raise TypeError("key should be a 'str' object, got {}".format(key.__class__.__name__))
-
-        ptr = self._borrow_field_class_ptr_by_name(key)
-
-        if ptr is None:
-            raise KeyError(key)
-
-        return _create_field_class_from_ptr_and_get_ref(ptr)
-
-    def _borrow_field_class_ptr_by_name(self, key):
-        element_ptr = self._borrow_element_by_name(self._ptr, key)
-        if element_ptr is None:
-            return
-
-        return self._element_borrow_field_class(element_ptr)
-
-    def __iter__(self):
-        for idx in range(len(self)):
-            element_ptr = self._borrow_element_by_index(self._ptr, idx)
-            assert element_ptr is not None
-
-            yield self._element_get_name(element_ptr)
-
-    def _append_element_common(self, name, field_class):
-        utils._check_str(name)
-        utils._check_type(field_class, _FieldClass)
-        ret = self._append_element(self._ptr, name, field_class._ptr)
-        utils._handle_ret(ret, "cannot add field to {} field class object".format(self._NAME.lower()))
-
-    def __iadd__(self, fields):
-        for name, field_class in fields.items():
-            self._append_element_common(name, field_class)
-
-        return self
-
-    def _at_index(self, index):
-        utils._check_uint64(index)
-
-        if index < 0 or index >= len(self):
-            raise IndexError
-
-        element_ptr = self._borrow_element_by_index(self._ptr, index)
-        assert element_ptr is not None
-
-        field_class_ptr = self._element_borrow_field_class(element_ptr)
-
-        return _create_field_class_from_ptr_and_get_ref(field_class_ptr)
-
-
-class _StructureFieldClass(_FieldClass, _FieldContainer):
-    _NAME = 'Structure'
-    _borrow_element_by_index = staticmethod(native_bt.field_class_structure_borrow_member_by_index_const)
-    _borrow_element_by_name = staticmethod(native_bt.field_class_structure_borrow_member_by_name_const)
-    _element_get_name = staticmethod(native_bt.field_class_structure_member_get_name)
-    _element_borrow_field_class = staticmethod(native_bt.field_class_structure_member_borrow_field_class_const)
-    _get_element_count = staticmethod(native_bt.field_class_structure_get_member_count)
-    _append_element = staticmethod(native_bt.field_class_structure_append_member)
-
-    def append_member(self, name, field_class):
-        return self._append_element_common(name, field_class)
-
-    def member_at_index(self, index):
-        return self._at_index(index)
-
-
-class _VariantFieldClass(_FieldClass, _FieldContainer):
-    _NAME = 'Variant'
-    _borrow_element_by_index = staticmethod(native_bt.field_class_variant_borrow_option_by_index_const)
-    _borrow_element_by_name = staticmethod(native_bt.field_class_variant_borrow_option_by_name_const)
-    _element_get_name = staticmethod(native_bt.field_class_variant_option_get_name)
-    _element_borrow_field_class = staticmethod(native_bt.field_class_variant_option_borrow_field_class_const)
-    _get_element_count = staticmethod(native_bt.field_class_variant_get_option_count)
-    _append_element = staticmethod(native_bt.field_class_variant_append_option)
-
-    def append_option(self, name, field_class):
-        return self._append_element_common(name, field_class)
-
-    def option_at_index(self, index):
-        return self._at_index(index)
-
-    @property
-    def selector_field_path(self):
-        ptr = native_bt.field_class_variant_borrow_selector_field_path_const(self._ptr)
-        if ptr is None:
-            return
-
-        return bt2.field_path._FieldPath._create_from_ptr_and_get_ref(ptr)
-
-    def _set_selector_field_class(self, selector_fc):
-        utils._check_type(selector_fc, bt2.field_class._EnumerationFieldClass)
-        ret = native_bt.field_class_variant_set_selector_field_class(self._ptr, selector_fc._ptr)
-        utils._handle_ret(ret, "cannot set variant selector field type")
-
-    _selector_field_class = property(fset=_set_selector_field_class)
-
-
-class _ArrayFieldClass(_FieldClass):
-    @property
-    def element_field_class(self):
-        elem_fc_ptr = native_bt.field_class_array_borrow_element_field_class_const(self._ptr)
-        return _create_field_class_from_ptr_and_get_ref(elem_fc_ptr)
-
-
-class _StaticArrayFieldClass(_ArrayFieldClass):
-    @property
-    def length(self):
-        return native_bt.field_class_static_array_get_length(self._ptr)
-
-
-class _DynamicArrayFieldClass(_ArrayFieldClass):
-    @property
-    def length_field_path(self):
-        ptr = native_bt.field_class_dynamic_array_borrow_length_field_path_const(self._ptr)
-        if ptr is None:
-            return
-
-        return bt2.field_path._FieldPath._create_from_ptr_and_get_ref(ptr)
-
-    def _set_length_field_class(self, length_fc):
-        utils._check_type(length_fc, _UnsignedIntegerFieldClass)
-        ret = native_bt.field_class_dynamic_array_set_length_field_class(self._ptr, length_fc._ptr)
-        utils._handle_ret(ret, "cannot set dynamic array length field type")
-
-    _length_field_class = property(fset=_set_length_field_class)
-
-
-_FIELD_CLASS_TYPE_TO_OBJ = {
-    native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerFieldClass,
-    native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerFieldClass,
-    native_bt.FIELD_CLASS_TYPE_REAL: _RealFieldClass,
-    native_bt.FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: _UnsignedEnumerationFieldClass,
-    native_bt.FIELD_CLASS_TYPE_SIGNED_ENUMERATION: _SignedEnumerationFieldClass,
-    native_bt.FIELD_CLASS_TYPE_STRING: _StringFieldClass,
-    native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureFieldClass,
-    native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayFieldClass,
-    native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY: _DynamicArrayFieldClass,
-    native_bt.FIELD_CLASS_TYPE_VARIANT: _VariantFieldClass,
-}
diff --git a/bindings/python/bt2/bt2/field_path.py b/bindings/python/bt2/bt2/field_path.py
deleted file mode 100644 (file)
index 2191171..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-import collections
-from bt2 import native_bt, object
-
-
-class Scope:
-    PACKET_CONTEXT = native_bt.SCOPE_PACKET_CONTEXT
-    EVENT_COMMON_CONTEXT = native_bt.SCOPE_EVENT_COMMON_CONTEXT
-    EVENT_SPECIFIC_CONTEXT = native_bt.SCOPE_EVENT_SPECIFIC_CONTEXT
-    EVENT_PAYLOAD = native_bt.SCOPE_EVENT_PAYLOAD
-
-
-class _FieldPathItem:
-    pass
-
-
-class _IndexFieldPathItem(_FieldPathItem):
-    def __init__(self, index):
-        self._index = index
-
-    @property
-    def index(self):
-        return self._index
-
-
-class _CurrentArrayElementFieldPathItem(_FieldPathItem):
-    pass
-
-
-class _FieldPath(object._SharedObject, collections.abc.Iterable):
-    _get_ref = staticmethod(native_bt.field_path_get_ref)
-    _put_ref = staticmethod(native_bt.field_path_put_ref)
-
-    @property
-    def root_scope(self):
-        scope = native_bt.field_path_get_root_scope(self._ptr)
-        return _SCOPE_TO_OBJ[scope]
-
-    def __len__(self):
-        return native_bt.field_path_get_item_count(self._ptr)
-
-    def __iter__(self):
-        for idx in range(len(self)):
-            item_ptr = native_bt.field_path_borrow_item_by_index_const(self._ptr, idx)
-            assert item_ptr is not None
-            item_type = native_bt.field_path_item_get_type(item_ptr)
-            if item_type == native_bt.FIELD_PATH_ITEM_TYPE_INDEX:
-                idx = native_bt.field_path_item_index_get_index(item_ptr)
-                yield _IndexFieldPathItem(idx)
-            elif item_type == native_bt.FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
-                yield  _CurrentArrayElementFieldPathItem()
-            else:
-                assert False
-
-
-_SCOPE_TO_OBJ = {
-    native_bt.SCOPE_PACKET_CONTEXT: Scope.PACKET_CONTEXT,
-    native_bt.SCOPE_EVENT_COMMON_CONTEXT: Scope.EVENT_COMMON_CONTEXT,
-    native_bt.SCOPE_EVENT_SPECIFIC_CONTEXT: Scope.EVENT_SPECIFIC_CONTEXT,
-    native_bt.SCOPE_EVENT_PAYLOAD: Scope.EVENT_PAYLOAD
-}
diff --git a/bindings/python/bt2/bt2/graph.py b/bindings/python/bt2/bt2/graph.py
deleted file mode 100644 (file)
index 998d310..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.connection
-import bt2.component
-import functools
-import bt2.port
-import bt2
-
-
-def _graph_port_added_listener_from_native(user_listener,
-                                           component_ptr, component_type,
-                                           port_ptr, port_type):
-    component = bt2.component._create_component_from_ptr_and_get_ref(component_ptr, component_type)
-    port = bt2.port._create_from_ptr_and_get_ref(port_ptr, port_type)
-    user_listener(component, port)
-
-
-def _graph_ports_connected_listener_from_native(user_listener,
-                                                upstream_component_ptr, upstream_component_type,
-                                                upstream_port_ptr,
-                                                downstream_component_ptr, downstream_component_type,
-                                                downstream_port_ptr):
-    upstream_component = bt2.component._create_component_from_ptr_and_get_ref(
-        upstream_component_ptr, upstream_component_type)
-    upstream_port = bt2.port._create_from_ptr_and_get_ref(
-        upstream_port_ptr, native_bt.PORT_TYPE_OUTPUT)
-    downstream_component = bt2.component._create_component_from_ptr_and_get_ref(
-        downstream_component_ptr, downstream_component_type)
-    downstream_port = bt2.port._create_from_ptr_and_get_ref(
-        downstream_port_ptr, native_bt.PORT_TYPE_INPUT)
-    user_listener(upstream_component, upstream_port, downstream_component, downstream_port)
-
-
-class Graph(object._SharedObject):
-    _get_ref = staticmethod(native_bt.graph_get_ref)
-    _put_ref = staticmethod(native_bt.graph_put_ref)
-
-    def __init__(self):
-        ptr = native_bt.graph_create()
-
-        if ptr is None:
-            raise bt2.CreationError('cannot create graph object')
-
-        super().__init__(ptr)
-
-    def _handle_status(self, status, gen_error_msg):
-        if status == native_bt.GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
-            raise bt2.PortConnectionRefused
-        elif status == native_bt.GRAPH_STATUS_CANCELED:
-            raise bt2.GraphCanceled
-        elif status == native_bt.GRAPH_STATUS_END:
-            raise bt2.Stop
-        elif status == native_bt.GRAPH_STATUS_AGAIN:
-            raise bt2.TryAgain
-        elif status < 0:
-            raise bt2.Error(gen_error_msg)
-
-    def add_component(self, component_class, name, params=None):
-        if isinstance(component_class, bt2.component._GenericSourceComponentClass):
-            cc_ptr = component_class._ptr
-            add_fn = native_bt.graph_add_source_component
-            cc_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE
-        elif isinstance(component_class, bt2.component._GenericFilterComponentClass):
-            cc_ptr = component_class._ptr
-            add_fn = native_bt.graph_add_filter_component
-            cc_type = native_bt.COMPONENT_CLASS_TYPE_FILTER
-        elif isinstance(component_class, bt2.component._GenericSinkComponentClass):
-            cc_ptr = component_class._ptr
-            add_fn = native_bt.graph_add_sink_component
-            cc_type = native_bt.COMPONENT_CLASS_TYPE_SINK
-        elif issubclass(component_class, bt2.component._UserSourceComponent):
-            cc_ptr = component_class._cc_ptr
-            add_fn = native_bt.graph_add_source_component
-            cc_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE
-        elif issubclass(component_class, bt2.component._UserSinkComponent):
-            cc_ptr = component_class._cc_ptr
-            add_fn = native_bt.graph_add_sink_component
-            cc_type = native_bt.COMPONENT_CLASS_TYPE_SINK
-        elif issubclass(component_class, bt2.component._UserFilterComponent):
-            cc_ptr = component_class._cc_ptr
-            add_fn = native_bt.graph_add_filter_component
-            cc_type = native_bt.COMPONENT_CLASS_TYPE_FILTER
-        else:
-            raise TypeError("'{}' is not a component class".format(
-                component_class.__class__.__name__))
-
-        utils._check_str(name)
-        params = bt2.create_value(params)
-
-        params_ptr = params._ptr if params is not None else None
-
-        status, comp_ptr = add_fn(self._ptr, cc_ptr, name, params_ptr)
-        self._handle_status(status, 'cannot add component to graph')
-        assert comp_ptr
-        return bt2.component._create_component_from_ptr(comp_ptr, cc_type)
-
-    def connect_ports(self, upstream_port, downstream_port):
-        utils._check_type(upstream_port, bt2.port._OutputPort)
-        utils._check_type(downstream_port, bt2.port._InputPort)
-        status, conn_ptr = native_bt.graph_connect_ports(self._ptr,
-                                                         upstream_port._ptr,
-                                                         downstream_port._ptr)
-        self._handle_status(status, 'cannot connect component ports within graph')
-        assert(conn_ptr)
-        return bt2.connection._Connection._create_from_ptr(conn_ptr)
-
-    def add_port_added_listener(self, listener):
-        if not callable(listener):
-            raise TypeError("'listener' parameter is not callable")
-
-        fn = native_bt.py3_graph_add_port_added_listener
-        listener_from_native = functools.partial(_graph_port_added_listener_from_native,
-                                                 listener)
-
-        listener_ids = fn(self._ptr, listener_from_native)
-        if listener_ids is None:
-            utils._raise_bt2_error('cannot add listener to graph object')
-        return bt2._ListenerHandle(listener_ids, self)
-
-    def add_ports_connected_listener(self, listener):
-        if not callable(listener):
-            raise TypeError("'listener' parameter is not callable")
-
-        fn = native_bt.py3_graph_add_ports_connected_listener
-        listener_from_native = functools.partial(_graph_ports_connected_listener_from_native,
-                                                 listener)
-
-        listener_ids = fn(self._ptr, listener_from_native)
-        if listener_ids is None:
-            utils._raise_bt2_error('cannot add listener to graph object')
-        return bt2._ListenerHandle(listener_ids, self)
-
-    def run(self):
-        status = native_bt.graph_run(self._ptr)
-
-        if status == native_bt.GRAPH_STATUS_END:
-            return
-
-        self._handle_status(status, 'graph object stopped running because of an unexpected error')
-
-    def cancel(self):
-        status = native_bt.graph_cancel(self._ptr)
-        self._handle_status(status, 'cannot cancel graph object')
-
-    @property
-    def is_canceled(self):
-        is_canceled = native_bt.graph_is_canceled(self._ptr)
-        assert(is_canceled >= 0)
-        return is_canceled > 0
-
-    def create_output_port_message_iterator(self, output_port):
-        utils._check_type(output_port, bt2.port._OutputPort)
-        msg_iter_ptr = native_bt.port_output_message_iterator_create(self._ptr, output_port._ptr)
-
-        if msg_iter_ptr is None:
-            raise bt2.CreationError('cannot create output port message iterator')
-
-        return bt2.message_iterator._OutputPortMessageIterator(msg_iter_ptr)
diff --git a/bindings/python/bt2/bt2/logging.c b/bindings/python/bt2/bt2/logging.c
deleted file mode 100644 (file)
index 698baf9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_python_bindings_bt2_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_python_bindings_bt2_log_level,
-       "BABELTRACE_PYTHON_BT2_LOG_LEVEL");
diff --git a/bindings/python/bt2/bt2/logging.h b/bindings/python/bt2/bt2/logging.h
deleted file mode 100644 (file)
index 21b5850..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef BABELTRACE_BINDINGS_PYTHON_BT2_LOGGING_H
-#define BABELTRACE_BINDINGS_PYTHON_BT2_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_python_bindings_bt2_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_python_bindings_bt2_log_level);
-
-#endif /* BABELTRACE_BINDINGS_PYTHON_BT2_LOGGING_H */
diff --git a/bindings/python/bt2/bt2/logging.py b/bindings/python/bt2/bt2/logging.py
deleted file mode 100644 (file)
index 51d898c..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2
-
-
-class LoggingLevel:
-    VERBOSE = native_bt.LOGGING_LEVEL_VERBOSE
-    DEBUG = native_bt.LOGGING_LEVEL_DEBUG
-    INFO = native_bt.LOGGING_LEVEL_INFO
-    WARN = native_bt.LOGGING_LEVEL_WARN
-    ERROR = native_bt.LOGGING_LEVEL_ERROR
-    FATAL = native_bt.LOGGING_LEVEL_FATAL
-    NONE = native_bt.LOGGING_LEVEL_NONE
-
-
-def get_minimal_logging_level():
-    return native_bt.logging_get_minimal_level()
-
-
-def get_global_logging_level():
-    return native_bt.logging_get_global_level()
-
-
-def set_global_logging_level(level):
-    levels = (
-        LoggingLevel.VERBOSE,
-        LoggingLevel.DEBUG,
-        LoggingLevel.INFO,
-        LoggingLevel.WARN,
-        LoggingLevel.ERROR,
-        LoggingLevel.FATAL,
-        LoggingLevel.NONE,
-    )
-
-    if level not in levels:
-        raise TypeError("'{}' is not a valid logging level".format(level))
-
-    return native_bt.logging_set_global_level(level)
diff --git a/bindings/python/bt2/bt2/message.py b/bindings/python/bt2/bt2/message.py
deleted file mode 100644 (file)
index 56b545d..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.clock_snapshot
-import bt2.packet
-import bt2.stream
-import bt2.event
-import bt2
-
-
-def _create_from_ptr(ptr):
-    msg_type = native_bt.message_get_type(ptr)
-
-    if msg_type not in _MESSAGE_TYPE_TO_CLS:
-        raise bt2.Error('unknown message type: {}'.format(msg_type))
-
-    return _MESSAGE_TYPE_TO_CLS[msg_type]._create_from_ptr(ptr)
-
-
-class _Message(object._SharedObject):
-    _get_ref = staticmethod(native_bt.message_get_ref)
-    _put_ref = staticmethod(native_bt.message_put_ref)
-
-    @staticmethod
-    def _check_has_default_clock_class(clock_class):
-        if clock_class is None:
-            raise bt2.NonexistentClockSnapshot('cannot get default clock snapshot: stream class has no default clock class')
-
-
-class _MessageWithDefaultClockSnapshot:
-    def _get_default_clock_snapshot(self, borrow_clock_snapshot_ptr):
-        snapshot_ptr = borrow_clock_snapshot_ptr(self._ptr)
-
-        return bt2.clock_snapshot._ClockSnapshot._create_from_ptr_and_get_ref(
-            snapshot_ptr, self._ptr, self._get_ref, self._put_ref)
-
-
-class _EventMessage(_Message, _MessageWithDefaultClockSnapshot):
-    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_event_borrow_default_clock_snapshot_const)
-
-    @property
-    def default_clock_snapshot(self):
-        self._check_has_default_clock_class(self.event.packet.stream.cls.default_clock_class)
-        return self._get_default_clock_snapshot(self._borrow_default_clock_snapshot_ptr)
-
-    @property
-    def event(self):
-        event_ptr = native_bt.message_event_borrow_event(self._ptr)
-        assert event_ptr is not None
-        return bt2.event._Event._create_from_ptr_and_get_ref(
-            event_ptr, self._ptr, self._get_ref, self._put_ref)
-
-
-class _PacketMessage(_Message, _MessageWithDefaultClockSnapshot):
-    @property
-    def default_clock_snapshot(self):
-        self._check_has_default_clock_class(self.packet.stream.cls.default_clock_class)
-        return self._get_default_clock_snapshot(self._borrow_default_clock_snapshot_ptr)
-
-    @property
-    def packet(self):
-        packet_ptr = self._borrow_packet_ptr(self._ptr)
-        assert packet_ptr is not None
-        return bt2.packet._Packet._create_from_ptr_and_get_ref(packet_ptr)
-
-
-class _PacketBeginningMessage(_PacketMessage):
-    _borrow_packet_ptr = staticmethod(native_bt.message_packet_beginning_borrow_packet)
-    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_packet_beginning_borrow_default_clock_snapshot_const)
-
-
-class _PacketEndMessage(_PacketMessage):
-    _borrow_packet_ptr = staticmethod(native_bt.message_packet_end_borrow_packet)
-    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_packet_end_borrow_default_clock_snapshot_const)
-
-
-class _StreamMessage(_Message):
-    @property
-    def stream(self):
-        stream_ptr = self._borrow_stream_ptr(self._ptr)
-        assert stream_ptr
-        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
-
-
-class _StreamBeginningMessage(_StreamMessage):
-    _borrow_stream_ptr = staticmethod(native_bt.message_stream_beginning_borrow_stream)
-
-
-class _StreamEndMessage(_StreamMessage):
-    _borrow_stream_ptr = staticmethod(native_bt.message_stream_end_borrow_stream)
-
-
-class _StreamActivityMessage(_Message):
-    @property
-    def default_clock_snapshot(self):
-        self._check_has_default_clock_class(self.stream.cls.default_clock_class)
-        status, snapshot_ptr = self._borrow_default_clock_snapshot_ptr(self._ptr)
-
-        if status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
-            snapshot_type = bt2.clock_snapshot._ClockSnapshot
-        elif status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
-            snapshot_type = bt2.clock_snapshot._UnknownClockSnapshot
-        elif status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
-            snapshot_type = bt2.clock_snapshot._InfiniteClockSnapshot
-        else:
-            raise bt2.Error('cannot borrow default clock snapshot from message')
-
-        assert snapshot_ptr is not None
-
-        return snapshot_type._create_from_ptr_and_get_ref(
-            snapshot_ptr, self._ptr, self._get_ref, self._put_ref)
-
-    def _default_clock_snapshot(self, value):
-        self._set_default_clock_snapshot_ptr(self._ptr, value)
-
-    _default_clock_snapshot = property(fset=_default_clock_snapshot)
-
-    @property
-    def stream(self):
-        stream_ptr = self._borrow_stream_ptr(self._ptr)
-        assert stream_ptr
-        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
-
-
-class _StreamActivityBeginningMessage(_StreamActivityMessage):
-    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_beginning_borrow_default_clock_snapshot_const)
-    _set_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_beginning_set_default_clock_snapshot)
-    _borrow_stream_ptr = staticmethod(native_bt.message_stream_activity_beginning_borrow_stream)
-
-
-class _StreamActivityEndMessage(_StreamActivityMessage):
-    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_end_borrow_default_clock_snapshot_const)
-    _set_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_end_set_default_clock_snapshot)
-    _borrow_stream_ptr = staticmethod(native_bt.message_stream_activity_end_borrow_stream)
-
-
-class _MessageIteratorInactivityMessage(_Message, _MessageWithDefaultClockSnapshot):
-    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_message_iterator_inactivity_borrow_default_clock_snapshot_const)
-
-    @property
-    def default_clock_snapshot(self):
-        # This kind of message always has a default clock class: no
-        # need to call self._check_has_default_clock_class() here.
-        return self._get_default_clock_snapshot(self._borrow_default_clock_snapshot_ptr)
-
-
-class _DiscardedMessage(_Message, _MessageWithDefaultClockSnapshot):
-    @property
-    def stream(self):
-        stream_ptr = self._borrow_stream_ptr(self._ptr)
-        assert stream_ptr
-        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
-
-    @property
-    def count(self):
-        avail, count = self._get_count(self._ptr)
-        if avail is native_bt.PROPERTY_AVAILABILITY_AVAILABLE:
-            return count
-
-    def _set_count(self, count):
-        utils._check_uint64(count)
-        self._set_count(self._ptr, count)
-
-    _count = property(fset=_set_count)
-
-    def _check_has_default_clock_snapshots(self):
-        if not self._has_default_clock_snapshots:
-            raise bt2.NonexistentClockSnapshot('cannot get default clock snapshot: such a message has no clock snapshots for this stream class')
-
-    @property
-    def beginning_default_clock_snapshot(self):
-        self._check_has_default_clock_snapshots()
-        return self._get_default_clock_snapshot(self._borrow_beginning_clock_snapshot_ptr)
-
-    @property
-    def end_default_clock_snapshot(self):
-        self._check_has_default_clock_snapshots()
-        return self._get_default_clock_snapshot(self._borrow_end_clock_snapshot_ptr)
-
-
-class _DiscardedEventsMessage(_DiscardedMessage):
-    _borrow_stream_ptr = staticmethod(native_bt.message_discarded_events_borrow_stream_const)
-    _get_count = staticmethod(native_bt.message_discarded_events_get_count)
-    _set_count = staticmethod(native_bt.message_discarded_events_set_count)
-    _borrow_beginning_clock_snapshot_ptr = staticmethod(native_bt.message_discarded_events_borrow_beginning_default_clock_snapshot_const)
-    _borrow_end_clock_snapshot_ptr = staticmethod(native_bt.message_discarded_events_borrow_end_default_clock_snapshot_const)
-
-    @property
-    def _has_default_clock_snapshots(self):
-        return self.stream.cls.discarded_events_have_default_clock_snapshots
-
-
-class _DiscardedPacketsMessage(_DiscardedMessage):
-    _borrow_stream_ptr = staticmethod(native_bt.message_discarded_packets_borrow_stream_const)
-    _get_count = staticmethod(native_bt.message_discarded_packets_get_count)
-    _set_count = staticmethod(native_bt.message_discarded_packets_set_count)
-    _borrow_beginning_clock_snapshot_ptr = staticmethod(native_bt.message_discarded_packets_borrow_beginning_default_clock_snapshot_const)
-    _borrow_end_clock_snapshot_ptr = staticmethod(native_bt.message_discarded_packets_borrow_end_default_clock_snapshot_const)
-
-    @property
-    def _has_default_clock_snapshots(self):
-        return self.stream.cls.discarded_packets_have_default_clock_snapshots
-
-
-_MESSAGE_TYPE_TO_CLS = {
-    native_bt.MESSAGE_TYPE_EVENT: _EventMessage,
-    native_bt.MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY: _MessageIteratorInactivityMessage,
-    native_bt.MESSAGE_TYPE_STREAM_BEGINNING: _StreamBeginningMessage,
-    native_bt.MESSAGE_TYPE_STREAM_END: _StreamEndMessage,
-    native_bt.MESSAGE_TYPE_PACKET_BEGINNING: _PacketBeginningMessage,
-    native_bt.MESSAGE_TYPE_PACKET_END: _PacketEndMessage,
-    native_bt.MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING: _StreamActivityBeginningMessage,
-    native_bt.MESSAGE_TYPE_STREAM_ACTIVITY_END: _StreamActivityEndMessage,
-    native_bt.MESSAGE_TYPE_DISCARDED_EVENTS: _DiscardedEventsMessage,
-    native_bt.MESSAGE_TYPE_DISCARDED_PACKETS: _DiscardedPacketsMessage,
-}
diff --git a/bindings/python/bt2/bt2/message_iterator.py b/bindings/python/bt2/bt2/message_iterator.py
deleted file mode 100644 (file)
index 7f996b0..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.message
-import collections.abc
-import bt2.component
-import bt2
-
-
-class _MessageIterator(collections.abc.Iterator):
-    def _handle_status(self, status, gen_error_msg):
-        if status == native_bt.MESSAGE_ITERATOR_STATUS_AGAIN:
-            raise bt2.TryAgain
-        elif status == native_bt.MESSAGE_ITERATOR_STATUS_END:
-            raise bt2.Stop
-        elif status < 0:
-            raise bt2.Error(gen_error_msg)
-
-    def __next__(self):
-        raise NotImplementedError
-
-
-class _GenericMessageIterator(object._SharedObject, _MessageIterator):
-    def __init__(self, ptr):
-            self._current_msgs = []
-            self._at = 0
-            super().__init__(ptr)
-
-    def __next__(self):
-        if len(self._current_msgs) == self._at:
-            status, msgs = self._get_msg_range(self._ptr)
-            self._handle_status(status,
-                                'unexpected error: cannot advance the message iterator')
-            self._current_msgs = msgs
-            self._at = 0
-
-        msg_ptr = self._current_msgs[self._at]
-        self._at += 1
-
-        return bt2.message._create_from_ptr(msg_ptr)
-
-
-# This is created when a component wants to iterate on one of its input ports.
-class _UserComponentInputPortMessageIterator(_GenericMessageIterator):
-    _get_msg_range = staticmethod(native_bt.py3_self_component_port_input_get_msg_range)
-    _get_ref = staticmethod(native_bt.self_component_port_input_message_iterator_get_ref)
-    _put_ref = staticmethod(native_bt.self_component_port_input_message_iterator_put_ref)
-
-
-# This is created when the user wants to iterate on a component's output port,
-# from outside the graph.
-class _OutputPortMessageIterator(_GenericMessageIterator):
-    _get_msg_range = staticmethod(native_bt.py3_port_output_get_msg_range)
-    _get_ref = staticmethod(native_bt.port_output_message_iterator_get_ref)
-    _put_ref = staticmethod(native_bt.port_output_message_iterator_put_ref)
-
-
-# This is extended by the user to implement component classes in Python.  It
-# is created for a given output port when an input port message iterator is
-# created on the input port on the other side of the connection.  It is also
-# created when an output port message iterator is created on this output port.
-#
-# Its purpose is to feed the messages that should go out through this output
-# port.
-class _UserMessageIterator(_MessageIterator):
-    def __new__(cls, ptr):
-        # User iterator objects are always created by the native side,
-        # that is, never instantiated directly by Python code.
-        #
-        # The native code calls this, then manually calls
-        # self.__init__() without the `ptr` argument. The user has
-        # access to self.component during this call, thanks to this
-        # self._ptr argument being set.
-        #
-        # self._ptr is NOT owned by this object here, so there's nothing
-        # to do in __del__().
-        self = super().__new__(cls)
-        self._ptr = ptr
-        return self
-
-    def _init_from_native(self, self_output_port_ptr):
-        self_output_port = bt2.port._create_self_from_ptr_and_get_ref(
-            self_output_port_ptr, native_bt.PORT_TYPE_OUTPUT)
-        self.__init__(self_output_port)
-
-    def __init__(self, output_port):
-        pass
-
-    @property
-    def _component(self):
-        return native_bt.py3_get_user_component_from_user_msg_iter(self._ptr)
-
-    @property
-    def addr(self):
-        return int(self._ptr)
-
-    def _finalize(self):
-        pass
-
-    def __next__(self):
-        raise bt2.Stop
-
-    def _next_from_native(self):
-        # this can raise anything: it's catched by the native part
-        try:
-            msg = next(self)
-        except StopIteration:
-            raise bt2.Stop
-        except:
-            raise
-
-        utils._check_type(msg, bt2.message._Message)
-
-        # Release the reference to the native part.
-        ptr = msg._release()
-        return int(ptr)
-
-    # Validate that the presence or lack of presence of a
-    # `default_clock_snapshot` value is valid in the context of `stream_class`.
-    @staticmethod
-    def _validate_default_clock_snapshot(stream_class, default_clock_snapshot):
-        stream_class_has_default_clock_class = stream_class.default_clock_class is not None
-
-        if stream_class_has_default_clock_class and default_clock_snapshot is None:
-            raise bt2.Error(
-                'stream class has a default clock class, default_clock_snapshot should not be None')
-
-        if not stream_class_has_default_clock_class and default_clock_snapshot is not None:
-            raise bt2.Error(
-                'stream class has no default clock class, default_clock_snapshot should be None')
-
-    def _create_event_message(self, event_class, packet, default_clock_snapshot=None):
-        utils._check_type(event_class, bt2.event_class._EventClass)
-        utils._check_type(packet, bt2.packet._Packet)
-        self._validate_default_clock_snapshot(packet.stream.cls, default_clock_snapshot)
-
-        if default_clock_snapshot is not None:
-            utils._check_uint64(default_clock_snapshot)
-            ptr = native_bt.message_event_create_with_default_clock_snapshot(
-                self._ptr, event_class._ptr, packet._ptr, default_clock_snapshot)
-        else:
-            ptr = native_bt.message_event_create(
-                self._ptr, event_class._ptr, packet._ptr)
-
-        if ptr is None:
-            raise bt2.CreationError('cannot create event message object')
-
-        return bt2.message._EventMessage(ptr)
-
-    def _create_message_iterator_inactivity_message(self, clock_class, clock_snapshot):
-        utils._check_type(clock_class, bt2.clock_class._ClockClass)
-        ptr = native_bt.message_message_iterator_inactivity_create(
-            self._ptr, clock_class._ptr, clock_snapshot)
-
-        if ptr is None:
-            raise bt2.CreationError('cannot create inactivity message object')
-
-        return bt2.message._MessageIteratorInactivityMessage(ptr)
-
-    def _create_stream_beginning_message(self, stream):
-        utils._check_type(stream, bt2.stream._Stream)
-
-        ptr = native_bt.message_stream_beginning_create(self._ptr, stream._ptr)
-        if ptr is None:
-            raise bt2.CreationError('cannot create stream beginning message object')
-
-        return bt2.message._StreamBeginningMessage(ptr)
-
-    def _create_stream_activity_beginning_message(self, stream, default_clock_snapshot=None):
-        utils._check_type(stream, bt2.stream._Stream)
-        self._validate_default_clock_snapshot(stream.cls, default_clock_snapshot)
-
-        ptr = native_bt.message_stream_activity_beginning_create(self._ptr, stream._ptr)
-
-        if ptr is None:
-            raise bt2.CreationError(
-                'cannot create stream activity beginning message object')
-
-        msg = bt2.message._StreamActivityBeginningMessage(ptr)
-
-        if default_clock_snapshot is not None:
-            msg._default_clock_snapshot = default_clock_snapshot
-
-        return msg
-
-    def _create_stream_activity_end_message(self, stream, default_clock_snapshot=None):
-        utils._check_type(stream, bt2.stream._Stream)
-        self._validate_default_clock_snapshot(stream.cls, default_clock_snapshot)
-
-        ptr = native_bt.message_stream_activity_end_create(self._ptr, stream._ptr)
-
-        if ptr is None:
-            raise bt2.CreationError(
-                'cannot create stream activity end message object')
-
-        msg = bt2.message._StreamActivityEndMessage(ptr)
-
-        if default_clock_snapshot is not None:
-            msg._default_clock_snapshot = default_clock_snapshot
-
-        return msg
-
-    def _create_stream_end_message(self, stream):
-        utils._check_type(stream, bt2.stream._Stream)
-
-        ptr = native_bt.message_stream_end_create(self._ptr, stream._ptr)
-        if ptr is None:
-            raise bt2.CreationError('cannot create stream end message object')
-
-        return bt2.message._StreamEndMessage(ptr)
-
-    def _create_packet_beginning_message(self, packet, default_clock_snapshot=None):
-        utils._check_type(packet, bt2.packet._Packet)
-
-        if packet.stream.cls.packets_have_beginning_default_clock_snapshot:
-            if default_clock_snapshot is None:
-                raise ValueError("packet beginning messages in this stream must have a default clock snapshots")
-
-            utils._check_uint64(default_clock_snapshot)
-            ptr = native_bt.message_packet_beginning_create_with_default_clock_snapshot(
-                self._ptr, packet._ptr, default_clock_snapshot)
-        else:
-            if default_clock_snapshot is not None:
-                raise ValueError("packet beginning messages in this stream must not have a default clock snapshots")
-
-            ptr = native_bt.message_packet_beginning_create(self._ptr, packet._ptr)
-
-        if ptr is None:
-            raise bt2.CreationError('cannot create packet beginning message object')
-
-        return bt2.message._PacketBeginningMessage(ptr)
-
-    def _create_packet_end_message(self, packet, default_clock_snapshot=None):
-        utils._check_type(packet, bt2.packet._Packet)
-
-        if packet.stream.cls.packets_have_end_default_clock_snapshot:
-            if default_clock_snapshot is None:
-                raise ValueError("packet end messages in this stream must have a default clock snapshots")
-
-            utils._check_uint64(default_clock_snapshot)
-            ptr = native_bt.message_packet_end_create_with_default_clock_snapshot(
-                self._ptr, packet._ptr, default_clock_snapshot)
-        else:
-            if default_clock_snapshot is not None:
-                raise ValueError("packet end messages in this stream must not have a default clock snapshots")
-
-            ptr = native_bt.message_packet_end_create(self._ptr, packet._ptr)
-
-        if ptr is None:
-            raise bt2.CreationError('cannot create packet end message object')
-
-        return bt2.message._PacketEndMessage(ptr)
-
-    def _create_discarded_events_message(self, stream, count=None,
-                                         beg_clock_snapshot=None,
-                                         end_clock_snapshot=None):
-        utils._check_type(stream, bt2.stream._Stream)
-
-        if not stream.cls.supports_discarded_events:
-            raise ValueError('stream class does not support discarded events')
-
-        if stream.cls.discarded_events_have_default_clock_snapshots:
-            if beg_clock_snapshot is None or end_clock_snapshot is None:
-                raise ValueError('discarded events have default clock snapshots for this stream class')
-
-            utils._check_uint64(beg_clock_snapshot)
-            utils._check_uint64(end_clock_snapshot)
-            ptr = native_bt.message_discarded_events_create_with_default_clock_snapshots(
-                self._ptr, stream._ptr, beg_clock_snapshot, end_clock_snapshot)
-        else:
-            if beg_clock_snapshot is not None or end_clock_snapshot is not None:
-                raise ValueError('discarded events have no default clock snapshots for this stream class')
-
-            ptr = native_bt.message_discarded_events_create(
-                self._ptr, stream._ptr)
-
-        if ptr is None:
-            raise bt2.CreationError('cannot discarded events message object')
-
-        msg = bt2.message._DiscardedEventsMessage(ptr)
-
-        if count is not None:
-            msg._count = count
-
-        return msg
-
-    def _create_discarded_packets_message(self, stream, count=None, beg_clock_snapshot=None, end_clock_snapshot=None):
-        utils._check_type(stream, bt2.stream._Stream)
-
-        if not stream.cls.supports_discarded_packets:
-            raise ValueError('stream class does not support discarded packets')
-
-        if stream.cls.discarded_packets_have_default_clock_snapshots:
-            if beg_clock_snapshot is None or end_clock_snapshot is None:
-                raise ValueError('discarded packets have default clock snapshots for this stream class')
-
-            utils._check_uint64(beg_clock_snapshot)
-            utils._check_uint64(end_clock_snapshot)
-            ptr = native_bt.message_discarded_packets_create_with_default_clock_snapshots(
-                self._ptr, stream._ptr, beg_clock_snapshot, end_clock_snapshot)
-        else:
-            if beg_clock_snapshot is not None or end_clock_snapshot is not None:
-                raise ValueError('discarded packets have no default clock snapshots for this stream class')
-
-            ptr = native_bt.message_discarded_packets_create(
-                self._ptr, stream._ptr)
-
-        if ptr is None:
-            raise bt2.CreationError('cannot discarded packets message object')
-
-        msg = bt2.message._DiscardedPacketsMessage(ptr)
-
-        if count is not None:
-            msg._count = count
-
-        return msg
-
diff --git a/bindings/python/bt2/bt2/native_bt.i b/bindings/python/bt2/bt2/native_bt.i
deleted file mode 100644 (file)
index 8a43edf..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef SWIGPYTHON
-# error Unsupported output language
-#endif
-
-%module native_bt
-
-%{
-#define BT_LOG_TAG "PY-NATIVE"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/property.h>
-#include <babeltrace2/assert-internal.h>
-
-typedef const uint8_t *bt_uuid;
-%}
-
-typedef int bt_bool;
-
-/* For uint*_t/int*_t */
-%include "stdint.i"
-
-/*
- * Remove `bt_` and `BT_` prefixes from function names, global variables and
- * enumeration items
- */
-%rename("%(strip:[bt_])s", %$isfunction) "";
-%rename("%(strip:[bt_])s", %$isvariable) "";
-%rename("%(strip:[BT_])s", %$isenumitem) "";
-
-/*
- * Output argument typemap for string output (always appends)
- *
- * We initialize the output parameter `temp_value` to an invalid but non-zero
- * pointer value.  This is to make sure we don't rely on its initial value in
- * the epilogue (where we call SWIG_Python_str_FromChar).  When they fail,
- * functions on which we apply this typemap don't guarantee that the value of
- * `temp_value` will be unchanged or valid.
- */
-%typemap(in, numinputs=0) (const char **OUT) (char *temp_value = (void *) 1) {
-       $1 = &temp_value;
-}
-
-%typemap(argout) (const char **OUT) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result, SWIG_Python_str_FromChar(*$1));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* Output argument typemap for value output (always appends) */
-%typemap(in, numinputs=0) (bt_value **OUT) (struct bt_value *temp_value = NULL) {
-       $1 = &temp_value;
-}
-
-%typemap(argout) (bt_value **OUT) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_value, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* Output argument typemap for initialized uint64_t output parameter (always appends) */
-%typemap(in, numinputs=0) (uint64_t *OUT) (uint64_t temp) {
-       $1 = &temp;
-}
-
-%typemap(argout) uint64_t *OUT {
-       $result = SWIG_Python_AppendOutput(resultobj,
-                       SWIG_From_unsigned_SS_long_SS_long((*$1)));
-}
-
-/* Output argument typemap for initialized int64_t output parameter (always appends) */
-%typemap(in, numinputs=0) (int64_t *OUT) (int64_t temp) {
-       $1 = &temp;
-}
-
-%typemap(argout) (int64_t *OUT) {
-       $result = SWIG_Python_AppendOutput(resultobj, SWIG_From_long_SS_long((*$1)));
-}
-
-/* Output argument typemap for initialized unsigned int output parameter (always appends) */
-%typemap(in, numinputs=0) (unsigned int *OUT) (unsigned int temp) {
-       $1 = &temp;
-}
-
-%typemap(argout) (unsigned int *OUT) {
-       $result = SWIG_Python_AppendOutput(resultobj,
-                       SWIG_From_unsigned_SS_long_SS_long((uint64_t) (*$1)));
-}
-/* Output argument typemap for initialized double output parameter (always appends) */
-%typemap(in, numinputs=0) (double *OUT) (double temp) {
-       $1 = &temp;
-}
-
-%typemap(argout) (double *OUT) {
-       $result = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*$1)));
-}
-
-/* Input argument typemap for UUID bytes */
-%typemap(in) bt_uuid {
-       $1 = (unsigned char *) PyBytes_AsString($input);
-}
-
-/* Output argument typemap for UUID bytes */
-%typemap(out) bt_uuid {
-       if (!$1) {
-               Py_INCREF(Py_None);
-               $result = Py_None;
-       } else {
-               $result = PyBytes_FromStringAndSize((const char *) $1, 16);
-       }
-}
-
-/* Input argument typemap for bt_bool */
-%typemap(in) bt_bool {
-       $1 = PyObject_IsTrue($input);
-}
-
-/* Output argument typemap for bt_bool */
-%typemap(out) bt_bool {
-       if ($1 > 0) {
-               $result = Py_True;
-       } else {
-               $result = Py_False;
-       }
-       Py_INCREF($result);
-       return $result;
-}
-
-/*
- * Input and output argument typemaps for raw Python objects (direct).
- *
- * Those typemaps honor the convention of Python C function calls with
- * respect to reference counting: parameters are passed as borrowed
- * references, and objects are returned as new references. The wrapped
- * C function must ensure that the return value is always a new
- * reference, and never steal parameter references.
- */
-%typemap(in) PyObject * {
-       $1 = $input;
-}
-
-%typemap(out) PyObject * {
-       $result = $1;
-}
-
-/* From property.h */
-
-typedef enum bt_property_availability {
-       BT_PROPERTY_AVAILABILITY_AVAILABLE,
-       BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE,
-} bt_property_availability;
-
-/* Per-module interface files */
-%include "native_bt_clock_class.i"
-%include "native_bt_clock_snapshot.i"
-%include "native_bt_component.i"
-%include "native_bt_component_class.i"
-%include "native_bt_connection.i"
-%include "native_bt_event.i"
-%include "native_bt_event_class.i"
-%include "native_bt_field.i"
-%include "native_bt_field_class.i"
-%include "native_bt_field_path.i"
-%include "native_bt_graph.i"
-%include "native_bt_logging.i"
-%include "native_bt_message.i"
-%include "native_bt_notifier.i"
-%include "native_bt_packet.i"
-%include "native_bt_plugin.i"
-%include "native_bt_port.i"
-%include "native_bt_query_exec.i"
-%include "native_bt_stream.i"
-%include "native_bt_stream_class.i"
-%include "native_bt_trace.i"
-%include "native_bt_trace_class.i"
-%include "native_bt_value.i"
-%include "native_bt_version.i"
diff --git a/bindings/python/bt2/bt2/native_bt_clock_class.i b/bindings/python/bt2/bt2/native_bt_clock_class.i
deleted file mode 100644 (file)
index bf8ea43..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From clock-class-const.h */
-
-typedef enum bt_clock_class_status {
-       BT_CLOCK_CLASS_STATUS_OK = 0,
-       BT_CLOCK_CLASS_STATUS_NOMEM = -12,
-       BT_CLOCK_CLASS_STATUS_OVERFLOW = -75,
-} bt_clock_class_status;
-
-extern const char *bt_clock_class_get_name(
-               const bt_clock_class *clock_class);
-
-extern const char *bt_clock_class_get_description(
-               const bt_clock_class *clock_class);
-
-extern uint64_t bt_clock_class_get_frequency(
-               const bt_clock_class *clock_class);
-
-extern uint64_t bt_clock_class_get_precision(
-               const bt_clock_class *clock_class);
-
-extern void bt_clock_class_get_offset(const bt_clock_class *clock_class,
-               int64_t *OUT, uint64_t *OUT);
-
-extern bt_bool bt_clock_class_origin_is_unix_epoch(
-               const bt_clock_class *clock_class);
-
-extern bt_uuid bt_clock_class_get_uuid(
-               const bt_clock_class *clock_class);
-
-extern bt_clock_class_status bt_clock_class_cycles_to_ns_from_origin(
-               const bt_clock_class *clock_class,
-               uint64_t cycles, int64_t *OUT);
-
-extern void bt_clock_class_get_ref(const bt_clock_class *clock_class);
-
-extern void bt_clock_class_put_ref(const bt_clock_class *clock_class);
-
-/* From clock-class.h */
-
-extern bt_clock_class *bt_clock_class_create(bt_self_component *self_comp);
-
-extern bt_clock_class_status bt_clock_class_set_name(
-               bt_clock_class *clock_class, const char *name);
-
-extern bt_clock_class_status bt_clock_class_set_description(
-               bt_clock_class *clock_class, const char *description);
-
-extern void bt_clock_class_set_frequency(bt_clock_class *clock_class,
-               uint64_t freq);
-
-extern void bt_clock_class_set_precision(bt_clock_class *clock_class,
-               uint64_t precision);
-
-extern void bt_clock_class_set_offset(bt_clock_class *clock_class,
-               int64_t seconds, uint64_t cycles);
-
-extern void bt_clock_class_set_origin_is_unix_epoch(bt_clock_class *clock_class,
-               bt_bool origin_is_unix_epoch);
-
-extern void bt_clock_class_set_uuid(bt_clock_class *clock_class,
-               bt_uuid uuid);
diff --git a/bindings/python/bt2/bt2/native_bt_clock_snapshot.i b/bindings/python/bt2/bt2/native_bt_clock_snapshot.i
deleted file mode 100644 (file)
index a2ca8e8..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From clock-snapshot-const.h */
-
-typedef enum bt_clock_snapshot_status {
-       BT_CLOCK_SNAPSHOT_STATUS_OK = 0,
-       BT_CLOCK_SNAPSHOT_STATUS_OVERFLOW = -75,
-} bt_clock_snapshot_status;
-
-extern const bt_clock_class *bt_clock_snapshot_borrow_clock_class_const(
-               const bt_clock_snapshot *clock_snapshot);
-
-extern uint64_t bt_clock_snapshot_get_value(
-               const bt_clock_snapshot *clock_snapshot);
-
-extern bt_clock_snapshot_status bt_clock_snapshot_get_ns_from_origin(
-               const bt_clock_snapshot *clock_snapshot,
-               int64_t *OUT);
diff --git a/bindings/python/bt2/bt2/native_bt_component.i b/bindings/python/bt2/bt2/native_bt_component.i
deleted file mode 100644 (file)
index f484263..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* Output argument typemap for self port output (always appends) */
-%typemap(in, numinputs=0)
-       (bt_self_component_port_input **OUT)
-       (bt_self_component_port_input *temp_self_port = NULL) {
-       $1 = &temp_self_port;
-}
-
-%typemap(argout) bt_self_component_port_input **OUT {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_self_component_port_input, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* Output argument typemap for self port output (always appends) */
-%typemap(in, numinputs=0)
-       (bt_self_component_port_output **OUT)
-       (bt_self_component_port_output *temp_self_port = NULL) {
-       $1 = &temp_self_port;
-}
-
-%typemap(argout) (bt_self_component_port_output **OUT) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_self_component_port_output, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* Typemaps used for user data attached to self component ports. */
-
-/*
- * The user data Python object is kept as the user data of the port, we pass
- * the PyObject pointer directly to the port creation function.
- */
-%typemap(in) void *PY_SELF_PORT_USER_DATA {
-       $1 = $input;
-}
-
-/*
- * The port, if created successfully, now owns a reference to the Python object,
- * we reflect that here.
- */
-%typemap(argout) void *PY_SELF_PORT_USER_DATA {
-       if (PyLong_AsLong($result) == BT_SELF_COMPONENT_STATUS_OK) {
-               Py_INCREF($1);
-       }
-}
-
-/* From component-const.h */
-
-extern const char *bt_component_get_name(const bt_component *component);
-
-extern const bt_component_class *bt_component_borrow_class_const(
-               const bt_component *component);
-
-extern bt_component_class_type bt_component_get_class_type(
-               const bt_component *component);
-
-bt_bool bt_component_is_source(const bt_component *component);
-
-bt_bool bt_component_is_filter(const bt_component *component);
-
-bt_bool bt_component_is_sink(const bt_component *component);
-
-extern bt_bool bt_component_graph_is_canceled(
-               const bt_component *component);
-
-extern void bt_component_get_ref(const bt_component *component);
-
-extern void bt_component_put_ref(const bt_component *component);
-
-/* From component-source-const.h */
-
-const bt_component *bt_component_source_as_component_const(
-               const bt_component_source *component);
-
-extern const bt_component_class_source *
-bt_component_source_borrow_class_const(
-               const bt_component_source *component);
-
-extern uint64_t bt_component_source_get_output_port_count(
-               const bt_component_source *component);
-
-extern const bt_port_output *
-bt_component_source_borrow_output_port_by_name_const(
-               const bt_component_source *component, const char *name);
-
-extern const bt_port_output *
-bt_component_source_borrow_output_port_by_index_const(
-               const bt_component_source *component, uint64_t index);
-
-extern void bt_component_source_get_ref(
-               const bt_component_source *component_source);
-
-extern void bt_component_source_put_ref(
-               const bt_component_source *component_source);
-
-/* From component-filter-const.h */
-
-const bt_component *bt_component_filter_as_component_const(
-               const bt_component_filter *component);
-
-extern const bt_component_class_filter *
-bt_component_filter_borrow_class_const(
-               const bt_component_filter *component);
-
-extern uint64_t bt_component_filter_get_input_port_count(
-               const bt_component_filter *component);
-
-extern const bt_port_input *
-bt_component_filter_borrow_input_port_by_name_const(
-               const bt_component_filter *component, const char *name);
-
-extern const bt_port_input *
-bt_component_filter_borrow_input_port_by_index_const(
-               const bt_component_filter *component, uint64_t index);
-
-extern uint64_t bt_component_filter_get_output_port_count(
-               const bt_component_filter *component);
-
-extern const bt_port_output *
-bt_component_filter_borrow_output_port_by_name_const(
-               const bt_component_filter *component, const char *name);
-
-extern const bt_port_output *
-bt_component_filter_borrow_output_port_by_index_const(
-               const bt_component_filter *component, uint64_t index);
-
-extern void bt_component_filter_get_ref(
-               const bt_component_filter *component_filter);
-
-extern void bt_component_filter_put_ref(
-               const bt_component_filter *component_filter);
-
-/* From component-sink-const.h */
-
-const bt_component *bt_component_sink_as_component_const(
-               const bt_component_sink *component);
-
-extern const bt_component_class_sink *
-bt_component_sink_borrow_class_const(
-               const bt_component_sink *component);
-
-extern uint64_t bt_component_sink_get_input_port_count(
-               const bt_component_sink *component);
-
-extern const bt_port_input *
-bt_component_sink_borrow_input_port_by_name_const(
-               const bt_component_sink *component, const char *name);
-
-extern const bt_port_input *
-bt_component_sink_borrow_input_port_by_index_const(
-               const bt_component_sink *component, uint64_t index);
-
-extern void bt_component_sink_get_ref(
-               const bt_component_sink *component_sink);
-
-extern void bt_component_sink_put_ref(
-               const bt_component_sink *component_sink);
-
-/* From self-component.h */
-
-typedef enum bt_self_component_status {
-       BT_SELF_COMPONENT_STATUS_OK = 0,
-       BT_SELF_COMPONENT_STATUS_END = 1,
-       BT_SELF_COMPONENT_STATUS_AGAIN = 11,
-       BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION = 111,
-       BT_SELF_COMPONENT_STATUS_ERROR = -1,
-       BT_SELF_COMPONENT_STATUS_NOMEM = -12,
-} bt_self_component_status;
-
-const bt_component *bt_self_component_as_component(
-               bt_self_component *self_component);
-
-extern void *bt_self_component_get_data(
-               const bt_self_component *self_component);
-
-extern void bt_self_component_set_data(
-               bt_self_component *self_component, void *data);
-
-/* From self-component-source.h */
-
-bt_self_component *bt_self_component_source_as_self_component(
-               bt_self_component_source *self_comp_source);
-
-const bt_component_source *
-bt_self_component_source_as_component_source(
-               bt_self_component_source *self_comp_source);
-
-extern bt_self_component_port_output *
-bt_self_component_source_borrow_output_port_by_name(
-               bt_self_component_source *self_component,
-               const char *name);
-
-extern bt_self_component_port_output *
-bt_self_component_source_borrow_output_port_by_index(
-               bt_self_component_source *self_component,
-               uint64_t index);
-
-extern bt_self_component_status
-bt_self_component_source_add_output_port(
-               bt_self_component_source *self_component,
-               const char *name, void *PY_SELF_PORT_USER_DATA,
-               bt_self_component_port_output **OUT);
-
-/* From self-component-filter.h */
-
-bt_self_component *bt_self_component_filter_as_self_component(
-               bt_self_component_filter *self_comp_filter);
-
-const bt_component_filter *
-bt_self_component_filter_as_component_filter(
-               bt_self_component_filter *self_comp_filter);
-
-extern bt_self_component_port_output *
-bt_self_component_filter_borrow_output_port_by_name(
-               bt_self_component_filter *self_component,
-               const char *name);
-
-extern bt_self_component_port_output *
-bt_self_component_filter_borrow_output_port_by_index(
-               bt_self_component_filter *self_component,
-               uint64_t index);
-
-extern bt_self_component_status
-bt_self_component_filter_add_output_port(
-               bt_self_component_filter *self_component,
-               const char *name, void *PY_SELF_PORT_USER_DATA,
-               bt_self_component_port_output **OUT);
-
-extern bt_self_component_port_input *
-bt_self_component_filter_borrow_input_port_by_name(
-               bt_self_component_filter *self_component,
-               const char *name);
-
-extern bt_self_component_port_input *
-bt_self_component_filter_borrow_input_port_by_index(
-               bt_self_component_filter *self_component,
-               uint64_t index);
-
-extern bt_self_component_status
-bt_self_component_filter_add_input_port(
-               bt_self_component_filter *self_component,
-               const char *name, void *PY_SELF_PORT_USER_DATA,
-               bt_self_component_port_input **OUT);
-
-/* From self-component-sink.h */
-
-bt_self_component *bt_self_component_sink_as_self_component(
-               bt_self_component_sink *self_comp_sink);
-
-const bt_component_sink *
-bt_self_component_sink_as_component_sink(
-               bt_self_component_sink *self_comp_sink);
-
-extern bt_self_component_port_input *
-bt_self_component_sink_borrow_input_port_by_name(
-               bt_self_component_sink *self_component,
-               const char *name);
-
-extern bt_self_component_port_input *
-bt_self_component_sink_borrow_input_port_by_index(
-               bt_self_component_sink *self_component, uint64_t index);
-
-extern bt_self_component_status
-bt_self_component_sink_add_input_port(
-               bt_self_component_sink *self_component,
-               const char *name, void *PY_SELF_PORT_USER_DATA,
-               bt_self_component_port_input **OUT);
diff --git a/bindings/python/bt2/bt2/native_bt_component_class.i b/bindings/python/bt2/bt2/native_bt_component_class.i
deleted file mode 100644 (file)
index 1dfa011..0000000
+++ /dev/null
@@ -1,1761 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From component-class-const.h */
-
-typedef enum bt_component_class_status {
-       BT_COMPONENT_CLASS_STATUS_OK = 0,
-       BT_COMPONENT_CLASS_STATUS_NOMEM = -12,
-} bt_component_class_status;
-
-typedef enum bt_component_class_type {
-       BT_COMPONENT_CLASS_TYPE_SOURCE = 0,
-       BT_COMPONENT_CLASS_TYPE_FILTER = 1,
-       BT_COMPONENT_CLASS_TYPE_SINK = 2,
-} bt_component_class_type;
-
-extern const char *bt_component_class_get_name(
-               const bt_component_class *component_class);
-
-extern const char *bt_component_class_get_description(
-               const bt_component_class *component_class);
-
-extern const char *bt_component_class_get_help(
-               const bt_component_class *component_class);
-
-extern bt_component_class_type bt_component_class_get_type(
-               const bt_component_class *component_class);
-
-bt_bool bt_component_class_is_source(
-               const bt_component_class *component_class);
-
-bt_bool bt_component_class_is_filter(
-               const bt_component_class *component_class);
-
-bt_bool bt_component_class_is_sink(
-               const bt_component_class *component_class);
-
-extern void bt_component_class_get_ref(
-               const bt_component_class *component_class);
-
-extern void bt_component_class_put_ref(
-               const bt_component_class *component_class);
-
-/* From component-class-source-const.h */
-
-const bt_component_class *
-bt_component_class_source_as_component_class_const(
-               const bt_component_class_source *comp_cls_source);
-
-extern void bt_component_class_source_get_ref(
-               const bt_component_class_source *component_class_source);
-
-extern void bt_component_class_source_put_ref(
-               const bt_component_class_source *component_class_source);
-
-/* From component-class-source.h */
-
-typedef bt_self_component_status
-(*bt_component_class_source_init_method)(
-               bt_self_component_source *self_component,
-               const bt_value *params, void *init_method_data);
-
-typedef void (*bt_component_class_source_finalize_method)(
-               bt_self_component_source *self_component);
-
-typedef bt_self_message_iterator_status
-(*bt_component_class_source_message_iterator_init_method)(
-               bt_self_message_iterator *message_iterator,
-               bt_self_component_source *self_component,
-               bt_self_component_port_output *port);
-
-typedef void
-(*bt_component_class_source_message_iterator_finalize_method)(
-               bt_self_message_iterator *message_iterator);
-
-typedef bt_self_message_iterator_status
-(*bt_component_class_source_message_iterator_next_method)(
-               bt_self_message_iterator *message_iterator,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count);
-
-typedef bt_self_message_iterator_status
-(*bt_component_class_source_message_iterator_seek_ns_from_origin_method)(
-               bt_self_message_iterator *message_iterator,
-               int64_t ns_from_origin);
-
-typedef bt_self_message_iterator_status
-(*bt_component_class_source_message_iterator_seek_beginning_method)(
-               bt_self_message_iterator *message_iterator);
-
-typedef bt_bool
-(*bt_component_class_source_message_iterator_can_seek_ns_from_origin_method)(
-               bt_self_message_iterator *message_iterator,
-               int64_t ns_from_origin);
-
-typedef bt_bool
-(*bt_component_class_source_message_iterator_can_seek_beginning_method)(
-               bt_self_message_iterator *message_iterator);
-
-typedef bt_query_status (*bt_component_class_source_query_method)(
-               bt_self_component_class_source *comp_class,
-               const bt_query_executor *query_executor,
-               const char *object, const bt_value *params,
-               const bt_value **result);
-
-typedef bt_self_component_status
-(*bt_component_class_source_accept_output_port_connection_method)(
-               bt_self_component_source *self_component,
-               bt_self_component_port_output *self_port,
-               const bt_port_input *other_port);
-
-typedef bt_self_component_status
-(*bt_component_class_source_output_port_connected_method)(
-               bt_self_component_source *self_component,
-               bt_self_component_port_output *self_port,
-               const bt_port_input *other_port);
-
-bt_component_class *bt_component_class_source_as_component_class(
-               bt_component_class_source *comp_cls_source);
-
-extern
-bt_component_class_source *bt_component_class_source_create(
-               const char *name,
-               bt_component_class_source_message_iterator_next_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_init_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_init_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_finalize_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_finalize_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_accept_output_port_connection_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_accept_output_port_connection_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_output_port_connected_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_output_port_connected_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_query_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_query_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_message_iterator_init_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_message_iterator_init_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_message_iterator_finalize_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_message_iterator_finalize_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_message_iterator_seek_ns_from_origin_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_message_iterator_seek_ns_from_origin_method method);
-
-extern bt_component_class_status
-bt_component_class_source_set_message_iterator_seek_beginning_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_message_iterator_seek_beginning_method method);
-
-extern bt_bool
-bt_component_class_source_set_message_iterator_can_seek_ns_from_origin_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_message_iterator_can_seek_ns_from_origin_method method);
-
-extern bt_bool
-bt_component_class_source_set_message_iterator_can_seek_beginning_method(
-               bt_component_class_source *comp_class,
-               bt_component_class_source_message_iterator_can_seek_beginning_method method);
-
-/* From component-class-filter-const.h */
-
-const bt_component_class *
-bt_component_class_filter_as_component_class_const(
-               const bt_component_class_filter *comp_cls_filter);
-
-extern void bt_component_class_filter_get_ref(
-               const bt_component_class_filter *component_class_filter);
-
-extern void bt_component_class_filter_put_ref(
-               const bt_component_class_filter *component_class_filter);
-
-/* From component-class-filter.h */
-
-typedef bt_self_component_status
-(*bt_component_class_filter_init_method)(
-               bt_self_component_filter *self_component,
-               const bt_value *params, void *init_method_data);
-
-typedef void (*bt_component_class_filter_finalize_method)(
-               bt_self_component_filter *self_component);
-
-typedef bt_self_message_iterator_status
-(*bt_component_class_filter_message_iterator_init_method)(
-               bt_self_message_iterator *message_iterator,
-               bt_self_component_filter *self_component,
-               bt_self_component_port_output *port);
-
-typedef void
-(*bt_component_class_filter_message_iterator_finalize_method)(
-               bt_self_message_iterator *message_iterator);
-
-typedef bt_self_message_iterator_status
-(*bt_component_class_filter_message_iterator_next_method)(
-               bt_self_message_iterator *message_iterator,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count);
-
-typedef bt_self_message_iterator_status
-(*bt_component_class_filter_message_iterator_seek_ns_from_origin_method)(
-               bt_self_message_iterator *message_iterator,
-               int64_t ns_from_origin);
-
-typedef bt_self_message_iterator_status
-(*bt_component_class_filter_message_iterator_seek_beginning_method)(
-               bt_self_message_iterator *message_iterator);
-
-typedef bt_bool
-(*bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method)(
-               bt_self_message_iterator *message_iterator,
-               int64_t ns_from_origin);
-
-typedef bt_bool
-(*bt_component_class_filter_message_iterator_can_seek_beginning_method)(
-               bt_self_message_iterator *message_iterator);
-
-typedef bt_query_status
-(*bt_component_class_filter_query_method)(
-               bt_self_component_class_filter *comp_class,
-               const bt_query_executor *query_executor,
-               const char *object, const bt_value *params,
-               const bt_value **result);
-
-typedef bt_self_component_status
-(*bt_component_class_filter_accept_input_port_connection_method)(
-               bt_self_component_filter *self_component,
-               bt_self_component_port_input *self_port,
-               const bt_port_output *other_port);
-
-typedef bt_self_component_status
-(*bt_component_class_filter_accept_output_port_connection_method)(
-               bt_self_component_filter *self_component,
-               bt_self_component_port_output *self_port,
-               const bt_port_input *other_port);
-
-typedef bt_self_component_status
-(*bt_component_class_filter_input_port_connected_method)(
-               bt_self_component_filter *self_component,
-               bt_self_component_port_input *self_port,
-               const bt_port_output *other_port);
-
-typedef bt_self_component_status
-(*bt_component_class_filter_output_port_connected_method)(
-               bt_self_component_filter *self_component,
-               bt_self_component_port_output *self_port,
-               const bt_port_input *other_port);
-
-bt_component_class *bt_component_class_filter_as_component_class(
-               bt_component_class_filter *comp_cls_filter);
-
-extern
-bt_component_class_filter *bt_component_class_filter_create(
-               const char *name,
-               bt_component_class_filter_message_iterator_next_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_init_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_init_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_finalize_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_finalize_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_accept_input_port_connection_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_accept_input_port_connection_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_accept_output_port_connection_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_accept_output_port_connection_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_input_port_connected_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_input_port_connected_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_output_port_connected_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_output_port_connected_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_query_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_query_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_message_iterator_init_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_message_iterator_init_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_message_iterator_finalize_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_message_iterator_finalize_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_message_iterator_seek_ns_from_origin_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_message_iterator_seek_ns_from_origin_method method);
-
-extern bt_component_class_status
-bt_component_class_filter_set_message_iterator_seek_beginning_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_message_iterator_seek_beginning_method method);
-
-extern bt_bool
-bt_component_class_filter_set_message_iterator_can_seek_ns_from_origin_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method method);
-
-extern bt_bool
-bt_component_class_filter_set_message_iterator_can_seek_beginning_method(
-               bt_component_class_filter *comp_class,
-               bt_component_class_filter_message_iterator_can_seek_beginning_method method);
-
-/* From component-class-sink-const.h */
-
-const bt_component_class *
-bt_component_class_sink_as_component_class_const(
-               const bt_component_class_sink *comp_cls_sink);
-
-extern void bt_component_class_sink_get_ref(
-               const bt_component_class_sink *component_class_sink);
-
-extern void bt_component_class_sink_put_ref(
-               const bt_component_class_sink *component_class_sink);
-
-/* From component-class-sink.h */
-
-typedef bt_self_component_status (*bt_component_class_sink_init_method)(
-               bt_self_component_sink *self_component,
-               const bt_value *params, void *init_method_data);
-
-typedef void (*bt_component_class_sink_finalize_method)(
-               bt_self_component_sink *self_component);
-
-typedef bt_query_status
-(*bt_component_class_sink_query_method)(
-               bt_self_component_class_sink *comp_class,
-               const bt_query_executor *query_executor,
-               const char *object, const bt_value *params,
-               const bt_value **result);
-
-typedef bt_self_component_status
-(*bt_component_class_sink_accept_input_port_connection_method)(
-               bt_self_component_sink *self_component,
-               bt_self_component_port_input *self_port,
-               const bt_port_output *other_port);
-
-typedef bt_self_component_status
-(*bt_component_class_sink_input_port_connected_method)(
-               bt_self_component_sink *self_component,
-               bt_self_component_port_input *self_port,
-               const bt_port_output *other_port);
-
-typedef bt_self_component_status
-(*bt_component_class_sink_graph_is_configured_method)(
-               bt_self_component_sink *self_component);
-
-typedef bt_self_component_status (*bt_component_class_sink_consume_method)(
-       bt_self_component_sink *self_component);
-
-bt_component_class *bt_component_class_sink_as_component_class(
-               bt_component_class_sink *comp_cls_sink);
-
-extern
-bt_component_class_sink *bt_component_class_sink_create(
-               const char *name,
-               bt_component_class_sink_consume_method method);
-
-extern bt_component_class_status bt_component_class_sink_set_init_method(
-               bt_component_class_sink *comp_class,
-               bt_component_class_sink_init_method method);
-
-extern bt_component_class_status bt_component_class_sink_set_finalize_method(
-               bt_component_class_sink *comp_class,
-               bt_component_class_sink_finalize_method method);
-
-extern bt_component_class_status
-bt_component_class_sink_set_accept_input_port_connection_method(
-               bt_component_class_sink *comp_class,
-               bt_component_class_sink_accept_input_port_connection_method method);
-
-extern bt_component_class_status
-bt_component_class_sink_set_input_port_connected_method(
-               bt_component_class_sink *comp_class,
-               bt_component_class_sink_input_port_connected_method method);
-
-extern bt_component_class_status
-bt_component_class_sink_set_graph_is_configured_method(
-               bt_component_class_sink *comp_class,
-               bt_component_class_sink_graph_is_configured_method method);
-
-extern bt_component_class_status bt_component_class_sink_set_query_method(
-               bt_component_class_sink *comp_class,
-               bt_component_class_sink_query_method method);
-
-/* From self-component-class-source.h */
-
-const bt_component_class_source *
-bt_self_component_class_source_as_component_class_source(
-               bt_self_component_class_source *self_comp_cls_source);
-
-/* From self-component-class-filter.h */
-
-const bt_component_class_filter *
-bt_self_component_class_filter_as_component_class_filter(
-               bt_self_component_class_filter *self_comp_cls_filter);
-
-/* From self-component-class-sink.h */
-
-const bt_component_class_sink *
-bt_self_component_class_sink_as_component_class_sink(
-               bt_self_component_class_sink *self_comp_cls_sink);
-
-%{
-/*
- * This hash table associates a BT component class object address to a
- * user-defined Python class (PyObject *). The keys and values are NOT
- * owned by this hash table. The Python class objects are owned by the
- * Python module, which should not be unloaded until it is not possible
- * to create a user Python component anyway.
- *
- * This hash table is written to when a user-defined Python component
- * class is created by one of the bt_py3_component_class_*_create()
- * functions.
- *
- * This function is read from when a user calls bt_component_create()
- * with a component class pointer created by one of the functions above.
- * In this case, the original Python class needs to be found to
- * instantiate it and associate the created Python component object with
- * a BT component object instance.
- */
-
-static GHashTable *bt_cc_ptr_to_py_cls;
-
-static void register_cc_ptr_to_py_cls(struct bt_component_class *bt_cc,
-               PyObject *py_cls)
-{
-       if (!bt_cc_ptr_to_py_cls) {
-               /*
-                * Lazy-initializing this GHashTable because GLib
-                * might not be initialized yet and it needs to be
-                * before we call g_hash_table_new()
-                */
-               BT_LOGD_STR("Creating native component class to Python component class hash table.");
-               bt_cc_ptr_to_py_cls = g_hash_table_new(g_direct_hash, g_direct_equal);
-               BT_ASSERT(bt_cc_ptr_to_py_cls);
-       }
-
-       g_hash_table_insert(bt_cc_ptr_to_py_cls, (gpointer) bt_cc,
-               (gpointer) py_cls);
-}
-
-static PyObject *lookup_cc_ptr_to_py_cls(const bt_component_class *bt_cc)
-{
-       if (!bt_cc_ptr_to_py_cls) {
-               BT_LOGW("Cannot look up Python component class because hash table is NULL: "
-                       "comp-cls-addr=%p", bt_cc);
-               return NULL;
-       }
-
-       return (PyObject *) g_hash_table_lookup(bt_cc_ptr_to_py_cls,
-               (gconstpointer) bt_cc);
-}
-
-
-/*
- * Useful Python objects.
- */
-
-static PyObject *py_mod_bt2 = NULL;
-static PyObject *py_mod_bt2_exc_error_type = NULL;
-static PyObject *py_mod_bt2_exc_try_again_type = NULL;
-static PyObject *py_mod_bt2_exc_stop_type = NULL;
-static PyObject *py_mod_bt2_exc_port_connection_refused_type = NULL;
-static PyObject *py_mod_bt2_exc_msg_iter_canceled_type = NULL;
-static PyObject *py_mod_bt2_exc_invalid_query_object_type = NULL;
-static PyObject *py_mod_bt2_exc_invalid_query_params_type = NULL;
-
-static void bt_py3_cc_init_from_bt2(void)
-{
-       /*
-        * This is called once the bt2 package is loaded.
-        *
-        * Those modules and functions are needed while the package is
-        * used. Loading them here is safe because we know the bt2
-        * package is imported, and we know that the user cannot use the
-        * code here without importing bt2 first.
-        */
-       py_mod_bt2 = PyImport_ImportModule("bt2");
-       BT_ASSERT(py_mod_bt2);
-       py_mod_bt2_exc_error_type =
-               PyObject_GetAttrString(py_mod_bt2, "Error");
-       BT_ASSERT(py_mod_bt2_exc_error_type);
-       py_mod_bt2_exc_try_again_type =
-               PyObject_GetAttrString(py_mod_bt2, "TryAgain");
-       BT_ASSERT(py_mod_bt2_exc_try_again_type);
-       py_mod_bt2_exc_stop_type =
-               PyObject_GetAttrString(py_mod_bt2, "Stop");
-       BT_ASSERT(py_mod_bt2_exc_stop_type);
-       py_mod_bt2_exc_port_connection_refused_type =
-               PyObject_GetAttrString(py_mod_bt2, "PortConnectionRefused");
-       BT_ASSERT(py_mod_bt2_exc_port_connection_refused_type);
-       py_mod_bt2_exc_invalid_query_object_type =
-               PyObject_GetAttrString(py_mod_bt2, "InvalidQueryObject");
-       BT_ASSERT(py_mod_bt2_exc_invalid_query_object_type);
-       py_mod_bt2_exc_invalid_query_params_type =
-               PyObject_GetAttrString(py_mod_bt2, "InvalidQueryParams");
-       BT_ASSERT(py_mod_bt2_exc_invalid_query_params_type);
-}
-
-static void bt_py3_cc_exit_handler(void)
-{
-       /*
-        * This is an exit handler (set by the bt2 package).
-        *
-        * We only give back the references that we took in
-        * bt_py3_cc_init_from_bt2() here. The global variables continue
-        * to exist for the code of this file, but they are now borrowed
-        * references. If this code is executed, it means that somehow
-        * the modules are still loaded, so it should be safe to use
-        * them even without a strong reference.
-        *
-        * We cannot do this in the library's destructor because it
-        * gets executed once Python is already finalized.
-        */
-       Py_XDECREF(py_mod_bt2);
-       Py_XDECREF(py_mod_bt2_exc_error_type);
-       Py_XDECREF(py_mod_bt2_exc_try_again_type);
-       Py_XDECREF(py_mod_bt2_exc_stop_type);
-       Py_XDECREF(py_mod_bt2_exc_port_connection_refused_type);
-       Py_XDECREF(py_mod_bt2_exc_msg_iter_canceled_type);
-       Py_XDECREF(py_mod_bt2_exc_invalid_query_object_type);
-       Py_XDECREF(py_mod_bt2_exc_invalid_query_params_type);
-}
-
-
-/* Library destructor */
-
-__attribute__((destructor))
-static void bt_py3_native_comp_class_dtor(void) {
-       /* Destroy component class association hash table */
-       if (bt_cc_ptr_to_py_cls) {
-               BT_LOGD_STR("Destroying native component class to Python component class hash table.");
-               g_hash_table_destroy(bt_cc_ptr_to_py_cls);
-       }
-}
-
-
-// TODO: maybe we can wrap code in the Python methods (e.g. _query_from_native)
-// in a try catch and print the error there instead, it would be simpler.
-static
-void bt2_py_loge_exception(void)
-{
-       PyObject *type = NULL;
-       PyObject *value = NULL;
-       PyObject *traceback = NULL;
-       PyObject *traceback_module = NULL;
-       PyObject *format_exception_func = NULL;
-       PyObject *exc_str_list = NULL;
-       GString *msg_buf = NULL;
-       Py_ssize_t i;
-
-       BT_ASSERT(PyErr_Occurred() != NULL);
-
-       PyErr_Fetch(&type, &value, &traceback);
-
-       BT_ASSERT(type != NULL);
-
-       /*
-       * traceback can be NULL, when we fail to call a Python function from the
-       * native code (there is not Python stack at that point).  E.g.:
-       *
-       *   TypeError: _accept_port_connection_from_native() takes 3 positional arguments but 4 were given
-       */
-
-
-       /* Make sure `value` is what we expected - an instance of `type`. */
-       PyErr_NormalizeException(&type, &value, &traceback);
-
-       traceback_module = PyImport_ImportModule("traceback");
-       if (!traceback_module) {
-               BT_LOGE_STR("Failed to log Python exception (could not import traceback module).");
-               goto end;
-       }
-
-       format_exception_func = PyObject_GetAttrString(traceback_module,
-               traceback ? "format_exception" : "format_exception_only");
-       if (!format_exception_func) {
-               BT_LOGE_STR("Failed to log Python exception (could not find format_exception).");
-               goto end;
-       }
-
-       if (!PyCallable_Check(format_exception_func)) {
-               BT_LOGE_STR("Failed to log Python exception (format_exception is not callable).");
-               goto end;
-       }
-
-       exc_str_list = PyObject_CallFunctionObjArgs(format_exception_func, type, value, traceback, NULL);
-       if (!exc_str_list) {
-               PyErr_Print();
-               BT_LOGE_STR("Failed to log Python exception (call to format_exception failed).");
-               goto end;
-       }
-
-       msg_buf = g_string_new(NULL);
-
-       for (i = 0; i < PyList_Size(exc_str_list); i++) {
-               PyObject *exc_str = PyList_GetItem(exc_str_list, i);
-               const char *str = PyUnicode_AsUTF8(exc_str);
-               if (!str) {
-                       BT_LOGE_STR("Failed to log Python exception (failed to convert exception to string).");
-                       goto end;
-               }
-
-               g_string_append(msg_buf, str);
-       }
-
-       BT_LOGE_STR(msg_buf->str);
-
-end:
-       if (msg_buf) {
-               g_string_free(msg_buf, TRUE);
-       }
-       Py_XDECREF(exc_str_list);
-       Py_XDECREF(format_exception_func);
-       Py_XDECREF(traceback_module);
-
-       /* PyErr_Restore takes our references. */
-       PyErr_Restore(type, value, traceback);
-}
-
-static bt_self_component_status bt_py3_exc_to_self_component_status(void)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       PyObject *exc = PyErr_Occurred();
-
-       if (!exc) {
-               goto end;
-       }
-
-       if (PyErr_GivenExceptionMatches(exc,
-                       py_mod_bt2_exc_try_again_type)) {
-               status = BT_SELF_COMPONENT_STATUS_AGAIN;
-       } else if (PyErr_GivenExceptionMatches(exc,
-                       py_mod_bt2_exc_stop_type)) {
-               status = BT_SELF_COMPONENT_STATUS_END;
-       } else if (PyErr_GivenExceptionMatches(exc,
-                       py_mod_bt2_exc_port_connection_refused_type)) {
-               status = BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION;
-       } else {
-               bt2_py_loge_exception();
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-       }
-
-end:
-       PyErr_Clear();
-       return status;
-}
-
-/* Component class proxy methods (delegate to the attached Python object) */
-
-static bt_self_message_iterator_status
-bt_py3_exc_to_self_message_iterator_status(void)
-{
-       enum bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       PyObject *exc = PyErr_Occurred();
-
-       if (!exc) {
-               goto end;
-       }
-
-       if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_stop_type)) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-       } else if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_try_again_type)) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN;
-       } else {
-               bt2_py_loge_exception();
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-       }
-
-end:
-       PyErr_Clear();
-       return status;
-}
-
-static enum bt_query_status bt_py3_exc_to_query_status(void)
-{
-       enum bt_query_status status = BT_QUERY_STATUS_OK;
-       PyObject *exc = PyErr_Occurred();
-
-       if (!exc) {
-               goto end;
-       }
-
-       if (PyErr_GivenExceptionMatches(exc,
-                       py_mod_bt2_exc_invalid_query_object_type)) {
-               status = BT_QUERY_STATUS_INVALID_OBJECT;
-       } else if (PyErr_GivenExceptionMatches(exc,
-                       py_mod_bt2_exc_invalid_query_params_type)) {
-               status = BT_QUERY_STATUS_INVALID_PARAMS;
-       } else if (PyErr_GivenExceptionMatches(exc,
-                       py_mod_bt2_exc_try_again_type)) {
-               status = BT_QUERY_STATUS_AGAIN;
-       } else {
-               bt2_py_loge_exception();
-               status = BT_QUERY_STATUS_ERROR;
-       }
-
-end:
-       PyErr_Clear();
-       return status;
-}
-
-static bt_self_component_status
-bt_py3_component_class_init(
-               bt_self_component *self_component,
-               void *self_component_v,
-               swig_type_info *self_comp_cls_type_swig_type,
-               const bt_value *params,
-               void *init_method_data)
-{
-       const bt_component *component = bt_self_component_as_component(self_component);
-       const bt_component_class *component_class = bt_component_borrow_class_const(component);
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       PyObject *py_cls = NULL;
-       PyObject *py_comp = NULL;
-       PyObject *py_params_ptr = NULL;
-       PyObject *py_comp_ptr = NULL;
-
-       (void) init_method_data;
-
-       BT_ASSERT(self_component);
-       BT_ASSERT(self_component_v);
-       BT_ASSERT(self_comp_cls_type_swig_type);
-
-       /*
-        * Get the user-defined Python class which created this
-        * component's class in the first place (borrowed
-        * reference).
-        */
-       py_cls = lookup_cc_ptr_to_py_cls(component_class);
-       if (!py_cls) {
-               BT_LOGE("Cannot find Python class associated to native component class: "
-                       "comp-cls-addr=%p", component_class);
-               goto error;
-       }
-
-       /* Parameters pointer -> SWIG pointer Python object */
-       py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params),
-               SWIGTYPE_p_bt_value, 0);
-       if (!py_params_ptr) {
-               BT_LOGE_STR("Failed to create a SWIG pointer object.");
-               goto error;
-       }
-
-       py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_v),
-               self_comp_cls_type_swig_type, 0);
-       if (!py_comp_ptr) {
-               BT_LOGE_STR("Failed to create a SWIG pointer object.");
-               goto error;
-       }
-
-       /*
-        * Do the equivalent of this:
-        *
-        *     py_comp = py_cls._init_from_native(py_comp_ptr, py_params_ptr)
-        *
-        * _UserComponentType._init_from_native() calls the Python
-        * component object's __init__() function.
-        */
-       py_comp = PyObject_CallMethod(py_cls,
-               "_init_from_native", "(OO)", py_comp_ptr, py_params_ptr);
-       if (!py_comp) {
-               bt2_py_loge_exception();
-               BT_LOGE("Failed to call Python class's _init_from_native() method: "
-                       "py-cls-addr=%p", py_cls);
-
-               goto error;
-       }
-
-       /*
-        * Our user Python component object is now fully created and
-        * initialized by the user. Since we just created it, this
-        * native component is its only (persistent) owner.
-        */
-       bt_self_component_set_data(self_component, py_comp);
-       py_comp = NULL;
-       goto end;
-
-error:
-       status = BT_SELF_COMPONENT_STATUS_ERROR;
-
-       /*
-        * Clear any exception: we're returning a bad status anyway. If
-        * this call originated from Python (creation from a plugin's
-        * component class, for example), then the user gets an
-        * appropriate creation error.
-        */
-       PyErr_Clear();
-
-end:
-       Py_XDECREF(py_comp);
-       Py_XDECREF(py_params_ptr);
-       Py_XDECREF(py_comp_ptr);
-       return status;
-}
-
-/*
- * Method of bt_component_class_source to initialize a bt_self_component_source
- * of that class.
- */
-
-static bt_self_component_status
-bt_py3_component_class_source_init(bt_self_component_source *self_component_source,
-               const bt_value *params, void *init_method_data)
-{
-       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
-       return bt_py3_component_class_init(
-               self_component,
-               self_component_source,
-               SWIGTYPE_p_bt_self_component_source,
-               params, init_method_data);
-}
-
-static bt_self_component_status
-bt_py3_component_class_filter_init(bt_self_component_filter *self_component_filter,
-               const bt_value *params, void *init_method_data)
-{
-       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
-       return bt_py3_component_class_init(
-               self_component,
-               self_component_filter,
-               SWIGTYPE_p_bt_self_component_filter,
-               params, init_method_data);
-}
-
-static bt_self_component_status
-bt_py3_component_class_sink_init(bt_self_component_sink *self_component_sink,
-               const bt_value *params, void *init_method_data)
-{
-       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
-       return bt_py3_component_class_init(
-               self_component,
-               self_component_sink,
-               SWIGTYPE_p_bt_self_component_sink,
-               params, init_method_data);
-}
-
-static void bt_py3_component_class_finalize(bt_self_component *self_component)
-{
-       PyObject *py_comp = bt_self_component_get_data(self_component);
-       BT_ASSERT(py_comp);
-
-       /* Call user's _finalize() method */
-       PyObject *py_method_result = PyObject_CallMethod(py_comp,
-               "_finalize", NULL);
-
-       if (PyErr_Occurred()) {
-               BT_LOGW("User's _finalize() method raised an exception: ignoring.");
-       }
-
-       /*
-        * Ignore any exception raised by the _finalize() method because
-        * it won't change anything at this point: the component is
-        * being destroyed anyway.
-        */
-       PyErr_Clear();
-       Py_XDECREF(py_method_result);
-       Py_DECREF(py_comp);
-}
-
-static void
-bt_py3_component_class_source_finalize(bt_self_component_source *self_component_source)
-{
-       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
-       bt_py3_component_class_finalize(self_component);
-}
-
-static void
-bt_py3_component_class_filter_finalize(bt_self_component_filter *self_component_filter)
-{
-       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
-       bt_py3_component_class_finalize(self_component);
-}
-
-static void
-bt_py3_component_class_sink_finalize(bt_self_component_sink *self_component_sink)
-{
-       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
-       bt_py3_component_class_finalize(self_component);
-}
-
-static bt_self_component_status
-bt_py3_component_class_accept_port_connection(
-               bt_self_component *self_component,
-               bt_self_component_port *self_component_port,
-               bt_port_type self_component_port_type,
-               const bt_port *other_port)
-{
-       enum bt_self_component_status status;
-       PyObject *py_comp = NULL;
-       PyObject *py_self_port_ptr = NULL;
-       PyObject *py_other_port_ptr = NULL;
-       PyObject *py_method_result = NULL;
-
-       py_comp = bt_self_component_get_data(self_component);
-       BT_ASSERT(py_comp);
-
-       swig_type_info *self_component_port_swig_type = NULL;
-       swig_type_info *other_port_swig_type = NULL;
-       switch (self_component_port_type) {
-       case BT_PORT_TYPE_INPUT:
-               self_component_port_swig_type = SWIGTYPE_p_bt_self_component_port_input;
-               other_port_swig_type = SWIGTYPE_p_bt_port_output;
-               break;
-       case BT_PORT_TYPE_OUTPUT:
-               self_component_port_swig_type = SWIGTYPE_p_bt_self_component_port_output;
-               other_port_swig_type = SWIGTYPE_p_bt_port_input;
-               break;
-       }
-       BT_ASSERT(self_component_port_swig_type != NULL);
-       BT_ASSERT(other_port_swig_type != NULL);
-
-       py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port),
-               self_component_port_swig_type, 0);
-       if (!py_self_port_ptr) {
-               BT_LOGE_STR("Failed to create a SWIG pointer object.");
-               goto error;
-       }
-
-       py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port),
-               other_port_swig_type, 0);
-       if (!py_other_port_ptr) {
-               BT_LOGE_STR("Failed to create a SWIG pointer object.");
-               goto error;
-       }
-
-       py_method_result = PyObject_CallMethod(py_comp,
-               "_accept_port_connection_from_native", "(OiO)", py_self_port_ptr,
-               self_component_port_type, py_other_port_ptr);
-
-       status = bt_py3_exc_to_self_component_status();
-       if (!py_method_result && status == BT_SELF_COMPONENT_STATUS_OK) {
-               /* Pretty sure this should never happen, but just in case */
-               BT_LOGE("User's _accept_port_connection() method failed without raising an exception: "
-                       "status=%d", status);
-               goto error;
-       }
-
-       if (status == BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
-               /*
-                * Looks like the user method raised
-                * PortConnectionRefused: accept this like if it
-                * returned False.
-                */
-               goto end;
-       } else if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               BT_LOGE("User's _accept_port_connection() raised an unexpected exception: "
-                       "status=%d", status);
-               goto error;
-       }
-
-       BT_ASSERT(PyBool_Check(py_method_result));
-
-       if (py_method_result == Py_True) {
-               status = BT_SELF_COMPONENT_STATUS_OK;
-       } else {
-               status = BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION;
-       }
-
-       goto end;
-
-error:
-       status = BT_SELF_COMPONENT_STATUS_ERROR;
-
-       /*
-        * Clear any exception: we're returning a bad status anyway. If
-        * this call originated from Python, then the user gets an
-        * appropriate error.
-        */
-       PyErr_Clear();
-
-end:
-       Py_XDECREF(py_self_port_ptr);
-       Py_XDECREF(py_other_port_ptr);
-       Py_XDECREF(py_method_result);
-       return status;
-}
-
-static bt_self_component_status
-bt_py3_component_class_source_accept_output_port_connection(bt_self_component_source *self_component_source,
-        bt_self_component_port_output *self_component_port_output,
-        const bt_port_input *other_port_input)
-{
-       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
-       bt_self_component_port *self_component_port = bt_self_component_port_output_as_self_component_port(self_component_port_output);
-       const bt_port *other_port = bt_port_input_as_port_const(other_port_input);
-       return bt_py3_component_class_accept_port_connection(self_component, self_component_port, BT_PORT_TYPE_OUTPUT, other_port);
-}
-
-static bt_self_component_status
-bt_py3_component_class_filter_accept_input_port_connection(bt_self_component_filter *self_component_filter,
-               bt_self_component_port_input *self_component_port_input,
-               const bt_port_output *other_port_output)
-{
-       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
-       bt_self_component_port *self_component_port = bt_self_component_port_input_as_self_component_port(self_component_port_input);
-       const bt_port *other_port = bt_port_output_as_port_const(other_port_output);
-       return bt_py3_component_class_accept_port_connection(self_component, self_component_port, BT_PORT_TYPE_INPUT, other_port);
-}
-
-static bt_self_component_status
-bt_py3_component_class_filter_accept_output_port_connection(bt_self_component_filter *self_component_filter,
-               bt_self_component_port_output *self_component_port_output,
-               const bt_port_input *other_port_input)
-{
-       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
-       bt_self_component_port *self_component_port = bt_self_component_port_output_as_self_component_port(self_component_port_output);
-       const bt_port *other_port = bt_port_input_as_port_const(other_port_input);
-       return bt_py3_component_class_accept_port_connection(self_component, self_component_port, BT_PORT_TYPE_OUTPUT, other_port);
-}
-
-static bt_self_component_status
-bt_py3_component_class_sink_accept_input_port_connection(bt_self_component_sink *self_component_sink,
-               bt_self_component_port_input *self_component_port_input,
-               const bt_port_output *other_port_output)
-{
-       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
-       bt_self_component_port *self_component_port = bt_self_component_port_input_as_self_component_port(self_component_port_input);
-       const bt_port *other_port = bt_port_output_as_port_const(other_port_output);
-       return bt_py3_component_class_accept_port_connection(self_component, self_component_port, BT_PORT_TYPE_INPUT, other_port);
-}
-
-static bt_self_component_status
-bt_py3_component_class_port_connected(
-               bt_self_component *self_component,
-               void *self_component_port,
-               swig_type_info *self_component_port_swig_type,
-               bt_port_type self_component_port_type,
-               const void *other_port,
-               swig_type_info *other_port_swig_type)
-{
-       bt_self_component_status status;
-       PyObject *py_comp = NULL;
-       PyObject *py_self_port_ptr = NULL;
-       PyObject *py_other_port_ptr = NULL;
-       PyObject *py_method_result = NULL;
-
-       py_comp = bt_self_component_get_data(self_component);
-       BT_ASSERT(py_comp);
-
-       py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port),
-               self_component_port_swig_type, 0);
-       if (!py_self_port_ptr) {
-               BT_LOGF_STR("Failed to create a SWIG pointer object.");
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port),
-               other_port_swig_type, 0);
-       if (!py_other_port_ptr) {
-               BT_LOGF_STR("Failed to create a SWIG pointer object.");
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;       }
-
-       py_method_result = PyObject_CallMethod(py_comp,
-               "_port_connected_from_native", "(OiO)", py_self_port_ptr,
-               self_component_port_type, py_other_port_ptr);
-
-       BT_ASSERT(!py_method_result || py_method_result == Py_None);
-
-       status = bt_py3_exc_to_self_component_status();
-
-end:
-       Py_XDECREF(py_self_port_ptr);
-       Py_XDECREF(py_other_port_ptr);
-       Py_XDECREF(py_method_result);
-
-       return status;
-}
-
-static bt_self_component_status
-bt_py3_component_class_source_output_port_connected(
-               bt_self_component_source *self_component_source,
-               bt_self_component_port_output *self_component_port_output,
-               const bt_port_input *other_port_input)
-{
-       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
-
-       return bt_py3_component_class_port_connected(
-               self_component,
-               self_component_port_output,
-               SWIGTYPE_p_bt_self_component_port_output,
-               BT_PORT_TYPE_OUTPUT,
-               other_port_input,
-               SWIGTYPE_p_bt_port_input);
-}
-
-static bt_self_component_status
-bt_py3_component_class_filter_input_port_connected(
-               bt_self_component_filter *self_component_filter,
-               bt_self_component_port_input *self_component_port_input,
-               const bt_port_output *other_port_output)
-{
-       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
-
-       return bt_py3_component_class_port_connected(
-               self_component,
-               self_component_port_input,
-               SWIGTYPE_p_bt_self_component_port_input,
-               BT_PORT_TYPE_INPUT,
-               other_port_output,
-               SWIGTYPE_p_bt_port_output);
-}
-
-static bt_self_component_status
-bt_py3_component_class_filter_output_port_connected(
-               bt_self_component_filter *self_component_filter,
-               bt_self_component_port_output *self_component_port_output,
-               const bt_port_input *other_port_input)
-{
-       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
-
-       return bt_py3_component_class_port_connected(
-               self_component,
-               self_component_port_output,
-               SWIGTYPE_p_bt_self_component_port_output,
-               BT_PORT_TYPE_OUTPUT,
-               other_port_input,
-               SWIGTYPE_p_bt_port_input);
-}
-
-static bt_self_component_status
-bt_py3_component_class_sink_input_port_connected(
-               bt_self_component_sink *self_component_sink,
-               bt_self_component_port_input *self_component_port_input,
-               const bt_port_output *other_port_output)
-{
-       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
-
-       return bt_py3_component_class_port_connected(
-               self_component,
-               self_component_port_input,
-               SWIGTYPE_p_bt_self_component_port_input,
-               BT_PORT_TYPE_INPUT,
-               other_port_output,
-               SWIGTYPE_p_bt_port_output);
-}
-
-static bt_self_component_status
-bt_py3_component_class_sink_graph_is_configured(bt_self_component_sink *self_component_sink)
-{
-       PyObject *py_comp = NULL;
-       PyObject *py_method_result = NULL;
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
-
-       py_comp = bt_self_component_get_data(self_component);
-       py_method_result = PyObject_CallMethod(py_comp,
-               "_graph_is_configured_from_native", NULL);
-
-       BT_ASSERT(!py_method_result || py_method_result == Py_None);
-
-       status = bt_py3_exc_to_self_component_status();
-
-       Py_XDECREF(py_method_result);
-
-       return status;
-}
-
-static bt_query_status
-bt_py3_component_class_query(
-               const bt_component_class *component_class,
-               const bt_query_executor *query_executor,
-               const char *object, const bt_value *params,
-               const bt_value **result)
-{
-       PyObject *py_cls = NULL;
-       PyObject *py_params_ptr = NULL;
-       PyObject *py_query_exec_ptr = NULL;
-       PyObject *py_query_func = NULL;
-       PyObject *py_object = NULL;
-       PyObject *py_results_addr = NULL;
-       bt_query_status status = BT_QUERY_STATUS_OK;
-
-       py_cls = lookup_cc_ptr_to_py_cls(component_class);
-       if (!py_cls) {
-               BT_LOGE("Cannot find Python class associated to native component class: "
-                       "comp-cls-addr=%p", component_class);
-               goto error;
-       }
-
-       py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params),
-               SWIGTYPE_p_bt_value, 0);
-       if (!py_params_ptr) {
-               BT_LOGE_STR("Failed to create a SWIG pointer object.");
-               goto error;
-       }
-
-       py_query_exec_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(query_executor),
-               SWIGTYPE_p_bt_query_executor, 0);
-       if (!py_query_exec_ptr) {
-               BT_LOGE_STR("Failed to create a SWIG pointer object.");
-               goto error;
-       }
-
-       py_object = SWIG_FromCharPtr(object);
-       if (!py_object) {
-               BT_LOGE_STR("Failed to create a Python string.");
-               goto error;
-       }
-
-       py_results_addr = PyObject_CallMethod(py_cls,
-               "_query_from_native", "(OOO)", py_query_exec_ptr,
-               py_object, py_params_ptr);
-
-       if (!py_results_addr) {
-               BT_LOGE("Failed to call Python class's _query_from_native() method: "
-                       "py-cls-addr=%p", py_cls);
-               status = bt_py3_exc_to_query_status();
-               goto end;
-       }
-
-       /*
-        * The returned object, on success, is an integer object
-        * (PyLong) containing the address of a BT value object (new
-        * reference).
-        */
-       *result = PyLong_AsVoidPtr(py_results_addr);
-       BT_ASSERT(!PyErr_Occurred());
-       BT_ASSERT(*result);
-       goto end;
-
-error:
-       PyErr_Clear();
-       status = BT_QUERY_STATUS_ERROR;
-
-end:
-       Py_XDECREF(py_params_ptr);
-       Py_XDECREF(py_query_exec_ptr);
-       Py_XDECREF(py_query_func);
-       Py_XDECREF(py_object);
-       Py_XDECREF(py_results_addr);
-       return status;
-}
-
-static bt_query_status
-bt_py3_component_class_source_query(
-               bt_self_component_class_source *self_component_class_source,
-               const bt_query_executor *query_executor,
-               const char *object, const bt_value *params,
-               const bt_value **result)
-{
-       const bt_component_class_source *component_class_source = bt_self_component_class_source_as_component_class_source(self_component_class_source);
-       const bt_component_class *component_class = bt_component_class_source_as_component_class_const(component_class_source);
-       return bt_py3_component_class_query(component_class, query_executor, object, params, result);
-}
-
-static bt_query_status
-bt_py3_component_class_filter_query(
-               bt_self_component_class_filter *self_component_class_filter,
-               const bt_query_executor *query_executor,
-               const char *object, const bt_value *params,
-               const bt_value **result)
-{
-       const bt_component_class_filter *component_class_filter = bt_self_component_class_filter_as_component_class_filter(self_component_class_filter);
-       const bt_component_class *component_class = bt_component_class_filter_as_component_class_const(component_class_filter);
-       return bt_py3_component_class_query(component_class, query_executor, object, params, result);
-}
-
-static bt_query_status
-bt_py3_component_class_sink_query(
-               bt_self_component_class_sink *self_component_class_sink,
-               const bt_query_executor *query_executor,
-               const char *object, const bt_value *params,
-               const bt_value **result)
-{
-       const bt_component_class_sink *component_class_sink = bt_self_component_class_sink_as_component_class_sink(self_component_class_sink);
-       const bt_component_class *component_class = bt_component_class_sink_as_component_class_const(component_class_sink);
-       return bt_py3_component_class_query(component_class, query_executor, object, params, result);
-}
-
-static bt_self_message_iterator_status
-bt_py3_component_class_message_iterator_init(
-               bt_self_message_iterator *self_message_iterator,
-               bt_self_component *self_component,
-               bt_self_component_port_output *self_component_port_output)
-{
-       bt_self_message_iterator_status status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       PyObject *py_comp_cls = NULL;
-       PyObject *py_iter_cls = NULL;
-       PyObject *py_iter_ptr = NULL;
-       PyObject *py_component_port_output_ptr = NULL;
-       PyObject *py_init_method_result = NULL;
-       PyObject *py_iter = NULL;
-       PyObject *py_comp;
-
-       py_comp = bt_self_component_get_data(self_component);
-
-       /* Find user's Python message iterator class */
-       py_comp_cls = PyObject_GetAttrString(py_comp, "__class__");
-       if (!py_comp_cls) {
-               BT_LOGE_STR("Cannot get Python object's `__class__` attribute.");
-               goto error;
-       }
-
-       py_iter_cls = PyObject_GetAttrString(py_comp_cls, "_iter_cls");
-       if (!py_iter_cls) {
-               BT_LOGE_STR("Cannot get Python class's `_iter_cls` attribute.");
-               goto error;
-       }
-
-       py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_message_iterator),
-               SWIGTYPE_p_bt_self_message_iterator, 0);
-       if (!py_iter_ptr) {
-               BT_LOGE_STR("Failed to create a SWIG pointer object.");
-               goto error;
-       }
-
-       /*
-        * Create object with borrowed native message iterator
-        * reference:
-        *
-        *     py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr)
-        */
-       py_iter = PyObject_CallMethod(py_iter_cls, "__new__",
-               "(OO)", py_iter_cls, py_iter_ptr);
-       if (!py_iter) {
-               BT_LOGE("Failed to call Python class's __new__() method: "
-                       "py-cls-addr=%p", py_iter_cls);
-               bt2_py_loge_exception();
-               goto error;
-       }
-
-       /*
-        * Initialize object:
-        *
-        *     py_iter.__init__(self_output_port)
-        *
-         * through the _init_for_native helper static method.
-        *
-        * At this point, py_iter._ptr is set, so this initialization
-        * function has access to self._component (which gives it the
-        * user Python component object from which the iterator was
-        * created).
-        */
-        py_component_port_output_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port_output),
-               SWIGTYPE_p_bt_self_component_port_output, 0);
-       if (!py_component_port_output_ptr) {
-               BT_LOGE_STR("Failed to create a SWIG pointer object.");
-               goto error;
-       }
-
-       py_init_method_result = PyObject_CallMethod(py_iter, "_init_from_native", "O", py_component_port_output_ptr);
-       if (!py_init_method_result) {
-               BT_LOGE_STR("User's __init__() method failed.");
-               bt2_py_loge_exception();
-               goto error;
-       }
-
-       /*
-        * Since the Python code can never instantiate a user-defined
-        * message iterator class, the native message iterator
-        * object does NOT belong to a user Python message iterator
-        * object (borrowed reference). However this Python object is
-        * owned by this native message iterator object.
-        *
-        * In the Python world, the lifetime of the native message
-        * iterator is managed by a _GenericMessageIterator
-        * instance:
-        *
-        *     _GenericMessageIterator instance:
-        *         owns a native bt_message_iterator object (iter)
-        *             owns a _UserMessageIterator instance (py_iter)
-        *                 self._ptr is a borrowed reference to the
-        *                 native bt_private_connection_private_message_iterator
-        *                 object (iter)
-        */
-       bt_self_message_iterator_set_data(self_message_iterator, py_iter);
-       py_iter = NULL;
-       goto end;
-
-error:
-       status = bt_py3_exc_to_self_message_iterator_status();
-       if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-               /*
-                * Looks like there wasn't any exception from the Python
-                * side, but we're still in an error state here.
-                */
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-       }
-
-       /*
-        * Clear any exception: we're returning a bad status anyway. If
-        * this call originated from Python, then the user gets an
-        * appropriate creation error.
-        */
-       PyErr_Clear();
-
-end:
-       Py_XDECREF(py_comp_cls);
-       Py_XDECREF(py_iter_cls);
-       Py_XDECREF(py_iter_ptr);
-       Py_XDECREF(py_component_port_output_ptr);
-       Py_XDECREF(py_init_method_result);
-       Py_XDECREF(py_iter);
-       return status;
-}
-
-static bt_self_message_iterator_status
-bt_py3_component_class_source_message_iterator_init(
-               bt_self_message_iterator *self_message_iterator,
-               bt_self_component_source *self_component_source,
-               bt_self_component_port_output *self_component_port_output)
-{
-       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
-       return bt_py3_component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output);
-}
-
-static bt_self_message_iterator_status
-bt_py3_component_class_filter_message_iterator_init(
-               bt_self_message_iterator *self_message_iterator,
-               bt_self_component_filter *self_component_filter,
-               bt_self_component_port_output *self_component_port_output)
-{
-       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
-       return bt_py3_component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output);
-}
-
-static void
-bt_py3_component_class_message_iterator_finalize(
-               bt_self_message_iterator *message_iterator)
-{
-       PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator);
-       PyObject *py_method_result = NULL;
-
-       BT_ASSERT(py_message_iter);
-
-       /* Call user's _finalize() method */
-       py_method_result = PyObject_CallMethod(py_message_iter,
-               "_finalize", NULL);
-
-       if (PyErr_Occurred()) {
-               BT_LOGW("User's _finalize() method raised an exception: ignoring.");
-       }
-
-       /*
-        * Ignore any exception raised by the _finalize() method because
-        * it won't change anything at this point: the component is
-        * being destroyed anyway.
-        */
-       PyErr_Clear();
-       Py_XDECREF(py_method_result);
-       Py_DECREF(py_message_iter);
-}
-
-/* Valid for both sources and filters. */
-
-static bt_self_message_iterator_status
-bt_py3_component_class_message_iterator_next(
-                       bt_self_message_iterator *message_iterator,
-                       bt_message_array_const msgs, uint64_t capacity,
-                       uint64_t *count)
-{
-       bt_self_message_iterator_status status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator);
-       PyObject *py_method_result = NULL;
-
-       BT_ASSERT(py_message_iter);
-       py_method_result = PyObject_CallMethod(py_message_iter,
-               "_next_from_native", NULL);
-       if (!py_method_result) {
-               status = bt_py3_exc_to_self_message_iterator_status();
-               BT_ASSERT(status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK);
-               goto end;
-       }
-
-       /*
-        * The returned object, on success, is an integer object
-        * (PyLong) containing the address of a native message
-        * object (which is now ours).
-        */
-       msgs[0] = PyLong_AsVoidPtr(py_method_result);
-       *count = 1;
-
-       /* Clear potential overflow error; should never happen */
-       BT_ASSERT(!PyErr_Occurred());
-       goto end;
-
-end:
-       Py_XDECREF(py_method_result);
-       return status;
-}
-
-static bt_self_component_status
-bt_py3_component_class_sink_consume(bt_self_component_sink *self_component_sink)
-{
-       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
-       PyObject *py_comp = bt_self_component_get_data(self_component);
-       PyObject *py_method_result = NULL;
-       bt_self_component_status status;
-
-       BT_ASSERT(py_comp);
-       py_method_result = PyObject_CallMethod(py_comp,
-               "_consume", NULL);
-
-       status = bt_py3_exc_to_self_component_status();
-       if (!py_method_result && status == BT_SELF_COMPONENT_STATUS_OK) {
-               /* Pretty sure this should never happen, but just in case */
-               BT_LOGE("User's _consume() method failed without raising an exception: "
-                       "status=%d", status);
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-       }
-
-       Py_XDECREF(py_method_result);
-       return status;
-}
-
-static
-int bt_py3_component_class_set_help_and_desc(
-               bt_component_class *component_class,
-               const char *description, const char *help)
-{
-       int ret;
-
-       if (description) {
-               ret = bt_component_class_set_description(component_class, description);
-               if (ret) {
-                       BT_LOGE("Cannot set component class's description: "
-                               "comp-cls-addr=%p", component_class);
-                       goto end;
-               }
-       }
-
-       if (help) {
-               ret = bt_component_class_set_help(component_class, help);
-               if (ret) {
-                       BT_LOGE("Cannot set component class's help text: "
-                               "comp-cls-addr=%p", component_class);
-                       goto end;
-               }
-       }
-
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-bt_component_class_source *bt_py3_component_class_source_create(
-               PyObject *py_cls, const char *name, const char *description,
-               const char *help)
-{
-       bt_component_class_source *component_class_source;
-       bt_component_class *component_class;
-       int ret;
-
-       BT_ASSERT(py_cls);
-
-       component_class_source = bt_component_class_source_create(name,
-               bt_py3_component_class_message_iterator_next);
-       if (!component_class_source) {
-               BT_LOGE_STR("Cannot create source component class.");
-               goto end;
-       }
-
-       component_class = bt_component_class_source_as_component_class(component_class_source);
-
-       if (bt_py3_component_class_set_help_and_desc(component_class, description, help)) {
-               goto end;
-       }
-
-       ret = bt_component_class_source_set_init_method(component_class_source, bt_py3_component_class_source_init);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_source_set_finalize_method (component_class_source, bt_py3_component_class_source_finalize);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_source_set_accept_output_port_connection_method(component_class_source,
-               bt_py3_component_class_source_accept_output_port_connection);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_source_set_output_port_connected_method(component_class_source,
-               bt_py3_component_class_source_output_port_connected);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_source_set_query_method(component_class_source, bt_py3_component_class_source_query);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_source_set_message_iterator_init_method(
-               component_class_source, bt_py3_component_class_source_message_iterator_init);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_source_set_message_iterator_finalize_method(
-               component_class_source, bt_py3_component_class_message_iterator_finalize);
-       BT_ASSERT(ret == 0);
-
-       register_cc_ptr_to_py_cls(component_class, py_cls);
-
-end:
-       return component_class_source;
-}
-
-static
-bt_component_class_filter *bt_py3_component_class_filter_create(
-               PyObject *py_cls, const char *name, const char *description,
-               const char *help)
-{
-       bt_component_class *component_class;
-       bt_component_class_filter *component_class_filter;
-       int ret;
-
-       BT_ASSERT(py_cls);
-
-       component_class_filter = bt_component_class_filter_create(name,
-               bt_py3_component_class_message_iterator_next);
-       if (!component_class_filter) {
-               BT_LOGE_STR("Cannot create filter component class.");
-               goto end;
-       }
-
-       component_class = bt_component_class_filter_as_component_class(component_class_filter);
-
-       if (bt_py3_component_class_set_help_and_desc(component_class, description, help)) {
-               goto end;
-       }
-
-       ret = bt_component_class_filter_set_init_method(component_class_filter, bt_py3_component_class_filter_init);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_filter_set_finalize_method (component_class_filter, bt_py3_component_class_filter_finalize);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_filter_set_accept_input_port_connection_method(component_class_filter,
-               bt_py3_component_class_filter_accept_input_port_connection);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_filter_set_accept_output_port_connection_method(component_class_filter,
-               bt_py3_component_class_filter_accept_output_port_connection);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_filter_set_input_port_connected_method(component_class_filter,
-               bt_py3_component_class_filter_input_port_connected);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_filter_set_output_port_connected_method(component_class_filter,
-               bt_py3_component_class_filter_output_port_connected);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_filter_set_query_method(component_class_filter, bt_py3_component_class_filter_query);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_filter_set_message_iterator_init_method(
-               component_class_filter, bt_py3_component_class_filter_message_iterator_init);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_filter_set_message_iterator_finalize_method(
-               component_class_filter, bt_py3_component_class_message_iterator_finalize);
-       BT_ASSERT(ret == 0);
-
-       register_cc_ptr_to_py_cls(component_class, py_cls);
-
-end:
-       return component_class_filter;
-}
-
-static
-bt_component_class_sink *bt_py3_component_class_sink_create(
-               PyObject *py_cls, const char *name, const char *description,
-               const char *help)
-{
-       bt_component_class_sink *component_class_sink;
-       bt_component_class *component_class;
-       int ret;
-
-       BT_ASSERT(py_cls);
-
-       component_class_sink = bt_component_class_sink_create(name, bt_py3_component_class_sink_consume);
-
-       if (!component_class_sink) {
-               BT_LOGE_STR("Cannot create sink component class.");
-               goto end;
-       }
-
-       component_class = bt_component_class_sink_as_component_class(component_class_sink);
-
-       if (bt_py3_component_class_set_help_and_desc(component_class, description, help)) {
-               goto end;
-       }
-
-       ret = bt_component_class_sink_set_init_method(component_class_sink, bt_py3_component_class_sink_init);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_sink_set_finalize_method(component_class_sink, bt_py3_component_class_sink_finalize);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_sink_set_accept_input_port_connection_method(component_class_sink,
-               bt_py3_component_class_sink_accept_input_port_connection);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_sink_set_input_port_connected_method(component_class_sink,
-               bt_py3_component_class_sink_input_port_connected);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_sink_set_graph_is_configured_method(component_class_sink,
-               bt_py3_component_class_sink_graph_is_configured);
-       BT_ASSERT(ret == 0);
-       ret = bt_component_class_sink_set_query_method(component_class_sink, bt_py3_component_class_sink_query);
-       BT_ASSERT(ret == 0);
-
-       register_cc_ptr_to_py_cls(component_class, py_cls);
-
-end:
-       return component_class_sink;
-}
-%}
-
-struct bt_component_class_source *bt_py3_component_class_source_create(
-               PyObject *py_cls, const char *name, const char *description,
-               const char *help);
-struct bt_component_class_filter *bt_py3_component_class_filter_create(
-               PyObject *py_cls, const char *name, const char *description,
-               const char *help);
-struct bt_component_class_sink *bt_py3_component_class_sink_create(
-               PyObject *py_cls, const char *name, const char *description,
-               const char *help);
-void bt_py3_cc_init_from_bt2(void);
-void bt_py3_cc_exit_handler(void);
diff --git a/bindings/python/bt2/bt2/native_bt_connection.i b/bindings/python/bt2/bt2/native_bt_connection.i
deleted file mode 100644 (file)
index dbdb04a..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From connection-const.h */
-
-extern const bt_port_input *bt_connection_borrow_downstream_port_const(
-               const bt_connection *connection);
-
-extern const bt_port_output *bt_connection_borrow_upstream_port_const(
-               const bt_connection *connection);
-
-extern void bt_connection_get_ref(const bt_connection *connection);
-
-extern void bt_connection_put_ref(const bt_connection *connection);
diff --git a/bindings/python/bt2/bt2/native_bt_event.i b/bindings/python/bt2/bt2/native_bt_event.i
deleted file mode 100644 (file)
index 82ddbfa..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From event-const.h */
-
-typedef enum bt_event_status {
-       BT_EVENT_STATUS_OK = 0,
-       BT_EVENT_STATUS_NOMEM = -12,
-} bt_event_status;
-
-extern const bt_event_class *bt_event_borrow_class_const(
-               const bt_event *event);
-
-extern const bt_packet *bt_event_borrow_packet_const(
-               const bt_event *event);
-
-extern const bt_stream *bt_event_borrow_stream_const(
-               const bt_event *event);
-
-extern const bt_field *bt_event_borrow_common_context_field_const(
-               const bt_event *event);
-
-extern const bt_field *bt_event_borrow_specific_context_field_const(
-               const bt_event *event);
-
-extern const bt_field *bt_event_borrow_payload_field_const(
-               const bt_event *event);
-
-/* From event.h */
-
-extern bt_event_class *bt_event_borrow_class(bt_event *event);
-
-extern bt_packet *bt_event_borrow_packet(bt_event *event);
-
-extern bt_stream *bt_event_borrow_stream(bt_event *event);
-
-extern bt_field *
-bt_event_borrow_common_context_field(bt_event *event);
-
-extern bt_field *
-bt_event_borrow_specific_context_field(bt_event *event);
-
-extern bt_field *bt_event_borrow_payload_field(bt_event *event);
diff --git a/bindings/python/bt2/bt2/native_bt_event_class.i b/bindings/python/bt2/bt2/native_bt_event_class.i
deleted file mode 100644 (file)
index cac0c41..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* Output argument typemap for initialized event class log level output
- * parameter (always appends).
- */
-%typemap(in, numinputs=0)
-       (bt_event_class_log_level *OUT)
-       (bt_event_class_log_level temp = -1) {
-       $1 = &temp;
-}
-
-%typemap(argout) bt_event_class_log_level *OUT {
-       /* SWIG_Python_AppendOutput() steals the created object */
-       $result = SWIG_Python_AppendOutput($result, SWIG_From_int(*$1));
-}
-
-/* From event-class-const.h */
-
-typedef enum bt_event_class_status {
-       BT_EVENT_CLASS_STATUS_OK = 0,
-       BT_EVENT_CLASS_STATUS_NOMEM = -12,
-} bt_event_class_status;
-
-typedef enum bt_event_class_log_level {
-       BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY,
-       BT_EVENT_CLASS_LOG_LEVEL_ALERT,
-       BT_EVENT_CLASS_LOG_LEVEL_CRITICAL,
-       BT_EVENT_CLASS_LOG_LEVEL_ERROR,
-       BT_EVENT_CLASS_LOG_LEVEL_WARNING,
-       BT_EVENT_CLASS_LOG_LEVEL_NOTICE,
-       BT_EVENT_CLASS_LOG_LEVEL_INFO,
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM,
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM,
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS,
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE,
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT,
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION,
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE,
-       BT_EVENT_CLASS_LOG_LEVEL_DEBUG,
-} bt_event_class_log_level;
-
-extern const bt_stream_class *bt_event_class_borrow_stream_class_const(
-               const bt_event_class *event_class);
-
-extern const char *bt_event_class_get_name(const bt_event_class *event_class);
-
-extern uint64_t bt_event_class_get_id(const bt_event_class *event_class);
-
-extern bt_property_availability bt_event_class_get_log_level(
-               const bt_event_class *event_class,
-               bt_event_class_log_level *OUT);
-
-extern const char *bt_event_class_get_emf_uri(
-               const bt_event_class *event_class);
-
-extern const bt_field_class *
-bt_event_class_borrow_specific_context_field_class_const(
-               const bt_event_class *event_class);
-
-extern const bt_field_class *bt_event_class_borrow_payload_field_class_const(
-               const bt_event_class *event_class);
-
-extern void bt_event_class_get_ref(const bt_event_class *event_class);
-
-extern void bt_event_class_put_ref(const bt_event_class *event_class);
-
-/* From event-class.h */
-
-extern bt_event_class *bt_event_class_create(
-               bt_stream_class *stream_class);
-
-extern bt_event_class *bt_event_class_create_with_id(
-               bt_stream_class *stream_class, uint64_t id);
-
-extern bt_stream_class *bt_event_class_borrow_stream_class(
-               bt_event_class *event_class);
-
-extern bt_event_class_status bt_event_class_set_name(
-               bt_event_class *event_class, const char *name);
-
-extern void bt_event_class_set_log_level(bt_event_class *event_class,
-               bt_event_class_log_level log_level);
-
-extern bt_event_class_status bt_event_class_set_emf_uri(
-               bt_event_class *event_class, const char *emf_uri);
-
-extern bt_event_class_status
-bt_event_class_set_specific_context_field_class(bt_event_class *event_class,
-               bt_field_class *field_class);
-
-extern bt_field_class *
-bt_event_class_borrow_specific_context_field_class(bt_event_class *event_class);
-
-extern bt_event_class_status bt_event_class_set_payload_field_class(
-               bt_event_class *event_class,
-               bt_field_class *field_class);
-
-extern bt_field_class *bt_event_class_borrow_payload_field_class(
-               bt_event_class *event_class);
diff --git a/bindings/python/bt2/bt2/native_bt_field.i b/bindings/python/bt2/bt2/native_bt_field.i
deleted file mode 100644 (file)
index f4511f4..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* For label type mappings. */
-%include "native_bt_field_class.i"
-
-/* From field-const.h */
-
-typedef enum bt_field_status {
-       BT_FIELD_STATUS_OK = 0,
-       BT_FIELD_STATUS_NOMEM = -12,
-} bt_field_status;
-
-extern const bt_field_class *bt_field_borrow_class_const(
-               const bt_field *field);
-
-extern bt_field_class_type bt_field_get_class_type(
-               const bt_field *field);
-
-extern int64_t bt_field_signed_integer_get_value(const bt_field *field);
-
-extern uint64_t bt_field_unsigned_integer_get_value(
-               const bt_field *field);
-
-extern double bt_field_real_get_value(const bt_field *field);
-
-extern bt_field_status bt_field_unsigned_enumeration_get_mapping_labels(
-               const bt_field *field,
-               bt_field_class_enumeration_mapping_label_array *LABELARRAY,
-               uint64_t *LABELCOUNT);
-
-extern bt_field_status bt_field_signed_enumeration_get_mapping_labels(
-               const bt_field *field,
-               bt_field_class_enumeration_mapping_label_array *LABELARRAY,
-               uint64_t *LABELCOUNT);
-
-extern const char *bt_field_string_get_value(const bt_field *field);
-
-extern uint64_t bt_field_string_get_length(const bt_field *field);
-
-extern const bt_field *
-bt_field_structure_borrow_member_field_by_index_const(
-               const bt_field *field, uint64_t index);
-
-extern const bt_field *
-bt_field_structure_borrow_member_field_by_name_const(
-               const bt_field *field, const char *name);
-
-extern uint64_t bt_field_array_get_length(const bt_field *field);
-
-extern const bt_field *
-bt_field_array_borrow_element_field_by_index_const(
-               const bt_field *field, uint64_t index);
-
-extern uint64_t bt_field_variant_get_selected_option_field_index(
-               const bt_field *field);
-
-extern const bt_field *
-bt_field_variant_borrow_selected_option_field_const(
-               const bt_field *field);
-
-/* From field.h */
-
-extern void bt_field_signed_integer_set_value(bt_field *field,
-               int64_t value);
-
-extern void bt_field_unsigned_integer_set_value(bt_field *field,
-               uint64_t value);
-
-extern void bt_field_real_set_value(bt_field *field, double value);
-
-extern bt_field_status bt_field_string_set_value(bt_field *field,
-               const char *value);
-
-extern bt_field_status bt_field_string_append(bt_field *field,
-               const char *value);
-
-extern bt_field_status bt_field_string_append_with_length(bt_field *field,
-               const char *value, uint64_t length);
-
-extern bt_field_status bt_field_string_clear(bt_field *field);
-
-extern bt_field *bt_field_structure_borrow_member_field_by_index(
-               bt_field *field, uint64_t index);
-
-extern bt_field *bt_field_structure_borrow_member_field_by_name(
-               bt_field *field, const char *name);
-
-extern bt_field *bt_field_array_borrow_element_field_by_index(
-               bt_field *field, uint64_t index);
-
-extern bt_field_status bt_field_dynamic_array_set_length(bt_field *field,
-               uint64_t length);
-
-extern bt_field_status bt_field_variant_select_option_field(
-               bt_field *field, uint64_t index);
-
-extern bt_field *bt_field_variant_borrow_selected_option_field(
-               bt_field *field);
diff --git a/bindings/python/bt2/bt2/native_bt_field_class.i b/bindings/python/bt2/bt2/native_bt_field_class.i
deleted file mode 100644 (file)
index b6173c0..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-%typemap(in, numinputs=0)
-       (bt_field_class_enumeration_mapping_label_array *LABELARRAY, uint64_t *LABELCOUNT)
-       (bt_field_class_enumeration_mapping_label_array temp_array, uint64_t temp_label_count = 0) {
-       $1 = &temp_array;
-       $2 = &temp_label_count;
-}
-
-%typemap(argout)
-       (bt_field_class_enumeration_mapping_label_array *LABELARRAY, uint64_t *LABELCOUNT) {
-       if (*$1) {
-               PyObject *py_label_list = PyList_New(*$2);
-               for (int i = 0; i < *$2; i++) {
-                       PyList_SET_ITEM(py_label_list, i, PyUnicode_FromString((*$1)[i]));
-               }
-
-               $result = SWIG_Python_AppendOutput($result, py_label_list);
-       } else {
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* Output argument typemap for value output (always appends) */
-%typemap(in, numinputs=0)
-       (const bt_field_class_signed_enumeration_mapping_ranges **ENUM_RANGE_MAPPING)
-       (bt_field_class_signed_enumeration_mapping_ranges *temp_value = NULL) {
-       $1 = &temp_value;
-}
-
-%typemap(argout)
-       (const bt_field_class_signed_enumeration_mapping_ranges **ENUM_RANGE_MAPPING) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_field_class_signed_enumeration_mapping_ranges, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* Output argument typemap for value output (always appends) */
-%typemap(in, numinputs=0)
-       (const bt_field_class_unsigned_enumeration_mapping_ranges **ENUM_RANGE_MAPPING)
-       (bt_field_class_unsigned_enumeration_mapping_ranges *temp_value = NULL) {
-       $1 = &temp_value;
-}
-
-%typemap(argout)
-       (const bt_field_class_unsigned_enumeration_mapping_ranges **ENUM_RANGE_MAPPING ) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_field_class_unsigned_enumeration_mapping_ranges, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* From field-class-const.h */
-
-typedef enum bt_field_class_status {
-       BT_FIELD_CLASS_STATUS_OK = 0,
-       BT_FIELD_CLASS_STATUS_NOMEM = -12,
-} bt_field_class_status;
-
-typedef enum bt_field_class_type {
-       BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER,
-       BT_FIELD_CLASS_TYPE_SIGNED_INTEGER,
-       BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
-       BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
-       BT_FIELD_CLASS_TYPE_REAL,
-       BT_FIELD_CLASS_TYPE_STRING,
-       BT_FIELD_CLASS_TYPE_STRUCTURE,
-       BT_FIELD_CLASS_TYPE_STATIC_ARRAY,
-       BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY,
-       BT_FIELD_CLASS_TYPE_VARIANT,
-} bt_field_class_type;
-
-typedef enum bt_field_class_integer_preferred_display_base {
-       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY,
-       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL,
-       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
-} bt_field_class_integer_preferred_display_base;
-
-extern bt_field_class_type bt_field_class_get_type(
-               const bt_field_class *field_class);
-
-extern uint64_t bt_field_class_integer_get_field_value_range(
-               const bt_field_class *field_class);
-
-extern bt_field_class_integer_preferred_display_base
-bt_field_class_integer_get_preferred_display_base(
-               const bt_field_class *field_class);
-
-extern bt_bool bt_field_class_real_is_single_precision(
-               const bt_field_class *field_class);
-
-extern uint64_t bt_field_class_enumeration_get_mapping_count(
-               const bt_field_class *field_class);
-
-extern const bt_field_class_unsigned_enumeration_mapping *
-bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
-               const bt_field_class *field_class, uint64_t index);
-
-extern const bt_field_class_signed_enumeration_mapping *
-bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
-               const bt_field_class *field_class, uint64_t index);
-
-const bt_field_class_enumeration_mapping *
-bt_field_class_unsigned_enumeration_mapping_as_mapping_const(
-               const bt_field_class_unsigned_enumeration_mapping *mapping);
-
-const bt_field_class_enumeration_mapping *
-bt_field_class_signed_enumeration_mapping_as_mapping_const(
-               const bt_field_class_signed_enumeration_mapping *mapping);
-
-extern const char *bt_field_class_enumeration_mapping_get_label(
-               const bt_field_class_enumeration_mapping *mapping);
-
-extern uint64_t bt_field_class_enumeration_mapping_get_range_count(
-               const bt_field_class_enumeration_mapping *mapping);
-
-extern void
-bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
-               const bt_field_class_unsigned_enumeration_mapping *mapping,
-               uint64_t index, uint64_t *OUT, uint64_t *OUT);
-
-extern void
-bt_field_class_signed_enumeration_mapping_get_range_by_index(
-               const bt_field_class_signed_enumeration_mapping *mapping,
-               uint64_t index, int64_t *OUT, int64_t *OUT);
-
-extern bt_field_class_status
-bt_field_class_unsigned_enumeration_get_mapping_labels_by_value(
-               const bt_field_class *field_class, uint64_t value,
-               bt_field_class_enumeration_mapping_label_array *LABELARRAY,
-               uint64_t *LABELCOUNT);
-
-extern bt_field_class_status
-bt_field_class_signed_enumeration_get_mapping_labels_by_value(
-               const bt_field_class *field_class, int64_t value,
-               bt_field_class_enumeration_mapping_label_array *LABELARRAY,
-               uint64_t *LABELCOUNT);
-
-extern uint64_t bt_field_class_structure_get_member_count(
-               const bt_field_class *field_class);
-
-extern const bt_field_class_structure_member *
-bt_field_class_structure_borrow_member_by_index_const(
-               const bt_field_class *field_class, uint64_t index);
-
-extern const bt_field_class_structure_member *
-bt_field_class_structure_borrow_member_by_name_const(
-               const bt_field_class *field_class, const char *name);
-
-extern const char *bt_field_class_structure_member_get_name(
-               const bt_field_class_structure_member *member);
-
-extern const bt_field_class *
-bt_field_class_structure_member_borrow_field_class_const(
-               const bt_field_class_structure_member *member);
-
-extern const bt_field_class *
-bt_field_class_array_borrow_element_field_class_const(
-               const bt_field_class *field_class);
-
-extern uint64_t bt_field_class_static_array_get_length(
-               const bt_field_class *field_class);
-
-extern const bt_field_path *
-bt_field_class_dynamic_array_borrow_length_field_path_const(
-               const bt_field_class *field_class);
-
-extern const bt_field_path *
-bt_field_class_variant_borrow_selector_field_path_const(
-               const bt_field_class *field_class);
-
-extern uint64_t bt_field_class_variant_get_option_count(
-               const bt_field_class *field_class);
-
-extern const bt_field_class_variant_option *
-bt_field_class_variant_borrow_option_by_index_const(
-               const bt_field_class *field_class, uint64_t index);
-
-extern const bt_field_class_variant_option *
-bt_field_class_variant_borrow_option_by_name_const(
-               const bt_field_class *field_class, const char *name);
-
-extern const char *bt_field_class_variant_option_get_name(
-               const bt_field_class_variant_option *option);
-
-extern const bt_field_class *
-bt_field_class_variant_option_borrow_field_class_const(
-               const bt_field_class_variant_option *option);
-
-extern void bt_field_class_get_ref(const bt_field_class *field_class);
-
-extern void bt_field_class_put_ref(const bt_field_class *field_class);
-
-/* From field-class.h */
-
-extern bt_field_class *bt_field_class_unsigned_integer_create(
-               bt_trace_class *trace_class);
-
-extern bt_field_class *bt_field_class_signed_integer_create(
-               bt_trace_class *trace_class);
-
-extern void bt_field_class_integer_set_field_value_range(
-               bt_field_class *field_class, uint64_t size);
-
-extern void bt_field_class_integer_set_preferred_display_base(
-               bt_field_class *field_class,
-               bt_field_class_integer_preferred_display_base base);
-
-extern bt_field_class *bt_field_class_real_create(bt_trace_class *trace_class);
-
-extern void bt_field_class_real_set_is_single_precision(
-               bt_field_class *field_class,
-               bt_bool is_single_precision);
-
-extern bt_field_class *bt_field_class_unsigned_enumeration_create(
-               bt_trace_class *trace_class);
-
-extern bt_field_class *bt_field_class_signed_enumeration_create(
-               bt_trace_class *trace_class);
-
-extern bt_field_class_status bt_field_class_unsigned_enumeration_map_range(
-               bt_field_class *field_class, const char *label,
-               uint64_t range_lower, uint64_t range_upper);
-
-extern bt_field_class_status bt_field_class_signed_enumeration_map_range(
-               bt_field_class *field_class, const char *label,
-               int64_t range_lower, int64_t range_upper);
-
-extern bt_field_class *bt_field_class_string_create(
-               bt_trace_class *trace_class);
-
-extern bt_field_class *bt_field_class_structure_create(
-               bt_trace_class *trace_class);
-
-extern bt_field_class_status bt_field_class_structure_append_member(
-               bt_field_class *struct_field_class,
-               const char *name, bt_field_class *field_class);
-
-extern bt_field_class_structure_member *
-bt_field_class_structure_borrow_member_by_index(
-               bt_field_class *field_class, uint64_t index);
-
-extern bt_field_class_structure_member *
-bt_field_class_structure_borrow_member_by_name(
-               bt_field_class *field_class, const char *name);
-
-extern bt_field_class *bt_field_class_static_array_create(
-               bt_trace_class *trace_class,
-               bt_field_class *elem_field_class, uint64_t length);
-
-extern bt_field_class *bt_field_class_dynamic_array_create(
-               bt_trace_class *trace_class,
-               bt_field_class *elem_field_class);
-
-extern bt_field_class *bt_field_class_array_borrow_element_field_class(
-               bt_field_class *field_class);
-
-extern bt_field_class_status
-bt_field_class_dynamic_array_set_length_field_class(
-               bt_field_class *field_class,
-               bt_field_class *length_field_class);
-
-extern bt_field_class *bt_field_class_variant_create(
-               bt_trace_class *trace_class);
-
-extern bt_field_class_status
-bt_field_class_variant_set_selector_field_class(bt_field_class *field_class,
-               bt_field_class *selector_field_class);
-
-extern bt_field_class_status bt_field_class_variant_append_option(
-               bt_field_class *var_field_class,
-               const char *name, bt_field_class *field_class);
-
-extern bt_field_class_variant_option *
-bt_field_class_variant_borrow_option_by_index(
-               bt_field_class *field_class, uint64_t index);
-
-extern bt_field_class_variant_option *
-bt_field_class_variant_borrow_option_by_name(
-               bt_field_class *field_class, char *name);
-
-extern bt_field_class *bt_field_class_variant_option_borrow_field_class(
-               bt_field_class_variant_option *option);
diff --git a/bindings/python/bt2/bt2/native_bt_field_path.i b/bindings/python/bt2/bt2/native_bt_field_path.i
deleted file mode 100644 (file)
index 5369f44..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From field-path-const.h */
-
-typedef enum bt_field_path_item_type {
-       BT_FIELD_PATH_ITEM_TYPE_INDEX,
-       BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT,
-} bt_field_path_item_type;
-
-typedef enum bt_scope {
-       BT_SCOPE_PACKET_CONTEXT,
-       BT_SCOPE_EVENT_COMMON_CONTEXT,
-       BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
-       BT_SCOPE_EVENT_PAYLOAD,
-} bt_scope;
-
-extern bt_scope bt_field_path_get_root_scope(
-               const bt_field_path *field_path);
-
-extern uint64_t bt_field_path_get_item_count(
-               const bt_field_path *field_path);
-
-extern const bt_field_path_item *bt_field_path_borrow_item_by_index_const(
-               const bt_field_path *field_path, uint64_t index);
-
-extern bt_field_path_item_type bt_field_path_item_get_type(
-               const bt_field_path_item *field_path_item);
-
-extern uint64_t bt_field_path_item_index_get_index(
-               const bt_field_path_item *field_path_item);
-
-extern void bt_field_path_get_ref(const bt_field_path *field_path);
-
-extern void bt_field_path_put_ref(const bt_field_path *field_path);
diff --git a/bindings/python/bt2/bt2/native_bt_graph.i b/bindings/python/bt2/bt2/native_bt_graph.i
deleted file mode 100644 (file)
index bb7a5d1..0000000
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* Output argument typemap for connection output (always appends) */
-%typemap(in, numinputs=0)
-       (const bt_connection **BTOUTCONN)
-       (bt_connection *temp_conn = NULL) {
-       $1 = &temp_conn;
-}
-
-%typemap(argout)
-       (const bt_connection **BTOUTCONN) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_connection, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* Output argument typemap for component output (always appends) */
-%typemap(in, numinputs=0)
-       (const bt_component_source **OUT)
-       (bt_component_source *temp_comp = NULL) {
-       $1 = &temp_comp;
-}
-
-%typemap(in, numinputs=0)
-       (const bt_component_filter **OUT)
-       (bt_component_filter *temp_comp = NULL) {
-       $1 = &temp_comp;
-}
-
-%typemap(in, numinputs=0)
-       (const bt_component_sink **OUT)
-       (bt_component_sink *temp_comp = NULL) {
-       $1 = &temp_comp;
-}
-
-%typemap(argout) (const bt_component_source **OUT) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_component_source, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-%typemap(argout) (const bt_component_filter **OUT) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_component_filter, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-%typemap(argout) (const bt_component_sink **OUT) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_component_sink, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* From graph-const.h */
-
-typedef enum bt_graph_status {
-       BT_GRAPH_STATUS_OK = 0,
-       BT_GRAPH_STATUS_END = 1,
-       BT_GRAPH_STATUS_AGAIN = 11,
-       BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION = 111,
-       BT_GRAPH_STATUS_CANCELED = 125,
-       BT_GRAPH_STATUS_ERROR = -1,
-       BT_GRAPH_STATUS_NOMEM = -12,
-} bt_graph_status;
-
-extern bt_bool bt_graph_is_canceled(const bt_graph *graph);
-
-extern void bt_graph_get_ref(const bt_graph *graph);
-
-extern void bt_graph_put_ref(const bt_graph *graph);
-
-/* From graph.h */
-
-typedef enum bt_graph_listener_status {
-       BT_GRAPH_LISTENER_STATUS_OK = 0,
-       BT_GRAPH_LISTENER_STATUS_ERROR = -1,
-       BT_GRAPH_LISTENER_STATUS_NOMEM = -12,
-} bt_graph_listener_status;
-
-
-typedef bt_graph_listener_status
-(*bt_graph_filter_component_input_port_added_listener_func)(
-               const bt_component_filter *component,
-               const bt_port_input *port, void *data);
-
-typedef bt_graph_listener_status
-(*bt_graph_sink_component_input_port_added_listener_func)(
-               const bt_component_sink *component,
-               const bt_port_input *port, void *data);
-
-typedef bt_graph_listener_status
-(*bt_graph_source_component_output_port_added_listener_func)(
-               const bt_component_source *component,
-               const bt_port_output *port, void *data);
-
-typedef bt_graph_listener_status
-(*bt_graph_filter_component_output_port_added_listener_func)(
-               const bt_component_filter *component,
-               const bt_port_output *port, void *data);
-
-typedef bt_graph_listener_status
-(*bt_graph_source_filter_component_ports_connected_listener_func)(
-               const bt_component_source *source_component,
-               const bt_component_filter *filter_component,
-               const bt_port_output *upstream_port,
-               const bt_port_input *downstream_port, void *data);
-
-typedef bt_graph_listener_status
-(*bt_graph_source_sink_component_ports_connected_listener_func)(
-               const bt_component_source *source_component,
-               const bt_component_sink *sink_component,
-               const bt_port_output *upstream_port,
-               const bt_port_input *downstream_port, void *data);
-
-typedef bt_graph_listener_status
-(*bt_graph_filter_filter_component_ports_connected_listener_func)(
-               const bt_component_filter *filter_component_upstream,
-               const bt_component_filter *filter_component_downstream,
-               const bt_port_output *upstream_port,
-               const bt_port_input *downstream_port,
-               void *data);
-
-typedef bt_graph_listener_status
-(*bt_graph_filter_sink_component_ports_connected_listener_func)(
-               const bt_component_filter *filter_component,
-               const bt_component_sink *sink_component,
-               const bt_port_output *upstream_port,
-               const bt_port_input *downstream_port, void *data);
-
-typedef void (* bt_graph_listener_removed_func)(void *data);
-
-extern bt_graph *bt_graph_create(void);
-
-extern bt_graph_status bt_graph_add_source_component(bt_graph *graph,
-               const bt_component_class_source *component_class,
-               const char *name, const bt_value *params,
-               const bt_component_source **OUT);
-
-extern bt_graph_status bt_graph_add_source_component_with_init_method_data(
-               bt_graph *graph,
-               const bt_component_class_source *component_class,
-               const char *name, const bt_value *params,
-               void *init_method_data,
-               const bt_component_source **OUT);
-
-extern bt_graph_status bt_graph_add_filter_component(bt_graph *graph,
-               const bt_component_class_filter *component_class,
-               const char *name, const bt_value *params,
-               const bt_component_filter **OUT);
-
-extern bt_graph_status bt_graph_add_filter_component_with_init_method_data(
-               bt_graph *graph,
-               const bt_component_class_filter *component_class,
-               const char *name, const bt_value *params,
-               void *init_method_data,
-               const bt_component_filter **OUT);
-
-extern bt_graph_status bt_graph_add_sink_component(
-               bt_graph *graph, const bt_component_class_sink *component_class,
-               const char *name, const bt_value *params,
-               const bt_component_sink **OUT);
-
-extern bt_graph_status bt_graph_add_sink_component_with_init_method_data(
-               bt_graph *graph, const bt_component_class_sink *component_class,
-               const char *name, const bt_value *params,
-               void *init_method_data,
-               const bt_component_sink **OUT);
-
-extern bt_graph_status bt_graph_connect_ports(bt_graph *graph,
-               const bt_port_output *upstream,
-               const bt_port_input *downstream,
-               const bt_connection **BTOUTCONN);
-
-extern bt_graph_status bt_graph_run(bt_graph *graph);
-
-extern bt_graph_status bt_graph_consume(bt_graph *graph);
-
-extern bt_graph_status bt_graph_add_filter_component_input_port_added_listener(
-               bt_graph *graph,
-               bt_graph_filter_component_input_port_added_listener_func listener,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *listener_id);
-
-extern bt_graph_status bt_graph_add_sink_component_input_port_added_listener(
-               bt_graph *graph,
-               bt_graph_sink_component_input_port_added_listener_func listener,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *listener_id);
-
-extern bt_graph_status bt_graph_add_source_component_output_port_added_listener(
-               bt_graph *graph,
-               bt_graph_source_component_output_port_added_listener_func listener,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *listener_id);
-
-extern bt_graph_status bt_graph_add_filter_component_output_port_added_listener(
-               bt_graph *graph,
-               bt_graph_filter_component_output_port_added_listener_func listener,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *listener_id);
-
-extern bt_graph_status
-bt_graph_add_source_filter_component_ports_connected_listener(
-               bt_graph *graph,
-               bt_graph_source_filter_component_ports_connected_listener_func listener,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *listener_id);
-
-extern bt_graph_status
-bt_graph_add_filter_filter_component_ports_connected_listener(
-               bt_graph *graph,
-               bt_graph_filter_filter_component_ports_connected_listener_func listener,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *listener_id);
-
-extern bt_graph_status
-bt_graph_add_source_sink_component_ports_connected_listener(
-               bt_graph *graph,
-               bt_graph_source_sink_component_ports_connected_listener_func listener,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *listener_id);
-
-extern bt_graph_status
-bt_graph_add_filter_sink_component_ports_connected_listener(
-               bt_graph *graph,
-               bt_graph_filter_sink_component_ports_connected_listener_func listener,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *listener_id);
-
-extern bt_graph_status bt_graph_cancel(bt_graph *graph);
-
-/* Helper functions for Python */
-
-%{
-
-static void graph_listener_removed(void *py_callable)
-{
-       BT_ASSERT(py_callable);
-       Py_DECREF(py_callable);
-}
-
-static bt_graph_listener_status
-port_added_listener(
-       const void *component,
-       swig_type_info *component_swig_type,
-       bt_component_class_type component_class_type,
-       const void *port,
-       swig_type_info *port_swig_type,
-       bt_port_type port_type,
-       void *py_callable)
-{
-       PyObject *py_component_ptr = NULL;
-       PyObject *py_port_ptr = NULL;
-       PyObject *py_res = NULL;
-       bt_graph_listener_status status;
-
-       py_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component), component_swig_type, 0);
-       if (!py_component_ptr) {
-               BT_LOGF_STR("Failed to create component SWIG pointer object.");
-               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
-               goto end;
-       }
-
-       py_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(port), port_swig_type, 0);
-       if (!py_port_ptr) {
-               BT_LOGF_STR("Failed to create port SWIG pointer object.");
-               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
-               goto end;
-       }
-
-       py_res = PyObject_CallFunction(py_callable, "(OiOi)",
-               py_component_ptr, component_class_type, py_port_ptr, port_type);
-       if (!py_res) {
-               bt2_py_loge_exception();
-               PyErr_Clear();
-               status = BT_GRAPH_LISTENER_STATUS_ERROR;
-               goto end;
-       }
-       
-       BT_ASSERT(py_res == Py_None);
-       status = BT_GRAPH_LISTENER_STATUS_OK;
-
-end:
-       Py_XDECREF(py_res);
-       Py_XDECREF(py_port_ptr);
-       Py_XDECREF(py_component_ptr);
-
-       return status;
-}
-
-static bt_graph_listener_status
-source_component_output_port_added_listener(const bt_component_source *component_source,
-                                           const bt_port_output *port_output, void *py_callable)
-{
-       return port_added_listener(
-               component_source, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE,
-               port_output, SWIGTYPE_p_bt_port_output, BT_PORT_TYPE_OUTPUT, py_callable);
-}
-
-static bt_graph_listener_status
-filter_component_input_port_added_listener(const bt_component_filter *component_filter,
-                                          const bt_port_input *port_input, void *py_callable)
-{
-       return port_added_listener(
-               component_filter, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
-               port_input, SWIGTYPE_p_bt_port_input, BT_PORT_TYPE_INPUT, py_callable);
-}
-
-static bt_graph_listener_status
-filter_component_output_port_added_listener(const bt_component_filter *component_filter,
-                                           const bt_port_output *port_output, void *py_callable)
-{
-       return port_added_listener(
-               component_filter, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
-               port_output, SWIGTYPE_p_bt_port_output, BT_PORT_TYPE_OUTPUT, py_callable);
-}
-
-static bt_graph_listener_status
-sink_component_input_port_added_listener(const bt_component_sink *component_sink,
-                                        const bt_port_input *port_input, void *py_callable)
-{
-       return port_added_listener(
-               component_sink, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK,
-               port_input, SWIGTYPE_p_bt_port_input, BT_PORT_TYPE_INPUT, py_callable);
-}
-
-static PyObject *
-bt_py3_graph_add_port_added_listener(struct bt_graph *graph,
-                                    PyObject *py_callable)
-{
-       PyObject *py_listener_ids = NULL;
-       PyObject *py_listener_id = NULL;
-       int listener_id;
-       bt_graph_status status;
-
-       BT_ASSERT(graph);
-       BT_ASSERT(py_callable);
-
-       /*
-        * Behind the scene, we will be registering 4 different listeners and
-        * return all of their ids.
-        */
-       py_listener_ids = PyTuple_New(4);
-       if (!py_listener_ids) {
-               goto error;
-       }
-
-       /* source output port */
-       status = bt_graph_add_source_component_output_port_added_listener(
-               graph, source_component_output_port_added_listener,
-               graph_listener_removed, py_callable, &listener_id);
-       if (status != BT_GRAPH_STATUS_OK) {
-               goto error;
-       }
-
-       py_listener_id = PyLong_FromLong(listener_id);
-       if (!py_listener_id) {
-               goto error;
-       }
-
-       PyTuple_SET_ITEM(py_listener_ids, 0, py_listener_id);
-       py_listener_id = NULL;
-
-       /* filter input port */
-       status = bt_graph_add_filter_component_input_port_added_listener(
-               graph, filter_component_input_port_added_listener,
-               graph_listener_removed, py_callable, &listener_id);
-       if (status != BT_GRAPH_STATUS_OK) {
-               goto error;
-       }
-
-       py_listener_id = PyLong_FromLong(listener_id);
-       if (!py_listener_id) {
-               goto error;
-       }
-
-       PyTuple_SET_ITEM(py_listener_ids, 1, py_listener_id);
-       py_listener_id = NULL;
-
-       /* filter output port */
-       status = bt_graph_add_filter_component_output_port_added_listener(
-               graph, filter_component_output_port_added_listener,
-               graph_listener_removed, py_callable, &listener_id);
-       if (status != BT_GRAPH_STATUS_OK) {
-               goto error;
-       }
-
-       py_listener_id = PyLong_FromLong(listener_id);
-       if (!py_listener_id) {
-               goto error;
-       }
-
-       PyTuple_SET_ITEM(py_listener_ids, 2, py_listener_id);
-       py_listener_id = NULL;
-
-       /* sink input port */
-       status = bt_graph_add_sink_component_input_port_added_listener(
-               graph, sink_component_input_port_added_listener,
-               graph_listener_removed, py_callable, &listener_id);
-       if (status != BT_GRAPH_STATUS_OK) {
-               goto error;
-       }
-
-       py_listener_id = PyLong_FromLong(listener_id);
-       if (!py_listener_id) {
-               goto error;
-       }
-
-
-       PyTuple_SET_ITEM(py_listener_ids, 3, py_listener_id);
-       py_listener_id = NULL;
-
-       Py_INCREF(py_callable);
-       Py_INCREF(py_callable);
-       Py_INCREF(py_callable);
-       Py_INCREF(py_callable);
-
-       goto end;
-
-error:
-       Py_XDECREF(py_listener_ids);
-       py_listener_ids = Py_None;
-       Py_INCREF(py_listener_ids);
-
-end:
-
-       Py_XDECREF(py_listener_id);
-       return py_listener_ids;
-}
-
-static bt_graph_listener_status
-ports_connected_listener(
-               const void *upstream_component,
-               swig_type_info *upstream_component_swig_type,
-               bt_component_class_type upstream_component_class_type,
-               const bt_port_output *upstream_port,
-               const void *downstream_component,
-               swig_type_info *downstream_component_swig_type,
-               bt_component_class_type downstream_component_class_type,
-               const bt_port_input *downstream_port,
-               void *py_callable)
-{
-       PyObject *py_upstream_component_ptr = NULL;
-       PyObject *py_upstream_port_ptr = NULL;
-       PyObject *py_downstream_component_ptr = NULL;
-       PyObject *py_downstream_port_ptr = NULL;
-       PyObject *py_res = NULL;
-       bt_graph_listener_status status;
-
-       py_upstream_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(upstream_component),
-               upstream_component_swig_type, 0);
-       if (!py_upstream_component_ptr) {
-               BT_LOGF_STR("Failed to create upstream component SWIG pointer object.");
-               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
-               goto end;
-       }
-
-       py_upstream_port_ptr = SWIG_NewPointerObj(
-               SWIG_as_voidptr(upstream_port), SWIGTYPE_p_bt_port_output, 0);
-       if (!py_upstream_port_ptr) {
-               BT_LOGF_STR("Failed to create upstream port SWIG pointer object.");
-               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
-               goto end;
-       }
-       
-       py_downstream_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(downstream_component),
-               downstream_component_swig_type, 0);
-       if (!py_downstream_component_ptr) {
-               BT_LOGF_STR("Failed to create downstream component SWIG pointer object.");
-               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
-               goto end;
-       }
-
-       py_downstream_port_ptr = SWIG_NewPointerObj(
-               SWIG_as_voidptr(downstream_port), SWIGTYPE_p_bt_port_input, 0);
-       if (!py_downstream_port_ptr) {
-               BT_LOGF_STR("Failed to create downstream port SWIG pointer object.");
-               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
-               goto end;
-       }
-
-       py_res = PyObject_CallFunction(py_callable, "(OiOOiO)",
-               py_upstream_component_ptr, upstream_component_class_type,
-               py_upstream_port_ptr,
-               py_downstream_component_ptr, downstream_component_class_type,
-               py_downstream_port_ptr);
-       if (!py_res) {
-               bt2_py_loge_exception();
-               PyErr_Clear();
-               status = BT_GRAPH_LISTENER_STATUS_ERROR;
-               goto end;
-       }
-       
-       BT_ASSERT(py_res == Py_None);
-       status = BT_GRAPH_LISTENER_STATUS_OK;
-
-end:
-       Py_XDECREF(py_upstream_component_ptr);
-       Py_XDECREF(py_upstream_port_ptr);
-       Py_XDECREF(py_downstream_component_ptr);
-       Py_XDECREF(py_downstream_port_ptr);
-       Py_XDECREF(py_res);
-
-       return status;
-}
-
-static bt_graph_listener_status
-source_filter_component_ports_connected_listener(
-       const bt_component_source *source_component,
-       const bt_component_filter *filter_component,
-       const bt_port_output *upstream_port,
-       const bt_port_input *downstream_port, void *py_callable)
-{
-       return ports_connected_listener(
-               source_component, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE,
-               upstream_port,
-               filter_component, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
-               downstream_port,
-               py_callable);
-}
-
-static bt_graph_listener_status
-source_sink_component_ports_connected_listener(
-       const bt_component_source *source_component,
-       const bt_component_sink *sink_component,
-       const bt_port_output *upstream_port,
-       const bt_port_input *downstream_port, void *py_callable)
-{
-       return ports_connected_listener(
-               source_component, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE,
-               upstream_port,
-               sink_component, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK,
-               downstream_port,
-               py_callable);
-}
-
-static bt_graph_listener_status
-filter_filter_component_ports_connected_listener(
-       const bt_component_filter *filter_component_left,
-       const bt_component_filter *filter_component_right,
-       const bt_port_output *upstream_port,
-       const bt_port_input *downstream_port, void *py_callable)
-{
-       return ports_connected_listener(
-               filter_component_left, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
-               upstream_port,
-               filter_component_right, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
-               downstream_port,
-               py_callable);
-}
-
-static bt_graph_listener_status
-filter_sink_component_ports_connected_listener(
-       const bt_component_filter *filter_component,
-       const bt_component_sink *sink_component,
-       const bt_port_output *upstream_port,
-       const bt_port_input *downstream_port, void *py_callable)
-{
-       return ports_connected_listener(
-               filter_component, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
-               upstream_port,
-               sink_component, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK,
-               downstream_port,
-               py_callable);
-}
-
-static PyObject*
-bt_py3_graph_add_ports_connected_listener(struct bt_graph *graph,
-       PyObject *py_callable)
-{
-       PyObject *py_listener_ids = NULL;
-       PyObject *py_listener_id = NULL;
-       int listener_id;
-       bt_graph_status status;
-
-       BT_ASSERT(graph);
-       BT_ASSERT(py_callable);
-
-       /* Behind the scene, we will be registering 4 different listeners and
-        * return all of their ids. */
-       py_listener_ids = PyTuple_New(4);
-       if (!py_listener_ids) {
-               goto error;
-       }
-
-       /* source -> filter connection */
-       status = bt_graph_add_source_filter_component_ports_connected_listener(
-               graph, source_filter_component_ports_connected_listener,
-               graph_listener_removed, py_callable, &listener_id);
-       if (status != BT_GRAPH_STATUS_OK) {
-               goto error;
-       }
-
-       py_listener_id = PyLong_FromLong(listener_id);
-       if (!py_listener_id) {
-               goto error;
-       }
-
-       PyTuple_SET_ITEM(py_listener_ids, 0, py_listener_id);
-       py_listener_id = NULL;
-
-       /* source -> sink connection */
-       status = bt_graph_add_source_sink_component_ports_connected_listener(
-               graph, source_sink_component_ports_connected_listener,
-               graph_listener_removed, py_callable, &listener_id);
-       if (status != BT_GRAPH_STATUS_OK) {
-               goto error;
-       }
-
-       py_listener_id = PyLong_FromLong(listener_id);
-       if (!py_listener_id) {
-               goto error;
-       }
-
-       PyTuple_SET_ITEM(py_listener_ids, 1, py_listener_id);
-       py_listener_id = NULL;
-
-       /* filter -> filter connection */
-       status = bt_graph_add_filter_filter_component_ports_connected_listener(
-               graph, filter_filter_component_ports_connected_listener,
-               graph_listener_removed, py_callable, &listener_id);
-       if (status != BT_GRAPH_STATUS_OK) {
-               goto error;
-       }
-
-       py_listener_id = PyLong_FromLong(listener_id);
-       if (!py_listener_id) {
-               goto error;
-       }
-
-       PyTuple_SET_ITEM(py_listener_ids, 2, py_listener_id);
-       py_listener_id = NULL;
-
-       /* filter -> sink connection */
-       status = bt_graph_add_filter_sink_component_ports_connected_listener(
-               graph, filter_sink_component_ports_connected_listener,
-               graph_listener_removed, py_callable, &listener_id);
-       if (status != BT_GRAPH_STATUS_OK) {
-               goto error;
-       }
-
-       py_listener_id = PyLong_FromLong(listener_id);
-       if (!py_listener_id) {
-               goto error;
-       }
-
-       PyTuple_SET_ITEM(py_listener_ids, 3, py_listener_id);
-       py_listener_id = NULL;
-
-       Py_INCREF(py_callable);
-       Py_INCREF(py_callable);
-       Py_INCREF(py_callable);
-       Py_INCREF(py_callable);
-
-       goto end;
-
-error:
-       Py_XDECREF(py_listener_ids);
-       py_listener_ids = Py_None;
-       Py_INCREF(py_listener_ids);
-
-end:
-
-       Py_XDECREF(py_listener_id);
-       return py_listener_ids;
-}
-
-%}
-
-PyObject *bt_py3_graph_add_port_added_listener(struct bt_graph *graph,
-               PyObject *py_callable);
-PyObject *bt_py3_graph_add_ports_connected_listener(struct bt_graph *graph,
-               PyObject *py_callable);
diff --git a/bindings/python/bt2/bt2/native_bt_logging.i b/bindings/python/bt2/bt2/native_bt_logging.i
deleted file mode 100644 (file)
index df364bd..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-%{
-#include <babeltrace2/logging.h>
-%}
-
-/* Log levels */
-enum bt_logging_level {
-       BT_LOGGING_LEVEL_VERBOSE = 1,
-       BT_LOGGING_LEVEL_DEBUG = 2,
-       BT_LOGGING_LEVEL_INFO = 3,
-       BT_LOGGING_LEVEL_WARN = 4,
-       BT_LOGGING_LEVEL_ERROR = 5,
-       BT_LOGGING_LEVEL_FATAL = 6,
-       BT_LOGGING_LEVEL_NONE = 0xff,
-};
-
-/* Logging functions */
-enum bt_logging_level bt_logging_get_minimal_level(void);
-enum bt_logging_level bt_logging_get_global_level(void);
-void bt_logging_set_global_level(enum bt_logging_level log_level);
diff --git a/bindings/python/bt2/bt2/native_bt_message.i b/bindings/python/bt2/bt2/native_bt_message.i
deleted file mode 100644 (file)
index 0c81b93..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-
-/* Output argument typemap for clock value output (always appends) */
-%typemap(in, numinputs=0)
-       (const bt_clock_snapshot **BTOUTCLOCKSNAPSHOT)
-       (bt_clock_snapshot *temp_clock_snapshot = NULL) {
-       $1 = &temp_clock_snapshot;
-}
-
-%typemap(argout)
-       (const bt_clock_snapshot **BTOUTCLOCKSNAPSHOT) {
-       if (*$1) {
-               /* SWIG_Python_AppendOutput() steals the created object */
-               $result = SWIG_Python_AppendOutput($result,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
-                                       SWIGTYPE_p_bt_clock_snapshot, 0));
-       } else {
-               /* SWIG_Python_AppendOutput() steals Py_None */
-               Py_INCREF(Py_None);
-               $result = SWIG_Python_AppendOutput($result, Py_None);
-       }
-}
-
-/* From message-const.h */
-
-typedef enum bt_message_type {
-       BT_MESSAGE_TYPE_EVENT = 0,
-       BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY = 1,
-       BT_MESSAGE_TYPE_STREAM_BEGINNING = 2,
-       BT_MESSAGE_TYPE_STREAM_END = 3,
-       BT_MESSAGE_TYPE_PACKET_BEGINNING = 4,
-       BT_MESSAGE_TYPE_PACKET_END = 5,
-       BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING = 6,
-       BT_MESSAGE_TYPE_STREAM_ACTIVITY_END = 7,
-       BT_MESSAGE_TYPE_DISCARDED_EVENTS = 8,
-       BT_MESSAGE_TYPE_DISCARDED_PACKETS = 9,
-} bt_message_type;
-
-extern bt_message_type bt_message_get_type(const bt_message *message);
-
-extern void bt_message_get_ref(const bt_message *message);
-
-extern void bt_message_put_ref(const bt_message *message);
-
-/* From message-event-const.h */
-
-extern const bt_event *bt_message_event_borrow_event_const(
-               const bt_message *message);
-
-extern const bt_clock_snapshot *
-bt_message_event_borrow_default_clock_snapshot_const(
-               const bt_message *msg);
-
-extern const bt_clock_class *
-bt_message_event_borrow_stream_class_default_clock_class_const(
-               const bt_message *msg);
-
-/* From message-event.h */
-
-extern
-bt_message *bt_message_event_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_event_class *event_class,
-               const bt_packet *packet);
-
-extern
-bt_message *bt_message_event_create_with_default_clock_snapshot(
-               bt_self_message_iterator *message_iterator,
-               const bt_event_class *event_class,
-               const bt_packet *packet, uint64_t raw_clock_value);
-
-extern bt_event *bt_message_event_borrow_event(
-               bt_message *message);
-
-/* From message-message-iterator-inactivity-const.h */
-
-extern const bt_clock_snapshot *
-bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
-               const bt_message *msg);
-
-/* From message-message-iterator-inactivity.h */
-
-extern
-bt_message *bt_message_message_iterator_inactivity_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_clock_class *default_clock_class, uint64_t raw_value);
-
-/* From message-stream-beginning-const.h */
-
-extern const bt_stream *bt_message_stream_beginning_borrow_stream_const(
-               const bt_message *message);
-
-/* From message-stream-beginning.h */
-
-extern
-bt_message *bt_message_stream_beginning_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_stream *stream);
-
-extern bt_stream *bt_message_stream_beginning_borrow_stream(
-               bt_message *message);
-
-/* From message-stream-end-const.h */
-
-extern const bt_stream *bt_message_stream_end_borrow_stream_const(
-               const bt_message *message);
-
-/* From message-stream-end.h */
-
-extern
-bt_message *bt_message_stream_end_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_stream *stream);
-
-extern bt_stream *bt_message_stream_end_borrow_stream(
-               bt_message *message);
-
-/* From message-packet-beginning-const.h */
-
-extern const bt_packet *bt_message_packet_beginning_borrow_packet_const(
-               const bt_message *message);
-
-extern const bt_clock_snapshot *
-bt_message_packet_beginning_borrow_default_clock_snapshot_const(
-               const bt_message *msg);
-
-extern const bt_clock_class *
-bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
-               const bt_message *msg);
-
-/* From message-packet-beginning.h */
-
-extern
-bt_message *bt_message_packet_beginning_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_packet *packet);
-
-extern
-bt_message *bt_message_packet_beginning_create_with_default_clock_snapshot(
-               bt_self_message_iterator *message_iterator,
-               const bt_packet *packet, uint64_t raw_value);
-
-extern bt_packet *bt_message_packet_beginning_borrow_packet(
-               bt_message *message);
-
-/* From message-packet-end-const.h */
-
-extern const bt_packet *bt_message_packet_end_borrow_packet_const(
-               const bt_message *message);
-
-extern const bt_clock_snapshot *
-bt_message_packet_end_borrow_default_clock_snapshot_const(
-               const bt_message *msg);
-
-extern const bt_clock_class *
-bt_message_packet_end_borrow_stream_class_default_clock_class_const(
-               const bt_message *msg);
-
-/* From message-packet-end.h */
-
-extern
-bt_message *bt_message_packet_end_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_packet *packet);
-
-extern
-bt_message *bt_message_packet_end_create_with_default_clock_snapshot(
-               bt_self_message_iterator *message_iterator,
-               const bt_packet *packet, uint64_t raw_value);
-
-extern bt_packet *bt_message_packet_end_borrow_packet(
-               bt_message *message);
-
-/* From message-stream-activity-const.h */
-
-typedef enum bt_message_stream_activity_clock_snapshot_state {
-       BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN,
-       BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN,
-       BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE,
-} bt_message_stream_activity_clock_snapshot_state;
-
-/* From message-stream-activity-beginning-const.h */
-
-extern bt_message_stream_activity_clock_snapshot_state
-bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
-               const bt_message *msg, const bt_clock_snapshot **BTOUTCLOCKSNAPSHOT);
-
-extern const bt_clock_class *
-bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
-               const bt_message *msg);
-
-extern const bt_stream *
-bt_message_stream_activity_beginning_borrow_stream_const(
-               const bt_message *message);
-
-/* From message-stream-activity-beginning.h */
-
-extern bt_message *bt_message_stream_activity_beginning_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_stream *stream);
-
-extern bt_stream *bt_message_stream_activity_beginning_borrow_stream(
-               bt_message *message);
-
-extern void bt_message_stream_activity_beginning_set_default_clock_snapshot_state(
-               bt_message *msg,
-               bt_message_stream_activity_clock_snapshot_state state);
-
-extern void bt_message_stream_activity_beginning_set_default_clock_snapshot(
-               bt_message *msg, uint64_t raw_value);
-
-/* From message-stream-activity-end-const.h */
-
-extern bt_message_stream_activity_clock_snapshot_state
-bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
-               const bt_message *msg, const bt_clock_snapshot **BTOUTCLOCKSNAPSHOT);
-
-extern const bt_clock_class *
-bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
-               const bt_message *msg);
-
-extern const bt_stream *
-bt_message_stream_activity_end_borrow_stream_const(
-               const bt_message *message);
-
-/* From message-stream-activity-end.h */
-
-extern bt_message *bt_message_stream_activity_end_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_stream *stream);
-
-extern void bt_message_stream_activity_end_set_default_clock_snapshot_state(
-               bt_message *msg,
-               bt_message_stream_activity_clock_snapshot_state state);
-
-extern void bt_message_stream_activity_end_set_default_clock_snapshot(
-               bt_message *msg, uint64_t raw_value);
-
-extern bt_stream *bt_message_stream_activity_end_borrow_stream(
-               bt_message *message);
-
-/* From message-discarded-events-const.h */
-
-extern const bt_clock_snapshot *
-bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-               const bt_message *msg);
-
-extern const bt_clock_snapshot *
-bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
-               const bt_message *msg);
-
-extern const bt_clock_class *
-bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
-               const bt_message *msg);
-
-extern const bt_stream *
-bt_message_discarded_events_borrow_stream_const(const bt_message *message);
-
-extern bt_property_availability bt_message_discarded_events_get_count(
-               const bt_message *message, uint64_t *OUT);
-
-/* From message-discarded-events.h */
-
-extern bt_message *bt_message_discarded_events_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_stream *stream);
-
-extern bt_message *bt_message_discarded_events_create_with_default_clock_snapshots(
-               bt_self_message_iterator *message_iterator,
-               const bt_stream *stream, uint64_t beginning_raw_value,
-               uint64_t end_raw_value);
-
-extern bt_stream *bt_message_discarded_events_borrow_stream(
-               bt_message *message);
-
-extern void bt_message_discarded_events_set_count(bt_message *message,
-               uint64_t count);
-
-/* From message-discarded-packets-const.h */
-
-extern const bt_clock_snapshot *
-bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-               const bt_message *msg);
-
-extern const bt_clock_snapshot *
-bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
-               const bt_message *msg);
-
-extern const bt_clock_class *
-bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
-               const bt_message *msg);
-
-extern const bt_stream *
-bt_message_discarded_packets_borrow_stream_const(const bt_message *message);
-
-extern bt_property_availability bt_message_discarded_packets_get_count(
-               const bt_message *message, uint64_t *OUT);
-
-/* From message-discarded-packets.h */
-
-extern bt_message *bt_message_discarded_packets_create(
-               bt_self_message_iterator *message_iterator,
-               const bt_stream *stream);
-
-extern bt_message *bt_message_discarded_packets_create_with_default_clock_snapshots(
-               bt_self_message_iterator *message_iterator,
-               const bt_stream *stream, uint64_t beginning_raw_value,
-               uint64_t end_raw_value);
-
-extern bt_stream *bt_message_discarded_packets_borrow_stream(
-               bt_message *message);
-
-extern void bt_message_discarded_packets_set_count(bt_message *message,
-               uint64_t count);
diff --git a/bindings/python/bt2/bt2/native_bt_notifier.i b/bindings/python/bt2/bt2/native_bt_notifier.i
deleted file mode 100644 (file)
index b5f5390..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From message-iterator-const.h */
-
-typedef enum bt_message_iterator_status {
-       BT_MESSAGE_ITERATOR_STATUS_OK = 0,
-       BT_MESSAGE_ITERATOR_STATUS_END = 1,
-       BT_MESSAGE_ITERATOR_STATUS_AGAIN = 11,
-       BT_MESSAGE_ITERATOR_STATUS_ERROR = -1,
-       BT_MESSAGE_ITERATOR_STATUS_NOMEM = -12,
-} bt_message_iterator_status;
-
-/* From self-message-iterator.h */
-
-typedef enum bt_self_message_iterator_status {
-       BT_SELF_MESSAGE_ITERATOR_STATUS_OK = BT_MESSAGE_ITERATOR_STATUS_OK,
-       BT_SELF_MESSAGE_ITERATOR_STATUS_END = BT_MESSAGE_ITERATOR_STATUS_END,
-       BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN = BT_MESSAGE_ITERATOR_STATUS_AGAIN,
-       BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR = BT_MESSAGE_ITERATOR_STATUS_ERROR,
-       BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM = BT_MESSAGE_ITERATOR_STATUS_NOMEM,
-} bt_self_message_iterator_status;
-
-extern bt_self_component *
-bt_self_message_iterator_borrow_component(
-               bt_self_message_iterator *message_iterator);
-
-extern bt_self_port_output *
-bt_self_message_iterator_borrow_port(
-               bt_self_message_iterator *message_iterator);
-
-extern void bt_self_message_iterator_set_data(
-               bt_self_message_iterator *message_iterator,
-               void *user_data);
-
-extern void *bt_self_message_iterator_get_data(
-               const bt_self_message_iterator *message_iterator);
-
-/* From self-component-port-input-message-iterator.h */
-
-bt_message_iterator *
-bt_self_component_port_input_message_iterator_as_message_iterator(
-               bt_self_component_port_input_message_iterator *iterator);
-
-extern bt_self_component_port_input_message_iterator *
-bt_self_component_port_input_message_iterator_create(
-               bt_self_component_port_input *input_port);
-
-extern bt_component *
-bt_self_component_port_input_message_iterator_borrow_component(
-               bt_self_component_port_input_message_iterator *iterator);
-
-extern bt_message_iterator_status
-bt_self_component_port_input_message_iterator_next(
-               bt_self_component_port_input_message_iterator *iterator,
-               bt_message_array_const *msgs, uint64_t *count);
-
-extern bt_bool
-bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
-               bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin);
-
-extern bt_bool bt_self_component_port_input_message_iterator_can_seek_beginning(
-               bt_self_component_port_input_message_iterator *iterator);
-
-extern bt_message_iterator_status
-bt_self_component_port_input_message_iterator_seek_ns_from_origin(
-               bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin);
-
-extern bt_message_iterator_status
-bt_self_component_port_input_message_iterator_seek_beginning(
-               bt_self_component_port_input_message_iterator *iterator);
-
-extern void bt_self_component_port_input_message_iterator_get_ref(
-               const bt_self_component_port_input_message_iterator *self_component_port_input_message_iterator);
-
-extern void bt_self_component_port_input_message_iterator_put_ref(
-               const bt_self_component_port_input_message_iterator *self_component_port_input_message_iterator);
-
-/* From port-output-message-iterator.h */
-
-bt_message_iterator *
-bt_port_output_message_iterator_as_message_iterator(
-               bt_port_output_message_iterator *iterator);
-
-extern bt_port_output_message_iterator *
-bt_port_output_message_iterator_create(
-               bt_graph *graph,
-               const bt_port_output *output_port);
-
-extern bt_message_iterator_status
-bt_port_output_message_iterator_next(
-               bt_port_output_message_iterator *iterator,
-               bt_message_array_const *msgs, uint64_t *count);
-
-extern bt_bool bt_port_output_message_iterator_can_seek_ns_from_origin(
-               bt_port_output_message_iterator *iterator,
-               int64_t ns_from_origin);
-
-extern bt_bool bt_port_output_message_iterator_can_seek_beginning(
-               bt_port_output_message_iterator *iterator);
-
-extern bt_message_iterator_status
-bt_port_output_message_iterator_seek_ns_from_origin(
-               bt_port_output_message_iterator *iterator,
-               int64_t ns_from_origin);
-
-extern bt_message_iterator_status
-bt_port_output_message_iterator_seek_beginning(
-               bt_port_output_message_iterator *iterator);
-
-extern void bt_port_output_message_iterator_get_ref(
-               const bt_port_output_message_iterator *port_output_message_iterator);
-
-extern void bt_port_output_message_iterator_put_ref(
-               const bt_port_output_message_iterator *port_output_message_iterator);
-
-/* Helper functions for Python */
-%{
-static PyObject *bt_py3_get_user_component_from_user_msg_iter(
-               bt_self_message_iterator *self_message_iterator)
-{
-       bt_self_component *self_component = bt_self_message_iterator_borrow_component(self_message_iterator);
-       PyObject *py_comp;
-
-       BT_ASSERT(self_component);
-       py_comp = bt_self_component_get_data(self_component);
-       BT_ASSERT(py_comp);
-
-       /* Return new reference */
-       Py_INCREF(py_comp);
-       return py_comp;
-}
-
-static inline
-PyObject *create_pylist_from_messages(bt_message_array_const messages,
-               uint64_t message_count)
-{
-       uint64_t i;
-       PyObject *py_msg_list = PyList_New(message_count);
-       BT_ASSERT(py_msg_list);
-       for (i = 0; i < message_count; i++) {
-               PyList_SET_ITEM(py_msg_list, i,
-                               SWIG_NewPointerObj(SWIG_as_voidptr(messages[i]),
-                                       SWIGTYPE_p_bt_message, 0));
-       }
-
-       return py_msg_list;
-}
-
-static
-PyObject *bt_py3_get_msg_range_common(bt_message_iterator_status status,
-               bt_message_array_const messages, uint64_t message_count)
-{
-       PyObject *py_status;
-       PyObject *py_return_tuple;
-       PyObject *py_msg_list = Py_None;
-       
-       py_status = SWIG_From_long_SS_long(status);
-       if (status != BT_MESSAGE_ITERATOR_STATUS_OK) {
-               goto end;
-       }
-
-       py_msg_list = create_pylist_from_messages(messages, message_count);
-
-end:
-       py_return_tuple = PyTuple_New(2);
-       BT_ASSERT(py_return_tuple);
-       PyTuple_SET_ITEM(py_return_tuple, 0, py_status);
-       PyTuple_SET_ITEM(py_return_tuple, 1, py_msg_list);
-
-       return py_return_tuple;
-}
-
-static PyObject
-*bt_py3_self_component_port_input_get_msg_range(
-               bt_self_component_port_input_message_iterator *iter)
-{
-       bt_message_array_const messages;
-       uint64_t message_count = 0;
-       bt_message_iterator_status status;
-
-       status = bt_self_component_port_input_message_iterator_next(iter, &messages,
-                               &message_count);
-       
-       return bt_py3_get_msg_range_common(status, messages, message_count);
-}
-
-static PyObject
-*bt_py3_port_output_get_msg_range(
-               bt_port_output_message_iterator *iter)
-{
-       bt_message_array_const messages;
-       uint64_t message_count = 0;
-       bt_message_iterator_status status;
-
-       status =
-               bt_port_output_message_iterator_next(iter, &messages,
-                               &message_count);
-       
-       return bt_py3_get_msg_range_common(status, messages, message_count);
-}
-%}
-
-PyObject *bt_py3_get_user_component_from_user_msg_iter(
-    bt_self_message_iterator *self_message_iterator);
-PyObject *bt_py3_self_component_port_input_get_msg_range(
-               bt_self_component_port_input_message_iterator *iter);
-PyObject *bt_py3_port_output_get_msg_range(
-               bt_port_output_message_iterator *iter);
diff --git a/bindings/python/bt2/bt2/native_bt_packet.i b/bindings/python/bt2/bt2/native_bt_packet.i
deleted file mode 100644 (file)
index b4c9073..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From packet-const.h */
-
-typedef enum bt_packet_status {
-       BT_PACKET_STATUS_OK = 0,
-       BT_PACKET_STATUS_NOMEM = -12,
-} bt_packet_status;
-
-extern const bt_stream *bt_packet_borrow_stream_const(
-               const bt_packet *packet);
-
-extern
-const bt_field *bt_packet_borrow_context_field_const(
-               const bt_packet *packet);
-
-extern void bt_packet_get_ref(const bt_packet *packet);
-
-extern void bt_packet_put_ref(const bt_packet *packet);
-
-/* From packet.h */
-
-extern bt_packet *bt_packet_create(const bt_stream *stream);
-
-extern bt_stream *bt_packet_borrow_stream(bt_packet *packet);
-
-extern
-bt_field *bt_packet_borrow_context_field(bt_packet *packet);
-
-extern
-bt_packet_status bt_packet_move_context_field(bt_packet *packet,
-               bt_packet_context_field *context);
diff --git a/bindings/python/bt2/bt2/native_bt_plugin.i b/bindings/python/bt2/bt2/native_bt_plugin.i
deleted file mode 100644 (file)
index 435d40f..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From plugin-const.h */
-
-extern const bt_plugin *bt_plugin_find(const char *plugin_name);
-
-extern const bt_plugin_set *bt_plugin_find_all_from_file(
-               const char *path);
-
-extern const bt_plugin_set *bt_plugin_find_all_from_dir(
-               const char *path, bt_bool recurse);
-
-extern const bt_plugin_set *bt_plugin_find_all_from_static(void);
-
-extern const char *bt_plugin_get_name(const bt_plugin *plugin);
-
-extern const char *bt_plugin_get_author(const bt_plugin *plugin);
-
-extern const char *bt_plugin_get_license(const bt_plugin *plugin);
-
-extern const char *bt_plugin_get_description(const bt_plugin *plugin);
-
-extern const char *bt_plugin_get_path(const bt_plugin *plugin);
-
-extern bt_property_availability bt_plugin_get_version(
-               const bt_plugin *plugin, unsigned int *OUT,
-               unsigned int *OUT, unsigned int *OUT, const char **OUT);
-
-extern uint64_t bt_plugin_get_source_component_class_count(
-               const bt_plugin *plugin);
-
-extern uint64_t bt_plugin_get_filter_component_class_count(
-               const bt_plugin *plugin);
-
-extern uint64_t bt_plugin_get_sink_component_class_count(
-               const bt_plugin *plugin);
-
-extern const bt_component_class_source *
-bt_plugin_borrow_source_component_class_by_index_const(
-               const bt_plugin *plugin, uint64_t index);
-
-extern const bt_component_class_filter *
-bt_plugin_borrow_filter_component_class_by_index_const(
-               const bt_plugin *plugin, uint64_t index);
-
-extern const bt_component_class_sink *
-bt_plugin_borrow_sink_component_class_by_index_const(
-               const bt_plugin *plugin, uint64_t index);
-
-extern const bt_component_class_source *
-bt_plugin_borrow_source_component_class_by_name_const(
-               const bt_plugin *plugin, const char *name);
-
-extern const bt_component_class_filter *
-bt_plugin_borrow_filter_component_class_by_name_const(
-               const bt_plugin *plugin, const char *name);
-
-extern const bt_component_class_sink *
-bt_plugin_borrow_sink_component_class_by_name_const(
-               const bt_plugin *plugin, const char *name);
-
-extern void bt_plugin_get_ref(const bt_plugin *plugin);
-
-extern void bt_plugin_put_ref(const bt_plugin *plugin);
-
-/* From plugin-set-const.h */
-
-extern uint64_t bt_plugin_set_get_plugin_count(
-               const bt_plugin_set *plugin_set);
-
-extern const bt_plugin *bt_plugin_set_borrow_plugin_by_index_const(
-               const bt_plugin_set *plugin_set, uint64_t index);
-
-extern void bt_plugin_set_get_ref(const bt_plugin_set *plugin_set);
-
-extern void bt_plugin_set_put_ref(const bt_plugin_set *plugin_set);
-
-/* Helpers */
-
-bt_property_availability bt_plugin_get_version_wrapper(
-               const bt_plugin *plugin, unsigned int *OUT,
-               unsigned int *OUT, unsigned int *OUT, const char **OUT);
-
-%{
-
-/*
- * This wrapper ensures that when the API function fails, the `*extra` output
- * parameter is set to NULL.  This is necessary because the epilogue of the
- * "char **OUT" typemap will use that value to make a Python str object.  We
- * can't rely on the initial value of `*extra`, it could point to unreadable
- * memory.
- */
-
-bt_property_availability bt_plugin_get_version_wrapper(
-               const bt_plugin *plugin, unsigned int *major,
-               unsigned int *minor, unsigned int *patch, const char **extra)
-{
-       bt_property_availability ret;
-
-       ret = bt_plugin_get_version(plugin, major, minor, patch, extra);
-
-       if (ret == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
-               *extra = NULL;
-       }
-
-       return ret;
-}
-
-%}
diff --git a/bindings/python/bt2/bt2/native_bt_port.i b/bindings/python/bt2/bt2/native_bt_port.i
deleted file mode 100644 (file)
index 873c613..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/*
- * Typemap for the user data attached to (and owned by) a self component port.
- * The pointer saved as the port's user data is directly the PyObject *.
- *
- * As per the CPython calling convention, we need to return a new reference to
- * the returned object, which will be transferred to the caller.  The following
- * typedef allows us to apply the typemap.
- */
-%{
-typedef void *PY_SELF_PORT_USER_DATA;
-%}
-
-%typemap(out) PY_SELF_PORT_USER_DATA {
-       Py_INCREF($1);
-       $result = $1;
-}
-
-/* From port-const.h */
-
-typedef enum bt_port_type {
-       BT_PORT_TYPE_INPUT = 0,
-       BT_PORT_TYPE_OUTPUT = 1,
-} bt_port_type;
-
-extern const char *bt_port_get_name(const bt_port *port);
-
-extern bt_port_type bt_port_get_type(const bt_port *port);
-
-extern const bt_connection *bt_port_borrow_connection_const(
-               const bt_port *port);
-
-extern const bt_component *bt_port_borrow_component_const(
-               const bt_port *port);
-
-extern bt_bool bt_port_is_connected(const bt_port *port);
-
-bt_bool bt_port_is_input(const bt_port *port);
-
-bt_bool bt_port_is_output(const bt_port *port);
-
-extern void bt_port_get_ref(const bt_port *port);
-
-extern void bt_port_put_ref(const bt_port *port);
-
-/* From port-output-const.h */
-
-const bt_port *bt_port_output_as_port_const(const bt_port_output *port_output);
-
-extern void bt_port_output_get_ref(const bt_port_output *port_output);
-
-extern void bt_port_output_put_ref(const bt_port_output *port_output);
-
-/* From port-input-const.h */
-
-const bt_port *bt_port_input_as_port_const(const bt_port_input *port_input);
-
-extern void bt_port_input_get_ref(const bt_port_input *port_input);
-
-extern void bt_port_input_put_ref(const bt_port_input *port_input);
-
-/* From self-component-port.h */
-
-typedef enum bt_self_component_port_status {
-       BT_SELF_PORT_STATUS_OK = 0,
-} bt_self_component_port_status;
-
-const bt_port *bt_self_component_port_as_port(
-               bt_self_component_port *self_port);
-
-extern bt_self_component *bt_self_component_port_borrow_component(
-               bt_self_component_port *self_port);
-
-extern PY_SELF_PORT_USER_DATA bt_self_component_port_get_data(
-               const bt_self_component_port *self_port);
-
-/* From self-component-port-output.h */
-
-bt_self_component_port *
-bt_self_component_port_output_as_self_component_port(
-               bt_self_component_port_output *self_component_port);
-
-const bt_port_output *bt_self_component_port_output_as_port_output(
-               bt_self_component_port_output *self_component_port);
-
-/* From self-component-port-input.h */
-
-bt_self_component_port *
-bt_self_component_port_input_as_self_component_port(
-               bt_self_component_port_input *self_component_port);
-
-const bt_port_input *bt_self_component_port_input_as_port_input(
-               const bt_self_component_port_input *self_component_port);
diff --git a/bindings/python/bt2/bt2/native_bt_query_exec.i b/bindings/python/bt2/bt2/native_bt_query_exec.i
deleted file mode 100644 (file)
index af78efa..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From query-executor-const.h */
-
-typedef enum bt_query_executor_status {
-       BT_QUERY_EXECUTOR_STATUS_OK = 0,
-       BT_QUERY_EXECUTOR_STATUS_AGAIN = 11,
-       BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED = 95,
-       BT_QUERY_EXECUTOR_STATUS_CANCELED = 125,
-       BT_QUERY_EXECUTOR_STATUS_ERROR = -1,
-       BT_QUERY_EXECUTOR_STATUS_NOMEM = -12,
-       BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT = -23,
-       BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS = -24,
-} bt_query_executor_status;
-
-extern
-bt_bool bt_query_executor_is_canceled(
-               const bt_query_executor *query_executor);
-
-extern void bt_query_executor_get_ref(
-               const bt_query_executor *query_executor);
-
-extern void bt_query_executor_put_ref(
-               const bt_query_executor *query_executor);
-
-/* From query-executor.h */
-
-extern
-bt_query_executor *bt_query_executor_create(void);
-
-extern
-bt_query_executor_status bt_query_executor_query(
-               bt_query_executor *query_executor,
-               const bt_component_class *component_class,
-               const char *object, const bt_value *params,
-               const bt_value **OUT);
-
-extern
-bt_query_executor_status bt_query_executor_cancel(
-               bt_query_executor *query_executor);
diff --git a/bindings/python/bt2/bt2/native_bt_stream.i b/bindings/python/bt2/bt2/native_bt_stream.i
deleted file mode 100644 (file)
index 394d987..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From stream-const.h */
-
-typedef enum bt_stream_status {
-       BT_STREAM_STATUS_OK = 0,
-       BT_STREAM_STATUS_NOMEM = -12,
-} bt_stream_status;
-
-extern const bt_stream_class *bt_stream_borrow_class_const(
-               const bt_stream *stream);
-
-extern const bt_trace *bt_stream_borrow_trace_const(
-               const bt_stream *stream);
-
-extern const char *bt_stream_get_name(const bt_stream *stream);
-
-extern uint64_t bt_stream_get_id(const bt_stream *stream);
-
-extern void bt_stream_get_ref(const bt_stream *stream);
-
-extern void bt_stream_put_ref(const bt_stream *stream);
-
-/* From stream.h */
-
-extern bt_stream *bt_stream_create(bt_stream_class *stream_class,
-               bt_trace *trace);
-
-extern bt_stream *bt_stream_create_with_id(
-               bt_stream_class *stream_class,
-               bt_trace *trace, uint64_t id);
-
-extern bt_trace *bt_stream_borrow_trace(bt_stream *stream);
-
-extern bt_stream_class *bt_stream_borrow_class(bt_stream *stream);
-
-extern bt_stream_status bt_stream_set_name(bt_stream *stream,
-               const char *name);
diff --git a/bindings/python/bt2/bt2/native_bt_stream_class.i b/bindings/python/bt2/bt2/native_bt_stream_class.i
deleted file mode 100644 (file)
index e592704..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From stream-class-const.h */
-
-typedef enum bt_stream_class_status {
-       BT_STREAM_CLASS_STATUS_OK = 0,
-       BT_STREAM_CLASS_STATUS_NOMEM = -12,
-} bt_stream_class_status;
-
-extern const bt_trace_class *bt_stream_class_borrow_trace_class_const(
-               const bt_stream_class *stream_class);
-
-extern const char *bt_stream_class_get_name(
-               const bt_stream_class *stream_class);
-
-extern bt_bool bt_stream_class_assigns_automatic_event_class_id(
-               const bt_stream_class *stream_class);
-
-extern bt_bool bt_stream_class_assigns_automatic_stream_id(
-               const bt_stream_class *stream_class);
-
-extern bt_bool bt_stream_class_packets_have_beginning_default_clock_snapshot(
-               const bt_stream_class *stream_class);
-
-extern bt_bool bt_stream_class_packets_have_end_default_clock_snapshot(
-               const bt_stream_class *stream_class);
-
-extern bt_bool bt_stream_class_supports_discarded_events(
-               const bt_stream_class *stream_class);
-
-extern bt_bool bt_stream_class_supports_discarded_packets(
-               const bt_stream_class *stream_class);
-
-extern bt_bool bt_stream_class_discarded_events_have_default_clock_snapshots(
-               const bt_stream_class *stream_class);
-
-extern bt_bool bt_stream_class_discarded_packets_have_default_clock_snapshots(
-               const bt_stream_class *stream_class);
-
-extern uint64_t bt_stream_class_get_id(
-               const bt_stream_class *stream_class);
-
-extern const bt_field_class *
-bt_stream_class_borrow_packet_context_field_class_const(
-               const bt_stream_class *stream_class);
-
-extern const bt_field_class *
-bt_stream_class_borrow_event_common_context_field_class_const(
-               const bt_stream_class *stream_class);
-
-extern uint64_t bt_stream_class_get_event_class_count(
-               const bt_stream_class *stream_class);
-
-extern const bt_event_class *
-bt_stream_class_borrow_event_class_by_index_const(
-               const bt_stream_class *stream_class, uint64_t index);
-
-extern const bt_event_class *
-bt_stream_class_borrow_event_class_by_id_const(
-               const bt_stream_class *stream_class, uint64_t id);
-
-extern const bt_clock_class *
-bt_stream_class_borrow_default_clock_class_const(
-               const bt_stream_class *stream_class);
-
-extern void bt_stream_class_get_ref(const bt_stream_class *stream_class);
-
-extern void bt_stream_class_put_ref(const bt_stream_class *stream_class);
-
-/* From stream-class-const.h */
-
-extern bt_stream_class *bt_stream_class_create(
-               bt_trace_class *trace_class);
-
-extern bt_stream_class *bt_stream_class_create_with_id(
-               bt_trace_class *trace_class, uint64_t id);
-
-extern bt_trace_class *bt_stream_class_borrow_trace_class(
-               bt_stream_class *stream_class);
-
-extern bt_stream_class_status bt_stream_class_set_name(
-               bt_stream_class *stream_class, const char *name);
-
-extern void bt_stream_class_set_assigns_automatic_event_class_id(
-               bt_stream_class *stream_class, bt_bool value);
-
-extern void bt_stream_class_set_assigns_automatic_stream_id(
-               bt_stream_class *stream_class, bt_bool value);
-
-extern void bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
-               bt_stream_class *stream_class, bt_bool value);
-
-extern void bt_stream_class_set_packets_have_end_default_clock_snapshot(
-               bt_stream_class *stream_class, bt_bool value);
-
-extern void bt_stream_class_set_supports_discarded_events(
-               bt_stream_class *stream_class,
-               bt_bool supports_discarded_events,
-               bt_bool with_default_clock_snapshots);
-
-extern void bt_stream_class_set_supports_discarded_packets(
-               bt_stream_class *stream_class,
-               bt_bool supports_discarded_packets,
-               bt_bool with_default_clock_snapshots);
-
-extern bt_stream_class_status
-bt_stream_class_set_packet_context_field_class(
-               bt_stream_class *stream_class,
-               bt_field_class *field_class);
-
-extern bt_field_class *
-bt_stream_class_borrow_packet_context_field_class(
-               bt_stream_class *stream_class);
-
-extern bt_stream_class_status
-bt_stream_class_set_event_common_context_field_class(
-               bt_stream_class *stream_class,
-               bt_field_class *field_class);
-
-extern bt_field_class *
-bt_stream_class_borrow_event_common_context_field_class(
-               bt_stream_class *stream_class);
-
-extern bt_event_class *
-bt_stream_class_borrow_event_class_by_index(
-               bt_stream_class *stream_class, uint64_t index);
-
-extern bt_event_class *
-bt_stream_class_borrow_event_class_by_id(
-               bt_stream_class *stream_class, uint64_t id);
-
-extern bt_clock_class *bt_stream_class_borrow_default_clock_class(
-               bt_stream_class *stream_class);
-
-extern bt_stream_class_status bt_stream_class_set_default_clock_class(
-               bt_stream_class *stream_class,
-               bt_clock_class *clock_class);
diff --git a/bindings/python/bt2/bt2/native_bt_trace.i b/bindings/python/bt2/bt2/native_bt_trace.i
deleted file mode 100644 (file)
index 2d8f538..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From trace-const.h */
-
-typedef enum bt_trace_status {
-       BT_TRACE_STATUS_OK = 0,
-       BT_TRACE_STATUS_NOMEM = -12,
-} bt_trace_status;
-
-typedef void (* bt_trace_destruction_listener_func)(
-               const bt_trace *trace, void *data);
-
-extern const bt_trace_class *bt_trace_borrow_class_const(
-               const bt_trace *trace);
-
-extern const char *bt_trace_get_name(const bt_trace *trace);
-
-extern uint64_t bt_trace_get_stream_count(const bt_trace *trace);
-
-extern const bt_stream *bt_trace_borrow_stream_by_index_const(
-               const bt_trace *trace, uint64_t index);
-
-extern const bt_stream *bt_trace_borrow_stream_by_id_const(
-               const bt_trace *trace, uint64_t id);
-
-extern bt_trace_status bt_trace_add_destruction_listener(
-               const bt_trace *trace,
-               bt_trace_destruction_listener_func listener,
-               void *data, uint64_t *listener_id);
-
-extern bt_trace_status bt_trace_remove_destruction_listener(
-               const bt_trace *trace, uint64_t listener_id);
-
-extern void bt_trace_get_ref(const bt_trace *trace);
-
-extern void bt_trace_put_ref(const bt_trace *trace);
-
-/* From trace.h */
-
-extern bt_trace_class *bt_trace_borrow_class(bt_trace *trace);
-
-extern bt_trace *bt_trace_create(bt_trace_class *trace_class);
-
-extern bt_trace_status bt_trace_set_name(bt_trace *trace,
-               const char *name);
-
-extern bt_stream *bt_trace_borrow_stream_by_index(bt_trace *trace,
-               uint64_t index);
-
-extern bt_stream *bt_trace_borrow_stream_by_id(bt_trace *trace,
-               uint64_t id);
-
-%{
-static void
-trace_destroyed_listener(const bt_trace *trace, void *py_callable)
-{
-       PyObject *py_trace_ptr = NULL;
-       PyObject *py_res = NULL;
-
-       py_trace_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace),
-               SWIGTYPE_p_bt_trace, 0);
-       if (!py_trace_ptr) {
-               BT_LOGF_STR("Failed to create a SWIG pointer object.");
-               abort();
-       }
-
-       py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_ptr);
-       if (py_res != NULL) {
-               BT_ASSERT(py_res == Py_None);
-       } else {
-               bt2_py_loge_exception();
-       }
-
-       Py_DECREF(py_trace_ptr);
-       Py_XDECREF(py_res);
-}
-
-uint64_t bt_py3_trace_add_destruction_listener(bt_trace *trace, PyObject *py_callable)
-{
-       uint64_t id = UINT64_C(-1);
-       bt_trace_status status;
-
-       BT_ASSERT(trace);
-       BT_ASSERT(py_callable);
-
-       status = bt_trace_add_destruction_listener(
-               trace, trace_destroyed_listener, py_callable, &id);
-       if (status != BT_TRACE_STATUS_OK) {
-               BT_LOGF_STR("Failed to add trace destruction listener.");
-               abort();
-       }
-
-       Py_INCREF(py_callable);
-
-       return id;
-}
-%}
-
-uint64_t bt_py3_trace_add_destruction_listener(bt_trace *trace,
-       PyObject *py_callable);
diff --git a/bindings/python/bt2/bt2/native_bt_trace_class.i b/bindings/python/bt2/bt2/native_bt_trace_class.i
deleted file mode 100644 (file)
index 71061ff..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From trace-class-const.h */
-
-typedef enum bt_trace_class_status {
-       BT_TRACE_CLASS_STATUS_OK = 0,
-       BT_TRACE_CLASS_STATUS_NOMEM = -12,
-} bt_trace_class_status;
-
-typedef void (* bt_trace_class_destruction_listener_func)(
-               const bt_trace_class *trace_class, void *data);
-
-extern bt_bool bt_trace_class_assigns_automatic_stream_class_id(
-               const bt_trace_class *trace_class);
-
-extern const char *bt_trace_class_get_name(
-               const bt_trace_class *trace_class);
-
-extern bt_uuid bt_trace_class_get_uuid(
-               const bt_trace_class *trace_class);
-
-extern uint64_t bt_trace_class_get_environment_entry_count(
-               const bt_trace_class *trace_class);
-
-extern void bt_trace_class_borrow_environment_entry_by_index_const(
-               const bt_trace_class *trace_class, uint64_t index,
-               const char **OUT, const bt_value **OUT);
-
-extern const bt_value *
-bt_trace_class_borrow_environment_entry_value_by_name_const(
-               const bt_trace_class *trace_class, const char *name);
-
-extern uint64_t bt_trace_class_get_stream_class_count(
-               const bt_trace_class *trace_class);
-
-extern const bt_stream_class *
-bt_trace_class_borrow_stream_class_by_index_const(
-               const bt_trace_class *trace_class, uint64_t index);
-
-extern const bt_stream_class *bt_trace_class_borrow_stream_class_by_id_const(
-               const bt_trace_class *trace_class, uint64_t id);
-
-extern bt_trace_class_status bt_trace_class_add_destruction_listener(
-        const bt_trace_class *trace_class,
-        bt_trace_class_destruction_listener_func listener,
-        void *data, uint64_t *listener_id);
-
-extern bt_trace_class_status bt_trace_class_remove_destruction_listener(
-        const bt_trace_class *trace_class, uint64_t listener_id);
-
-extern void bt_trace_class_get_ref(const bt_trace_class *trace_class);
-
-extern void bt_trace_class_put_ref(const bt_trace_class *trace_class);
-
-/* From trace-class.h */
-
-extern bt_trace_class *bt_trace_class_create(bt_self_component *self_comp);
-
-extern void bt_trace_class_set_assigns_automatic_stream_class_id(
-               bt_trace_class *trace_class, bt_bool value);
-
-extern bt_trace_class_status bt_trace_class_set_name(
-               bt_trace_class *trace_class, const char *name);
-
-extern void bt_trace_class_set_uuid(bt_trace_class *trace_class,
-               bt_uuid uuid);
-
-extern bt_trace_class_status bt_trace_class_set_environment_entry_integer(
-               bt_trace_class *trace_class,
-               const char *name, int64_t value);
-
-extern bt_trace_class_status bt_trace_class_set_environment_entry_string(
-               bt_trace_class *trace_class,
-               const char *name, const char *value);
-
-extern bt_stream_class *bt_trace_class_borrow_stream_class_by_index(
-               bt_trace_class *trace_class, uint64_t index);
-
-extern bt_stream_class *bt_trace_class_borrow_stream_class_by_id(
-               bt_trace_class *trace_class, uint64_t id);
-
-/* Helper functions for Python */
-%{
-static void
-trace_class_destroyed_listener(const bt_trace_class *trace_class, void *py_callable)
-{
-       PyObject *py_trace_class_ptr = NULL;
-       PyObject *py_res = NULL;
-
-       py_trace_class_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace_class),
-               SWIGTYPE_p_bt_trace_class, 0);
-       if (!py_trace_class_ptr) {
-               BT_LOGF_STR("Failed to create a SWIG pointer object.");
-               abort();
-       }
-
-       py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_class_ptr);
-       if (py_res != NULL) {
-               BT_ASSERT(py_res == Py_None);
-       } else {
-               bt2_py_loge_exception();
-       }
-
-       Py_DECREF(py_trace_class_ptr);
-       Py_XDECREF(py_res);
-}
-
-uint64_t bt_py3_trace_class_add_destruction_listener(bt_trace_class *trace_class,
-       PyObject *py_callable)
-{
-       uint64_t id = UINT64_C(-1);
-       bt_trace_class_status status;
-
-       BT_ASSERT(trace_class);
-       BT_ASSERT(py_callable);
-
-       status = bt_trace_class_add_destruction_listener(
-               trace_class, trace_class_destroyed_listener, py_callable, &id);
-       if (status != BT_TRACE_CLASS_STATUS_OK) {
-               BT_LOGF_STR("Failed to add trace class destruction listener.");
-               abort();
-       }
-
-       Py_INCREF(py_callable);
-
-       return id;
-}
-%}
-
-uint64_t bt_py3_trace_class_add_destruction_listener(bt_trace_class *trace_class,
-       PyObject *py_callable);
diff --git a/bindings/python/bt2/bt2/native_bt_value.i b/bindings/python/bt2/bt2/native_bt_value.i
deleted file mode 100644 (file)
index 1ecd21e..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* From value-const.h */
-
-typedef enum bt_value_status {
-       /// Operation canceled.
-       BT_VALUE_STATUS_CANCELED        = 125,
-
-       /// Cannot allocate memory.
-       BT_VALUE_STATUS_NOMEM           = -12,
-
-       /// Okay, no error.
-       BT_VALUE_STATUS_OK              = 0,
-} bt_value_status;
-
-typedef enum bt_value_type {
-       /// Null value object.
-       BT_VALUE_TYPE_NULL              = 0,
-
-       /// Boolean value object (holds #BT_TRUE or #BT_FALSE).
-       BT_VALUE_TYPE_BOOL              = 1,
-
-       /// Unsigned integer value object (holds an unsigned 64-bit integer raw value).
-       BT_VALUE_TYPE_UNSIGNED_INTEGER  = 2,
-
-       /// Signed integer value object (holds a signed 64-bit integer raw value).
-       BT_VALUE_TYPE_SIGNED_INTEGER    = 3,
-
-       /// Floating point number value object (holds a \c double raw value).
-       BT_VALUE_TYPE_REAL              = 4,
-
-       /// String value object.
-       BT_VALUE_TYPE_STRING            = 5,
-
-       /// Array value object.
-       BT_VALUE_TYPE_ARRAY             = 6,
-
-       /// Map value object.
-       BT_VALUE_TYPE_MAP               = 7,
-} bt_value_type;
-
-extern bt_value_type bt_value_get_type(const bt_value *object);
-
-extern bt_value_status bt_value_copy(const bt_value *object,
-               bt_value **copy);
-
-extern bt_bool bt_value_compare(const bt_value *object_a,
-               const bt_value *object_b);
-
-extern bt_bool bt_value_bool_get(const bt_value *bool_obj);
-
-extern uint64_t bt_value_unsigned_integer_get(const bt_value *integer_obj);
-
-extern int64_t bt_value_signed_integer_get(const bt_value *integer_obj);
-
-extern double bt_value_real_get(const bt_value *real_obj);
-
-extern const char *bt_value_string_get(const bt_value *string_obj);
-
-extern uint64_t bt_value_array_get_size(const bt_value *array_obj);
-
-extern const bt_value *bt_value_array_borrow_element_by_index_const(
-               const bt_value *array_obj, uint64_t index);
-
-extern uint64_t bt_value_map_get_size(const bt_value *map_obj);
-
-extern const bt_value *bt_value_map_borrow_entry_value_const(
-               const bt_value *map_obj, const char *key);
-
-typedef bt_bool (* bt_value_map_foreach_entry_const_func)(const char *key,
-               const bt_value *object, void *data);
-
-extern bt_value_status bt_value_map_foreach_entry_const(
-               const bt_value *map_obj,
-               bt_value_map_foreach_entry_const_func func, void *data);
-
-extern bt_bool bt_value_map_has_entry(const bt_value *map_obj,
-               const char *key);
-
-extern bt_value_status bt_value_map_extend(
-               const bt_value *base_map_obj,
-               const bt_value *extension_map_obj,
-               bt_value **extended_map_obj);
-
-extern void bt_value_get_ref(const bt_value *value);
-
-extern void bt_value_put_ref(const bt_value *value);
-
-/* From value.h */
-
-extern bt_value *const bt_value_null;
-
-extern bt_value *bt_value_bool_create(void);
-
-extern bt_value *bt_value_bool_create_init(bt_bool val);
-
-extern void bt_value_bool_set(bt_value *bool_obj, bt_bool val);
-
-extern bt_value *bt_value_unsigned_integer_create(void);
-
-extern bt_value *bt_value_unsigned_integer_create_init(uint64_t val);
-
-extern void bt_value_unsigned_integer_set(bt_value *integer_obj, uint64_t val);
-
-extern bt_value *bt_value_signed_integer_create(void);
-
-extern bt_value *bt_value_signed_integer_create_init(int64_t val);
-
-extern void bt_value_signed_integer_set(bt_value *integer_obj, int64_t val);
-
-extern bt_value *bt_value_real_create(void);
-
-extern bt_value *bt_value_real_create_init(double val);
-
-extern void bt_value_real_set(bt_value *real_obj, double val);
-
-extern bt_value *bt_value_string_create(void);
-
-extern bt_value *bt_value_string_create_init(const char *val);
-
-extern bt_value_status bt_value_string_set(bt_value *string_obj,
-               const char *val);
-
-extern bt_value *bt_value_array_create(void);
-
-extern bt_value *bt_value_array_borrow_element_by_index(
-               bt_value *array_obj, uint64_t index);
-
-extern bt_value_status bt_value_array_append_element(
-               bt_value *array_obj,
-               bt_value *element_obj);
-
-extern bt_value_status bt_value_array_append_bool_element(
-               bt_value *array_obj, bt_bool val);
-
-extern bt_value_status bt_value_array_append_unsigned_integer_element(
-               bt_value *array_obj, uint64_t val);
-
-extern bt_value_status bt_value_array_append_signed_integer_element(
-               bt_value *array_obj, int64_t val);
-
-extern bt_value_status bt_value_array_append_real_element(
-               bt_value *array_obj, double val);
-
-extern bt_value_status bt_value_array_append_string_element(
-               bt_value *array_obj, const char *val);
-
-extern bt_value_status bt_value_array_append_empty_array_element(
-               bt_value *array_obj);
-
-extern bt_value_status bt_value_array_append_empty_map_element(
-               bt_value *array_obj);
-
-extern bt_value_status bt_value_array_set_element_by_index(
-               bt_value *array_obj, uint64_t index,
-               bt_value *element_obj);
-
-extern bt_value *bt_value_map_create(void);
-
-extern bt_value *bt_value_map_borrow_entry_value(
-               bt_value *map_obj, const char *key);
-
-typedef bt_bool (* bt_value_map_foreach_entry_func)(const char *key,
-               bt_value *object, void *data);
-
-extern bt_value_status bt_value_map_foreach_entry(
-               bt_value *map_obj,
-               bt_value_map_foreach_entry_func func, void *data);
-
-extern bt_value_status bt_value_map_insert_entry(
-               bt_value *map_obj, const char *key,
-               bt_value *element_obj);
-
-extern bt_value_status bt_value_map_insert_bool_entry(
-               bt_value *map_obj, const char *key, bt_bool val);
-
-extern bt_value_status bt_value_map_insert_unsigned_integer_entry(
-               bt_value *map_obj, const char *key, uint64_t val);
-
-extern bt_value_status bt_value_map_insert_signed_integer_entry(
-               bt_value *map_obj, const char *key, int64_t val);
-
-extern bt_value_status bt_value_map_insert_real_entry(
-               bt_value *map_obj, const char *key, double val);
-
-extern bt_value_status bt_value_map_insert_string_entry(
-               bt_value *map_obj, const char *key,
-               const char *val);
-
-extern bt_value_status bt_value_map_insert_empty_array_entry(
-               bt_value *map_obj, const char *key);
-
-extern bt_value_status bt_value_map_insert_empty_map_entry(
-               bt_value *map_obj, const char *key);
-
-%{
-struct bt_value_map_get_keys_data {
-       struct bt_value *keys;
-};
-
-static int bt_value_map_get_keys_cb(const char *key, const struct bt_value *object, void *data)
-{
-       enum bt_value_status status;
-       struct bt_value_map_get_keys_data *priv_data = data;
-
-       status = bt_value_array_append_string_element(priv_data->keys, key);
-       if (status != BT_VALUE_STATUS_OK) {
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj)
-{
-       enum bt_value_status status;
-       struct bt_value_map_get_keys_data data;
-
-       data.keys = bt_value_array_create();
-       if (!data.keys) {
-               return NULL;
-       }
-
-       status = bt_value_map_foreach_entry_const(map_obj, bt_value_map_get_keys_cb,
-               &data);
-       if (status != BT_VALUE_STATUS_OK) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       if (data.keys) {
-               BT_VALUE_PUT_REF_AND_RESET(data.keys);
-       }
-
-end:
-       return data.keys;
-}
-%}
-
-struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj);
diff --git a/bindings/python/bt2/bt2/native_bt_version.i b/bindings/python/bt2/bt2/native_bt_version.i
deleted file mode 100644 (file)
index 3d99e7d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* Version functions */
-int bt_version_get_major(void);
-int bt_version_get_minor(void);
-int bt_version_get_patch(void);
-const char *bt_version_get_extra(void);
diff --git a/bindings/python/bt2/bt2/object.py b/bindings/python/bt2/bt2/object.py
deleted file mode 100644 (file)
index 218965d..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-
-class _BaseObject:
-    # Ensure that the object always has _ptr set, even if it throws during
-    # construction.
-
-    def __new__(cls, *args, **kwargs):
-        obj = super().__new__(cls)
-        obj._ptr = None
-        return obj
-
-    def __init__(self, ptr):
-        self._ptr = ptr
-
-    @property
-    def addr(self):
-        return int(self._ptr)
-
-    def __repr__(self):
-        return '<{}.{} object @ {}>'.format(self.__class__.__module__,
-                                            self.__class__.__name__,
-                                            hex(self.addr))
-
-    def __copy__(self):
-        raise NotImplementedError
-
-    def __deepcopy__(self, memo):
-        raise NotImplementedError
-
-
-# A Python object that is itself not refcounted, but is wholly owned by an
-# object that is itself refcounted (a _SharedObject).  A Babeltrace unique
-# object gets destroyed once its owner gets destroyed (its refcount drops to
-# 0).
-#
-# In the Python bindings, to avoid having to deal with issues with the lifetime
-# of unique objects, we make it so acquiring a reference on a unique object
-# acquires a reference on its owner.
-
-class _UniqueObject(_BaseObject):
-
-    # Create a _UniqueObject.
-    #
-    #   - ptr: SWIG Object, pointer to the unique object.
-    #   - owner_ptr: SWIG Object, pointer to the owner of the unique
-    #     object.  A new reference is acquired.
-    #   - owner_get_ref: Callback to get a reference on the owner
-    #   - owner_put_ref: Callback to put a reference on the owner.
-
-    @classmethod
-    def _create_from_ptr_and_get_ref(cls, ptr, owner_ptr,
-                                     owner_get_ref, owner_put_ref):
-        obj = cls.__new__(cls)
-
-        obj._ptr = ptr
-        obj._owner_ptr = owner_ptr
-        obj._owner_get_ref = owner_get_ref
-        obj._owner_put_ref = owner_put_ref
-
-        obj._owner_get_ref(obj._owner_ptr)
-
-        return obj
-
-    def __del__(self):
-        self._owner_put_ref(self._owner_ptr)
-
-
-# Python object that owns a reference to a Babeltrace object.
-class _SharedObject(_BaseObject):
-
-    # Get a new reference on ptr.
-    #
-    # This must be implemented by subclasses to work correctly with a pointer
-    # of the native type they wrap.
-
-    @staticmethod
-    def _get_ref(ptr):
-        raise NotImplementedError
-
-    # Put a reference on ptr.
-    #
-    # This must be implemented by subclasses to work correctly with a pointer
-    # of the native type they wrap.
-
-    @staticmethod
-    def _put_ref(ptr):
-        raise NotImplementedError
-
-    # Create a _SharedObject from an existing reference.
-    #
-    # This assumes that the caller owns a reference to the Babeltrace object
-    # and transfers this ownership to the newly created Python object.
-
-    @classmethod
-    def _create_from_ptr(cls, ptr_owned):
-        obj = cls.__new__(cls)
-        obj._ptr = ptr_owned
-        return obj
-
-    # Like _create_from_ptr, but acquire a new reference rather than
-    # stealing the caller's reference.
-
-    @classmethod
-    def _create_from_ptr_and_get_ref(cls, ptr):
-        obj = cls._create_from_ptr(ptr)
-        cls._get_ref(obj._ptr)
-        return obj
-
-    def _release(self):
-        """Return the wrapped pointer, transfer its ownership to the
-        caller."""
-        ptr = self._ptr
-        self._ptr = None
-        return ptr
-
-    def __del__(self):
-        self._put_ref(self._ptr)
diff --git a/bindings/python/bt2/bt2/packet.py b/bindings/python/bt2/bt2/packet.py
deleted file mode 100644 (file)
index 93e9ac8..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object
-import bt2.field
-import bt2
-
-
-class _Packet(object._SharedObject):
-    _get_ref = staticmethod(native_bt.packet_get_ref)
-    _put_ref = staticmethod(native_bt.packet_put_ref)
-
-    @property
-    def stream(self):
-        stream_ptr = native_bt.packet_borrow_stream(self._ptr)
-        assert stream_ptr is not None
-        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
-
-    @property
-    def context_field(self):
-        field_ptr = native_bt.packet_borrow_context_field(self._ptr)
-
-        if field_ptr is None:
-            return
-
-        return bt2.field._create_field_from_ptr(field_ptr, self._ptr,
-                                                self._get_ref,
-                                                self._put_ref)
diff --git a/bindings/python/bt2/bt2/plugin.py b/bindings/python/bt2/bt2/plugin.py
deleted file mode 100644 (file)
index 2d0d8b0..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import collections.abc
-import bt2.component
-import os.path
-import bt2
-
-
-def find_plugins(path, recurse=True):
-    utils._check_str(path)
-    utils._check_bool(recurse)
-    plugin_set_ptr = None
-
-    if os.path.isfile(path):
-        plugin_set_ptr = native_bt.plugin_find_all_from_file(path)
-    elif os.path.isdir(path):
-        plugin_set_ptr = native_bt.plugin_find_all_from_dir(path, int(recurse))
-
-    if plugin_set_ptr is None:
-        return
-
-    return _PluginSet._create_from_ptr(plugin_set_ptr)
-
-
-def find_plugin(name):
-    utils._check_str(name)
-    ptr = native_bt.plugin_find(name)
-
-    if ptr is None:
-        return
-
-    return _Plugin._create_from_ptr(ptr)
-
-
-class _PluginSet(object._SharedObject, collections.abc.Sequence):
-    _put_ref = staticmethod(native_bt.plugin_set_put_ref)
-    _get_ref = staticmethod(native_bt.plugin_set_get_ref)
-
-    def __len__(self):
-        count = native_bt.plugin_set_get_plugin_count(self._ptr)
-        assert(count >= 0)
-        return count
-
-    def __getitem__(self, index):
-        utils._check_uint64(index)
-
-        if index >= len(self):
-            raise IndexError
-
-        plugin_ptr = native_bt.plugin_set_borrow_plugin_by_index_const(self._ptr, index)
-        assert plugin_ptr is not None
-        return _Plugin._create_from_ptr_and_get_ref(plugin_ptr)
-
-
-class _PluginVersion:
-    def __init__(self, major, minor, patch, extra):
-        self._major = major
-        self._minor = minor
-        self._patch = patch
-        self._extra = extra
-
-    @property
-    def major(self):
-        return self._major
-
-    @property
-    def minor(self):
-        return self._minor
-
-    @property
-    def patch(self):
-        return self._patch
-
-    @property
-    def extra(self):
-        return self._extra
-
-    def __str__(self):
-        extra = ''
-
-        if self._extra is not None:
-            extra = self._extra
-
-        return '{}.{}.{}{}'.format(self._major, self._minor, self._patch, extra)
-
-
-class _PluginComponentClassesIterator(collections.abc.Iterator):
-    def __init__(self, plugin_comp_cls):
-        self._plugin_comp_cls = plugin_comp_cls
-        self._at = 0
-
-    def __next__(self):
-        plugin_ptr = self._plugin_comp_cls._plugin._ptr
-        total = self._plugin_comp_cls._component_class_count(plugin_ptr)
-
-        if self._at == total:
-            raise StopIteration
-
-        comp_cls_ptr = self._plugin_comp_cls._borrow_component_class_by_index(plugin_ptr, self._at)
-        assert comp_cls_ptr is not None
-        self._at += 1
-
-        comp_cls_type = self._plugin_comp_cls._comp_cls_type
-        comp_cls_pycls = bt2.component._COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS[comp_cls_type]
-        comp_cls_ptr = comp_cls_pycls._as_component_class_ptr(comp_cls_ptr)
-        name = native_bt.component_class_get_name(comp_cls_ptr)
-        assert name is not None
-        return name
-
-
-class _PluginComponentClasses(collections.abc.Mapping):
-    def __init__(self, plugin):
-        self._plugin = plugin
-
-    def __getitem__(self, key):
-        utils._check_str(key)
-        cc_ptr = self._borrow_component_class_by_name(self._plugin._ptr, key)
-
-        if cc_ptr is None:
-            raise KeyError(key)
-
-        return bt2.component._create_component_class_from_ptr_and_get_ref(cc_ptr, self._comp_cls_type)
-
-    def __len__(self):
-        return self._component_class_count(self._plugin._ptr)
-
-    def __iter__(self):
-        return _PluginComponentClassesIterator(self)
-
-
-class _PluginSourceComponentClasses(_PluginComponentClasses):
-    _component_class_count = staticmethod(native_bt.plugin_get_source_component_class_count)
-    _borrow_component_class_by_name = staticmethod(native_bt.plugin_borrow_source_component_class_by_name_const)
-    _borrow_component_class_by_index = staticmethod(native_bt.plugin_borrow_source_component_class_by_index_const)
-    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE
-
-
-class _PluginFilterComponentClasses(_PluginComponentClasses):
-    _component_class_count = staticmethod(native_bt.plugin_get_filter_component_class_count)
-    _borrow_component_class_by_name = staticmethod(native_bt.plugin_borrow_filter_component_class_by_name_const)
-    _borrow_component_class_by_index = staticmethod(native_bt.plugin_borrow_filter_component_class_by_index_const)
-    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_FILTER
-
-
-class _PluginSinkComponentClasses(_PluginComponentClasses):
-    _component_class_count = staticmethod(native_bt.plugin_get_sink_component_class_count)
-    _borrow_component_class_by_name = staticmethod(native_bt.plugin_borrow_sink_component_class_by_name_const)
-    _borrow_component_class_by_index = staticmethod(native_bt.plugin_borrow_sink_component_class_by_index_const)
-    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_SINK
-
-
-class _Plugin(object._SharedObject):
-    _put_ref = staticmethod(native_bt.plugin_put_ref)
-    _get_ref = staticmethod(native_bt.plugin_get_ref)
-
-    @property
-    def name(self):
-        name = native_bt.plugin_get_name(self._ptr)
-        assert(name is not None)
-        return name
-
-    @property
-    def author(self):
-        return native_bt.plugin_get_author(self._ptr)
-
-    @property
-    def license(self):
-        return native_bt.plugin_get_license(self._ptr)
-
-    @property
-    def description(self):
-        return native_bt.plugin_get_description(self._ptr)
-
-    @property
-    def path(self):
-        return native_bt.plugin_get_path(self._ptr)
-
-    @property
-    def version(self):
-        status, major, minor, patch, extra = native_bt.plugin_get_version_wrapper(self._ptr)
-
-        if status == native_bt.PROPERTY_AVAILABILITY_NOT_AVAILABLE:
-            return
-
-        return _PluginVersion(major, minor, patch, extra)
-
-    @property
-    def source_component_classes(self):
-        return _PluginSourceComponentClasses(self)
-
-    @property
-    def filter_component_classes(self):
-        return _PluginFilterComponentClasses(self)
-
-    @property
-    def sink_component_classes(self):
-        return _PluginSinkComponentClasses(self)
diff --git a/bindings/python/bt2/bt2/port.py b/bindings/python/bt2/bt2/port.py
deleted file mode 100644 (file)
index f7c2366..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object
-import bt2.component
-import bt2.connection
-import bt2.message_iterator
-import bt2.message
-import bt2
-
-
-def _create_from_ptr_and_get_ref(ptr, port_type):
-    cls = _PORT_TYPE_TO_PYCLS.get(port_type, None)
-
-    if cls is None:
-        raise bt2.Error('unknown port type: {}'.format(port_type))
-
-    return cls._create_from_ptr_and_get_ref(ptr)
-
-
-def _create_self_from_ptr_and_get_ref(ptr, port_type):
-    cls = _PORT_TYPE_TO_USER_PYCLS.get(port_type, None)
-
-    if cls is None:
-        raise bt2.Error('unknown port type: {}'.format(port_type))
-
-    return cls._create_from_ptr_and_get_ref(ptr)
-
-
-class _Port(object._SharedObject):
-    @classmethod
-    def _get_ref(cls, ptr):
-        ptr = cls._as_port_ptr(ptr)
-        return native_bt.port_get_ref(ptr)
-
-    @classmethod
-    def _put_ref(cls, ptr):
-        ptr = cls._as_port_ptr(ptr)
-        return native_bt.port_put_ref(ptr)
-
-    @property
-    def name(self):
-        ptr = self._as_port_ptr(self._ptr)
-        name = native_bt.port_get_name(ptr)
-        assert name is not None
-        return name
-
-    @property
-    def connection(self):
-        ptr = self._as_port_ptr(self._ptr)
-        conn_ptr = native_bt.port_borrow_connection_const(ptr)
-
-        if conn_ptr is None:
-            return
-
-        return bt2.connection._Connection._create_from_ptr_and_get_ref(conn_ptr)
-
-    @property
-    def is_connected(self):
-        return self.connection is not None
-
-
-class _InputPort(_Port):
-    _as_port_ptr = staticmethod(native_bt.port_input_as_port_const)
-
-
-class _OutputPort(_Port):
-    _as_port_ptr = staticmethod(native_bt.port_output_as_port_const)
-
-
-class _UserComponentPort(_Port):
-    @classmethod
-    def _as_port_ptr(cls, ptr):
-        ptr = cls._as_self_port_ptr(ptr)
-        return native_bt.self_component_port_as_port(ptr)
-
-    @property
-    def connection(self):
-        ptr = self._as_port_ptr(self._ptr)
-        conn_ptr = native_bt.port_borrow_connection_const(ptr)
-
-        if conn_ptr is None:
-            return
-
-        return bt2.connection._Connection._create_from_ptr_and_get_ref(conn_ptr)
-
-    @property
-    def user_data(self):
-        ptr = self._as_self_port_ptr(self._ptr)
-        return native_bt.self_component_port_get_data(ptr)
-
-
-class _UserComponentInputPort(_UserComponentPort, _InputPort):
-    _as_self_port_ptr = staticmethod(native_bt.self_component_port_input_as_self_component_port)
-
-    def create_message_iterator(self):
-        msg_iter_ptr = native_bt.self_component_port_input_message_iterator_create(self._ptr)
-        if msg_iter_ptr is None:
-            raise bt2.CreationError('cannot create message iterator object')
-
-        return bt2.message_iterator._UserComponentInputPortMessageIterator(msg_iter_ptr)
-
-
-class _UserComponentOutputPort(_UserComponentPort, _OutputPort):
-    _as_self_port_ptr = staticmethod(native_bt.self_component_port_output_as_self_component_port)
-
-
-_PORT_TYPE_TO_PYCLS = {
-    native_bt.PORT_TYPE_INPUT: _InputPort,
-    native_bt.PORT_TYPE_OUTPUT: _OutputPort,
-}
-
-
-_PORT_TYPE_TO_USER_PYCLS = {
-    native_bt.PORT_TYPE_INPUT: _UserComponentInputPort,
-    native_bt.PORT_TYPE_OUTPUT: _UserComponentOutputPort,
-}
diff --git a/bindings/python/bt2/bt2/py_plugin.py b/bindings/python/bt2/bt2/py_plugin.py
deleted file mode 100644 (file)
index b845030..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import utils
-import bt2.component
-
-
-def plugin_component_class(component_class):
-    if not issubclass(component_class, bt2.component._UserComponent):
-        raise TypeError('component class is not a subclass of a user component class')
-
-    component_class._bt_plugin_component_class = None
-    return component_class
-
-
-def register_plugin(module_name, name, description=None, author=None,
-                    license=None, version=None):
-    import sys
-
-    if module_name not in sys.modules:
-        raise RuntimeError("cannot find module '{}' in loaded modules".format(module_name))
-
-    utils._check_str(name)
-
-    if description is not None:
-        utils._check_str(description)
-
-    if author is not None:
-        utils._check_str(author)
-
-    if license is not None:
-        utils._check_str(license)
-
-    if version is not None:
-        if not _validate_version(version):
-            raise ValueError('wrong version: expecting a tuple: (major, minor, patch) or (major, minor, patch, extra)')
-
-    sys.modules[module_name]._bt_plugin_info = _PluginInfo(name, description,
-                                                           author, license,
-                                                           version)
-
-
-def _validate_version(version):
-    if version is None:
-        return True
-
-    if not isinstance(version, tuple):
-        return False
-
-    if len(version) < 3 or len(version) > 4:
-        return False
-
-    if not isinstance(version[0], int):
-        return False
-
-    if not isinstance(version[1], int):
-        return False
-
-    if not isinstance(version[2], int):
-        return False
-
-    if len(version) == 4:
-        if not isinstance(version[3], str):
-            return False
-
-    return True
-
-
-class _PluginInfo:
-    def __init__(self, name, description, author, license, version):
-        self.name = name
-        self.description = description
-        self.author = author
-        self.license = license
-        self.version = version
-        self.comp_class_addrs = None
-
-
-# called by the BT plugin system
-def _try_load_plugin_module(path):
-    import importlib.machinery
-    import inspect
-    import hashlib
-
-    if path is None:
-        raise TypeError('missing path')
-
-    # In order to load the module uniquely from its path, even from
-    # different files which have the same basename, we hash the path
-    # and prefix with `bt_plugin_`. This is its key in sys.modules.
-    h = hashlib.sha256()
-    h.update(path.encode())
-    module_name = 'bt_plugin_{}'.format(h.hexdigest())
-
-    # try loading the module: any raised exception is catched by the caller
-    mod = importlib.machinery.SourceFileLoader(module_name, path).load_module()
-
-    # we have the module: look for its plugin info first
-    if not hasattr(mod, '_bt_plugin_info'):
-        raise RuntimeError("missing '_bt_plugin_info' module attribute")
-
-    plugin_info = mod._bt_plugin_info
-
-    # search for user component classes
-    def is_user_comp_class(obj):
-        if not inspect.isclass(obj):
-            return False
-
-        if not hasattr(obj, '_bt_plugin_component_class'):
-            return False
-
-        return True
-
-    comp_class_entries = inspect.getmembers(mod, is_user_comp_class)
-    plugin_info.comp_class_addrs = [entry[1].addr for entry in comp_class_entries]
-    return plugin_info
diff --git a/bindings/python/bt2/bt2/query_executor.py b/bindings/python/bt2/bt2/query_executor.py
deleted file mode 100644 (file)
index a87713f..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.component
-import bt2
-
-
-class QueryExecutor(object._SharedObject):
-    _get_ref = staticmethod(native_bt.query_executor_get_ref)
-    _put_ref = staticmethod(native_bt.query_executor_put_ref)
-
-    def _handle_status(self, status, gen_error_msg):
-        if status == native_bt.QUERY_EXECUTOR_STATUS_AGAIN:
-            raise bt2.TryAgain
-        elif status == native_bt.QUERY_EXECUTOR_STATUS_CANCELED:
-            raise bt2.QueryExecutorCanceled
-        elif status == native_bt.QUERY_EXECUTOR_STATUS_INVALID_OBJECT:
-            raise bt2.InvalidQueryObject
-        elif status == native_bt.QUERY_EXECUTOR_STATUS_INVALID_PARAMS:
-            raise bt2.InvalidQueryParams
-        elif status < 0:
-            raise bt2.Error(gen_error_msg)
-
-    def __init__(self):
-        ptr = native_bt.query_executor_create()
-
-        if ptr is None:
-            raise bt2.CreationError('cannot create query executor object')
-
-        super().__init__(ptr)
-
-    def cancel(self):
-        status = native_bt.query_executor_cancel(self._ptr)
-        self._handle_status(status, 'cannot cancel query executor object')
-
-    @property
-    def is_canceled(self):
-        is_canceled = native_bt.query_executor_is_canceled(self._ptr)
-        assert(is_canceled >= 0)
-        return is_canceled > 0
-
-    def query(self, component_class, object, params=None):
-        if self.is_canceled:
-            raise bt2.QueryExecutorCanceled
-
-        if not isinstance(component_class, bt2.component._GenericComponentClass):
-            err = False
-
-            try:
-                if not issubclass(component_class, bt2.component._UserComponent):
-                    err = True
-            except TypeError:
-                err = True
-
-            if err:
-                o = component_class
-                raise TypeError("'{}' is not a component class object".format(o))
-
-        utils._check_str(object)
-
-        if params is None:
-            params_ptr = native_bt.value_null
-        else:
-            params = bt2.create_value(params)
-            params_ptr = params._ptr
-
-        cc_ptr = component_class._component_class_ptr()
-
-        status, result_ptr = native_bt.query_executor_query(self._ptr, cc_ptr,
-                                                            object, params_ptr)
-        self._handle_status(status, 'cannot query component class')
-        assert(result_ptr)
-        return bt2.value._create_from_ptr(result_ptr)
diff --git a/bindings/python/bt2/bt2/stream.py b/bindings/python/bt2/bt2/stream.py
deleted file mode 100644 (file)
index 5accfcd..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, utils
-import bt2.packet
-import bt2.event
-import bt2
-
-
-class _Stream(bt2.object._SharedObject):
-    _get_ref = staticmethod(native_bt.stream_get_ref)
-    _put_ref = staticmethod(native_bt.stream_put_ref)
-
-    @property
-    def cls(self):
-        stream_class_ptr = native_bt.stream_borrow_class(self._ptr)
-        assert stream_class_ptr is not None
-        return bt2.stream_class._StreamClass._create_from_ptr_and_get_ref(stream_class_ptr)
-
-    @property
-    def name(self):
-        return native_bt.stream_get_name(self._ptr)
-
-    def _name(self, name):
-        utils._check_str(name)
-        native_bt.stream_set_name(self._ptr, name)
-
-    _name = property(fset=_name)
-
-    @property
-    def id(self):
-        id = native_bt.stream_get_id(self._ptr)
-        return id if id >= 0 else None
-
-    def create_packet(self):
-        packet_ptr = native_bt.packet_create(self._ptr)
-
-        if packet_ptr is None:
-            raise bt2.CreationError('cannot create packet object')
-
-        return bt2.packet._Packet._create_from_ptr(packet_ptr)
diff --git a/bindings/python/bt2/bt2/stream_class.py b/bindings/python/bt2/bt2/stream_class.py
deleted file mode 100644 (file)
index 54b5b38..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.field_class
-import bt2.event_class
-import collections.abc
-import bt2.stream
-import bt2
-
-
-class _StreamClass(object._SharedObject, collections.abc.Mapping):
-    _get_ref = staticmethod(native_bt.stream_class_get_ref)
-    _put_ref = staticmethod(native_bt.stream_class_put_ref)
-
-    def __getitem__(self, key):
-        utils._check_int64(key)
-        ec_ptr = native_bt.stream_class_borrow_event_class_by_id(self._ptr, key)
-
-        if ec_ptr is None:
-            raise KeyError(key)
-
-        return bt2.event_class._EventClass._create_from_ptr_and_get_ref(ec_ptr)
-
-    def __len__(self):
-        count = native_bt.stream_class_get_event_class_count(self._ptr)
-        assert count >= 0
-        return count
-
-    def __iter__(self):
-        for idx in range(len(self)):
-            ec_ptr = native_bt.stream_class_borrow_event_class_by_index_const(self._ptr, idx)
-            assert ec_ptr is not None
-
-            id = native_bt.event_class_get_id(ec_ptr)
-            assert id >= 0
-
-            yield id
-
-    def create_event_class(self, id=None, name=None, log_level=None, emf_uri=None,
-                           specific_context_field_class=None,
-                           payload_field_class=None):
-        if self.assigns_automatic_event_class_id:
-            if id is not None:
-                raise ValueError('id provided, but stream class assigns automatic event class ids')
-
-            ec_ptr = native_bt.event_class_create(self._ptr)
-        else:
-            if id is None:
-                raise ValueError('id not provided, but stream class does not assign automatic event class ids')
-
-            utils._check_uint64(id)
-            ec_ptr = native_bt.event_class_create_with_id(self._ptr, id)
-
-        event_class = bt2.event_class._EventClass._create_from_ptr(ec_ptr)
-
-        if name is not None:
-            event_class._name = name
-
-        if log_level is not None:
-            event_class._log_level = log_level
-
-        if emf_uri is not None:
-            event_class._emf_uri = emf_uri
-
-        if specific_context_field_class is not None:
-            event_class._specific_context_field_class = specific_context_field_class
-
-        if payload_field_class is not None:
-            event_class._payload_field_class = payload_field_class
-
-        return event_class
-
-    @property
-    def trace_class(self):
-        tc_ptr = native_bt.stream_class_borrow_trace_class_const(self._ptr)
-
-        if tc_ptr is not None:
-            return bt2._TraceClass._create_from_ptr_and_get_ref(tc_ptr)
-
-    @property
-    def name(self):
-        return native_bt.stream_class_get_name(self._ptr)
-
-    def _name(self, name):
-        utils._check_str(name)
-        ret = native_bt.stream_class_set_name(self._ptr, name)
-        utils._handle_ret(ret, "cannot set stream class object's name")
-
-    _name = property(fset=_name)
-
-    @property
-    def assigns_automatic_event_class_id(self):
-        return native_bt.stream_class_assigns_automatic_event_class_id(self._ptr)
-
-    def _assigns_automatic_event_class_id(self, auto_id):
-        utils._check_bool(auto_id)
-        return native_bt.stream_class_set_assigns_automatic_event_class_id(self._ptr, auto_id)
-
-    _assigns_automatic_event_class_id = property(fset=_assigns_automatic_event_class_id)
-
-    @property
-    def assigns_automatic_stream_id(self):
-        return native_bt.stream_class_assigns_automatic_stream_id(self._ptr)
-
-    def _assigns_automatic_stream_id(self, auto_id):
-        utils._check_bool(auto_id)
-        return native_bt.stream_class_set_assigns_automatic_stream_id(self._ptr, auto_id)
-
-    _assigns_automatic_stream_id = property(fset=_assigns_automatic_stream_id)
-
-    @property
-    def packets_have_beginning_default_clock_snapshot(self):
-        return native_bt.stream_class_packets_have_beginning_default_clock_snapshot(self._ptr)
-
-    def _packets_have_beginning_default_clock_snapshot(self, value):
-        utils._check_bool(value)
-        native_bt.stream_class_set_packets_have_beginning_default_clock_snapshot(self._ptr, value)
-
-    _packets_have_beginning_default_clock_snapshot = property(fset=_packets_have_beginning_default_clock_snapshot)
-
-    @property
-    def packets_have_end_default_clock_snapshot(self):
-        return native_bt.stream_class_packets_have_end_default_clock_snapshot(self._ptr)
-
-    def _packets_have_end_default_clock_snapshot(self, value):
-        utils._check_bool(value)
-        native_bt.stream_class_set_packets_have_end_default_clock_snapshot(self._ptr, value)
-
-    _packets_have_end_default_clock_snapshot = property(fset=_packets_have_end_default_clock_snapshot)
-
-    @property
-    def supports_discarded_events(self):
-        return native_bt.stream_class_supports_discarded_events(self._ptr)
-
-    def _set_supports_discarded_events(self, supports, with_cs=False):
-        utils._check_bool(supports)
-        utils._check_bool(with_cs)
-
-        if not supports and with_cs:
-            raise ValueError('cannot not support discarded events, but have default clock snapshots')
-
-        native_bt.stream_class_set_supports_discarded_events(self._ptr, supports, with_cs)
-
-    @property
-    def discarded_events_have_default_clock_snapshots(self):
-        return native_bt.stream_class_discarded_events_have_default_clock_snapshots(self._ptr)
-
-    @property
-    def supports_discarded_packets(self):
-        return native_bt.stream_class_supports_discarded_packets(self._ptr)
-
-    def _set_supports_discarded_packets(self, supports, with_cs):
-        utils._check_bool(supports)
-        utils._check_bool(with_cs)
-
-        if not supports and with_cs:
-            raise ValueError('cannot not support discarded packets, but have default clock snapshots')
-
-        native_bt.stream_class_set_supports_discarded_packets(self._ptr, supports, with_cs)
-
-    @property
-    def discarded_packets_have_default_clock_snapshots(self):
-        return native_bt.stream_class_discarded_packets_have_default_clock_snapshots(self._ptr)
-
-    @property
-    def id(self):
-        id = native_bt.stream_class_get_id(self._ptr)
-
-        if id < 0:
-            return
-
-        return id
-
-    @id.setter
-    def id(self, id):
-        utils._check_int64(id)
-        ret = native_bt.stream_class_set_id(self._ptr, id)
-        utils._handle_ret(ret, "cannot set stream class object's ID")
-
-    @property
-    def packet_context_field_class(self):
-        fc_ptr = native_bt.stream_class_borrow_packet_context_field_class_const(self._ptr)
-
-        if fc_ptr is None:
-            return
-
-        return bt2.field_class._create_field_class_from_ptr_and_get_ref(fc_ptr)
-
-    def _packet_context_field_class(self, packet_context_field_class):
-        if packet_context_field_class is not None:
-            utils._check_type(packet_context_field_class,
-                              bt2.field_class._StructureFieldClass)
-            ret = native_bt.stream_class_set_packet_context_field_class(self._ptr,
-                                                                        packet_context_field_class._ptr)
-            utils._handle_ret(ret, "cannot set stream class' packet context field class")
-
-    _packet_context_field_class = property(fset=_packet_context_field_class)
-
-    @property
-    def event_common_context_field_class(self):
-        fc_ptr = native_bt.stream_class_borrow_event_common_context_field_class_const(self._ptr)
-
-        if fc_ptr is None:
-            return
-
-        return bt2.field_class._create_field_class_from_ptr_and_get_ref(fc_ptr)
-
-    def _event_common_context_field_class(self, event_common_context_field_class):
-        if event_common_context_field_class is not None:
-            utils._check_type(event_common_context_field_class,
-                              bt2.field_class._StructureFieldClass)
-
-            set_context_fn = native_bt.stream_class_set_event_common_context_field_class
-            ret = set_context_fn(self._ptr, event_common_context_field_class._ptr)
-
-            utils._handle_ret(ret, "cannot set stream class' event context field type")
-
-    _event_common_context_field_class = property(fset=_event_common_context_field_class)
-
-    @property
-    def default_clock_class(self):
-        cc_ptr = native_bt.stream_class_borrow_default_clock_class(self._ptr)
-        if cc_ptr is None:
-            return
-
-        return bt2.clock_class._ClockClass._create_from_ptr_and_get_ref(cc_ptr)
-
-    def _default_clock_class(self, clock_class):
-        utils._check_type(clock_class, bt2.clock_class._ClockClass)
-        native_bt.stream_class_set_default_clock_class(
-            self._ptr, clock_class._ptr)
-
-    _default_clock_class = property(fset=_default_clock_class)
diff --git a/bindings/python/bt2/bt2/trace.py b/bindings/python/bt2/bt2/trace.py
deleted file mode 100644 (file)
index 5830ec3..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import bt2.field_class
-import collections.abc
-import bt2.value
-import bt2.stream
-import bt2.trace_class
-import bt2
-import functools
-
-
-def _trace_destruction_listener_from_native(user_listener, trace_ptr):
-    trace = bt2.trace._Trace._create_from_ptr_and_get_ref(trace_ptr)
-    user_listener(trace)
-
-
-class _Trace(object._SharedObject, collections.abc.Mapping):
-    _get_ref = staticmethod(native_bt.trace_get_ref)
-    _put_ref = staticmethod(native_bt.trace_put_ref)
-
-    def __len__(self):
-        count = native_bt.trace_get_stream_count(self._ptr)
-        assert count >= 0
-        return count
-
-    def __getitem__(self, id):
-        utils._check_uint64(id)
-
-        stream_ptr = native_bt.trace_borrow_stream_by_id_const(self._ptr, id)
-
-        if stream_ptr is None:
-            raise KeyError(id)
-
-        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
-
-    def __iter__(self):
-        for idx in range(len(self)):
-            stream_ptr = native_bt.trace_borrow_stream_by_index_const(self._ptr, idx)
-            assert stream_ptr is not None
-
-            id = native_bt.stream_get_id(stream_ptr)
-            assert id >= 0
-
-            yield id
-
-    @property
-    def cls(self):
-        trace_class_ptr = native_bt.trace_borrow_class(self._ptr)
-        assert trace_class_ptr is not None
-        return bt2.trace_class._TraceClass._create_from_ptr_and_get_ref(trace_class_ptr)
-
-    @property
-    def name(self):
-        return native_bt.trace_get_name(self._ptr)
-
-    def _name(self, name):
-        utils._check_str(name)
-        ret = native_bt.trace_set_name(self._ptr, name)
-        utils._handle_ret(ret, "cannot set trace class object's name")
-
-    _name = property(fset=_name)
-
-    def create_stream(self, stream_class, id=None, name=None):
-        utils._check_type(stream_class, bt2.stream_class._StreamClass)
-
-        if stream_class.assigns_automatic_stream_id:
-            if id is not None:
-                raise ValueError("id provided, but stream class assigns automatic stream ids")
-
-            stream_ptr = native_bt.stream_create(stream_class._ptr, self._ptr)
-        else:
-            if id is None:
-                raise ValueError("id not provided, but stream class does not assign automatic stream ids")
-
-            utils._check_uint64(id)
-            stream_ptr = native_bt.stream_create_with_id(stream_class._ptr, self._ptr, id)
-
-        if stream_ptr is None:
-            raise bt2.CreationError('cannot create stream object')
-
-        stream = bt2.stream._Stream._create_from_ptr(stream_ptr)
-
-        if name is not None:
-            stream._name = name
-
-        return stream
-
-    def add_destruction_listener(self, listener):
-        '''Add a listener to be called when the trace is destroyed.'''
-        if not callable(listener):
-            raise TypeError("'listener' parameter is not callable")
-
-        fn = native_bt.py3_trace_add_destruction_listener
-        listener_from_native = functools.partial(_trace_destruction_listener_from_native,
-                                                 listener)
-
-        listener_id = fn(self._ptr, listener_from_native)
-        if listener_id is None:
-            utils._raise_bt2_error('cannot add destruction listener to trace object')
-
-        return bt2._ListenerHandle(listener_id, self)
diff --git a/bindings/python/bt2/bt2/trace_class.py b/bindings/python/bt2/bt2/trace_class.py
deleted file mode 100644 (file)
index 5713db8..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-# Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
-# Copyright (c) 2019 Simon Marchi <simon.marchi@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-__all__ = ['_TraceClass']
-
-import bt2
-from bt2 import native_bt, utils, object
-import bt2.stream_class
-import uuid as uuidp
-import collections.abc
-import functools
-
-
-class _TraceClassEnv(collections.abc.MutableMapping):
-    def __init__(self, trace_class):
-        self._trace_class = trace_class
-
-    def __getitem__(self, key):
-        utils._check_str(key)
-
-        borrow_entry_fn = native_bt.trace_class_borrow_environment_entry_value_by_name_const
-        value_ptr = borrow_entry_fn(self._trace_class._ptr, key)
-
-        if value_ptr is None:
-            raise KeyError(key)
-
-        return bt2.value._create_from_ptr_and_get_ref(value_ptr)
-
-    def __setitem__(self, key, value):
-        if isinstance(value, str):
-            set_env_entry_fn = native_bt.trace_class_set_environment_entry_string
-        elif isinstance(value, int):
-            set_env_entry_fn = native_bt.trace_class_set_environment_entry_integer
-        else:
-            raise TypeError('expected str or int, got {}'.format(type(value)))
-
-        ret = set_env_entry_fn(self._trace_class._ptr, key, value)
-
-        utils._handle_ret(ret, "cannot set trace class object's environment entry")
-
-    def __delitem__(self, key):
-        raise NotImplementedError
-
-    def __len__(self):
-        count = native_bt.trace_class_get_environment_entry_count(self._trace_class._ptr)
-        assert count >= 0
-        return count
-
-    def __iter__(self):
-        trace_class_ptr = self._trace_class_env._trace_class._ptr
-
-        for idx in range(len(self)):
-            borrow_entry_fn = native_bt.trace_class_borrow_environment_entry_by_index_const
-            entry_name, _ = borrow_entry_fn(trace_class_ptr, idx)
-            assert entry_name is not None
-            yield entry_name
-
-
-class _StreamClassIterator(collections.abc.Iterator):
-    def __init__(self, trace_class):
-        self._trace_class = trace_class
-        self._at = 0
-
-    def __next__(self):
-        if self._at == len(self._trace_class):
-            raise StopIteration
-
-        borrow_stream_class_fn = native_bt.trace_class_borrow_stream_class_by_index_const
-        sc_ptr = borrow_stream_class_fn(self._trace_class._ptr, self._at)
-        assert sc_ptr
-        id = native_bt.stream_class_get_id(sc_ptr)
-        assert id >= 0
-        self._at += 1
-        return id
-
-
-def _trace_class_destruction_listener_from_native(user_listener, trace_class_ptr):
-    trace_class = bt2.trace_class._TraceClass._create_from_ptr_and_get_ref(trace_class_ptr)
-    user_listener(trace_class)
-
-
-class _TraceClass(object._SharedObject, collections.abc.Mapping):
-    _get_ref = staticmethod(native_bt.trace_class_get_ref)
-    _put_ref = staticmethod(native_bt.trace_class_put_ref)
-
-    @property
-    def uuid(self):
-        uuid_bytes = native_bt.trace_class_get_uuid(self._ptr)
-        if uuid_bytes is None:
-            return
-
-        return uuidp.UUID(bytes=uuid_bytes)
-
-    def _uuid(self, uuid):
-        utils._check_type(uuid, uuidp.UUID)
-        native_bt.trace_class_set_uuid(self._ptr, uuid.bytes)
-
-    _uuid = property(fset=_uuid)
-
-    # Instantiate a trace of this class.
-
-    def __call__(self, name=None):
-        trace_ptr = native_bt.trace_create(self._ptr)
-
-        if trace_ptr is None:
-            raise bt2.CreationError('cannot create trace class object')
-
-        trace = bt2.trace._Trace._create_from_ptr(trace_ptr)
-
-        if name is not None:
-            trace._name = name
-
-        return trace
-
-    # Number of stream classes in this trace class.
-
-    def __len__(self):
-        count = native_bt.trace_class_get_stream_class_count(self._ptr)
-        assert count >= 0
-        return count
-
-    # Get a stream class by stream id.
-
-    def __getitem__(self, key):
-        utils._check_uint64(key)
-
-        sc_ptr = native_bt.trace_class_borrow_stream_class_by_id_const(self._ptr, key)
-        if sc_ptr is None:
-            raise KeyError(key)
-
-        return bt2.stream_class._StreamClass._create_from_ptr_and_get_ref(sc_ptr)
-
-    def __iter__(self):
-        for idx in range(len(self)):
-            sc_ptr = native_bt.trace_class_borrow_stream_class_by_index_const(self._ptr, idx)
-            assert sc_ptr is not None
-
-            id = native_bt.stream_class_get_id(sc_ptr)
-            assert id >= 0
-
-            yield id
-
-    @property
-    def env(self):
-        return _TraceClassEnv(self)
-
-    def create_stream_class(self, id=None,
-                            name=None,
-                            packet_context_field_class=None,
-                            event_common_context_field_class=None,
-                            default_clock_class=None,
-                            assigns_automatic_event_class_id=True,
-                            assigns_automatic_stream_id=True,
-                            packets_have_beginning_default_clock_snapshot=False,
-                            packets_have_end_default_clock_snapshot=False,
-                            supports_discarded_events=False,
-                            discarded_events_have_default_clock_snapshots=False,
-                            supports_discarded_packets=False,
-                            discarded_packets_have_default_clock_snapshots=False):
-
-        if self.assigns_automatic_stream_class_id:
-            if id is not None:
-                raise ValueError('id provided, but trace class assigns automatic stream class ids')
-
-            sc_ptr = native_bt.stream_class_create(self._ptr)
-        else:
-            if id is None:
-                raise ValueError('id not provided, but trace class does not assign automatic stream class ids')
-
-            utils._check_uint64(id)
-            sc_ptr = native_bt.stream_class_create_with_id(self._ptr, id)
-
-        sc = bt2.stream_class._StreamClass._create_from_ptr(sc_ptr)
-
-        if name is not None:
-            sc._name = name
-
-        if packet_context_field_class is not None:
-            sc._packet_context_field_class = packet_context_field_class
-
-        if event_common_context_field_class is not None:
-            sc._event_common_context_field_class = event_common_context_field_class
-
-        if default_clock_class is not None:
-            sc._default_clock_class = default_clock_class
-
-        sc._assigns_automatic_event_class_id = assigns_automatic_event_class_id
-        sc._assigns_automatic_stream_id = assigns_automatic_stream_id
-        sc._packets_have_beginning_default_clock_snapshot = packets_have_beginning_default_clock_snapshot
-        sc._packets_have_end_default_clock_snapshot = packets_have_end_default_clock_snapshot
-        sc._set_supports_discarded_events(supports_discarded_events,
-                                          discarded_events_have_default_clock_snapshots)
-        sc._set_supports_discarded_packets(supports_discarded_packets,
-                                           discarded_packets_have_default_clock_snapshots)
-        return sc
-
-    @property
-    def assigns_automatic_stream_class_id(self):
-        return native_bt.trace_class_assigns_automatic_stream_class_id(self._ptr)
-
-    def _assigns_automatic_stream_class_id(self, auto_id):
-        utils._check_bool(auto_id)
-        return native_bt.trace_class_set_assigns_automatic_stream_class_id(self._ptr, auto_id)
-
-    _assigns_automatic_stream_class_id = property(fset=_assigns_automatic_stream_class_id)
-
-    # Field class creation methods.
-
-    def _check_create_status(self, ptr, type_name):
-        if ptr is None:
-            raise bt2.CreationError(
-                'cannot create {} field class'.format(type_name))
-
-    def _create_integer_field_class(self, create_func, py_cls, type_name, field_value_range, preferred_display_base):
-        field_class_ptr = create_func(self._ptr)
-        self._check_create_status(field_class_ptr, type_name)
-
-        field_class = py_cls._create_from_ptr(field_class_ptr)
-
-        if field_value_range is not None:
-            field_class._field_value_range = field_value_range
-
-        if preferred_display_base is not None:
-            field_class._preferred_display_base = preferred_display_base
-
-        return field_class
-
-    def create_signed_integer_field_class(self, field_value_range=None, preferred_display_base=None):
-        return self._create_integer_field_class(native_bt.field_class_signed_integer_create,
-                                                bt2.field_class._SignedIntegerFieldClass,
-                                                'signed integer', field_value_range, preferred_display_base)
-
-    def create_unsigned_integer_field_class(self, field_value_range=None, preferred_display_base=None):
-        return self._create_integer_field_class(native_bt.field_class_unsigned_integer_create,
-                                                bt2.field_class._UnsignedIntegerFieldClass,
-                                                'unsigned integer', field_value_range, preferred_display_base)
-
-    def create_signed_enumeration_field_class(self, field_value_range=None, preferred_display_base=None):
-        return self._create_integer_field_class(native_bt.field_class_signed_enumeration_create,
-                                                bt2.field_class._SignedEnumerationFieldClass,
-                                                'signed enumeration', field_value_range, preferred_display_base)
-
-    def create_unsigned_enumeration_field_class(self, field_value_range=None, preferred_display_base=None):
-        return self._create_integer_field_class(native_bt.field_class_unsigned_enumeration_create,
-                                                bt2.field_class._UnsignedEnumerationFieldClass,
-                                                'unsigned enumeration', field_value_range, preferred_display_base)
-
-    def create_real_field_class(self, is_single_precision=False):
-        field_class_ptr = native_bt.field_class_real_create(self._ptr)
-        self._check_create_status(field_class_ptr, 'real')
-
-        field_class = bt2.field_class._RealFieldClass._create_from_ptr(field_class_ptr)
-
-        field_class._is_single_precision = is_single_precision
-
-        return field_class
-
-    def create_structure_field_class(self):
-        field_class_ptr = native_bt.field_class_structure_create(self._ptr)
-        self._check_create_status(field_class_ptr, 'structure')
-
-        return bt2.field_class._StructureFieldClass._create_from_ptr(field_class_ptr)
-
-    def create_string_field_class(self):
-        field_class_ptr = native_bt.field_class_string_create(self._ptr)
-        self._check_create_status(field_class_ptr, 'string')
-
-        return bt2.field_class._StringFieldClass._create_from_ptr(field_class_ptr)
-
-    def create_static_array_field_class(self, elem_fc, length):
-        utils._check_type(elem_fc, bt2.field_class._FieldClass)
-        utils._check_uint64(length)
-        ptr = native_bt.field_class_static_array_create(self._ptr, elem_fc._ptr, length)
-        self._check_create_status(ptr, 'static array')
-
-        return bt2.field_class._StaticArrayFieldClass._create_from_ptr_and_get_ref(ptr)
-
-    def create_dynamic_array_field_class(self, elem_fc, length_fc=None):
-        utils._check_type(elem_fc, bt2.field_class._FieldClass)
-        ptr = native_bt.field_class_dynamic_array_create(self._ptr, elem_fc._ptr)
-        self._check_create_status(ptr, 'dynamic array')
-        obj = bt2.field_class._DynamicArrayFieldClass._create_from_ptr(ptr)
-
-        if length_fc is not None:
-            obj._length_field_class = length_fc
-
-        return obj
-
-    def create_variant_field_class(self, selector_fc=None):
-        ptr = native_bt.field_class_variant_create(self._ptr)
-        self._check_create_status(ptr, 'variant')
-        obj = bt2.field_class._VariantFieldClass._create_from_ptr(ptr)
-
-        if selector_fc is not None:
-            obj._selector_field_class = selector_fc
-
-        return obj
-
-    # Add a listener to be called when the trace class is destroyed.
-
-    def add_destruction_listener(self, listener):
-
-        if not callable(listener):
-            raise TypeError("'listener' parameter is not callable")
-
-        fn = native_bt.py3_trace_class_add_destruction_listener
-        listener_from_native = functools.partial(_trace_class_destruction_listener_from_native,
-                                                 listener)
-
-        listener_id = fn(self._ptr, listener_from_native)
-        if listener_id is None:
-            utils._raise_bt2_error('cannot add destruction listener to trace class object')
-
-        return bt2._ListenerHandle(listener_id, self)
diff --git a/bindings/python/bt2/bt2/trace_collection_message_iterator.py b/bindings/python/bt2/bt2/trace_collection_message_iterator.py
deleted file mode 100644 (file)
index 10b555f..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import utils
-import bt2
-import itertools
-import bt2.message_iterator
-import datetime
-from collections import namedtuple
-import numbers
-
-
-# a pair of component and ComponentSpec
-_ComponentAndSpec = namedtuple('_ComponentAndSpec', ['comp', 'spec'])
-
-
-class ComponentSpec:
-    def __init__(self, plugin_name, class_name, params=None):
-        utils._check_str(plugin_name)
-        utils._check_str(class_name)
-        self._plugin_name = plugin_name
-        self._class_name = class_name
-
-        if type(params) is str:
-            self._params = bt2.create_value({'paths': [params]})
-        else:
-            self._params = bt2.create_value(params)
-
-    @property
-    def plugin_name(self):
-        return self._plugin_name
-
-    @property
-    def class_name(self):
-        return self._class_name
-
-    @property
-    def params(self):
-        return self._params
-
-
-# datetime.datetime or integral to nanoseconds
-def _get_ns(obj):
-    if obj is None:
-        return
-
-    if isinstance(obj, numbers.Real):
-        # consider that it's already in seconds
-        s = obj
-    elif isinstance(obj, datetime.datetime):
-        # s -> ns
-        s = obj.timestamp()
-    else:
-        raise TypeError('"{}" is not an integral number or a datetime.datetime object'.format(obj))
-
-    return int(s * 1e9)
-
-
-class _CompClsType:
-    SOURCE = 0
-    FILTER = 1
-
-
-class TraceCollectionMessageIterator(bt2.message_iterator._MessageIterator):
-    def __init__(self, source_component_specs, filter_component_specs=None,
-                 stream_intersection_mode=False, begin=None, end=None):
-        utils._check_bool(stream_intersection_mode)
-        self._stream_intersection_mode = stream_intersection_mode
-        self._begin_ns = _get_ns(begin)
-        self._end_ns = _get_ns(end)
-
-        if type(source_component_specs) is ComponentSpec:
-            source_component_specs = [source_component_specs]
-
-        if type(filter_component_specs) is ComponentSpec:
-            filter_component_specs = [filter_component_specs]
-        elif filter_component_specs is None:
-            filter_component_specs = []
-
-        self._src_comp_specs = source_component_specs
-        self._flt_comp_specs = filter_component_specs
-        self._next_suffix = 1
-        self._connect_ports = False
-
-        # lists of _ComponentAndSpec
-        self._src_comps_and_specs = []
-        self._flt_comps_and_specs = []
-
-        self._validate_component_specs(source_component_specs)
-        self._validate_component_specs(filter_component_specs)
-        self._build_graph()
-
-    def _validate_component_specs(self, comp_specs):
-        for comp_spec in comp_specs:
-            if type(comp_spec) is not ComponentSpec:
-                raise TypeError('"{}" object is not a ComponentSpec'.format(type(comp_spec)))
-
-    def __next__(self):
-        return next(self._msg_iter)
-
-    def _create_stream_intersection_trimmer(self, component, port):
-        # find the original parameters specified by the user to create
-        # this port's component to get the `path` parameter
-        for src_comp_and_spec in self._src_comps_and_specs:
-            if component == src_comp_and_spec.comp:
-                break
-
-        try:
-            paths = src_comp_and_spec.spec.params['paths']
-        except Exception as e:
-            raise bt2.Error('all source components must be created with a "paths" parameter in stream intersection mode') from e
-
-        params = {'paths': paths}
-
-        # query the port's component for the `trace-info` object which
-        # contains the stream intersection range for each exposed
-        # trace
-        query_exec = bt2.QueryExecutor()
-        trace_info_res = query_exec.query(src_comp_and_spec.comp.cls,
-                                          'trace-info', params)
-        begin = None
-        end = None
-
-        # find the trace info for this port's trace
-        try:
-            for trace_info in trace_info_res:
-                for stream in trace_info['streams']:
-                    if stream['port-name'] == port.name:
-                        range_ns = trace_info['intersection-range-ns']
-                        begin = range_ns['begin']
-                        end = range_ns['end']
-                        break
-        except Exception:
-            pass
-
-        if begin is None or end is None:
-            raise bt2.Error('cannot find stream intersection range for port "{}"'.format(port.name))
-
-        name = 'trimmer-{}-{}'.format(src_comp_and_spec.comp.name, port.name)
-        return self._create_trimmer(begin, end, name)
-
-    def _create_muxer(self):
-        plugin = bt2.find_plugin('utils')
-
-        if plugin is None:
-            raise bt2.Error('cannot find "utils" plugin (needed for the muxer)')
-
-        if 'muxer' not in plugin.filter_component_classes:
-            raise bt2.Error('cannot find "muxer" filter component class in "utils" plugin')
-
-        comp_cls = plugin.filter_component_classes['muxer']
-        return self._graph.add_component(comp_cls, 'muxer')
-
-    def _create_trimmer(self, begin_ns, end_ns, name):
-        plugin = bt2.find_plugin('utils')
-
-        if plugin is None:
-            raise bt2.Error('cannot find "utils" plugin (needed for the trimmer)')
-
-        if 'trimmer' not in plugin.filter_component_classes:
-            raise bt2.Error('cannot find "trimmer" filter component class in "utils" plugin')
-
-        params = {}
-
-        def ns_to_string(ns):
-            s_part = ns // 1000000000
-            ns_part = ns % 1000000000
-            return '{}.{:09d}'.format(s_part, ns_part)
-
-        if begin_ns is not None:
-            params['begin'] = ns_to_string(begin_ns)
-
-        if end_ns is not None:
-            params['end'] = ns_to_string(end_ns)
-
-        comp_cls = plugin.filter_component_classes['trimmer']
-        return self._graph.add_component(comp_cls, name, params)
-
-    def _get_unique_comp_name(self, comp_spec):
-        name = '{}-{}'.format(comp_spec.plugin_name,
-                              comp_spec.class_name)
-        comps_and_specs = itertools.chain(self._src_comps_and_specs,
-                                          self._flt_comps_and_specs)
-
-        if name in [comp_and_spec.comp.name for comp_and_spec in comps_and_specs]:
-            name += '-{}'.format(self._next_suffix)
-            self._next_suffix += 1
-
-        return name
-
-    def _create_comp(self, comp_spec, comp_cls_type):
-        plugin = bt2.find_plugin(comp_spec.plugin_name)
-
-        if plugin is None:
-            raise bt2.Error('no such plugin: {}'.format(comp_spec.plugin_name))
-
-        if comp_cls_type == _CompClsType.SOURCE:
-            comp_classes = plugin.source_component_classes
-        else:
-            comp_classes = plugin.filter_component_classes
-
-        if comp_spec.class_name not in comp_classes:
-            cc_type = 'source' if comp_cls_type == _CompClsType.SOURCE else 'filter'
-            raise bt2.Error('no such {} component class in "{}" plugin: {}'.format(cc_type,
-                                                                                   comp_spec.plugin_name,
-                                                                                   comp_spec.class_name))
-
-        comp_cls = comp_classes[comp_spec.class_name]
-        name = self._get_unique_comp_name(comp_spec)
-        comp = self._graph.add_component(comp_cls, name, comp_spec.params)
-        return comp
-
-    def _get_free_muxer_input_port(self):
-        for port in self._muxer_comp.input_ports.values():
-            if not port.is_connected:
-                return port
-
-    def _connect_src_comp_port(self, component, port):
-        # if this trace collection iterator is in stream intersection
-        # mode, we need this connection:
-        #
-        #     port -> trimmer -> muxer
-        #
-        # otherwise, simply:
-        #
-        #     port -> muxer
-        if self._stream_intersection_mode:
-            trimmer_comp = self._create_stream_intersection_trimmer(component, port)
-            self._graph.connect_ports(port, trimmer_comp.input_ports['in'])
-            port_to_muxer = trimmer_comp.output_ports['out']
-        else:
-            port_to_muxer = port
-
-        self._graph.connect_ports(port_to_muxer, self._get_free_muxer_input_port())
-
-    def _graph_port_added(self, component, port):
-        if not self._connect_ports:
-            return
-
-        if type(port) is bt2.port._InputPort:
-            return
-
-        if component not in [comp.comp for comp in self._src_comps_and_specs]:
-            # do not care about non-source components (muxer, trimmer, etc.)
-            return
-
-        self._connect_src_comp_port(component, port)
-
-    def _build_graph(self):
-        self._graph = bt2.Graph()
-        self._graph.add_port_added_listener(self._graph_port_added)
-        self._muxer_comp = self._create_muxer()
-
-        if self._begin_ns is not None or self._end_ns is not None:
-            trimmer_comp = self._create_trimmer(self._begin_ns,
-                                                self._end_ns, 'trimmer')
-            self._graph.connect_ports(self._muxer_comp.output_ports['out'],
-                                      trimmer_comp.input_ports['in'])
-            msg_iter_port = trimmer_comp.output_ports['out']
-        else:
-            msg_iter_port = self._muxer_comp.output_ports['out']
-
-        # create extra filter components (chained)
-        for comp_spec in self._flt_comp_specs:
-            comp = self._create_comp(comp_spec, _CompClsType.FILTER)
-            self._flt_comps_and_specs.append(_ComponentAndSpec(comp, comp_spec))
-
-        # connect the extra filter chain
-        for comp_and_spec in self._flt_comps_and_specs:
-            in_port = list(comp_and_spec.comp.input_ports.values())[0]
-            out_port = list(comp_and_spec.comp.output_ports.values())[0]
-            self._graph.connect_ports(msg_iter_port, in_port)
-            msg_iter_port = out_port
-
-        # Here we create the components, self._graph_port_added() is
-        # called when they add ports, but the callback returns early
-        # because self._connect_ports is False. This is because the
-        # self._graph_port_added() could not find the associated source
-        # component specification in self._src_comps_and_specs because
-        # it does not exist yet (it needs the created component to
-        # exist).
-        for comp_spec in self._src_comp_specs:
-            comp = self._create_comp(comp_spec, _CompClsType.SOURCE)
-            self._src_comps_and_specs.append(_ComponentAndSpec(comp, comp_spec))
-
-        # Now we connect the ports which exist at this point. We allow
-        # self._graph_port_added() to automatically connect _new_ ports.
-        self._connect_ports = True
-
-        for comp_and_spec in self._src_comps_and_specs:
-            # Keep a separate list because comp_and_spec.output_ports
-            # could change during the connection of one of its ports.
-            # Any new port is handled by self._graph_port_added().
-            out_ports = [port for port in comp_and_spec.comp.output_ports.values()]
-
-            for out_port in out_ports:
-                if out_port.is_connected:
-                    continue
-
-                self._connect_src_comp_port(comp_and_spec.comp, out_port)
-
-        # create this trace collection iterator's message iterator
-        self._msg_iter = self._graph.create_output_port_message_iterator(msg_iter_port)
diff --git a/bindings/python/bt2/bt2/utils.py b/bindings/python/bt2/bt2/utils.py
deleted file mode 100644 (file)
index bd8ebf8..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-import bt2
-
-
-def _check_bool(o):
-    if not isinstance(o, bool):
-        raise TypeError("'{}' is not a 'bool' object".format(o.__class__.__name__))
-
-
-def _check_int(o):
-    if not isinstance(o, int):
-        raise TypeError("'{}' is not an 'int' object".format(o.__class__.__name__))
-
-
-def _check_float(o):
-    if not isinstance(o, float):
-        raise TypeError("'{}' is not a 'float' object".format(o.__class__.__name__))
-
-
-def _check_str(o):
-    if not isinstance(o, str):
-        raise TypeError("'{}' is not a 'str' object".format(o.__class__.__name__))
-
-
-def _check_type(o, expected_type):
-    if not isinstance(o, expected_type):
-        raise TypeError("'{}' is not a '{}' object".format(o.__class__.__name__,
-                                                           expected_type))
-
-
-def _is_int64(v):
-    _check_int(v)
-    return v >= -(2**63) and v <= (2**63 - 1)
-
-
-def _is_uint64(v):
-    _check_int(v)
-    return v >= 0 and v <= (2**64 - 1)
-
-
-def _check_int64(v, msg=None):
-    if not _is_int64(v):
-        if msg is None:
-            msg = 'expecting a signed 64-bit integral value'
-
-        msg += ' (got {})'.format(v)
-        raise ValueError(msg)
-
-
-def _check_uint64(v, msg=None):
-    if not _is_uint64(v):
-        if msg is None:
-            msg = 'expecting an unsigned 64-bit integral value'
-
-        msg += ' (got {})'.format(v)
-        raise ValueError(msg)
-
-
-def _is_m1ull(v):
-    return v == 18446744073709551615
-
-
-def _is_pow2(v):
-    return v != 0 and ((v & (v - 1)) == 0)
-
-
-def _check_alignment(a):
-    _check_uint64(a)
-
-    if not _is_pow2(a):
-        raise ValueError('{} is not a power of two'.format(a))
-
-
-def _raise_bt2_error(msg):
-    if msg is None:
-        raise bt2.Error
-    else:
-        raise bt2.Error(msg)
-
-
-def _handle_ret(ret, msg=None):
-    if int(ret) < 0:
-        _raise_bt2_error(msg)
-
-
-def _handle_ptr(ptr, msg=None):
-    if ptr is None:
-        _raise_bt2_error(msg)
diff --git a/bindings/python/bt2/bt2/value.py b/bindings/python/bt2/bt2/value.py
deleted file mode 100644 (file)
index d8b8332..0000000
+++ /dev/null
@@ -1,712 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-from bt2 import native_bt, object, utils
-import collections.abc
-import functools
-import numbers
-import math
-import abc
-import bt2
-
-
-def _handle_status(status, obj_name):
-    if status >= 0:
-        return
-    else:
-        raise RuntimeError('unexpected error')
-
-
-def _create_from_ptr(ptr):
-    if ptr is None or ptr == native_bt.value_null:
-        return
-
-    typeid = native_bt.value_get_type(ptr)
-    return _TYPE_TO_OBJ[typeid]._create_from_ptr(ptr)
-
-
-def _create_from_ptr_and_get_ref(ptr):
-    if ptr is None or ptr == native_bt.value_null:
-        return
-
-    typeid = native_bt.value_get_type(ptr)
-    return _TYPE_TO_OBJ[typeid]._create_from_ptr_and_get_ref(ptr)
-
-
-def create_value(value):
-    if value is None:
-        # null value object
-        return
-
-    if isinstance(value, _Value):
-        return value
-
-    if isinstance(value, bool):
-        return BoolValue(value)
-
-    if isinstance(value, int):
-        return SignedIntegerValue(value)
-
-    if isinstance(value, float):
-        return RealValue(value)
-
-    if isinstance(value, str):
-        return StringValue(value)
-
-    try:
-        return MapValue(value)
-    except:
-        pass
-
-    try:
-        return ArrayValue(value)
-    except:
-        pass
-
-    raise TypeError("cannot create value object from '{}' object".format(value.__class__.__name__))
-
-
-class _Value(object._SharedObject, metaclass=abc.ABCMeta):
-    _get_ref = staticmethod(native_bt.value_get_ref)
-    _put_ref = staticmethod(native_bt.value_put_ref)
-
-    def __eq__(self, other):
-        if other is None:
-            # self is never the null value object
-            return False
-
-        # try type-specific comparison first
-        spec_eq = self._spec_eq(other)
-
-        if spec_eq is not None:
-            return spec_eq
-
-        if not isinstance(other, _Value):
-            # not comparing apples to apples
-            return False
-
-        # fall back to native comparison function
-        return native_bt.value_compare(self._ptr, other._ptr)
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    @abc.abstractmethod
-    def _spec_eq(self, other):
-        pass
-
-    def _handle_status(self, status):
-        _handle_status(status, self._NAME)
-
-    def _check_create_status(self, ptr):
-        if ptr is None:
-            raise bt2.CreationError(
-                'cannot create {} value object'.format(self._NAME.lower()))
-
-
-@functools.total_ordering
-class _NumericValue(_Value):
-    @staticmethod
-    def _extract_value(other):
-        if isinstance(other, _NumericValue):
-            return other._value
-
-        if other is True or other is False:
-            return other
-
-        if isinstance(other, numbers.Integral):
-            return int(other)
-
-        if isinstance(other, numbers.Real):
-            return float(other)
-
-        if isinstance(other, numbers.Complex):
-            return complex(other)
-
-        raise TypeError("'{}' object is not a number object".format(other.__class__.__name__))
-
-    def __int__(self):
-        return int(self._value)
-
-    def __float__(self):
-        return float(self._value)
-
-    def __repr__(self):
-        return repr(self._value)
-
-    def __lt__(self, other):
-        if not isinstance(other, numbers.Number):
-            raise TypeError('unorderable types: {}() < {}()'.format(self.__class__.__name__,
-                                                                    other.__class__.__name__))
-
-        return self._value < float(other)
-
-    def __le__(self, other):
-        if not isinstance(other, numbers.Number):
-            raise TypeError('unorderable types: {}() <= {}()'.format(self.__class__.__name__,
-                                                                     other.__class__.__name__))
-
-        return self._value <= float(other)
-
-    def _spec_eq(self, other):
-        pass
-
-    def __eq__(self, other):
-        if not isinstance(other, numbers.Number):
-            return False
-
-        return self._value == complex(other)
-
-    def __rmod__(self, other):
-        return self._extract_value(other) % self._value
-
-    def __mod__(self, other):
-        return self._value % self._extract_value(other)
-
-    def __rfloordiv__(self, other):
-        return self._extract_value(other) // self._value
-
-    def __floordiv__(self, other):
-        return self._value // self._extract_value(other)
-
-    def __round__(self, ndigits=None):
-        if ndigits is None:
-            return round(self._value)
-        else:
-            return round(self._value, ndigits)
-
-    def __ceil__(self):
-        return math.ceil(self._value)
-
-    def __floor__(self):
-        return math.floor(self._value)
-
-    def __trunc__(self):
-        return int(self._value)
-
-    def __abs__(self):
-        return abs(self._value)
-
-    def __add__(self, other):
-        return self._value + self._extract_value(other)
-
-    def __radd__(self, other):
-        return self.__add__(other)
-
-    def __neg__(self):
-        return -self._value
-
-    def __pos__(self):
-        return +self._value
-
-    def __mul__(self, other):
-        return self._value * self._extract_value(other)
-
-    def __rmul__(self, other):
-        return self.__mul__(other)
-
-    def __truediv__(self, other):
-        return self._value / self._extract_value(other)
-
-    def __rtruediv__(self, other):
-        return self._extract_value(other) / self._value
-
-    def __pow__(self, exponent):
-        return self._value ** self._extract_value(exponent)
-
-    def __rpow__(self, base):
-        return self._extract_value(base) ** self._value
-
-    def __iadd__(self, other):
-        self.value = self + other
-        return self
-
-    def __isub__(self, other):
-        self.value = self - other
-        return self
-
-    def __imul__(self, other):
-        self.value = self * other
-        return self
-
-    def __itruediv__(self, other):
-        self.value = self / other
-        return self
-
-    def __ifloordiv__(self, other):
-        self.value = self // other
-        return self
-
-    def __imod__(self, other):
-        self.value = self % other
-        return self
-
-    def __ipow__(self, other):
-        self.value = self ** other
-        return self
-
-
-class _IntegralValue(_NumericValue, numbers.Integral):
-    def __lshift__(self, other):
-        return self._value << self._extract_value(other)
-
-    def __rlshift__(self, other):
-        return self._extract_value(other) << self._value
-
-    def __rshift__(self, other):
-        return self._value >> self._extract_value(other)
-
-    def __rrshift__(self, other):
-        return self._extract_value(other) >> self._value
-
-    def __and__(self, other):
-        return self._value & self._extract_value(other)
-
-    def __rand__(self, other):
-        return self._extract_value(other) & self._value
-
-    def __xor__(self, other):
-        return self._value ^ self._extract_value(other)
-
-    def __rxor__(self, other):
-        return self._extract_value(other) ^ self._value
-
-    def __or__(self, other):
-        return self._value | self._extract_value(other)
-
-    def __ror__(self, other):
-        return self._extract_value(other) | self._value
-
-    def __invert__(self):
-        return ~self._value
-
-    def __ilshift__(self, other):
-        self.value = self << other
-        return self
-
-    def __irshift__(self, other):
-        self.value = self >> other
-        return self
-
-    def __iand__(self, other):
-        self.value = self & other
-        return self
-
-    def __ixor__(self, other):
-        self.value = self ^ other
-        return self
-
-    def __ior__(self, other):
-        self.value = self | other
-        return self
-
-
-class _RealValue(_NumericValue, numbers.Real):
-    pass
-
-
-class BoolValue(_Value):
-    _NAME = 'Boolean'
-
-    def __init__(self, value=None):
-        if value is None:
-            ptr = native_bt.value_bool_create()
-        else:
-            ptr = native_bt.value_bool_create_init(self._value_to_bool(value))
-
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-    def _spec_eq(self, other):
-        if isinstance(other, numbers.Number):
-            return self._value == bool(other)
-
-    def __bool__(self):
-        return self._value
-
-    def __repr__(self):
-        return repr(self._value)
-
-    def _value_to_bool(self, value):
-        if isinstance(value, BoolValue):
-            value = value._value
-
-        if not isinstance(value, bool):
-            raise TypeError("'{}' object is not a 'bool' or 'BoolValue' object".format(value.__class__))
-
-        return int(value)
-
-    @property
-    def _value(self):
-        value = native_bt.value_bool_get(self._ptr)
-        return value != 0
-
-    def _set_value(self, value):
-        native_bt.value_bool_set(self._ptr, self._value_to_bool(value))
-
-    value = property(fset=_set_value)
-
-
-class _IntegerValue(_IntegralValue):
-    def __init__(self, value=None):
-        if value is None:
-            ptr = self._create_default_value()
-        else:
-            ptr = self._create_value(self._value_to_int(value))
-
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-    def _value_to_int(self, value):
-        if not isinstance(value, numbers.Real):
-            raise TypeError('expecting a number object')
-
-        value = int(value)
-        self._check_int_range(value)
-        return value
-
-    @property
-    def _value(self):
-        return self._get_value(self._ptr)
-
-    def _prop_set_value(self, value):
-        self._set_value(self._ptr, self._value_to_int(value))
-
-    value = property(fset=_prop_set_value)
-
-
-class UnsignedIntegerValue(_IntegerValue):
-    _check_int_range = staticmethod(utils._check_uint64)
-    _create_default_value = staticmethod(native_bt.value_unsigned_integer_create)
-    _create_value = staticmethod(native_bt.value_unsigned_integer_create_init)
-    _set_value = staticmethod(native_bt.value_unsigned_integer_set)
-    _get_value = staticmethod(native_bt.value_unsigned_integer_get)
-
-
-class SignedIntegerValue(_IntegerValue):
-    _check_int_range = staticmethod(utils._check_int64)
-    _create_default_value = staticmethod(native_bt.value_signed_integer_create)
-    _create_value = staticmethod(native_bt.value_signed_integer_create_init)
-    _set_value = staticmethod(native_bt.value_signed_integer_set)
-    _get_value = staticmethod(native_bt.value_signed_integer_get)
-
-
-class RealValue(_RealValue):
-    _NAME = 'Real number'
-
-    def __init__(self, value=None):
-        if value is None:
-            ptr = native_bt.value_real_create()
-        else:
-            value = self._value_to_float(value)
-            ptr = native_bt.value_real_create_init(value)
-
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-    def _value_to_float(self, value):
-        if not isinstance(value, numbers.Real):
-            raise TypeError("expecting a real number object")
-
-        return float(value)
-
-    @property
-    def _value(self):
-        return native_bt.value_real_get(self._ptr)
-
-    def _set_value(self, value):
-        native_bt.value_real_set(self._ptr, self._value_to_float(value))
-
-    value = property(fset=_set_value)
-
-
-@functools.total_ordering
-class StringValue(collections.abc.Sequence, _Value):
-    _NAME = 'String'
-
-    def __init__(self, value=None):
-        if value is None:
-            ptr = native_bt.value_string_create()
-        else:
-            ptr = native_bt.value_string_create_init(self._value_to_str(value))
-
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-    def _value_to_str(self, value):
-        if isinstance(value, self.__class__):
-            value = value._value
-
-        utils._check_str(value)
-        return value
-
-    @property
-    def _value(self):
-        return native_bt.value_string_get(self._ptr)
-
-    def _set_value(self, value):
-        status = native_bt.value_string_set(self._ptr, self._value_to_str(value))
-        self._handle_status(status)
-
-    value = property(fset=_set_value)
-
-    def _spec_eq(self, other):
-        try:
-            return self._value == self._value_to_str(other)
-        except:
-            return
-
-    def __le__(self, other):
-        return self._value <= self._value_to_str(other)
-
-    def __lt__(self, other):
-        return self._value < self._value_to_str(other)
-
-    def __bool__(self):
-        return bool(self._value)
-
-    def __repr__(self):
-        return repr(self._value)
-
-    def __str__(self):
-        return self._value
-
-    def __getitem__(self, index):
-        return self._value[index]
-
-    def __len__(self):
-        return len(self._value)
-
-    def __iadd__(self, value):
-        curvalue = self._value
-        curvalue += self._value_to_str(value)
-        self.value = curvalue
-        return self
-
-
-class _Container:
-    def __bool__(self):
-        return len(self) != 0
-
-    def __delitem__(self, index):
-        raise NotImplementedError
-
-
-class ArrayValue(_Container, collections.abc.MutableSequence, _Value):
-    _NAME = 'Array'
-
-    def __init__(self, value=None):
-        ptr = native_bt.value_array_create()
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-        # Python will raise a TypeError if there's anything wrong with
-        # the iterable protocol.
-        if value is not None:
-            for elem in value:
-                self.append(elem)
-
-    def _spec_eq(self, other):
-        try:
-            if len(self) != len(other):
-                # early mismatch
-                return False
-
-            for self_elem, other_elem in zip(self, other):
-                if self_elem != other_elem:
-                    return False
-
-            return True
-        except:
-            return
-
-    def __len__(self):
-        size = native_bt.value_array_get_size(self._ptr)
-        assert(size >= 0)
-        return size
-
-    def _check_index(self, index):
-        # TODO: support slices also
-        if not isinstance(index, numbers.Integral):
-            raise TypeError("'{}' object is not an integral number object: invalid index".format(index.__class__.__name__))
-
-        index = int(index)
-
-        if index < 0 or index >= len(self):
-            raise IndexError('array value object index is out of range')
-
-    def __getitem__(self, index):
-        self._check_index(index)
-        ptr = native_bt.value_array_borrow_element_by_index(self._ptr, index)
-        assert(ptr)
-        return _create_from_ptr_and_get_ref(ptr)
-
-    def __setitem__(self, index, value):
-        self._check_index(index)
-        value = create_value(value)
-
-        if value is None:
-            ptr = native_bt.value_null
-        else:
-            ptr = value._ptr
-
-        status = native_bt.value_array_set_element_by_index(
-            self._ptr, index, ptr)
-        self._handle_status(status)
-
-    def append(self, value):
-        value = create_value(value)
-
-        if value is None:
-            ptr = native_bt.value_null
-        else:
-            ptr = value._ptr
-
-        status = native_bt.value_array_append_element(self._ptr, ptr)
-        self._handle_status(status)
-
-    def __iadd__(self, iterable):
-        # Python will raise a TypeError if there's anything wrong with
-        # the iterable protocol.
-        for elem in iterable:
-            self.append(elem)
-
-        return self
-
-    def __repr__(self):
-        return '[{}]'.format(', '.join([repr(v) for v in self]))
-
-    def insert(self, value):
-        raise NotImplementedError
-
-
-class _MapValueKeyIterator(collections.abc.Iterator):
-    def __init__(self, map_obj):
-        self._map_obj = map_obj
-        self._at = 0
-        keys_ptr = native_bt.value_map_get_keys(map_obj._ptr)
-
-        if keys_ptr is None:
-            raise RuntimeError('unexpected error: cannot get map value object keys')
-
-        self._keys = _create_from_ptr(keys_ptr)
-
-    def __next__(self):
-        if self._at == len(self._map_obj):
-            raise StopIteration
-
-        key = self._keys[self._at]
-        self._at += 1
-        return str(key)
-
-
-class MapValue(_Container, collections.abc.MutableMapping, _Value):
-    _NAME = 'Map'
-
-    def __init__(self, value=None):
-        ptr = native_bt.value_map_create()
-        self._check_create_status(ptr)
-        super().__init__(ptr)
-
-        # Python will raise a TypeError if there's anything wrong with
-        # the iterable/mapping protocol.
-        if value is not None:
-            for key, elem in value.items():
-                self[key] = elem
-
-    def __eq__(self, other):
-        return _Value.__eq__(self, other)
-
-    def __ne__(self, other):
-        return _Value.__ne__(self, other)
-
-    def _spec_eq(self, other):
-        try:
-            if len(self) != len(other):
-                # early mismatch
-                return False
-
-            for self_key in self:
-                if self_key not in other:
-                    return False
-
-                self_value = self[self_key]
-                other_value = other[self_key]
-
-                if self_value != other_value:
-                    return False
-
-            return True
-        except:
-            return
-
-    def __len__(self):
-        size = native_bt.value_map_get_size(self._ptr)
-        assert(size >= 0)
-        return size
-
-    def __contains__(self, key):
-        self._check_key_type(key)
-        return native_bt.value_map_has_entry(self._ptr, key)
-
-    def _check_key_type(self, key):
-        utils._check_str(key)
-
-    def _check_key(self, key):
-        if key not in self:
-            raise KeyError(key)
-
-    def __getitem__(self, key):
-        self._check_key(key)
-        ptr = native_bt.value_map_borrow_entry_value(self._ptr, key)
-        assert(ptr)
-        return _create_from_ptr_and_get_ref(ptr)
-
-    def __iter__(self):
-        return _MapValueKeyIterator(self)
-
-    def __setitem__(self, key, value):
-        self._check_key_type(key)
-        value = create_value(value)
-
-        if value is None:
-            ptr = native_bt.value_null
-        else:
-            ptr = value._ptr
-
-        status = native_bt.value_map_insert_entry(self._ptr, key, ptr)
-        self._handle_status(status)
-
-    def __repr__(self):
-        items = ['{}: {}'.format(repr(k), repr(v)) for k, v in self.items()]
-        return '{{{}}}'.format(', '.join(items))
-
-
-_TYPE_TO_OBJ = {
-    native_bt.VALUE_TYPE_BOOL: BoolValue,
-    native_bt.VALUE_TYPE_UNSIGNED_INTEGER: UnsignedIntegerValue,
-    native_bt.VALUE_TYPE_SIGNED_INTEGER: SignedIntegerValue,
-    native_bt.VALUE_TYPE_REAL: RealValue,
-    native_bt.VALUE_TYPE_STRING: StringValue,
-    native_bt.VALUE_TYPE_ARRAY: ArrayValue,
-    native_bt.VALUE_TYPE_MAP: MapValue,
-}
diff --git a/bindings/python/bt2/setup.py.in b/bindings/python/bt2/setup.py.in
deleted file mode 100644 (file)
index aeeac8f..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-# The MIT License (MIT)
-#
-# Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers@efficios.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-import sys
-
-from distutils.core import setup, Extension
-
-PY_PATH_WARN_MSG = """
--------------------------------------WARNING------------------------------------
-The install directory used:\n ({})\nis not included in your PYTHONPATH.
-
-To add this directory to your Python search path permanently you can add the
-following command to your .bashrc/.zshrc:
-    export PYTHONPATH="${{PYTHONPATH}}:{}"
---------------------------------------------------------------------------------
-"""
-
-def main():
-    babeltrace_ext = Extension('bt2._native_bt',
-                        sources=['bt2/native_bt.i', 'bt2/logging.c'],
-                        libraries=['babeltrace2', 'glib-2.0'],
-                        extra_objects=['@top_builddir@/logging/.libs/libbabeltrace2-logging.a',
-                            '@top_builddir@/common/.libs/libbabeltrace2-common.a'],)
-
-    dist = setup(name='bt2',
-            version='@PACKAGE_VERSION@',
-            description='Babeltrace 2 Python Bindings',
-            packages=['bt2'],
-            package_dir={'bt2': 'bt2'},
-            options={'build':
-                {
-                    'build_base': 'build',
-                    'build_lib': 'build/build_lib'
-                },
-                'build_ext':
-                {
-                    'build_lib': 'build/build_lib'
-                }
-            },
-            url='http://diamon.org/babeltrace',
-            ext_modules=[babeltrace_ext],
-            license='MIT',
-            classifiers=[
-                'Development Status :: 5 - Production/Stable',
-                'Intended Audience :: Developers',
-                'License :: OSI Approved :: The MIT License',
-                'Programming Language :: Python :: 3'
-                'Topic :: System :: Logging',
-                ])
-
-# After the installation, we check that the install directory is included in
-# the Python search path and we print a warning message when it's not.
-# We need to do this because Python search path differs depending on the distro
-# and some distros don't include any /usr/local/ in the search path. This is
-# also useful for out-of-tree installs and tests.
-# It's only relevant to make this check on the `install` command.
-
-    if 'install' in dist.command_obj:
-        install_dir = dist.command_obj['install'].install_libbase
-        if install_dir not in sys.path:
-            # We can't consider this an error because if affects every
-            # distro differently. We only warn the user that some
-            # extra configuration is needed to use the bindings
-            print(PY_PATH_WARN_MSG.format(install_dir, install_dir))
-
-if __name__ == "__main__":
-    main()
diff --git a/cli/Makefile.am b/cli/Makefile.am
deleted file mode 100644 (file)
index 6a7cc88..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-PLUGINS_PATH = $(abs_top_builddir)/plugins
-LTTNG_UTILS_PLUGIN_PATH =
-
-if ENABLE_DEBUG_INFO
-LTTNG_UTILS_PLUGIN_PATH += :$(PLUGINS_PATH)/lttng-utils
-endif
-
-if BABELTRACE_BUILD_WITH_MINGW
-IN_TREE_PLUGIN_PATH := $(shell cygpath -pm "$(PLUGINS_PATH)/ctf:$(PLUGINS_PATH)/text:$(PLUGINS_PATH)/utils$(LTTNG_UTILS_PLUGIN_PATH)")
-else
-IN_TREE_PLUGIN_PATH = $(PLUGINS_PATH)/ctf:$(PLUGINS_PATH)/text:$(PLUGINS_PATH)/utils$(LTTNG_UTILS_PLUGIN_PATH)
-endif
-
-AM_CPPFLAGS += '-DCONFIG_IN_TREE_PLUGIN_PATH="$(IN_TREE_PLUGIN_PATH)"'
-
-bin_PROGRAMS = babeltrace2.bin babeltrace2-log.bin
-noinst_PROGRAMS = babeltrace2 babeltrace2-log
-
-babeltrace2_bin_SOURCES = \
-       babeltrace2.c \
-       babeltrace2-cfg.c \
-       babeltrace2-cfg.h \
-       babeltrace2-cfg-cli-args.c \
-       babeltrace2-cfg-cli-args.h \
-       babeltrace2-cfg-cli-args-connect.c \
-       babeltrace2-cfg-cli-args-connect.h \
-       babeltrace2-cfg-cli-args-default.h \
-       babeltrace2-cfg-cli-args-default.c \
-       logging.c logging.h
-
-# -Wl,--no-as-needed is needed for recent gold linker who seems to think
-# it knows better and considers libraries with constructors having
-# side-effects as dead code.
-babeltrace2_bin_LDFLAGS = $(LD_NO_AS_NEEDED)
-
-# Add all the convenience libraries used by Babeltrace plugins and the
-# library. They will be used when embedding plugins (--enable-built-in-plugins),
-# otherwise we're looking after multiple definitions of the same symbols if
-# a plugin's archive (.a) includes the convenience library because
-# we're using --whole-archive below (needed to make sure the linker does
-# not discard the plugins since the CLI does not use their symbols
-# directly).
-babeltrace2_bin_LDADD = \
-       $(top_builddir)/lib/libbabeltrace2.la \
-       $(top_builddir)/compat/libcompat.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(POPT_LIBS)
-
-if ENABLE_BUILT_IN_PLUGINS
-# Takes a plugin name and outputs the needed LDFLAGS to embed it.
-#
-# The --whole-archive option is important here. From the GNU linker's
-# documentation:
-#
-#     For each archive mentioned on the command line after the
-#     --whole-archive option, include every object file in the archive in
-#     the link, rather than searching the archive for the required object
-#     files.
-#
-# In our case, we find the plugins thanks to special sections in the
-# binary that are filled by plugin objects. If the linker discards those
-# symbols because the CLI does not use them directly, the CLI reports
-# no plugins found (plugins are effectively not embedded).
-pluginarchive = $(LD_WHOLE_ARCHIVE)$(PLUGINS_PATH)/$(1)/.libs/babeltrace-plugin-$(1).a$(LD_NO_WHOLE_ARCHIVE)
-
-# Built-in plugins
-babeltrace2_bin_LDFLAGS += $(call pluginarchive,ctf)
-babeltrace2_bin_LDFLAGS += $(call pluginarchive,text)
-babeltrace2_bin_LDFLAGS += $(call pluginarchive,utils)
-
-if ENABLE_DEBUG_INFO
-babeltrace2_bin_LDFLAGS += $(call pluginarchive,lttng-utils)
-babeltrace2_bin_LDADD += $(ELFUTILS_LIBS)
-endif
-endif
-
-if BABELTRACE_BUILD_WITH_MINGW
-babeltrace2_bin_LDADD += -lws2_32 -lrpcrt4 -lintl -liconv -lole32 -lpthread
-endif
-
-# Only used for in-tree execution and tests
-babeltrace2_SOURCES = $(babeltrace2_bin_SOURCES)
-babeltrace2_LDFLAGS = $(babeltrace2_bin_LDFLAGS)
-babeltrace2_LDADD = $(babeltrace2_bin_LDADD)
-babeltrace2_CFLAGS = $(AM_CFLAGS) -DBT_SET_DEFAULT_IN_TREE_CONFIGURATION
-
-# babeltrace2-log rules and config below
-babeltrace2_log_bin_SOURCES = babeltrace2-log.c
-babeltrace2_log_bin_LDADD = \
-       $(top_builddir)/compat/libcompat.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(POPT_LIBS)
-babeltrace2_log_bin_CFLAGS = $(AM_CFLAGS) '-DBT_CLI_PATH="$(abs_top_builddir)/cli/babeltrace2$(EXEEXT)"'
-
-# Only used for in-tree execution and tests
-babeltrace2_log_SOURCES = $(babeltrace2_log_bin_SOURCES)
-babeltrace2_log_LDADD = $(babeltrace2_log_bin_LDADD)
-babeltrace2_log_CFLAGS = $(AM_CFLAGS) '-DBT_CLI_PATH="$(bindir)/babeltrace2$(EXEEXT)"'
diff --git a/cli/babeltrace2-cfg-cli-args-connect.c b/cli/babeltrace2-cfg-cli-args-connect.c
deleted file mode 100644 (file)
index f269ecc..0000000
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/common-internal.h>
-#include "babeltrace2-cfg.h"
-#include "babeltrace2-cfg-cli-args-connect.h"
-
-static bool all_named_and_printable_in_array(GPtrArray *comps)
-{
-       size_t i;
-       bool all_named_and_printable = true;
-
-       for (i = 0; i < comps->len; i++) {
-               struct bt_config_component *comp = g_ptr_array_index(comps, i);
-
-               if (comp->instance_name->len == 0) {
-                       all_named_and_printable = false;
-                       goto end;
-               }
-
-               if (!bt_common_string_is_printable(comp->instance_name->str)) {
-                       all_named_and_printable = false;
-                       goto end;
-               }
-       }
-
-end:
-       return all_named_and_printable;
-}
-
-static bool all_named_and_printable(struct bt_config *cfg)
-{
-       return all_named_and_printable_in_array(cfg->cmd_data.run.sources) &&
-               all_named_and_printable_in_array(cfg->cmd_data.run.filters) &&
-               all_named_and_printable_in_array(cfg->cmd_data.run.sinks);
-}
-
-static struct bt_config_connection *bt_config_connection_create(const char *arg)
-{
-       struct bt_config_connection *cfg_connection;
-
-       cfg_connection = g_new0(struct bt_config_connection, 1);
-       if (!cfg_connection) {
-               goto error;
-       }
-
-       cfg_connection->upstream_comp_name = g_string_new(NULL);
-       if (!cfg_connection->upstream_comp_name) {
-               goto error;
-       }
-
-       cfg_connection->downstream_comp_name = g_string_new(NULL);
-       if (!cfg_connection->downstream_comp_name) {
-               goto error;
-       }
-
-       cfg_connection->upstream_port_glob = g_string_new("*");
-       if (!cfg_connection->upstream_port_glob) {
-               goto error;
-       }
-
-       cfg_connection->downstream_port_glob = g_string_new("*");
-       if (!cfg_connection->downstream_port_glob) {
-               goto error;
-       }
-
-       cfg_connection->arg = g_string_new(arg);
-       if (!cfg_connection->arg) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       g_free(cfg_connection);
-       cfg_connection = NULL;
-
-end:
-       return cfg_connection;
-}
-
-static bool validate_port_glob(const char *port_glob)
-{
-       bool is_valid = true;
-       const char *ch = port_glob;
-
-       BT_ASSERT(port_glob);
-
-       while (*ch != '\0') {
-               switch (*ch) {
-               case '\\':
-                       switch (ch[1]) {
-                       case '\0':
-                               goto end;
-                       default:
-                               ch += 2;
-                               continue;
-                       }
-               case '?':
-               case '[':
-                       /*
-                        * This is reserved for future use, to support
-                        * full globbing patterns. Those characters must
-                        * be escaped with `\`.
-                        */
-                       is_valid = false;
-                       goto end;
-               default:
-                       ch++;
-                       break;
-               }
-       }
-
-end:
-       return is_valid;
-}
-
-static int normalize_glob_pattern(GString *glob_pattern_gs)
-{
-       int ret = 0;
-       char *glob_pattern = strdup(glob_pattern_gs->str);
-
-       if (!glob_pattern) {
-               ret = -1;
-               goto end;
-       }
-
-       bt_common_normalize_star_glob_pattern(glob_pattern);
-       g_string_assign(glob_pattern_gs, glob_pattern);
-       free(glob_pattern);
-
-end:
-       return ret;
-}
-
-static struct bt_config_connection *cfg_connection_from_arg(const char *arg)
-{
-       const char *at = arg;
-       size_t end_pos;
-       struct bt_config_connection *cfg_conn = NULL;
-       GString *gs = NULL;
-       enum {
-               UPSTREAM_NAME,
-               DOWNSTREAM_NAME,
-               UPSTREAM_PORT_GLOB,
-               DOWNSTREAM_PORT_GLOB,
-       } state = UPSTREAM_NAME;
-
-       if (!bt_common_string_is_printable(arg)) {
-               goto error;
-       }
-
-       cfg_conn = bt_config_connection_create(arg);
-       if (!cfg_conn) {
-               goto error;
-       }
-
-       while (true) {
-               switch (state) {
-               case UPSTREAM_NAME:
-                       gs = bt_common_string_until(at, ".:\\", ".:", &end_pos);
-                       if (!gs || gs->len == 0) {
-                               goto error;
-                       }
-
-                       g_string_free(cfg_conn->upstream_comp_name, TRUE);
-                       cfg_conn->upstream_comp_name = gs;
-                       gs = NULL;
-
-                       if (at[end_pos] == ':') {
-                               state = DOWNSTREAM_NAME;
-                       } else if (at[end_pos] == '.') {
-                               state = UPSTREAM_PORT_GLOB;
-                       } else {
-                               goto error;
-                       }
-
-                       at += end_pos + 1;
-                       break;
-               case DOWNSTREAM_NAME:
-                       gs = bt_common_string_until(at, ".:\\", ".:", &end_pos);
-                       if (!gs || gs->len == 0) {
-                               goto error;
-                       }
-
-                       g_string_free(cfg_conn->downstream_comp_name, TRUE);
-                       cfg_conn->downstream_comp_name = gs;
-                       gs = NULL;
-
-                       if (at[end_pos] == '.') {
-                               state = DOWNSTREAM_PORT_GLOB;
-                       } else if (at[end_pos] == '\0') {
-                               goto end;
-                       } else {
-                               goto error;
-                       }
-
-                       at += end_pos + 1;
-                       break;
-               case UPSTREAM_PORT_GLOB:
-                       gs = bt_common_string_until(at, ".:", ".:", &end_pos);
-                       if (!gs || gs->len == 0) {
-                               goto error;
-                       }
-
-                       if (!validate_port_glob(gs->str)) {
-                               goto error;
-                       }
-
-                       if (normalize_glob_pattern(gs)) {
-                               goto error;
-                       }
-
-                       g_string_free(cfg_conn->upstream_port_glob, TRUE);
-                       cfg_conn->upstream_port_glob = gs;
-                       gs = NULL;
-
-                       if (at[end_pos] == ':') {
-                               state = DOWNSTREAM_NAME;
-                       } else {
-                               goto error;
-                       }
-
-                       at += end_pos + 1;
-                       break;
-               case DOWNSTREAM_PORT_GLOB:
-                       gs = bt_common_string_until(at, ".:", ".:", &end_pos);
-                       if (!gs || gs->len == 0) {
-                               goto error;
-                       }
-
-                       if (!validate_port_glob(gs->str)) {
-                               goto error;
-                       }
-
-                       if (normalize_glob_pattern(gs)) {
-                               goto error;
-                       }
-
-                       g_string_free(cfg_conn->downstream_port_glob, TRUE);
-                       cfg_conn->downstream_port_glob = gs;
-                       gs = NULL;
-
-                       if (at[end_pos] == '\0') {
-                               goto end;
-                       } else {
-                               goto error;
-                       }
-                       break;
-               default:
-                       abort();
-               }
-       }
-
-error:
-       bt_config_connection_destroy(cfg_conn);
-       cfg_conn = NULL;
-
-end:
-       if (gs) {
-               g_string_free(gs, TRUE);
-       }
-
-       return cfg_conn;
-}
-
-static struct bt_config_component *find_component_in_array(GPtrArray *comps,
-               const char *name)
-{
-       size_t i;
-       struct bt_config_component *found_comp = NULL;
-
-       for (i = 0; i < comps->len; i++) {
-               struct bt_config_component *comp = g_ptr_array_index(comps, i);
-
-               if (strcmp(name, comp->instance_name->str) == 0) {
-                       found_comp = comp;
-                       bt_object_get_ref(found_comp);
-                       goto end;
-               }
-       }
-
-end:
-       return found_comp;
-}
-
-static struct bt_config_component *find_component(struct bt_config *cfg,
-               const char *name)
-{
-       struct bt_config_component *comp;
-
-       comp = find_component_in_array(cfg->cmd_data.run.sources, name);
-       if (comp) {
-               goto end;
-       }
-
-       comp = find_component_in_array(cfg->cmd_data.run.filters, name);
-       if (comp) {
-               goto end;
-       }
-
-       comp = find_component_in_array(cfg->cmd_data.run.sinks, name);
-       if (comp) {
-               goto end;
-       }
-
-end:
-       return comp;
-}
-
-static int validate_all_endpoints_exist(struct bt_config *cfg, char *error_buf,
-               size_t error_buf_size)
-{
-       size_t i;
-       int ret = 0;
-
-       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
-               struct bt_config_connection *connection =
-                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
-               struct bt_config_component *comp;
-
-               comp = find_component(cfg, connection->upstream_comp_name->str);
-               bt_object_put_ref(comp);
-               if (!comp) {
-                       snprintf(error_buf, error_buf_size,
-                               "Invalid connection: cannot find upstream component `%s`:\n    %s\n",
-                               connection->upstream_comp_name->str,
-                               connection->arg->str);
-                       ret = -1;
-                       goto end;
-               }
-
-               comp = find_component(cfg, connection->downstream_comp_name->str);
-               bt_object_put_ref(comp);
-               if (!comp) {
-                       snprintf(error_buf, error_buf_size,
-                               "Invalid connection: cannot find downstream component `%s`:\n    %s\n",
-                               connection->downstream_comp_name->str,
-                               connection->arg->str);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static int validate_connection_directions(struct bt_config *cfg,
-               char *error_buf, size_t error_buf_size)
-{
-       size_t i;
-       int ret = 0;
-       struct bt_config_component *src_comp = NULL;
-       struct bt_config_component *dst_comp = NULL;
-
-       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
-               struct bt_config_connection *connection =
-                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
-
-               src_comp = find_component(cfg,
-                       connection->upstream_comp_name->str);
-               BT_ASSERT(src_comp);
-               dst_comp = find_component(cfg,
-                       connection->downstream_comp_name->str);
-               BT_ASSERT(dst_comp);
-
-               if (src_comp->type == BT_COMPONENT_CLASS_TYPE_SOURCE) {
-                       if (dst_comp->type != BT_COMPONENT_CLASS_TYPE_FILTER &&
-                                       dst_comp->type != BT_COMPONENT_CLASS_TYPE_SINK) {
-                               snprintf(error_buf, error_buf_size,
-                                       "Invalid connection: source component `%s` not connected to filter or sink component:\n    %s\n",
-                                       connection->upstream_comp_name->str,
-                                       connection->arg->str);
-                               ret = -1;
-                               goto end;
-                       }
-               } else if (src_comp->type == BT_COMPONENT_CLASS_TYPE_FILTER) {
-                       if (dst_comp->type != BT_COMPONENT_CLASS_TYPE_FILTER &&
-                                       dst_comp->type != BT_COMPONENT_CLASS_TYPE_SINK) {
-                               snprintf(error_buf, error_buf_size,
-                                       "Invalid connection: filter component `%s` not connected to filter or sink component:\n    %s\n",
-                                       connection->upstream_comp_name->str,
-                                       connection->arg->str);
-                               ret = -1;
-                               goto end;
-                       }
-               } else {
-                       snprintf(error_buf, error_buf_size,
-                               "Invalid connection: cannot connect sink component `%s` to component `%s`:\n    %s\n",
-                               connection->upstream_comp_name->str,
-                               connection->downstream_comp_name->str,
-                               connection->arg->str);
-                       ret = -1;
-                       goto end;
-               }
-
-               BT_OBJECT_PUT_REF_AND_RESET(src_comp);
-               BT_OBJECT_PUT_REF_AND_RESET(dst_comp);
-       }
-
-end:
-       bt_object_put_ref(src_comp);
-       bt_object_put_ref(dst_comp);
-       return ret;
-}
-
-static int validate_no_cycles_rec(struct bt_config *cfg, GPtrArray *path,
-               char *error_buf, size_t error_buf_size)
-{
-       int ret = 0;
-       size_t conn_i;
-       const char *src_comp_name;
-
-       BT_ASSERT(path && path->len > 0);
-       src_comp_name = g_ptr_array_index(path, path->len - 1);
-
-       for (conn_i = 0; conn_i < cfg->cmd_data.run.connections->len; conn_i++) {
-               struct bt_config_connection *conn =
-                       g_ptr_array_index(cfg->cmd_data.run.connections, conn_i);
-
-               if (strcmp(conn->upstream_comp_name->str, src_comp_name) == 0) {
-                       size_t path_i;
-
-                       for (path_i = 0; path_i < path->len; path_i++) {
-                               const char *comp_name =
-                                       g_ptr_array_index(path, path_i);
-
-                               if (strcmp(comp_name, conn->downstream_comp_name->str) == 0) {
-                                       snprintf(error_buf, error_buf_size,
-                                               "Invalid connection: connection forms a cycle:\n    %s\n",
-                                               conn->arg->str);
-                                       ret = -1;
-                                       goto end;
-                               }
-                       }
-
-                       g_ptr_array_add(path, conn->downstream_comp_name->str);
-                       ret = validate_no_cycles_rec(cfg, path, error_buf,
-                                       error_buf_size);
-                       if (ret) {
-                               goto end;
-                       }
-
-                       g_ptr_array_remove_index(path, path->len - 1);
-               }
-       }
-
-end:
-       return ret;
-}
-
-static int validate_no_cycles(struct bt_config *cfg, char *error_buf,
-               size_t error_buf_size)
-{
-       size_t i;
-       int ret = 0;
-       GPtrArray *path;
-
-       path = g_ptr_array_new();
-       if (!path) {
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_add(path, NULL);
-
-       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
-               struct bt_config_connection *conn =
-                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
-
-               g_ptr_array_index(path, 0) = conn->upstream_comp_name->str;
-               ret = validate_no_cycles_rec(cfg, path,
-                       error_buf, error_buf_size);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       if (path) {
-               g_ptr_array_free(path, TRUE);
-       }
-
-       return ret;
-}
-
-static int validate_all_components_connected_in_array(GPtrArray *comps,
-               const bt_value *connected_components,
-               char *error_buf, size_t error_buf_size)
-{
-       int ret = 0;
-       size_t i;
-
-       for (i = 0; i < comps->len; i++) {
-               struct bt_config_component *comp = g_ptr_array_index(comps, i);
-
-               if (!bt_value_map_has_entry(connected_components,
-                               comp->instance_name->str)) {
-                       snprintf(error_buf, error_buf_size,
-                               "Component `%s` is not connected\n",
-                               comp->instance_name->str);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static int validate_all_components_connected(struct bt_config *cfg,
-               char *error_buf, size_t error_buf_size)
-{
-       size_t i;
-       int ret = 0;
-       bt_value *connected_components = bt_value_map_create();
-
-       if (!connected_components) {
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
-               struct bt_config_connection *connection =
-                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
-
-               ret = bt_value_map_insert_entry(connected_components,
-                       connection->upstream_comp_name->str, bt_value_null);
-               if (ret) {
-                       goto end;
-               }
-
-               ret = bt_value_map_insert_entry(connected_components,
-                       connection->downstream_comp_name->str, bt_value_null);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       ret = validate_all_components_connected_in_array(
-               cfg->cmd_data.run.sources,
-               connected_components,
-               error_buf, error_buf_size);
-       if (ret) {
-               goto end;
-       }
-
-       ret = validate_all_components_connected_in_array(
-               cfg->cmd_data.run.filters,
-               connected_components,
-               error_buf, error_buf_size);
-       if (ret) {
-               goto end;
-       }
-
-       ret = validate_all_components_connected_in_array(
-               cfg->cmd_data.run.sinks,
-               connected_components,
-               error_buf, error_buf_size);
-       if (ret) {
-               goto end;
-       }
-
-end:
-       bt_value_put_ref(connected_components);
-       return ret;
-}
-
-static int validate_no_duplicate_connection(struct bt_config *cfg,
-               char *error_buf, size_t error_buf_size)
-{
-       size_t i;
-       int ret = 0;
-       bt_value *flat_connection_names =
-               bt_value_map_create();
-       GString *flat_connection_name = NULL;
-
-       if (!flat_connection_names) {
-               ret = -1;
-               goto end;
-       }
-
-       flat_connection_name = g_string_new(NULL);
-       if (!flat_connection_name) {
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
-               struct bt_config_connection *connection =
-                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
-
-               g_string_printf(flat_connection_name, "%s\x01%s\x01%s\x01%s",
-                       connection->upstream_comp_name->str,
-                       connection->upstream_port_glob->str,
-                       connection->downstream_comp_name->str,
-                       connection->downstream_port_glob->str);
-
-               if (bt_value_map_has_entry(flat_connection_names,
-                                          flat_connection_name->str)) {
-                       snprintf(error_buf, error_buf_size,
-                               "Duplicate connection:\n    %s\n",
-                               connection->arg->str);
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = bt_value_map_insert_entry(flat_connection_names,
-                       flat_connection_name->str, bt_value_null);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       bt_value_put_ref(flat_connection_names);
-
-       if (flat_connection_name) {
-               g_string_free(flat_connection_name, TRUE);
-       }
-
-       return ret;
-}
-
-static int validate_connections(struct bt_config *cfg, char *error_buf,
-               size_t error_buf_size)
-{
-       int ret;
-
-       ret = validate_all_endpoints_exist(cfg, error_buf, error_buf_size);
-       if (ret) {
-               goto end;
-       }
-
-       ret = validate_connection_directions(cfg, error_buf, error_buf_size);
-       if (ret) {
-               goto end;
-       }
-
-       ret = validate_all_components_connected(cfg, error_buf, error_buf_size);
-       if (ret) {
-               goto end;
-       }
-
-       ret = validate_no_duplicate_connection(cfg, error_buf, error_buf_size);
-       if (ret) {
-               goto end;
-       }
-
-       ret = validate_no_cycles(cfg, error_buf, error_buf_size);
-       if (ret) {
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-int bt_config_cli_args_create_connections(struct bt_config *cfg,
-               const bt_value *connection_args,
-               char *error_buf, size_t error_buf_size)
-{
-       int ret;
-       size_t i;
-
-       if (!all_named_and_printable(cfg)) {
-               snprintf(error_buf, error_buf_size,
-                       "One or more components are unnamed (use --name) or contain a non-printable character\n");
-               goto error;
-       }
-
-       for (i = 0; i < bt_value_array_get_size(connection_args); i++) {
-               const bt_value *arg_value =
-                       bt_value_array_borrow_element_by_index_const(
-                               connection_args, i);
-               const char *arg;
-               struct bt_config_connection *cfg_connection;
-
-               arg = bt_value_string_get(arg_value);
-               cfg_connection = cfg_connection_from_arg(arg);
-               if (!cfg_connection) {
-                       snprintf(error_buf, error_buf_size, "Cannot parse --connect option's argument:\n    %s\n",
-                               arg);
-                       goto error;
-               }
-
-               g_ptr_array_add(cfg->cmd_data.run.connections,
-                       cfg_connection);
-       }
-
-
-       ret = validate_connections(cfg, error_buf, error_buf_size);
-       if (ret) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
diff --git a/cli/babeltrace2-cfg-cli-args-connect.h b/cli/babeltrace2-cfg-cli-args-connect.h
deleted file mode 100644 (file)
index 37799bb..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef CLI_BABELTRACE_CFG_CLI_ARGS_CONNECT_H
-#define CLI_BABELTRACE_CFG_CLI_ARGS_CONNECT_H
-
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <babeltrace2/value.h>
-#include <glib.h>
-#include "babeltrace2-cfg.h"
-
-int bt_config_cli_args_create_connections(struct bt_config *cfg,
-               const bt_value *connection_args,
-               char *error_buf, size_t error_buf_size);
-
-#endif /* CLI_BABELTRACE_CFG_CLI_ARGS_CONNECT_H */
diff --git a/cli/babeltrace2-cfg-cli-args-default.c b/cli/babeltrace2-cfg-cli-args-default.c
deleted file mode 100644 (file)
index aef23a5..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include "babeltrace2-cfg.h"
-#include "babeltrace2-cfg-cli-args.h"
-#include "babeltrace2-cfg-cli-args-default.h"
-
-#ifdef ENABLE_DEBUG_INFO
-# define BT_ENABLE_DEBUG_INFO  1
-#else
-# define BT_ENABLE_DEBUG_INFO  0
-#endif
-
-#ifdef BT_SET_DEFAULT_IN_TREE_CONFIGURATION
-
-struct bt_config *bt_config_cli_args_create_with_default(int argc,
-               const char *argv[], int *retcode)
-{
-       bt_value *initial_plugin_paths;
-       struct bt_config *cfg = NULL;
-       int ret;
-
-       initial_plugin_paths = bt_value_array_create();
-       if (!initial_plugin_paths) {
-               goto error;
-       }
-
-       ret = bt_config_append_plugin_paths(initial_plugin_paths,
-               CONFIG_IN_TREE_PLUGIN_PATH);
-       if (ret) {
-               goto error;
-       }
-
-       cfg = bt_config_cli_args_create(argc, argv, retcode, true, true,
-               initial_plugin_paths);
-       goto end;
-
-error:
-       *retcode = 1;
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       bt_value_put_ref(initial_plugin_paths);
-       return cfg;
-}
-
-#else /* BT_SET_DEFAULT_IN_TREE_CONFIGURATION */
-
-struct bt_config *bt_config_cli_args_create_with_default(int argc,
-               const char *argv[], int *retcode)
-{
-       return bt_config_cli_args_create(argc, argv, retcode, false, false,
-               NULL);
-}
-
-#endif /* BT_SET_DEFAULT_IN_TREE_CONFIGURATION */
diff --git a/cli/babeltrace2-cfg-cli-args-default.h b/cli/babeltrace2-cfg-cli-args-default.h
deleted file mode 100644 (file)
index 839b08c..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef CLI_BABELTRACE_CFG_CLI_ARGS_DEFAULT_H
-#define CLI_BABELTRACE_CFG_CLI_ARGS_DEFAULT_H
-
-/*
- * Babeltrace Trace Converter - Default Configuration
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "babeltrace2-cfg.h"
-
-struct bt_config *bt_config_cli_args_create_with_default(int argc,
-               const char *argv[], int *retcode);
-
-#endif /* CLI_BABELTRACE_CFG_CLI_ARGS_DEFAULT_H */
diff --git a/cli/babeltrace2-cfg-cli-args.c b/cli/babeltrace2-cfg-cli-args.c
deleted file mode 100644 (file)
index a042d89..0000000
+++ /dev/null
@@ -1,5107 +0,0 @@
-/*
- * Babeltrace trace converter - parameter parsing
- *
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CLI-CFG-CLI-ARGS"
-#include "logging.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <inttypes.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/common-internal.h>
-#include <popt.h>
-#include <glib.h>
-#include <sys/types.h>
-#include "babeltrace2-cfg.h"
-#include "babeltrace2-cfg-cli-args.h"
-#include "babeltrace2-cfg-cli-args-connect.h"
-#include "version.h"
-
-/*
- * Error printf() macro which prepends "Error: " the first time it's
- * called. This gives a nicer feel than having a bunch of error prefixes
- * (since the following lines usually describe the error and possible
- * solutions), or the error prefix just at the end.
- */
-#define printf_err(fmt, args...)                                       \
-       do {                                                            \
-               if (is_first_error) {                                   \
-                       fprintf(stderr, "Command line error: ");        \
-                       is_first_error = false;                         \
-               }                                                       \
-               fprintf(stderr, fmt, ##args);                           \
-       } while (0)
-
-static bool is_first_error = true;
-
-/* INI-style parsing FSM states */
-enum ini_parsing_fsm_state {
-       /* Expect a map key (identifier) */
-       INI_EXPECT_MAP_KEY,
-
-       /* Expect an equal character ('=') */
-       INI_EXPECT_EQUAL,
-
-       /* Expect a value */
-       INI_EXPECT_VALUE,
-
-       /* Expect a comma character (',') */
-       INI_EXPECT_COMMA,
-};
-
-/* INI-style parsing state variables */
-struct ini_parsing_state {
-       /* Lexical scanner (owned by this) */
-       GScanner *scanner;
-
-       /* Output map value object being filled (owned by this) */
-       bt_value *params;
-
-       /* Next expected FSM state */
-       enum ini_parsing_fsm_state expecting;
-
-       /* Last decoded map key (owned by this) */
-       char *last_map_key;
-
-       /* Complete INI-style string to parse (not owned by this) */
-       const char *arg;
-
-       /* Error buffer (not owned by this) */
-       GString *ini_error;
-};
-
-/* Offset option with "is set" boolean */
-struct offset_opt {
-       int64_t value;
-       bool is_set;
-};
-
-/* Legacy "ctf"/"lttng-live" format options */
-struct ctf_legacy_opts {
-       struct offset_opt offset_s;
-       struct offset_opt offset_ns;
-       bool stream_intersection;
-};
-
-/* Legacy "text" format options */
-struct text_legacy_opts {
-       /*
-        * output, dbg_info_dir, dbg_info_target_prefix, names,
-        * and fields are owned by this.
-        */
-       GString *output;
-       GString *dbg_info_dir;
-       GString *dbg_info_target_prefix;
-       const bt_value *names;
-       const bt_value *fields;
-
-       /* Flags */
-       bool no_delta;
-       bool clock_cycles;
-       bool clock_seconds;
-       bool clock_date;
-       bool clock_gmt;
-       bool dbg_info_full_path;
-       bool verbose;
-};
-
-/* Legacy input format format */
-enum legacy_input_format {
-       LEGACY_INPUT_FORMAT_NONE = 0,
-       LEGACY_INPUT_FORMAT_CTF,
-       LEGACY_INPUT_FORMAT_LTTNG_LIVE,
-};
-
-/* Legacy output format format */
-enum legacy_output_format {
-       LEGACY_OUTPUT_FORMAT_NONE = 0,
-       LEGACY_OUTPUT_FORMAT_TEXT,
-       LEGACY_OUTPUT_FORMAT_DUMMY,
-};
-
-/*
- * Prints the "out of memory" error.
- */
-static
-void print_err_oom(void)
-{
-       printf_err("Out of memory\n");
-}
-
-/*
- * Appends an "expecting token" error to the INI-style parsing state's
- * error buffer.
- */
-static
-void ini_append_error_expecting(struct ini_parsing_state *state,
-               GScanner *scanner, const char *expecting)
-{
-       size_t i;
-       size_t pos;
-
-       g_string_append_printf(state->ini_error, "Expecting %s:\n", expecting);
-
-       /* Only print error if there's one line */
-       if (strchr(state->arg, '\n') != NULL || strlen(state->arg) == 0) {
-               return;
-       }
-
-       g_string_append_printf(state->ini_error, "\n    %s\n", state->arg);
-       pos = g_scanner_cur_position(scanner) + 4;
-
-       if (!g_scanner_eof(scanner)) {
-               pos--;
-       }
-
-       for (i = 0; i < pos; ++i) {
-               g_string_append_printf(state->ini_error, " ");
-       }
-
-       g_string_append_printf(state->ini_error, "^\n\n");
-}
-
-/* Parse the next token as an unsigned integer. */
-static
-bt_value *ini_parse_uint(struct ini_parsing_state *state)
-{
-       bt_value *value = NULL;
-       GTokenType token_type = g_scanner_get_next_token(state->scanner);
-
-       if (token_type != G_TOKEN_INT) {
-               ini_append_error_expecting(state, state->scanner,
-                       "integer value");
-               goto end;
-       }
-
-       value = bt_value_unsigned_integer_create_init(
-               state->scanner->value.v_int64);
-
-end:
-       return value;
-}
-
-/* Parse the next token as a number and return its negation. */
-static
-bt_value *ini_parse_neg_number(struct ini_parsing_state *state)
-{
-       bt_value *value = NULL;
-       GTokenType token_type = g_scanner_get_next_token(state->scanner);
-
-       switch (token_type) {
-       case G_TOKEN_INT:
-       {
-               /* Negative integer */
-               uint64_t int_val = state->scanner->value.v_int64;
-
-               if (int_val > (((uint64_t) INT64_MAX) + 1)) {
-                       g_string_append_printf(state->ini_error,
-                               "Integer value -%" PRIu64 " is outside the range of a 64-bit signed integer\n",
-                               int_val);
-               } else {
-                       value = bt_value_signed_integer_create_init(
-                               -((int64_t) int_val));
-               }
-
-               break;
-       }
-       case G_TOKEN_FLOAT:
-               /* Negative floating point number */
-               value = bt_value_real_create_init(-state->scanner->value.v_float);
-               break;
-       default:
-               ini_append_error_expecting(state, state->scanner, "value");
-               break;
-       }
-
-       return value;
-}
-
-static bt_value *ini_parse_value(struct ini_parsing_state *state);
-
-/*
- * Parse the current and following tokens as an array.  Arrays are formatted as
- * an opening `[`, a list of comma-separated values and a closing `]`.  For
- * convenience we support an optional trailing comma, after the last value.
- *
- * The current token of the parser must be the opening square bracket of the
- * array.
- */
-static
-bt_value *ini_parse_array(struct ini_parsing_state *state)
-{
-       /* The [ character must have already been ingested. */
-       BT_ASSERT(g_scanner_cur_token(state->scanner) == G_TOKEN_CHAR);
-       BT_ASSERT(g_scanner_cur_value(state->scanner).v_char == '[');
-
-       bt_value *array_value;
-       GTokenType token_type;
-
-       array_value = bt_value_array_create ();
-       token_type = g_scanner_get_next_token(state->scanner);
-
-       /* While the current token is not a ]... */
-       while (!(token_type == G_TOKEN_CHAR && g_scanner_cur_value(state->scanner).v_char == ']')) {
-               /* Parse the item... */
-               bt_value *item_value;
-               bt_value_status status;
-
-               item_value = ini_parse_value(state);
-               if (!item_value) {
-                       goto error;
-               }
-
-               /* ... and add it to the result array. */
-               status = bt_value_array_append_element(array_value, item_value);
-               BT_VALUE_PUT_REF_AND_RESET(item_value);
-
-               if (status != BT_VALUE_STATUS_OK) {
-                       goto error;
-               }
-
-               /*
-                * Ingest the token following the value, it should be either a
-                * comma or closing square brace.
-                */
-               token_type = g_scanner_get_next_token(state->scanner);
-
-               if (token_type == G_TOKEN_CHAR && g_scanner_cur_value(state->scanner).v_char == ',') {
-                       /*
-                        * Ingest the token following the comma.  If it happens
-                        * to be a closing square bracket, we'll exit the loop
-                        * and we are done (we allow trailing commas).
-                        * Otherwise, we are ready for the next ini_parse_value call.
-                        */
-                       token_type = g_scanner_get_next_token(state->scanner);
-               } else if (token_type != G_TOKEN_CHAR || g_scanner_cur_value(state->scanner).v_char != ']') {
-                       ini_append_error_expecting(state, state->scanner, ", or ]");
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(array_value);
-
-end:
-       return array_value;
-}
-
-/*
- * Parse the current token (and the following ones if needed) as a value, return
- * it as a bt_value.
- */
-static
-bt_value *ini_parse_value(struct ini_parsing_state *state)
-{
-       bt_value *value = NULL;
-       GTokenType token_type = state->scanner->token;
-
-       switch (token_type) {
-       case G_TOKEN_CHAR:
-               if (state->scanner->value.v_char == '-') {
-                       /* Negative number */
-                       value = ini_parse_neg_number(state);
-               } else if (state->scanner->value.v_char == '+') {
-                       /* Unsigned integer */
-                       value = ini_parse_uint(state);
-               } else if (state->scanner->value.v_char == '[') {
-                       /* Array */
-                       value = ini_parse_array(state);
-               } else {
-                       ini_append_error_expecting(state, state->scanner, "value");
-               }
-               break;
-       case G_TOKEN_INT:
-       {
-               /* Positive, signed integer */
-               uint64_t int_val = state->scanner->value.v_int64;
-
-               if (int_val > INT64_MAX) {
-                       g_string_append_printf(state->ini_error,
-                               "Integer value %" PRIu64 " is outside the range of a 64-bit signed integer\n",
-                               int_val);
-               } else {
-                       value = bt_value_signed_integer_create_init(
-                               (int64_t) int_val);
-               }
-               break;
-       }
-       case G_TOKEN_FLOAT:
-               /* Positive floating point number */
-               value = bt_value_real_create_init(state->scanner->value.v_float);
-               break;
-       case G_TOKEN_STRING:
-               /* Quoted string */
-               value = bt_value_string_create_init(state->scanner->value.v_string);
-               break;
-       case G_TOKEN_IDENTIFIER:
-       {
-               /*
-                * Using symbols would be appropriate here,
-                * but said symbols are allowed as map key,
-                * so it's easier to consider everything an
-                * identifier.
-                *
-                * If one of the known symbols is not
-                * recognized here, then fall back to creating
-                * a string value.
-                */
-               const char *id = state->scanner->value.v_identifier;
-
-               if (!strcmp(id, "null") || !strcmp(id, "NULL") ||
-                               !strcmp(id, "nul")) {
-                       value = bt_value_null;
-               } else if (!strcmp(id, "true") || !strcmp(id, "TRUE") ||
-                               !strcmp(id, "yes") ||
-                               !strcmp(id, "YES")) {
-                       value = bt_value_bool_create_init(true);
-               } else if (!strcmp(id, "false") ||
-                               !strcmp(id, "FALSE") ||
-                               !strcmp(id, "no") ||
-                               !strcmp(id, "NO")) {
-                       value = bt_value_bool_create_init(false);
-               } else {
-                       value = bt_value_string_create_init(id);
-               }
-               break;
-       }
-       default:
-               /* Unset value variable will trigger the error */
-               ini_append_error_expecting(state, state->scanner, "value");
-               break;
-       }
-
-       return value;
-}
-
-static
-int ini_handle_state(struct ini_parsing_state *state)
-{
-       int ret = 0;
-       GTokenType token_type;
-       bt_value *value = NULL;
-
-       token_type = g_scanner_get_next_token(state->scanner);
-       if (token_type == G_TOKEN_EOF) {
-               if (state->expecting != INI_EXPECT_COMMA) {
-                       switch (state->expecting) {
-                       case INI_EXPECT_EQUAL:
-                               ini_append_error_expecting(state,
-                                       state->scanner, "'='");
-                               break;
-                       case INI_EXPECT_VALUE:
-                               ini_append_error_expecting(state,
-                                       state->scanner, "value");
-                               break;
-                       case INI_EXPECT_MAP_KEY:
-                               ini_append_error_expecting(state,
-                                       state->scanner, "unquoted map key");
-                               break;
-                       default:
-                               break;
-                       }
-                       goto error;
-               }
-
-               /* We're done! */
-               ret = 1;
-               goto success;
-       }
-
-       switch (state->expecting) {
-       case INI_EXPECT_MAP_KEY:
-               if (token_type != G_TOKEN_IDENTIFIER) {
-                       ini_append_error_expecting(state, state->scanner,
-                               "unquoted map key");
-                       goto error;
-               }
-
-               free(state->last_map_key);
-               state->last_map_key =
-                       strdup(state->scanner->value.v_identifier);
-               if (!state->last_map_key) {
-                       g_string_append(state->ini_error,
-                               "Out of memory\n");
-                       goto error;
-               }
-
-               if (bt_value_map_has_entry(state->params,
-                                          state->last_map_key)) {
-                       g_string_append_printf(state->ini_error,
-                               "Duplicate parameter key: `%s`\n",
-                               state->last_map_key);
-                       goto error;
-               }
-
-               state->expecting = INI_EXPECT_EQUAL;
-               goto success;
-       case INI_EXPECT_EQUAL:
-               if (token_type != G_TOKEN_CHAR) {
-                       ini_append_error_expecting(state,
-                               state->scanner, "'='");
-                       goto error;
-               }
-
-               if (state->scanner->value.v_char != '=') {
-                       ini_append_error_expecting(state,
-                               state->scanner, "'='");
-                       goto error;
-               }
-
-               state->expecting = INI_EXPECT_VALUE;
-               goto success;
-       case INI_EXPECT_VALUE:
-       {
-               value = ini_parse_value(state);
-               if (!value) {
-                       goto error;
-               }
-
-               state->expecting = INI_EXPECT_COMMA;
-               goto success;
-       }
-       case INI_EXPECT_COMMA:
-               if (token_type != G_TOKEN_CHAR) {
-                       ini_append_error_expecting(state,
-                               state->scanner, "','");
-                       goto error;
-               }
-
-               if (state->scanner->value.v_char != ',') {
-                       ini_append_error_expecting(state,
-                               state->scanner, "','");
-                       goto error;
-               }
-
-               state->expecting = INI_EXPECT_MAP_KEY;
-               goto success;
-       default:
-               abort();
-       }
-
-error:
-       ret = -1;
-       goto end;
-
-success:
-       if (value) {
-               if (bt_value_map_insert_entry(state->params,
-                               state->last_map_key, value)) {
-                       /* Only override return value on error */
-                       ret = -1;
-               }
-       }
-
-end:
-       BT_VALUE_PUT_REF_AND_RESET(value);
-       return ret;
-}
-
-/*
- * Converts an INI-style argument to an equivalent map value object.
- *
- * Return value is owned by the caller.
- */
-static
-bt_value *bt_value_from_ini(const char *arg,
-               GString *ini_error)
-{
-       /* Lexical scanner configuration */
-       GScannerConfig scanner_config = {
-               /* Skip whitespaces */
-               .cset_skip_characters = " \t\n",
-
-               /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
-               .cset_identifier_first =
-                       G_CSET_a_2_z
-                       "_"
-                       G_CSET_A_2_Z,
-               .cset_identifier_nth =
-                       G_CSET_a_2_z
-                       "_0123456789-.:"
-                       G_CSET_A_2_Z,
-
-               /* "hello" and "Hello" two different keys */
-               .case_sensitive = TRUE,
-
-               /* No comments */
-               .cpair_comment_single = NULL,
-               .skip_comment_multi = TRUE,
-               .skip_comment_single = TRUE,
-               .scan_comment_multi = FALSE,
-
-               /*
-                * Do scan identifiers, including 1-char identifiers,
-                * but NULL is a normal identifier.
-                */
-               .scan_identifier = TRUE,
-               .scan_identifier_1char = TRUE,
-               .scan_identifier_NULL = FALSE,
-
-               /*
-                * No specific symbols: null and boolean "symbols" are
-                * scanned as plain identifiers.
-                */
-               .scan_symbols = FALSE,
-               .symbol_2_token = FALSE,
-               .scope_0_fallback = FALSE,
-
-               /*
-                * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
-                * integers prefixed with "$".
-                */
-               .scan_binary = TRUE,
-               .scan_octal = TRUE,
-               .scan_float = TRUE,
-               .scan_hex = TRUE,
-               .scan_hex_dollar = FALSE,
-
-               /* Convert scanned numbers to integer tokens */
-               .numbers_2_int = TRUE,
-
-               /* Support both integers and floating-point numbers */
-               .int_2_float = FALSE,
-
-               /* Scan integers as 64-bit signed integers */
-               .store_int64 = TRUE,
-
-               /* Only scan double-quoted strings */
-               .scan_string_sq = FALSE,
-               .scan_string_dq = TRUE,
-
-               /* Do not converter identifiers to string tokens */
-               .identifier_2_string = FALSE,
-
-               /* Scan characters as G_TOKEN_CHAR token */
-               .char_2_token = FALSE,
-       };
-       struct ini_parsing_state state = {
-               .scanner = NULL,
-               .params = NULL,
-               .expecting = INI_EXPECT_MAP_KEY,
-               .arg = arg,
-               .ini_error = ini_error,
-       };
-
-       state.params = bt_value_map_create();
-       if (!state.params) {
-               goto error;
-       }
-
-       state.scanner = g_scanner_new(&scanner_config);
-       if (!state.scanner) {
-               goto error;
-       }
-
-       /* Let the scan begin */
-       g_scanner_input_text(state.scanner, arg, strlen(arg));
-
-       while (true) {
-               int ret = ini_handle_state(&state);
-
-               if (ret < 0) {
-                       /* Error */
-                       goto error;
-               } else if (ret > 0) {
-                       /* Done */
-                       break;
-               }
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(state.params);
-
-end:
-       if (state.scanner) {
-               g_scanner_destroy(state.scanner);
-       }
-
-       free(state.last_map_key);
-       return state.params;
-}
-
-/*
- * Returns the parameters map value object from a command-line
- * parameter option's argument.
- *
- * Return value is owned by the caller.
- */
-static
-bt_value *bt_value_from_arg(const char *arg)
-{
-       bt_value *params = NULL;
-       GString *ini_error = NULL;
-
-       ini_error = g_string_new(NULL);
-       if (!ini_error) {
-               print_err_oom();
-               goto end;
-       }
-
-       /* Try INI-style parsing */
-       params = bt_value_from_ini(arg, ini_error);
-       if (!params) {
-               printf_err("%s", ini_error->str);
-               goto end;
-       }
-
-end:
-       if (ini_error) {
-               g_string_free(ini_error, TRUE);
-       }
-
-       return params;
-}
-
-/*
- * Returns the plugin name, component class name, component class type,
- * and component name from a command-line --component option's argument.
- * arg must have the following format:
- *
- *     [NAME:]TYPE.PLUGIN.CLS
- *
- * where NAME is the optional component name, TYPE is either `source`,
- * `filter`, or `sink`, PLUGIN is the plugin name, and CLS is the
- * component class name.
- *
- * On success, both *plugin and *component are not NULL. *plugin
- * and *comp_cls are owned by the caller. On success, *name can be NULL
- * if no component class name was found, and *comp_cls_type is set.
- */
-static
-void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
-               char **comp_cls, bt_component_class_type *comp_cls_type)
-{
-       const char *at = arg;
-       GString *gs_name = NULL;
-       GString *gs_comp_cls_type = NULL;
-       GString *gs_plugin = NULL;
-       GString *gs_comp_cls = NULL;
-       size_t end_pos;
-
-       BT_ASSERT(arg);
-       BT_ASSERT(plugin);
-       BT_ASSERT(comp_cls);
-       BT_ASSERT(comp_cls_type);
-
-       if (!bt_common_string_is_printable(arg)) {
-               printf_err("Argument contains a non-printable character\n");
-               goto error;
-       }
-
-       /* Parse the component name */
-       gs_name = bt_common_string_until(at, ".:\\", ":", &end_pos);
-       if (!gs_name) {
-               goto error;
-       }
-
-       if (arg[end_pos] == ':') {
-               at += end_pos + 1;
-       } else {
-               /* No name */
-               g_string_assign(gs_name, "");
-       }
-
-       /* Parse the component class type */
-       gs_comp_cls_type = bt_common_string_until(at, ".:\\", ".", &end_pos);
-       if (!gs_comp_cls_type || at[end_pos] == '\0') {
-               printf_err("Missing component class type (`source`, `filter`, or `sink`)\n");
-               goto error;
-       }
-
-       if (strcmp(gs_comp_cls_type->str, "source") == 0 ||
-                       strcmp(gs_comp_cls_type->str, "src") == 0) {
-               *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SOURCE;
-       } else if (strcmp(gs_comp_cls_type->str, "filter") == 0 ||
-                       strcmp(gs_comp_cls_type->str, "flt") == 0) {
-               *comp_cls_type = BT_COMPONENT_CLASS_TYPE_FILTER;
-       } else if (strcmp(gs_comp_cls_type->str, "sink") == 0) {
-               *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SINK;
-       } else {
-               printf_err("Unknown component class type: `%s`\n",
-                       gs_comp_cls_type->str);
-               goto error;
-       }
-
-       at += end_pos + 1;
-
-       /* Parse the plugin name */
-       gs_plugin = bt_common_string_until(at, ".:\\", ".", &end_pos);
-       if (!gs_plugin || gs_plugin->len == 0 || at[end_pos] == '\0') {
-               printf_err("Missing plugin or component class name\n");
-               goto error;
-       }
-
-       at += end_pos + 1;
-
-       /* Parse the component class name */
-       gs_comp_cls = bt_common_string_until(at, ".:\\", ".", &end_pos);
-       if (!gs_comp_cls || gs_comp_cls->len == 0) {
-               printf_err("Missing component class name\n");
-               goto error;
-       }
-
-       if (at[end_pos] != '\0') {
-               /* Found a non-escaped `.` */
-               goto error;
-       }
-
-       if (name) {
-               if (gs_name->len == 0) {
-                       *name = NULL;
-                       g_string_free(gs_name, TRUE);
-               } else {
-                       *name = gs_name->str;
-                       g_string_free(gs_name, FALSE);
-               }
-       } else {
-               g_string_free(gs_name, TRUE);
-       }
-
-       *plugin = gs_plugin->str;
-       *comp_cls = gs_comp_cls->str;
-       g_string_free(gs_plugin, FALSE);
-       g_string_free(gs_comp_cls, FALSE);
-       gs_name = NULL;
-       gs_plugin = NULL;
-       gs_comp_cls = NULL;
-       goto end;
-
-error:
-       if (name) {
-               *name = NULL;
-       }
-
-       *plugin = NULL;
-       *comp_cls = NULL;
-
-end:
-       if (gs_name) {
-               g_string_free(gs_name, TRUE);
-       }
-
-       if (gs_plugin) {
-               g_string_free(gs_plugin, TRUE);
-       }
-
-       if (gs_comp_cls) {
-               g_string_free(gs_comp_cls, TRUE);
-       }
-
-       if (gs_comp_cls_type) {
-               g_string_free(gs_comp_cls_type, TRUE);
-       }
-
-       return;
-}
-
-/*
- * Prints the Babeltrace version.
- */
-static
-void print_version(void)
-{
-       if (GIT_VERSION[0] == '\0') {
-               puts("Babeltrace " VERSION);
-       } else {
-               puts("Babeltrace " VERSION  " - " GIT_VERSION);
-       }
-}
-
-/*
- * Destroys a component configuration.
- */
-static
-void bt_config_component_destroy(bt_object *obj)
-{
-       struct bt_config_component *bt_config_component =
-               container_of(obj, struct bt_config_component, base);
-
-       if (!obj) {
-               goto end;
-       }
-
-       if (bt_config_component->plugin_name) {
-               g_string_free(bt_config_component->plugin_name, TRUE);
-       }
-
-       if (bt_config_component->comp_cls_name) {
-               g_string_free(bt_config_component->comp_cls_name, TRUE);
-       }
-
-       if (bt_config_component->instance_name) {
-               g_string_free(bt_config_component->instance_name, TRUE);
-       }
-
-       BT_VALUE_PUT_REF_AND_RESET(bt_config_component->params);
-       g_free(bt_config_component);
-
-end:
-       return;
-}
-
-/*
- * Creates a component configuration using the given plugin name and
- * component name. `plugin_name` and `comp_cls_name` are copied (belong
- * to the return value).
- *
- * Return value is owned by the caller.
- */
-static
-struct bt_config_component *bt_config_component_create(
-               bt_component_class_type type,
-               const char *plugin_name, const char *comp_cls_name)
-{
-       struct bt_config_component *cfg_component = NULL;
-
-       cfg_component = g_new0(struct bt_config_component, 1);
-       if (!cfg_component) {
-               print_err_oom();
-               goto error;
-       }
-
-       bt_object_init_shared(&cfg_component->base,
-               bt_config_component_destroy);
-       cfg_component->type = type;
-       cfg_component->plugin_name = g_string_new(plugin_name);
-       if (!cfg_component->plugin_name) {
-               print_err_oom();
-               goto error;
-       }
-
-       cfg_component->comp_cls_name = g_string_new(comp_cls_name);
-       if (!cfg_component->comp_cls_name) {
-               print_err_oom();
-               goto error;
-       }
-
-       cfg_component->instance_name = g_string_new(NULL);
-       if (!cfg_component->instance_name) {
-               print_err_oom();
-               goto error;
-       }
-
-       /* Start with empty parameters */
-       cfg_component->params = bt_value_map_create();
-       if (!cfg_component->params) {
-               print_err_oom();
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg_component);
-
-end:
-       return cfg_component;
-}
-
-/*
- * Creates a component configuration from a command-line --component
- * option's argument.
- */
-static
-struct bt_config_component *bt_config_component_from_arg(const char *arg)
-{
-       struct bt_config_component *cfg_comp = NULL;
-       char *name = NULL;
-       char *plugin_name = NULL;
-       char *comp_cls_name = NULL;
-       bt_component_class_type type;
-
-       plugin_comp_cls_names(arg, &name, &plugin_name, &comp_cls_name, &type);
-       if (!plugin_name || !comp_cls_name) {
-               goto error;
-       }
-
-       cfg_comp = bt_config_component_create(type, plugin_name, comp_cls_name);
-       if (!cfg_comp) {
-               goto error;
-       }
-
-       if (name) {
-               g_string_assign(cfg_comp->instance_name, name);
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg_comp);
-
-end:
-       g_free(name);
-       g_free(plugin_name);
-       g_free(comp_cls_name);
-       return cfg_comp;
-}
-
-/*
- * Destroys a configuration.
- */
-static
-void bt_config_destroy(bt_object *obj)
-{
-       struct bt_config *cfg =
-               container_of(obj, struct bt_config, base);
-
-       if (!obj) {
-               goto end;
-       }
-
-       BT_VALUE_PUT_REF_AND_RESET(cfg->plugin_paths);
-
-       switch (cfg->command) {
-       case BT_CONFIG_COMMAND_RUN:
-               if (cfg->cmd_data.run.sources) {
-                       g_ptr_array_free(cfg->cmd_data.run.sources, TRUE);
-               }
-
-               if (cfg->cmd_data.run.filters) {
-                       g_ptr_array_free(cfg->cmd_data.run.filters, TRUE);
-               }
-
-               if (cfg->cmd_data.run.sinks) {
-                       g_ptr_array_free(cfg->cmd_data.run.sinks, TRUE);
-               }
-
-               if (cfg->cmd_data.run.connections) {
-                       g_ptr_array_free(cfg->cmd_data.run.connections,
-                               TRUE);
-               }
-               break;
-       case BT_CONFIG_COMMAND_LIST_PLUGINS:
-               break;
-       case BT_CONFIG_COMMAND_HELP:
-               BT_OBJECT_PUT_REF_AND_RESET(cfg->cmd_data.help.cfg_component);
-               break;
-       case BT_CONFIG_COMMAND_QUERY:
-               BT_OBJECT_PUT_REF_AND_RESET(cfg->cmd_data.query.cfg_component);
-
-               if (cfg->cmd_data.query.object) {
-                       g_string_free(cfg->cmd_data.query.object, TRUE);
-               }
-               break;
-       case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
-               if (cfg->cmd_data.print_ctf_metadata.path) {
-                       g_string_free(cfg->cmd_data.print_ctf_metadata.path,
-                               TRUE);
-                       g_string_free(
-                               cfg->cmd_data.print_ctf_metadata.output_path,
-                               TRUE);
-               }
-               break;
-       case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
-               if (cfg->cmd_data.print_lttng_live_sessions.url) {
-                       g_string_free(
-                               cfg->cmd_data.print_lttng_live_sessions.url,
-                               TRUE);
-                       g_string_free(
-                               cfg->cmd_data.print_lttng_live_sessions.output_path,
-                               TRUE);
-               }
-               break;
-       default:
-               abort();
-       }
-
-       g_free(cfg);
-
-end:
-       return;
-}
-
-static
-void destroy_glist_of_gstring(GList *list)
-{
-       GList *at;
-
-       if (!list) {
-               return;
-       }
-
-       for (at = list; at != NULL; at = g_list_next(at)) {
-               g_string_free(at->data, TRUE);
-       }
-
-       g_list_free(list);
-}
-
-/*
- * Creates a simple lexical scanner for parsing comma-delimited names
- * and fields.
- *
- * Return value is owned by the caller.
- */
-static
-GScanner *create_csv_identifiers_scanner(void)
-{
-       GScanner *scanner;
-       GScannerConfig scanner_config = {
-               .cset_skip_characters = " \t\n",
-               .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_",
-               .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-",
-               .case_sensitive = TRUE,
-               .cpair_comment_single = NULL,
-               .skip_comment_multi = TRUE,
-               .skip_comment_single = TRUE,
-               .scan_comment_multi = FALSE,
-               .scan_identifier = TRUE,
-               .scan_identifier_1char = TRUE,
-               .scan_identifier_NULL = FALSE,
-               .scan_symbols = FALSE,
-               .symbol_2_token = FALSE,
-               .scope_0_fallback = FALSE,
-               .scan_binary = FALSE,
-               .scan_octal = FALSE,
-               .scan_float = FALSE,
-               .scan_hex = FALSE,
-               .scan_hex_dollar = FALSE,
-               .numbers_2_int = FALSE,
-               .int_2_float = FALSE,
-               .store_int64 = FALSE,
-               .scan_string_sq = FALSE,
-               .scan_string_dq = FALSE,
-               .identifier_2_string = FALSE,
-               .char_2_token = TRUE,
-       };
-
-       scanner = g_scanner_new(&scanner_config);
-       if (!scanner) {
-               print_err_oom();
-       }
-
-       return scanner;
-}
-
-/*
- * Converts a comma-delimited list of known names (--names option) to
- * an array value object containing those names as string value objects.
- *
- * Return value is owned by the caller.
- */
-static
-bt_value *names_from_arg(const char *arg)
-{
-       GScanner *scanner = NULL;
-       bt_value *names = NULL;
-       bool found_all = false, found_none = false, found_item = false;
-
-       names = bt_value_array_create();
-       if (!names) {
-               print_err_oom();
-               goto error;
-       }
-
-       scanner = create_csv_identifiers_scanner();
-       if (!scanner) {
-               goto error;
-       }
-
-       g_scanner_input_text(scanner, arg, strlen(arg));
-
-       while (true) {
-               GTokenType token_type = g_scanner_get_next_token(scanner);
-
-               switch (token_type) {
-               case G_TOKEN_IDENTIFIER:
-               {
-                       const char *identifier = scanner->value.v_identifier;
-
-                       if (!strcmp(identifier, "payload") ||
-                                       !strcmp(identifier, "args") ||
-                                       !strcmp(identifier, "arg")) {
-                               found_item = true;
-                               if (bt_value_array_append_string_element(names,
-                                               "payload")) {
-                                       goto error;
-                               }
-                       } else if (!strcmp(identifier, "context") ||
-                                       !strcmp(identifier, "ctx")) {
-                               found_item = true;
-                               if (bt_value_array_append_string_element(names,
-                                               "context")) {
-                                       goto error;
-                               }
-                       } else if (!strcmp(identifier, "scope") ||
-                                       !strcmp(identifier, "header")) {
-                               found_item = true;
-                               if (bt_value_array_append_string_element(names,
-                                               identifier)) {
-                                       goto error;
-                               }
-                       } else if (!strcmp(identifier, "all")) {
-                               found_all = true;
-                               if (bt_value_array_append_string_element(names,
-                                               identifier)) {
-                                       goto error;
-                               }
-                       } else if (!strcmp(identifier, "none")) {
-                               found_none = true;
-                               if (bt_value_array_append_string_element(names,
-                                               identifier)) {
-                                       goto error;
-                               }
-                       } else {
-                               printf_err("Unknown name: `%s`\n",
-                                       identifier);
-                               goto error;
-                       }
-                       break;
-               }
-               case G_TOKEN_COMMA:
-                       continue;
-               case G_TOKEN_EOF:
-                       goto end;
-               default:
-                       goto error;
-               }
-       }
-
-end:
-       if (found_none && found_all) {
-               printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
-               goto error;
-       }
-       /*
-        * Legacy behavior is to clear the defaults (show none) when at
-        * least one item is specified.
-        */
-       if (found_item && !found_none && !found_all) {
-               if (bt_value_array_append_string_element(names, "none")) {
-                       goto error;
-               }
-       }
-       if (scanner) {
-               g_scanner_destroy(scanner);
-       }
-       return names;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(names);
-       if (scanner) {
-               g_scanner_destroy(scanner);
-       }
-       return names;
-}
-
-/*
- * Converts a comma-delimited list of known fields (--fields option) to
- * an array value object containing those fields as string
- * value objects.
- *
- * Return value is owned by the caller.
- */
-static
-bt_value *fields_from_arg(const char *arg)
-{
-       GScanner *scanner = NULL;
-       bt_value *fields;
-
-       fields = bt_value_array_create();
-       if (!fields) {
-               print_err_oom();
-               goto error;
-       }
-
-       scanner = create_csv_identifiers_scanner();
-       if (!scanner) {
-               goto error;
-       }
-
-       g_scanner_input_text(scanner, arg, strlen(arg));
-
-       while (true) {
-               GTokenType token_type = g_scanner_get_next_token(scanner);
-
-               switch (token_type) {
-               case G_TOKEN_IDENTIFIER:
-               {
-                       const char *identifier = scanner->value.v_identifier;
-
-                       if (!strcmp(identifier, "trace") ||
-                                       !strcmp(identifier, "trace:hostname") ||
-                                       !strcmp(identifier, "trace:domain") ||
-                                       !strcmp(identifier, "trace:procname") ||
-                                       !strcmp(identifier, "trace:vpid") ||
-                                       !strcmp(identifier, "loglevel") ||
-                                       !strcmp(identifier, "emf") ||
-                                       !strcmp(identifier, "callsite") ||
-                                       !strcmp(identifier, "all")) {
-                               if (bt_value_array_append_string_element(fields,
-                                               identifier)) {
-                                       goto error;
-                               }
-                       } else {
-                               printf_err("Unknown field: `%s`\n",
-                                       identifier);
-                               goto error;
-                       }
-                       break;
-               }
-               case G_TOKEN_COMMA:
-                       continue;
-               case G_TOKEN_EOF:
-                       goto end;
-               default:
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(fields);
-
-end:
-       if (scanner) {
-               g_scanner_destroy(scanner);
-       }
-       return fields;
-}
-
-static
-void append_param_arg(GString *params_arg, const char *key, const char *value)
-{
-       BT_ASSERT(params_arg);
-       BT_ASSERT(key);
-       BT_ASSERT(value);
-
-       if (params_arg->len != 0) {
-               g_string_append_c(params_arg, ',');
-       }
-
-       g_string_append(params_arg, key);
-       g_string_append_c(params_arg, '=');
-       g_string_append(params_arg, value);
-}
-
-/*
- * Inserts the equivalent "prefix-NAME=yes" strings into params_arg
- * where the names are in names_array.
- */
-static
-int insert_flat_params_from_array(GString *params_arg,
-               const bt_value *names_array, const char *prefix)
-{
-       int ret = 0;
-       int i;
-       GString *tmpstr = NULL, *default_value = NULL;
-       bool default_set = false, non_default_set = false;
-
-       /*
-        * names_array may be NULL if no CLI options were specified to
-        * trigger its creation.
-        */
-       if (!names_array) {
-               goto end;
-       }
-
-       tmpstr = g_string_new(NULL);
-       if (!tmpstr) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       default_value = g_string_new(NULL);
-       if (!default_value) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; i < bt_value_array_get_size(names_array); i++) {
-               const bt_value *str_obj =
-                       bt_value_array_borrow_element_by_index_const(names_array,
-                                                                    i);
-               const char *suffix;
-               bool is_default = false;
-
-               if (!str_obj) {
-                       printf_err("Unexpected error\n");
-                       ret = -1;
-                       goto end;
-               }
-
-               suffix = bt_value_string_get(str_obj);
-
-               g_string_assign(tmpstr, prefix);
-               g_string_append(tmpstr, "-");
-
-               /* Special-case for "all" and "none". */
-               if (!strcmp(suffix, "all")) {
-                       is_default = true;
-                       g_string_assign(default_value, "show");
-               } else if (!strcmp(suffix, "none")) {
-                       is_default = true;
-                       g_string_assign(default_value, "hide");
-               }
-               if (is_default) {
-                       default_set = true;
-                       g_string_append(tmpstr, "default");
-                       append_param_arg(params_arg, tmpstr->str,
-                               default_value->str);
-               } else {
-                       non_default_set = true;
-                       g_string_append(tmpstr, suffix);
-                       append_param_arg(params_arg, tmpstr->str, "yes");
-               }
-       }
-
-       /* Implicit field-default=hide if any non-default option is set. */
-       if (non_default_set && !default_set) {
-               g_string_assign(tmpstr, prefix);
-               g_string_append(tmpstr, "-default");
-               g_string_assign(default_value, "hide");
-               append_param_arg(params_arg, tmpstr->str, default_value->str);
-       }
-
-end:
-       if (default_value) {
-               g_string_free(default_value, TRUE);
-       }
-
-       if (tmpstr) {
-               g_string_free(tmpstr, TRUE);
-       }
-
-       return ret;
-}
-
-/* popt options */
-enum {
-       OPT_NONE = 0,
-       OPT_BASE_PARAMS,
-       OPT_BEGIN,
-       OPT_CLOCK_CYCLES,
-       OPT_CLOCK_DATE,
-       OPT_CLOCK_FORCE_CORRELATE,
-       OPT_CLOCK_GMT,
-       OPT_CLOCK_OFFSET,
-       OPT_CLOCK_OFFSET_NS,
-       OPT_CLOCK_SECONDS,
-       OPT_COLOR,
-       OPT_COMPONENT,
-       OPT_CONNECT,
-       OPT_DEBUG,
-       OPT_DEBUG_INFO,
-       OPT_DEBUG_INFO_DIR,
-       OPT_DEBUG_INFO_FULL_PATH,
-       OPT_DEBUG_INFO_TARGET_PREFIX,
-       OPT_END,
-       OPT_FIELDS,
-       OPT_HELP,
-       OPT_INPUT_FORMAT,
-       OPT_LIST,
-       OPT_NAME,
-       OPT_NAMES,
-       OPT_NO_DELTA,
-       OPT_OMIT_HOME_PLUGIN_PATH,
-       OPT_OMIT_SYSTEM_PLUGIN_PATH,
-       OPT_OUTPUT,
-       OPT_OUTPUT_FORMAT,
-       OPT_PARAMS,
-       OPT_PATH,
-       OPT_PLUGIN_PATH,
-       OPT_RESET_BASE_PARAMS,
-       OPT_RETRY_DURATION,
-       OPT_RUN_ARGS,
-       OPT_RUN_ARGS_0,
-       OPT_STREAM_INTERSECTION,
-       OPT_TIMERANGE,
-       OPT_URL,
-       OPT_VERBOSE,
-};
-
-enum bt_config_component_dest {
-       BT_CONFIG_COMPONENT_DEST_UNKNOWN = -1,
-       BT_CONFIG_COMPONENT_DEST_SOURCE,
-       BT_CONFIG_COMPONENT_DEST_FILTER,
-       BT_CONFIG_COMPONENT_DEST_SINK,
-};
-
-/*
- * Adds a configuration component to the appropriate configuration
- * array depending on the destination.
- */
-static
-void add_run_cfg_comp(struct bt_config *cfg,
-               struct bt_config_component *cfg_comp,
-               enum bt_config_component_dest dest)
-{
-       bt_object_get_ref(cfg_comp);
-
-       switch (dest) {
-       case BT_CONFIG_COMPONENT_DEST_SOURCE:
-               g_ptr_array_add(cfg->cmd_data.run.sources, cfg_comp);
-               break;
-       case BT_CONFIG_COMPONENT_DEST_FILTER:
-               g_ptr_array_add(cfg->cmd_data.run.filters, cfg_comp);
-               break;
-       case BT_CONFIG_COMPONENT_DEST_SINK:
-               g_ptr_array_add(cfg->cmd_data.run.sinks, cfg_comp);
-               break;
-       default:
-               abort();
-       }
-}
-
-static
-int add_run_cfg_comp_check_name(struct bt_config *cfg,
-               struct bt_config_component *cfg_comp,
-               enum bt_config_component_dest dest,
-               bt_value *instance_names)
-{
-       int ret = 0;
-
-       if (cfg_comp->instance_name->len == 0) {
-               printf_err("Found an unnamed component\n");
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_value_map_has_entry(instance_names,
-                                  cfg_comp->instance_name->str)) {
-               printf_err("Duplicate component instance name:\n    %s\n",
-                       cfg_comp->instance_name->str);
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_value_map_insert_entry(instance_names,
-                       cfg_comp->instance_name->str, bt_value_null)) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       add_run_cfg_comp(cfg, cfg_comp, dest);
-
-end:
-       return ret;
-}
-
-static
-int append_env_var_plugin_paths(bt_value *plugin_paths)
-{
-       int ret = 0;
-       const char *envvar;
-
-       if (bt_common_is_setuid_setgid()) {
-               BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
-               goto end;
-       }
-
-       envvar = getenv("BABELTRACE_PLUGIN_PATH");
-       if (!envvar) {
-               goto end;
-       }
-
-       ret = bt_config_append_plugin_paths(plugin_paths, envvar);
-
-end:
-       if (ret) {
-               printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
-       }
-
-       return ret;
-}
-
-static
-int append_home_and_system_plugin_paths(bt_value *plugin_paths,
-               bool omit_system_plugin_path, bool omit_home_plugin_path)
-{
-       int ret;
-
-       if (!omit_home_plugin_path) {
-               if (bt_common_is_setuid_setgid()) {
-                       BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
-               } else {
-                       char *home_plugin_dir =
-                               bt_common_get_home_plugin_path();
-
-                       if (home_plugin_dir) {
-                               ret = bt_config_append_plugin_paths(
-                                       plugin_paths, home_plugin_dir);
-                               free(home_plugin_dir);
-
-                               if (ret) {
-                                       printf_err("Invalid home plugin path\n");
-                                       goto error;
-                               }
-                       }
-               }
-       }
-
-       if (!omit_system_plugin_path) {
-               if (bt_config_append_plugin_paths(plugin_paths,
-                               bt_common_get_system_plugin_path())) {
-                       printf_err("Invalid system plugin path\n");
-                       goto error;
-               }
-       }
-       return 0;
-error:
-       printf_err("Cannot append home and system plugin paths\n");
-       return -1;
-}
-
-static
-int append_home_and_system_plugin_paths_cfg(struct bt_config *cfg)
-{
-       return append_home_and_system_plugin_paths(cfg->plugin_paths,
-               cfg->omit_system_plugin_path, cfg->omit_home_plugin_path);
-}
-
-static
-struct bt_config *bt_config_base_create(enum bt_config_command command,
-               const bt_value *initial_plugin_paths,
-               bool needs_plugins)
-{
-       struct bt_config *cfg;
-
-       /* Create config */
-       cfg = g_new0(struct bt_config, 1);
-       if (!cfg) {
-               print_err_oom();
-               goto error;
-       }
-
-       bt_object_init_shared(&cfg->base, bt_config_destroy);
-       cfg->command = command;
-       cfg->command_needs_plugins = needs_plugins;
-
-       if (initial_plugin_paths) {
-               bt_value *initial_plugin_paths_copy;
-
-               (void) bt_value_copy(initial_plugin_paths,
-                       &initial_plugin_paths_copy);
-               cfg->plugin_paths = initial_plugin_paths_copy;
-       } else {
-               cfg->plugin_paths = bt_value_array_create();
-               if (!cfg->plugin_paths) {
-                       print_err_oom();
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       return cfg;
-}
-
-static
-struct bt_config *bt_config_run_create(
-               const bt_value *initial_plugin_paths)
-{
-       struct bt_config *cfg;
-
-       /* Create config */
-       cfg = bt_config_base_create(BT_CONFIG_COMMAND_RUN,
-               initial_plugin_paths, true);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->cmd_data.run.sources = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_put_ref);
-       if (!cfg->cmd_data.run.sources) {
-               print_err_oom();
-               goto error;
-       }
-
-       cfg->cmd_data.run.filters = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_put_ref);
-       if (!cfg->cmd_data.run.filters) {
-               print_err_oom();
-               goto error;
-       }
-
-       cfg->cmd_data.run.sinks = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_put_ref);
-       if (!cfg->cmd_data.run.sinks) {
-               print_err_oom();
-               goto error;
-       }
-
-       cfg->cmd_data.run.connections = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_config_connection_destroy);
-       if (!cfg->cmd_data.run.connections) {
-               print_err_oom();
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       return cfg;
-}
-
-static
-struct bt_config *bt_config_list_plugins_create(
-               const bt_value *initial_plugin_paths)
-{
-       struct bt_config *cfg;
-
-       /* Create config */
-       cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS,
-               initial_plugin_paths, true);
-       if (!cfg) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       return cfg;
-}
-
-static
-struct bt_config *bt_config_help_create(
-               const bt_value *initial_plugin_paths)
-{
-       struct bt_config *cfg;
-
-       /* Create config */
-       cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP,
-               initial_plugin_paths, true);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->cmd_data.help.cfg_component =
-               bt_config_component_create(-1, NULL, NULL);
-       if (!cfg->cmd_data.help.cfg_component) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       return cfg;
-}
-
-static
-struct bt_config *bt_config_query_create(
-               const bt_value *initial_plugin_paths)
-{
-       struct bt_config *cfg;
-
-       /* Create config */
-       cfg = bt_config_base_create(BT_CONFIG_COMMAND_QUERY,
-               initial_plugin_paths, true);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->cmd_data.query.object = g_string_new(NULL);
-       if (!cfg->cmd_data.query.object) {
-               print_err_oom();
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       return cfg;
-}
-
-static
-struct bt_config *bt_config_print_ctf_metadata_create(
-               const bt_value *initial_plugin_paths)
-{
-       struct bt_config *cfg;
-
-       /* Create config */
-       cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_CTF_METADATA,
-               initial_plugin_paths, true);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->cmd_data.print_ctf_metadata.path = g_string_new(NULL);
-       if (!cfg->cmd_data.print_ctf_metadata.path) {
-               print_err_oom();
-               goto error;
-       }
-
-       cfg->cmd_data.print_ctf_metadata.output_path = g_string_new(NULL);
-       if (!cfg->cmd_data.print_ctf_metadata.output_path) {
-               print_err_oom();
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       return cfg;
-}
-
-static
-struct bt_config *bt_config_print_lttng_live_sessions_create(
-               const bt_value *initial_plugin_paths)
-{
-       struct bt_config *cfg;
-
-       /* Create config */
-       cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS,
-               initial_plugin_paths, true);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->cmd_data.print_lttng_live_sessions.url = g_string_new(NULL);
-       if (!cfg->cmd_data.print_lttng_live_sessions.url) {
-               print_err_oom();
-               goto error;
-       }
-
-       cfg->cmd_data.print_lttng_live_sessions.output_path =
-               g_string_new(NULL);
-       if (!cfg->cmd_data.print_lttng_live_sessions.output_path) {
-               print_err_oom();
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       return cfg;
-}
-
-static
-int bt_config_append_plugin_paths_check_setuid_setgid(
-               bt_value *plugin_paths, const char *arg)
-{
-       int ret = 0;
-
-       if (bt_common_is_setuid_setgid()) {
-               BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
-               goto end;
-       }
-
-       if (bt_config_append_plugin_paths(plugin_paths, arg)) {
-               printf_err("Invalid --plugin-path option's argument:\n    %s\n",
-                       arg);
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Prints the expected format for a --params option.
- */
-static
-void print_expected_params_format(FILE *fp)
-{
-       fprintf(fp, "Expected format of PARAMS\n");
-       fprintf(fp, "-------------------------\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "    PARAM=VALUE[,PARAM=VALUE]...\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
-       fprintf(fp, "where PARAM is the parameter name (C identifier plus the [:.-] characters),\n");
-       fprintf(fp, "and VALUE can be one of:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
-       fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
-       fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
-       fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
-       fprintf(fp, "  (`0x` prefix) unsigned (with `+` prefix) or signed 64-bit integer.\n");
-       fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
-       fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
-       fprintf(fp, "  the null and boolean value symbols above.\n");
-       fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
-       fprintf(fp, "* Array, formatted as an opening `[`, a list of comma-separated values\n");
-       fprintf(fp, "  (as described by the current list) and a closing `]`.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "You can put whitespaces allowed around individual `=` and `,` symbols.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Example:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "    many=null, fresh=yes, condition=false, squirrel=-782329,\n");
-       fprintf(fp, "    play=+23, observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
-       fprintf(fp, "    escape.chars-are:allowed=\"this is a \\\" double quote\",\n");
-       fprintf(fp, "    things=[1, \"2\", 3]\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run\n");
-       fprintf(fp, "babeltrace2 from a shell.\n");
-}
-
-
-/*
- * Prints the help command usage.
- */
-static
-void print_help_usage(FILE *fp)
-{
-       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
-       fprintf(fp, "       babeltrace2 [GENERAL OPTIONS] help [OPTIONS] TYPE.PLUGIN.CLS\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
-       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
-       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
-       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
-       fprintf(fp, "                                    dynamic plugins can be loaded\n");
-       fprintf(fp, "  -h, --help                        Show this help and quit\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Use `babeltrace2 list-plugins` to show the list of available plugins.\n");
-}
-
-static
-struct poptOption help_long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
-       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
-       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
-       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
-       { NULL, 0, '\0', NULL, 0, NULL, NULL },
-};
-
-/*
- * Creates a Babeltrace config object from the arguments of a help
- * command.
- *
- * *retcode is set to the appropriate exit code to use.
- */
-static
-struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
-               int *retcode, bool force_omit_system_plugin_path,
-               bool force_omit_home_plugin_path,
-               const bt_value *initial_plugin_paths)
-{
-       poptContext pc = NULL;
-       char *arg = NULL;
-       int opt;
-       int ret;
-       struct bt_config *cfg = NULL;
-       const char *leftover;
-       char *plugin_name = NULL, *comp_cls_name = NULL;
-
-       *retcode = 0;
-       cfg = bt_config_help_create(initial_plugin_paths);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->omit_system_plugin_path = force_omit_system_plugin_path;
-       cfg->omit_home_plugin_path = force_omit_home_plugin_path;
-       ret = append_env_var_plugin_paths(cfg->plugin_paths);
-       if (ret) {
-               goto error;
-       }
-
-       /* Parse options */
-       pc = poptGetContext(NULL, argc, (const char **) argv,
-               help_long_options, 0);
-       if (!pc) {
-               printf_err("Cannot get popt context\n");
-               goto error;
-       }
-
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) > 0) {
-               arg = poptGetOptArg(pc);
-
-               switch (opt) {
-               case OPT_PLUGIN_PATH:
-                       if (bt_config_append_plugin_paths_check_setuid_setgid(
-                                       cfg->plugin_paths, arg)) {
-                               goto error;
-                       }
-                       break;
-               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
-                       cfg->omit_system_plugin_path = true;
-                       break;
-               case OPT_OMIT_HOME_PLUGIN_PATH:
-                       cfg->omit_home_plugin_path = true;
-                       break;
-               case OPT_HELP:
-                       print_help_usage(stdout);
-                       *retcode = -1;
-                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-                       goto end;
-               default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
-                               opt);
-                       goto error;
-               }
-
-               free(arg);
-               arg = NULL;
-       }
-
-       /* Check for option parsing error */
-       if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
-                       poptBadOption(pc, 0), poptStrerror(opt));
-               goto error;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               plugin_comp_cls_names(leftover, NULL,
-                       &plugin_name, &comp_cls_name,
-                       &cfg->cmd_data.help.cfg_component->type);
-               if (plugin_name && comp_cls_name) {
-                       /* Component class help */
-                       g_string_assign(
-                               cfg->cmd_data.help.cfg_component->plugin_name,
-                               plugin_name);
-                       g_string_assign(
-                               cfg->cmd_data.help.cfg_component->comp_cls_name,
-                               comp_cls_name);
-               } else {
-                       /* Fall back to plugin help */
-                       g_string_assign(
-                               cfg->cmd_data.help.cfg_component->plugin_name,
-                               leftover);
-               }
-       } else {
-               print_help_usage(stdout);
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
-       }
-
-       if (append_home_and_system_plugin_paths_cfg(cfg)) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       *retcode = 1;
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       g_free(plugin_name);
-       g_free(comp_cls_name);
-
-       if (pc) {
-               poptFreeContext(pc);
-       }
-
-       free(arg);
-       return cfg;
-}
-
-/*
- * Prints the help command usage.
- */
-static
-void print_query_usage(FILE *fp)
-{
-       fprintf(fp, "Usage: babeltrace2 [GEN OPTS] query [OPTS] TYPE.PLUGIN.CLS OBJECT\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
-       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
-       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
-       fprintf(fp, "  -p, --params=PARAMS               Set the query parameters to PARAMS\n");
-       fprintf(fp, "                                    (see the expected format of PARAMS below)\n");
-       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
-       fprintf(fp, "                                    dynamic plugins can be loaded\n");
-       fprintf(fp, "  -h, --help                        Show this help and quit\n");
-       fprintf(fp, "\n\n");
-       print_expected_params_format(fp);
-}
-
-static
-struct poptOption query_long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
-       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
-       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
-       { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
-       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
-       { NULL, 0, '\0', NULL, 0, NULL, NULL },
-};
-
-/*
- * Creates a Babeltrace config object from the arguments of a query
- * command.
- *
- * *retcode is set to the appropriate exit code to use.
- */
-static
-struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
-               int *retcode, bool force_omit_system_plugin_path,
-               bool force_omit_home_plugin_path,
-               const bt_value *initial_plugin_paths)
-{
-       poptContext pc = NULL;
-       char *arg = NULL;
-       int opt;
-       int ret;
-       struct bt_config *cfg = NULL;
-       const char *leftover;
-       bt_value *params;
-
-       params = bt_value_null;
-       bt_value_get_ref(bt_value_null);
-
-       *retcode = 0;
-       cfg = bt_config_query_create(initial_plugin_paths);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->omit_system_plugin_path = force_omit_system_plugin_path;
-       cfg->omit_home_plugin_path = force_omit_home_plugin_path;
-       ret = append_env_var_plugin_paths(cfg->plugin_paths);
-       if (ret) {
-               goto error;
-       }
-
-       /* Parse options */
-       pc = poptGetContext(NULL, argc, (const char **) argv,
-               query_long_options, 0);
-       if (!pc) {
-               printf_err("Cannot get popt context\n");
-               goto error;
-       }
-
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) > 0) {
-               arg = poptGetOptArg(pc);
-
-               switch (opt) {
-               case OPT_PLUGIN_PATH:
-                       if (bt_config_append_plugin_paths_check_setuid_setgid(
-                                       cfg->plugin_paths, arg)) {
-                               goto error;
-                       }
-                       break;
-               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
-                       cfg->omit_system_plugin_path = true;
-                       break;
-               case OPT_OMIT_HOME_PLUGIN_PATH:
-                       cfg->omit_home_plugin_path = true;
-                       break;
-               case OPT_PARAMS:
-               {
-                       bt_value_put_ref(params);
-                       params = bt_value_from_arg(arg);
-                       if (!params) {
-                               printf_err("Invalid format for --params option's argument:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-                       break;
-               }
-               case OPT_HELP:
-                       print_query_usage(stdout);
-                       *retcode = -1;
-                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-                       goto end;
-               default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
-                               opt);
-                       goto error;
-               }
-
-               free(arg);
-               arg = NULL;
-       }
-
-       /* Check for option parsing error */
-       if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
-                       poptBadOption(pc, 0), poptStrerror(opt));
-               goto error;
-       }
-
-       /*
-        * We need exactly two leftover arguments which are the
-        * mandatory component class specification and query object.
-        */
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               cfg->cmd_data.query.cfg_component =
-                       bt_config_component_from_arg(leftover);
-               if (!cfg->cmd_data.query.cfg_component) {
-                       printf_err("Invalid format for component class specification:\n    %s\n",
-                               leftover);
-                       goto error;
-               }
-
-               BT_ASSERT(params);
-               BT_OBJECT_MOVE_REF(cfg->cmd_data.query.cfg_component->params,
-                       params);
-       } else {
-               print_query_usage(stdout);
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               if (strlen(leftover) == 0) {
-                       printf_err("Invalid empty object\n");
-                       goto error;
-               }
-
-               g_string_assign(cfg->cmd_data.query.object, leftover);
-       } else {
-               print_query_usage(stdout);
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               printf_err("Unexpected argument: %s\n", leftover);
-               goto error;
-       }
-
-       if (append_home_and_system_plugin_paths_cfg(cfg)) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       *retcode = 1;
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       if (pc) {
-               poptFreeContext(pc);
-       }
-
-       bt_value_put_ref(params);
-       free(arg);
-       return cfg;
-}
-
-/*
- * Prints the list-plugins command usage.
- */
-static
-void print_list_plugins_usage(FILE *fp)
-{
-       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
-       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
-       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
-       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
-       fprintf(fp, "                                    dynamic plugins can be loaded\n");
-       fprintf(fp, "  -h, --help                        Show this help and quit\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Use `babeltrace2 help` to get help for a specific plugin or component class.\n");
-}
-
-static
-struct poptOption list_plugins_long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
-       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
-       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
-       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
-       { NULL, 0, '\0', NULL, 0, NULL, NULL },
-};
-
-/*
- * Creates a Babeltrace config object from the arguments of a
- * list-plugins command.
- *
- * *retcode is set to the appropriate exit code to use.
- */
-static
-struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
-               int *retcode, bool force_omit_system_plugin_path,
-               bool force_omit_home_plugin_path,
-               const bt_value *initial_plugin_paths)
-{
-       poptContext pc = NULL;
-       char *arg = NULL;
-       int opt;
-       int ret;
-       struct bt_config *cfg = NULL;
-       const char *leftover;
-
-       *retcode = 0;
-       cfg = bt_config_list_plugins_create(initial_plugin_paths);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->omit_system_plugin_path = force_omit_system_plugin_path;
-       cfg->omit_home_plugin_path = force_omit_home_plugin_path;
-       ret = append_env_var_plugin_paths(cfg->plugin_paths);
-       if (ret) {
-               goto error;
-       }
-
-       /* Parse options */
-       pc = poptGetContext(NULL, argc, (const char **) argv,
-               list_plugins_long_options, 0);
-       if (!pc) {
-               printf_err("Cannot get popt context\n");
-               goto error;
-       }
-
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) > 0) {
-               arg = poptGetOptArg(pc);
-
-               switch (opt) {
-               case OPT_PLUGIN_PATH:
-                       if (bt_config_append_plugin_paths_check_setuid_setgid(
-                                       cfg->plugin_paths, arg)) {
-                               goto error;
-                       }
-                       break;
-               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
-                       cfg->omit_system_plugin_path = true;
-                       break;
-               case OPT_OMIT_HOME_PLUGIN_PATH:
-                       cfg->omit_home_plugin_path = true;
-                       break;
-               case OPT_HELP:
-                       print_list_plugins_usage(stdout);
-                       *retcode = -1;
-                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-                       goto end;
-               default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
-                               opt);
-                       goto error;
-               }
-
-               free(arg);
-               arg = NULL;
-       }
-
-       /* Check for option parsing error */
-       if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
-                       poptBadOption(pc, 0), poptStrerror(opt));
-               goto error;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               printf_err("Unexpected argument: %s\n", leftover);
-               goto error;
-       }
-
-       if (append_home_and_system_plugin_paths_cfg(cfg)) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       *retcode = 1;
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       if (pc) {
-               poptFreeContext(pc);
-       }
-
-       free(arg);
-       return cfg;
-}
-
-/*
- * Prints the run command usage.
- */
-static
-void print_run_usage(FILE *fp)
-{
-       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] run [OPTIONS]\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "  -b, --base-params=PARAMS          Set PARAMS as the current base parameters\n");
-       fprintf(fp, "                                    for all the following components until\n");
-       fprintf(fp, "                                    --reset-base-params is encountered\n");
-       fprintf(fp, "                                    (see the expected format of PARAMS below)\n");
-       fprintf(fp, "  -c, --component=[NAME:]TYPE.PLUGIN.CLS\n");
-       fprintf(fp, "                                    Instantiate the component class CLS of type\n");
-       fprintf(fp, "                                    TYPE (`source`, `filter`, or `sink`) found\n");
-       fprintf(fp, "                                    in the plugin PLUGIN, add it to the graph,\n");
-       fprintf(fp, "                                    and optionally name it NAME (you can also\n");
-       fprintf(fp, "                                    specify the name with --name)\n");
-       fprintf(fp, "  -x, --connect=CONNECTION          Connect two created components (see the\n");
-       fprintf(fp, "                                    expected format of CONNECTION below)\n");
-       fprintf(fp, "  -n, --name=NAME                   Set the name of the current component\n");
-       fprintf(fp, "                                    to NAME (must be unique amongst all the\n");
-       fprintf(fp, "                                    names of the created components)\n");
-       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
-       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
-       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
-       fprintf(fp, "  -p, --params=PARAMS               Add initialization parameters PARAMS to the\n");
-       fprintf(fp, "                                    current component (see the expected format\n");
-       fprintf(fp, "                                    of PARAMS below)\n");
-       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
-       fprintf(fp, "                                    dynamic plugins can be loaded\n");
-       fprintf(fp, "  -r, --reset-base-params           Reset the current base parameters to an\n");
-       fprintf(fp, "                                    empty map\n");
-       fprintf(fp, "      --retry-duration=DUR          When babeltrace2(1) needs to retry to run\n");
-       fprintf(fp, "                                    the graph later, retry in DUR µs\n");
-       fprintf(fp, "                                    (default: 100000)\n");
-       fprintf(fp, "  -h, --help                        Show this help and quit\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
-       fprintf(fp, "\n\n");
-       fprintf(fp, "Expected format of CONNECTION\n");
-       fprintf(fp, "-----------------------------\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "    UPSTREAM[.UPSTREAM-PORT]:DOWNSTREAM[.DOWNSTREAM-PORT]\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "UPSTREAM and DOWNSTREAM are names of the upstream and downstream\n");
-       fprintf(fp, "components to connect together. You must escape the following characters\n\n");
-       fprintf(fp, "with `\\`: `\\`, `.`, and `:`. You can set the name of the current\n");
-       fprintf(fp, "component with the --name option.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "UPSTREAM-PORT and DOWNSTREAM-PORT are optional globbing patterns to\n");
-       fprintf(fp, "identify the upstream and downstream ports to use for the connection.\n");
-       fprintf(fp, "When the port is not specified, `*` is used.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "When a component named UPSTREAM has an available port which matches the\n");
-       fprintf(fp, "UPSTREAM-PORT globbing pattern, it is connected to the first port which\n");
-       fprintf(fp, "matches the DOWNSTREAM-PORT globbing pattern of the component named\n");
-       fprintf(fp, "DOWNSTREAM.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "The only special character in UPSTREAM-PORT and DOWNSTREAM-PORT is `*`\n");
-       fprintf(fp, "which matches anything. You must escape the following characters\n");
-       fprintf(fp, "with `\\`: `\\`, `*`, `?`, `[`, `.`, and `:`.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "You can connect a source component to a filter or sink component. You\n");
-       fprintf(fp, "can connect a filter component to a sink component.\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Examples:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "    my-src:my-sink\n");
-       fprintf(fp, "    ctf-fs.*stream*:utils-muxer:*\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run\n");
-       fprintf(fp, "babeltrace2 from a shell.\n");
-       fprintf(fp, "\n\n");
-       print_expected_params_format(fp);
-}
-
-/*
- * Creates a Babeltrace config object from the arguments of a run
- * command.
- *
- * *retcode is set to the appropriate exit code to use.
- */
-static
-struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
-               int *retcode, bool force_omit_system_plugin_path,
-               bool force_omit_home_plugin_path,
-               const bt_value *initial_plugin_paths)
-{
-       poptContext pc = NULL;
-       char *arg = NULL;
-       struct bt_config_component *cur_cfg_comp = NULL;
-       enum bt_config_component_dest cur_cfg_comp_dest =
-                       BT_CONFIG_COMPONENT_DEST_UNKNOWN;
-       bt_value *cur_base_params = NULL;
-       int opt, ret = 0;
-       struct bt_config *cfg = NULL;
-       bt_value *instance_names = NULL;
-       bt_value *connection_args = NULL;
-       char error_buf[256] = { 0 };
-       long retry_duration = -1;
-       bt_value_status status;
-       struct poptOption run_long_options[] = {
-               { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
-               { "component", 'c', POPT_ARG_STRING, NULL, OPT_COMPONENT, NULL, NULL },
-               { "connect", 'x', POPT_ARG_STRING, NULL, OPT_CONNECT, NULL, NULL },
-               { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
-               { "name", 'n', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL },
-               { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
-               { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
-               { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
-               { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
-               { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
-               { "retry-duration", '\0', POPT_ARG_LONG, &retry_duration, OPT_RETRY_DURATION, NULL, NULL },
-               { NULL, 0, '\0', NULL, 0, NULL, NULL },
-       };
-
-       *retcode = 0;
-
-       if (argc <= 1) {
-               print_run_usage(stdout);
-               *retcode = -1;
-               goto end;
-       }
-
-       cfg = bt_config_run_create(initial_plugin_paths);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->cmd_data.run.retry_duration_us = 100000;
-       cfg->omit_system_plugin_path = force_omit_system_plugin_path;
-       cfg->omit_home_plugin_path = force_omit_home_plugin_path;
-       cur_base_params = bt_value_map_create();
-       if (!cur_base_params) {
-               print_err_oom();
-               goto error;
-       }
-
-       instance_names = bt_value_map_create();
-       if (!instance_names) {
-               print_err_oom();
-               goto error;
-       }
-
-       connection_args = bt_value_array_create();
-       if (!connection_args) {
-               print_err_oom();
-               goto error;
-       }
-
-       ret = append_env_var_plugin_paths(cfg->plugin_paths);
-       if (ret) {
-               goto error;
-       }
-
-       /* Parse options */
-       pc = poptGetContext(NULL, argc, (const char **) argv,
-               run_long_options, 0);
-       if (!pc) {
-               printf_err("Cannot get popt context\n");
-               goto error;
-       }
-
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) > 0) {
-               arg = poptGetOptArg(pc);
-
-               switch (opt) {
-               case OPT_PLUGIN_PATH:
-                       if (bt_config_append_plugin_paths_check_setuid_setgid(
-                                       cfg->plugin_paths, arg)) {
-                               goto error;
-                       }
-                       break;
-               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
-                       cfg->omit_system_plugin_path = true;
-                       break;
-               case OPT_OMIT_HOME_PLUGIN_PATH:
-                       cfg->omit_home_plugin_path = true;
-                       break;
-               case OPT_COMPONENT:
-               {
-                       enum bt_config_component_dest new_dest;
-
-                       if (cur_cfg_comp) {
-                               ret = add_run_cfg_comp_check_name(cfg,
-                                       cur_cfg_comp, cur_cfg_comp_dest,
-                                       instance_names);
-                               BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
-                               if (ret) {
-                                       goto error;
-                               }
-                       }
-
-                       cur_cfg_comp = bt_config_component_from_arg(arg);
-                       if (!cur_cfg_comp) {
-                               printf_err("Invalid format for --component option's argument:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       switch (cur_cfg_comp->type) {
-                       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                               new_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
-                               break;
-                       case BT_COMPONENT_CLASS_TYPE_FILTER:
-                               new_dest = BT_CONFIG_COMPONENT_DEST_FILTER;
-                               break;
-                       case BT_COMPONENT_CLASS_TYPE_SINK:
-                               new_dest = BT_CONFIG_COMPONENT_DEST_SINK;
-                               break;
-                       default:
-                               abort();
-                       }
-
-                       BT_ASSERT(cur_base_params);
-                       bt_value_put_ref(cur_cfg_comp->params);
-                       status = bt_value_copy(cur_base_params,
-                               &cur_cfg_comp->params);
-                       if (status != BT_VALUE_STATUS_OK) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       cur_cfg_comp_dest = new_dest;
-                       break;
-               }
-               case OPT_PARAMS:
-               {
-                       bt_value *params;
-                       bt_value *params_to_set;
-
-                       if (!cur_cfg_comp) {
-                               printf_err("Cannot add parameters to unavailable component:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       params = bt_value_from_arg(arg);
-                       if (!params) {
-                               printf_err("Invalid format for --params option's argument:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       status = bt_value_map_extend(cur_cfg_comp->params,
-                               params, &params_to_set);
-                       BT_VALUE_PUT_REF_AND_RESET(params);
-                       if (status != BT_VALUE_STATUS_OK) {
-                               printf_err("Cannot extend current component parameters with --params option's argument:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       BT_OBJECT_MOVE_REF(cur_cfg_comp->params, params_to_set);
-                       break;
-               }
-               case OPT_NAME:
-                       if (!cur_cfg_comp) {
-                               printf_err("Cannot set the name of unavailable component:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       g_string_assign(cur_cfg_comp->instance_name, arg);
-                       break;
-               case OPT_BASE_PARAMS:
-               {
-                       bt_value *params =
-                               bt_value_from_arg(arg);
-
-                       if (!params) {
-                               printf_err("Invalid format for --base-params option's argument:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       BT_OBJECT_MOVE_REF(cur_base_params, params);
-                       break;
-               }
-               case OPT_RESET_BASE_PARAMS:
-                       BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
-                       cur_base_params = bt_value_map_create();
-                       if (!cur_base_params) {
-                               print_err_oom();
-                               goto error;
-                       }
-                       break;
-               case OPT_CONNECT:
-                       if (bt_value_array_append_string_element(
-                                       connection_args, arg)) {
-                               print_err_oom();
-                               goto error;
-                       }
-                       break;
-               case OPT_RETRY_DURATION:
-                       if (retry_duration < 0) {
-                               printf_err("--retry-duration option's argument must be positive or 0: %ld\n",
-                                       retry_duration);
-                               goto error;
-                       }
-
-                       cfg->cmd_data.run.retry_duration_us =
-                               (uint64_t) retry_duration;
-                       break;
-               case OPT_HELP:
-                       print_run_usage(stdout);
-                       *retcode = -1;
-                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-                       goto end;
-               default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
-                               opt);
-                       goto error;
-               }
-
-               free(arg);
-               arg = NULL;
-       }
-
-       /* Check for option parsing error */
-       if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
-                       poptBadOption(pc, 0), poptStrerror(opt));
-               goto error;
-       }
-
-       /* This command does not accept leftover arguments */
-       if (poptPeekArg(pc)) {
-               printf_err("Unexpected argument: %s\n", poptPeekArg(pc));
-               goto error;
-       }
-
-       /* Add current component */
-       if (cur_cfg_comp) {
-               ret = add_run_cfg_comp_check_name(cfg, cur_cfg_comp,
-                       cur_cfg_comp_dest, instance_names);
-               BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       if (cfg->cmd_data.run.sources->len == 0) {
-               printf_err("Incomplete graph: no source component\n");
-               goto error;
-       }
-
-       if (cfg->cmd_data.run.sinks->len == 0) {
-               printf_err("Incomplete graph: no sink component\n");
-               goto error;
-       }
-
-       if (append_home_and_system_plugin_paths_cfg(cfg)) {
-               goto error;
-       }
-
-       ret = bt_config_cli_args_create_connections(cfg,
-               connection_args,
-               error_buf, 256);
-       if (ret) {
-               printf_err("Cannot creation connections:\n%s", error_buf);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       *retcode = 1;
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       if (pc) {
-               poptFreeContext(pc);
-       }
-
-       free(arg);
-       BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
-       BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
-       BT_VALUE_PUT_REF_AND_RESET(instance_names);
-       BT_VALUE_PUT_REF_AND_RESET(connection_args);
-       return cfg;
-}
-
-static
-struct bt_config *bt_config_run_from_args_array(const bt_value *run_args,
-               int *retcode, bool force_omit_system_plugin_path,
-               bool force_omit_home_plugin_path,
-               const bt_value *initial_plugin_paths)
-{
-       struct bt_config *cfg = NULL;
-       const char **argv;
-       int64_t i, len;
-       const size_t argc = bt_value_array_get_size(run_args) + 1;
-
-       argv = calloc(argc, sizeof(*argv));
-       if (!argv) {
-               print_err_oom();
-               goto end;
-       }
-
-       argv[0] = "run";
-
-       len = bt_value_array_get_size(run_args);
-       if (len < 0) {
-               printf_err("Invalid executable arguments\n");
-               goto end;
-       }
-       for (i = 0; i < len; i++) {
-               const bt_value *arg_value =
-                       bt_value_array_borrow_element_by_index_const(run_args,
-                                                                    i);
-               const char *arg;
-
-               BT_ASSERT(arg_value);
-               arg = bt_value_string_get(arg_value);
-               BT_ASSERT(arg);
-               argv[i + 1] = arg;
-       }
-
-       cfg = bt_config_run_from_args(argc, argv, retcode,
-               force_omit_system_plugin_path, force_omit_home_plugin_path,
-               initial_plugin_paths);
-
-end:
-       free(argv);
-       return cfg;
-}
-
-/*
- * Prints the convert command usage.
- */
-static
-void print_convert_usage(FILE *fp)
-{
-       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [convert] [OPTIONS] [PATH/URL]\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "  -c, --component=[NAME:]TYPE.PLUGIN.CLS\n");
-       fprintf(fp, "                                    Instantiate the component class CLS of type\n");
-       fprintf(fp, "                                    TYPE (`source`, `filter`, or `sink`) found\n");
-       fprintf(fp, "                                    in the plugin PLUGIN, add it to the\n");
-       fprintf(fp, "                                    conversion graph, and optionally name it\n");
-       fprintf(fp, "                                    NAME (you can also specify the name with\n");
-       fprintf(fp, "                                    --name)\n");
-       fprintf(fp, "      --name=NAME                   Set the name of the current component\n");
-       fprintf(fp, "                                    to NAME (must be unique amongst all the\n");
-       fprintf(fp, "                                    names of the created components)\n");
-       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
-       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
-       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
-       fprintf(fp, "  -p, --params=PARAMS               Add initialization parameters PARAMS to the\n");
-       fprintf(fp, "                                    current component (see the expected format\n");
-       fprintf(fp, "                                    of PARAMS below)\n");
-       fprintf(fp, "  -P, --path=PATH                   Set the `path` string parameter of the\n");
-       fprintf(fp, "                                    current component to PATH\n");
-       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
-       fprintf(fp, "      --retry-duration=DUR          When babeltrace2(1) needs to retry to run\n");
-       fprintf(fp, "                                    the graph later, retry in DUR µs\n");
-       fprintf(fp, "                                    (default: 100000)\n");
-       fprintf(fp, "                                    dynamic plugins can be loaded\n");
-       fprintf(fp, "      --run-args                    Print the equivalent arguments for the\n");
-       fprintf(fp, "                                    `run` command to the standard output,\n");
-       fprintf(fp, "                                    formatted for a shell, and quit\n");
-       fprintf(fp, "      --run-args-0                  Print the equivalent arguments for the\n");
-       fprintf(fp, "                                    `run` command to the standard output,\n");
-       fprintf(fp, "                                    formatted for `xargs -0`, and quit\n");
-       fprintf(fp, "      --stream-intersection         Only process events when all streams\n");
-       fprintf(fp, "                                    are active\n");
-       fprintf(fp, "  -u, --url=URL                     Set the `url` string parameter of the\n");
-       fprintf(fp, "                                    current component to URL\n");
-       fprintf(fp, "  -h, --help                        Show this help and quit\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Implicit `source.ctf.fs` component options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "      --clock-offset=SEC            Set clock offset to SEC seconds\n");
-       fprintf(fp, "      --clock-offset-ns=NS          Set clock offset to NS ns\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Implicit `sink.text.pretty` component options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "      --clock-cycles                Print timestamps in clock cycles\n");
-       fprintf(fp, "      --clock-date                  Print timestamp dates\n");
-       fprintf(fp, "      --clock-gmt                   Print and parse timestamps in the GMT\n");
-       fprintf(fp, "                                    time zone instead of the local time zone\n");
-       fprintf(fp, "      --clock-seconds               Print the timestamps as `SEC.NS` instead\n");
-       fprintf(fp, "                                    of `hh:mm:ss.nnnnnnnnn`\n");
-       fprintf(fp, "      --color=(never | auto | always)\n");
-       fprintf(fp, "                                    Never, automatically, or always emit\n");
-       fprintf(fp, "                                    console color codes\n");
-       fprintf(fp, "  -f, --fields=FIELD[,FIELD]...     Print additional fields; FIELD can be:\n");
-       fprintf(fp, "                                      `all`, `trace`, `trace:hostname`,\n");
-       fprintf(fp, "                                      `trace:domain`, `trace:procname`,\n");
-       fprintf(fp, "                                      `trace:vpid`, `loglevel`, `emf`\n");
-       fprintf(fp, "  -n, --names=NAME[,NAME]...        Print field names; NAME can be:\n");
-       fprintf(fp, "                                      `payload` (or `arg` or `args`), `none`,\n");
-       fprintf(fp, "                                      `all`, `scope`, `header`, `context`\n");
-       fprintf(fp, "                                      (or `ctx`)\n");
-       fprintf(fp, "      --no-delta                    Do not print time delta between\n");
-       fprintf(fp, "                                    consecutive events\n");
-       fprintf(fp, "  -w, --output=PATH                 Write output text to PATH instead of\n");
-       fprintf(fp, "                                    the standard output\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Implicit `filter.utils.muxer` component options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "      --clock-force-correlate       Assume that clocks are inherently\n");
-       fprintf(fp, "                                    correlated across traces\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Implicit `filter.utils.trimmer` component options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "  -b, --begin=BEGIN                 Set the beginning time of the conversion\n");
-       fprintf(fp, "                                    time range to BEGIN (see the format of\n");
-       fprintf(fp, "                                    BEGIN below)\n");
-       fprintf(fp, "  -e, --end=END                     Set the end time of the conversion time\n");
-       fprintf(fp, "                                    range to END (see the format of END below)\n");
-       fprintf(fp, "  -t, --timerange=TIMERANGE         Set conversion time range to TIMERANGE:\n");
-       fprintf(fp, "                                    BEGIN,END or [BEGIN,END] (literally `[` and\n");
-       fprintf(fp, "                                    `]`) (see the format of BEGIN/END below)\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Implicit `filter.lttng-utils.debug-info` component options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "      --debug-info                  Create an implicit\n");
-       fprintf(fp, "                                    `filter.lttng-utils.debug-info` component\n");
-       fprintf(fp, "      --debug-info-dir=DIR          Search for debug info in directory DIR\n");
-       fprintf(fp, "                                    instead of `/usr/lib/debug`\n");
-       fprintf(fp, "      --debug-info-full-path        Show full debug info source and\n");
-       fprintf(fp, "                                    binary paths instead of just names\n");
-       fprintf(fp, "      --debug-info-target-prefix=DIR\n");
-       fprintf(fp, "                                    Use directory DIR as a prefix when\n");
-       fprintf(fp, "                                    looking up executables during debug\n");
-       fprintf(fp, "                                    info analysis\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Legacy options that still work:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "  -i, --input-format=(ctf | lttng-live)\n");
-       fprintf(fp, "                                    `ctf`:\n");
-       fprintf(fp, "                                      Create an implicit `source.ctf.fs`\n");
-       fprintf(fp, "                                      component\n");
-       fprintf(fp, "                                    `lttng-live`:\n");
-       fprintf(fp, "                                      Create an implicit `source.ctf.lttng-live`\n");
-       fprintf(fp, "                                      component\n");
-       fprintf(fp, "  -o, --output-format=(text | ctf | dummy | ctf-metadata)\n");
-       fprintf(fp, "                                    `text`:\n");
-       fprintf(fp, "                                      Create an implicit `sink.text.pretty`\n");
-       fprintf(fp, "                                      component\n");
-       fprintf(fp, "                                    `ctf`:\n");
-       fprintf(fp, "                                      Create an implicit `sink.ctf.fs`\n");
-       fprintf(fp, "                                      component\n");
-       fprintf(fp, "                                    `dummy`:\n");
-       fprintf(fp, "                                      Create an implicit `sink.utils.dummy`\n");
-       fprintf(fp, "                                      component\n");
-       fprintf(fp, "                                    `ctf-metadata`:\n");
-       fprintf(fp, "                                      Query the `source.ctf.fs` component class\n");
-       fprintf(fp, "                                      for metadata text and quit\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
-       fprintf(fp, "\n\n");
-       fprintf(fp, "Format of BEGIN and END\n");
-       fprintf(fp, "-----------------------\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "    [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
-       fprintf(fp, "\n\n");
-       print_expected_params_format(fp);
-}
-
-static
-struct poptOption convert_long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       { "begin", 'b', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
-       { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
-       { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
-       { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
-       { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
-       { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
-       { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
-       { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
-       { "color", '\0', POPT_ARG_STRING, NULL, OPT_COLOR, NULL, NULL },
-       { "component", 'c', POPT_ARG_STRING, NULL, OPT_COMPONENT, NULL, NULL },
-       { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
-       { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
-       { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
-       { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
-       { "end", 'e', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
-       { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
-       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
-       { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
-       { "name", '\0', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL },
-       { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
-       { "debug-info", '\0', POPT_ARG_NONE, NULL, OPT_DEBUG_INFO, NULL, NULL },
-       { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
-       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
-       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
-       { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT, NULL, NULL },
-       { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
-       { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
-       { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
-       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
-       { "retry-duration", '\0', POPT_ARG_STRING, NULL, OPT_RETRY_DURATION, NULL, NULL },
-       { "run-args", '\0', POPT_ARG_NONE, NULL, OPT_RUN_ARGS, NULL, NULL },
-       { "run-args-0", '\0', POPT_ARG_NONE, NULL, OPT_RUN_ARGS_0, NULL, NULL },
-       { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
-       { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
-       { "url", 'u', POPT_ARG_STRING, NULL, OPT_URL, NULL, NULL },
-       { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
-       { NULL, 0, '\0', NULL, 0, NULL, NULL },
-};
-
-static
-GString *get_component_auto_name(const char *prefix,
-               const bt_value *existing_names)
-{
-       unsigned int i = 0;
-       GString *auto_name = g_string_new(NULL);
-
-       if (!auto_name) {
-               print_err_oom();
-               goto end;
-       }
-
-       if (!bt_value_map_has_entry(existing_names, prefix)) {
-               g_string_assign(auto_name, prefix);
-               goto end;
-       }
-
-       do {
-               g_string_printf(auto_name, "%s-%d", prefix, i);
-               i++;
-       } while (bt_value_map_has_entry(existing_names, auto_name->str));
-
-end:
-       return auto_name;
-}
-
-struct implicit_component_args {
-       bool exists;
-       GString *comp_arg;
-       GString *name_arg;
-       GString *params_arg;
-       bt_value *extra_params;
-};
-
-static
-int assign_name_to_implicit_component(struct implicit_component_args *args,
-               const char *prefix, bt_value *existing_names,
-               GList **comp_names, bool append_to_comp_names)
-{
-       int ret = 0;
-       GString *name = NULL;
-
-       if (!args->exists) {
-               goto end;
-       }
-
-       name = get_component_auto_name(prefix,
-               existing_names);
-
-       if (!name) {
-               ret = -1;
-               goto end;
-       }
-
-       g_string_assign(args->name_arg, name->str);
-
-       if (bt_value_map_insert_entry(existing_names, name->str,
-                       bt_value_null)) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       if (append_to_comp_names) {
-               *comp_names = g_list_append(*comp_names, name);
-               name = NULL;
-       }
-
-end:
-       if (name) {
-               g_string_free(name, TRUE);
-       }
-
-       return ret;
-}
-
-static
-int append_run_args_for_implicit_component(
-               struct implicit_component_args *impl_args,
-               bt_value *run_args)
-{
-       int ret = 0;
-       size_t i;
-
-       if (!impl_args->exists) {
-               goto end;
-       }
-
-       if (bt_value_array_append_string_element(run_args, "--component")) {
-               print_err_oom();
-               goto error;
-       }
-
-       if (bt_value_array_append_string_element(run_args, impl_args->comp_arg->str)) {
-               print_err_oom();
-               goto error;
-       }
-
-       if (bt_value_array_append_string_element(run_args, "--name")) {
-               print_err_oom();
-               goto error;
-       }
-
-       if (bt_value_array_append_string_element(run_args, impl_args->name_arg->str)) {
-               print_err_oom();
-               goto error;
-       }
-
-       if (impl_args->params_arg->len > 0) {
-               if (bt_value_array_append_string_element(run_args, "--params")) {
-                       print_err_oom();
-                       goto error;
-               }
-
-               if (bt_value_array_append_string_element(run_args,
-                               impl_args->params_arg->str)) {
-                       print_err_oom();
-                       goto error;
-               }
-       }
-
-       for (i = 0; i < bt_value_array_get_size(impl_args->extra_params);
-                       i++) {
-               const bt_value *elem;
-               const char *arg;
-
-               elem = bt_value_array_borrow_element_by_index(impl_args->extra_params,
-                                                             i);
-               if (!elem) {
-                       goto error;
-               }
-
-               BT_ASSERT(bt_value_is_string(elem));
-               arg = bt_value_string_get(elem);
-               ret = bt_value_array_append_string_element(run_args, arg);
-               if (ret) {
-                       print_err_oom();
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-void finalize_implicit_component_args(struct implicit_component_args *args)
-{
-       BT_ASSERT(args);
-
-       if (args->comp_arg) {
-               g_string_free(args->comp_arg, TRUE);
-       }
-
-       if (args->name_arg) {
-               g_string_free(args->name_arg, TRUE);
-       }
-
-       if (args->params_arg) {
-               g_string_free(args->params_arg, TRUE);
-       }
-
-       bt_value_put_ref(args->extra_params);
-}
-
-static
-int init_implicit_component_args(struct implicit_component_args *args,
-               const char *comp_arg, bool exists)
-{
-       int ret = 0;
-
-       args->exists = exists;
-       args->comp_arg = g_string_new(comp_arg);
-       args->name_arg = g_string_new(NULL);
-       args->params_arg = g_string_new(NULL);
-       args->extra_params = bt_value_array_create();
-
-       if (!args->comp_arg || !args->name_arg ||
-                       !args->params_arg || !args->extra_params) {
-               ret = -1;
-               finalize_implicit_component_args(args);
-               print_err_oom();
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-void append_implicit_component_param(struct implicit_component_args *args,
-       const char *key, const char *value)
-{
-       BT_ASSERT(args);
-       BT_ASSERT(key);
-       BT_ASSERT(value);
-       append_param_arg(args->params_arg, key, value);
-}
-
-/* Escape value to make it suitable to use as a string parameter value. */
-static
-gchar *escape_string_value(const char *value)
-{
-       GString *ret;
-       const char *in;
-
-       ret = g_string_new(NULL);
-       if (!ret) {
-               print_err_oom();
-               goto end;
-       }
-
-       in = value;
-       while (*in) {
-               switch (*in) {
-               case '"':
-               case '\\':
-                       g_string_append_c(ret, '\\');
-                       break;
-               }
-
-               g_string_append_c(ret, *in);
-
-               in++;
-       }
-
-end:
-       return g_string_free(ret, FALSE);
-}
-
-static
-int bt_value_to_cli_param_value_append(const bt_value *value, GString *buf)
-{
-       BT_ASSERT(buf);
-
-       int ret = -1;
-
-       switch (bt_value_get_type(value)) {
-       case BT_VALUE_TYPE_STRING:
-       {
-               const char *str_value = bt_value_string_get(value);
-               gchar *escaped_str_value;
-
-               escaped_str_value = escape_string_value(str_value);
-               if (!escaped_str_value) {
-                       goto end;
-               }
-
-               g_string_append_printf(buf, "\"%s\"", escaped_str_value);
-
-               g_free(escaped_str_value);
-               break;
-       }
-       case BT_VALUE_TYPE_ARRAY: {
-               g_string_append_c(buf, '[');
-               uint64_t sz = bt_value_array_get_size(value);
-               for (uint64_t i = 0; i < sz; i++) {
-                       const bt_value *item;
-                       int ret;
-
-                       if (i > 0) {
-                               g_string_append(buf, ", ");
-                       }
-
-                       item = bt_value_array_borrow_element_by_index_const(
-                               value, i);
-                       ret = bt_value_to_cli_param_value_append(item, buf);
-
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               g_string_append_c(buf, ']');
-               break;
-       }
-       default:
-               abort();
-       }
-
-       ret = 0;
-
-end:
-       return ret;
-}
-
-/*
- * Convert `value` to its equivalent representation as a command line parameter
- * value.
- */
-
-static
-gchar *bt_value_to_cli_param_value(bt_value *value)
-{
-       GString *buf;
-       gchar *result = NULL;
-
-       buf = g_string_new(NULL);
-       if (!buf) {
-               print_err_oom();
-               goto error;
-       }
-
-       if (bt_value_to_cli_param_value_append(value, buf)) {
-               goto error;
-       }
-
-       result = g_string_free(buf, FALSE);
-       buf = NULL;
-
-       goto end;
-
-error:
-       if (buf) {
-               g_string_free(buf, TRUE);
-       }
-
-end:
-       return result;
-}
-
-static
-int append_parameter_to_args(bt_value *args, const char *key, bt_value *value)
-{
-       BT_ASSERT(args);
-       BT_ASSERT(bt_value_get_type(args) == BT_VALUE_TYPE_ARRAY);
-       BT_ASSERT(key);
-       BT_ASSERT(value);
-
-       int ret = 0;
-       gchar *str_value = NULL;
-       GString *parameter = NULL;
-
-       if (bt_value_array_append_string_element(args, "--params")) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       str_value = bt_value_to_cli_param_value(value);
-       if (!str_value) {
-               ret = -1;
-               goto end;
-       }
-
-       parameter = g_string_new(NULL);
-       if (!parameter) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       g_string_printf(parameter, "%s=%s", key, str_value);
-
-       if (bt_value_array_append_string_element(args, parameter->str)) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-end:
-       if (parameter) {
-               g_string_free(parameter, TRUE);
-               parameter = NULL;
-       }
-
-       if (str_value) {
-               g_free(str_value);
-               str_value = NULL;
-       }
-
-       return ret;
-}
-
-static
-int append_string_parameter_to_args(bt_value *args, const char *key, const char *value)
-{
-       bt_value *str_value;
-       int ret;
-
-       str_value = bt_value_string_create_init(value);
-
-       if (!str_value) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       ret = append_parameter_to_args(args, key, str_value);
-
-end:
-       BT_VALUE_PUT_REF_AND_RESET(str_value);
-       return ret;
-}
-
-static
-int append_implicit_component_extra_param(struct implicit_component_args *args,
-               const char *key, const char *value)
-{
-       return append_string_parameter_to_args(args->extra_params, key, value);
-}
-
-static
-int convert_append_name_param(enum bt_config_component_dest dest,
-               GString *cur_name, GString *cur_name_prefix,
-               bt_value *run_args,
-               bt_value *all_names,
-               GList **source_names, GList **filter_names,
-               GList **sink_names)
-{
-       int ret = 0;
-
-       if (cur_name_prefix->len > 0) {
-               /* We're after a --component option */
-               GString *name = NULL;
-               bool append_name_opt = false;
-
-               if (cur_name->len == 0) {
-                       /*
-                        * No explicit name was provided for the user
-                        * component.
-                        */
-                       name = get_component_auto_name(cur_name_prefix->str,
-                               all_names);
-                       append_name_opt = true;
-               } else {
-                       /*
-                        * An explicit name was provided for the user
-                        * component.
-                        */
-                       if (bt_value_map_has_entry(all_names,
-                                                  cur_name->str)) {
-                               printf_err("Duplicate component instance name:\n    %s\n",
-                                       cur_name->str);
-                               goto error;
-                       }
-
-                       name = g_string_new(cur_name->str);
-               }
-
-               if (!name) {
-                       print_err_oom();
-                       goto error;
-               }
-
-               /*
-                * Remember this name globally, for the uniqueness of
-                * all component names.
-                */
-               if (bt_value_map_insert_entry(all_names, name->str, bt_value_null)) {
-                       print_err_oom();
-                       goto error;
-               }
-
-               /*
-                * Append the --name option if necessary.
-                */
-               if (append_name_opt) {
-                       if (bt_value_array_append_string_element(run_args, "--name")) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args, name->str)) {
-                               print_err_oom();
-                               goto error;
-                       }
-               }
-
-               /*
-                * Remember this name specifically for the type of the
-                * component. This is to create connection arguments.
-                */
-               switch (dest) {
-               case BT_CONFIG_COMPONENT_DEST_SOURCE:
-                       *source_names = g_list_append(*source_names, name);
-                       break;
-               case BT_CONFIG_COMPONENT_DEST_FILTER:
-                       *filter_names = g_list_append(*filter_names, name);
-                       break;
-               case BT_CONFIG_COMPONENT_DEST_SINK:
-                       *sink_names = g_list_append(*sink_names, name);
-                       break;
-               default:
-                       abort();
-               }
-
-               g_string_assign(cur_name_prefix, "");
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-/*
- * Escapes `.`, `:`, and `\` of `input` with `\`.
- */
-static
-GString *escape_dot_colon(const char *input)
-{
-       GString *output = g_string_new(NULL);
-       const char *ch;
-
-       if (!output) {
-               print_err_oom();
-               goto end;
-       }
-
-       for (ch = input; *ch != '\0'; ch++) {
-               if (*ch == '\\' || *ch == '.' || *ch == ':') {
-                       g_string_append_c(output, '\\');
-               }
-
-               g_string_append_c(output, *ch);
-       }
-
-end:
-       return output;
-}
-
-/*
- * Appends a --connect option to a list of arguments. `upstream_name`
- * and `downstream_name` are escaped with escape_dot_colon() in this
- * function.
- */
-static
-int append_connect_arg(bt_value *run_args,
-               const char *upstream_name, const char *downstream_name)
-{
-       int ret = 0;
-       GString *e_upstream_name = escape_dot_colon(upstream_name);
-       GString *e_downstream_name = escape_dot_colon(downstream_name);
-       GString *arg = g_string_new(NULL);
-
-       if (!e_upstream_name || !e_downstream_name || !arg) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_value_array_append_string_element(run_args, "--connect");
-       if (ret) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-       g_string_append(arg, e_upstream_name->str);
-       g_string_append_c(arg, ':');
-       g_string_append(arg, e_downstream_name->str);
-       ret = bt_value_array_append_string_element(run_args, arg->str);
-       if (ret) {
-               print_err_oom();
-               ret = -1;
-               goto end;
-       }
-
-end:
-       if (arg) {
-               g_string_free(arg, TRUE);
-       }
-
-       if (e_upstream_name) {
-               g_string_free(e_upstream_name, TRUE);
-       }
-
-       if (e_downstream_name) {
-               g_string_free(e_downstream_name, TRUE);
-       }
-
-       return ret;
-}
-
-/*
- * Appends the run command's --connect options for the convert command.
- */
-static
-int convert_auto_connect(bt_value *run_args,
-               GList *source_names, GList *filter_names,
-               GList *sink_names)
-{
-       int ret = 0;
-       GList *source_at = source_names;
-       GList *filter_at = filter_names;
-       GList *filter_prev;
-       GList *sink_at = sink_names;
-
-       BT_ASSERT(source_names);
-       BT_ASSERT(filter_names);
-       BT_ASSERT(sink_names);
-
-       /* Connect all sources to the first filter */
-       for (source_at = source_names; source_at != NULL; source_at = g_list_next(source_at)) {
-               GString *source_name = source_at->data;
-               GString *filter_name = filter_at->data;
-
-               ret = append_connect_arg(run_args, source_name->str,
-                       filter_name->str);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       filter_prev = filter_at;
-       filter_at = g_list_next(filter_at);
-
-       /* Connect remaining filters */
-       for (; filter_at != NULL; filter_prev = filter_at, filter_at = g_list_next(filter_at)) {
-               GString *filter_name = filter_at->data;
-               GString *filter_prev_name = filter_prev->data;
-
-               ret = append_connect_arg(run_args, filter_prev_name->str,
-                       filter_name->str);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       /* Connect last filter to all sinks */
-       for (sink_at = sink_names; sink_at != NULL; sink_at = g_list_next(sink_at)) {
-               GString *filter_name = filter_prev->data;
-               GString *sink_name = sink_at->data;
-
-               ret = append_connect_arg(run_args, filter_name->str,
-                       sink_name->str);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int split_timerange(const char *arg, char **begin, char **end)
-{
-       int ret = 0;
-       const char *ch = arg;
-       size_t end_pos;
-       GString *g_begin = NULL;
-       GString *g_end = NULL;
-
-       BT_ASSERT(arg);
-
-       if (*ch == '[') {
-               ch++;
-       }
-
-       g_begin = bt_common_string_until(ch, "", ",", &end_pos);
-       if (!g_begin || ch[end_pos] != ',' || g_begin->len == 0) {
-               goto error;
-       }
-
-       ch += end_pos + 1;
-
-       g_end = bt_common_string_until(ch, "", "]", &end_pos);
-       if (!g_end || g_end->len == 0) {
-               goto error;
-       }
-
-       BT_ASSERT(begin);
-       BT_ASSERT(end);
-       *begin = g_begin->str;
-       *end = g_end->str;
-       g_string_free(g_begin, FALSE);
-       g_string_free(g_end, FALSE);
-       g_begin = NULL;
-       g_end = NULL;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       if (g_begin) {
-               g_string_free(g_begin, TRUE);
-       }
-
-       if (g_end) {
-               g_string_free(g_end, TRUE);
-       }
-
-       return ret;
-}
-
-static
-int g_list_prepend_gstring(GList **list, const char *string)
-{
-       int ret = 0;
-       GString *gs = g_string_new(string);
-
-       BT_ASSERT(list);
-
-       if (!gs) {
-               print_err_oom();
-               goto end;
-       }
-
-       *list = g_list_prepend(*list, gs);
-
-end:
-       return ret;
-}
-
-/*
- * Creates a Babeltrace config object from the arguments of a convert
- * command.
- *
- * *retcode is set to the appropriate exit code to use.
- */
-static
-struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
-               int *retcode, bool force_omit_system_plugin_path,
-               bool force_omit_home_plugin_path,
-               const bt_value *initial_plugin_paths, char *log_level)
-{
-       poptContext pc = NULL;
-       char *arg = NULL;
-       enum bt_config_component_dest cur_comp_dest =
-                       BT_CONFIG_COMPONENT_DEST_UNKNOWN;
-       int opt, ret = 0;
-       struct bt_config *cfg = NULL;
-       bool got_input_format_opt = false;
-       bool got_output_format_opt = false;
-       bool trimmer_has_begin = false;
-       bool trimmer_has_end = false;
-       bool stream_intersection_mode = false;
-       GString *cur_name = NULL;
-       GString *cur_name_prefix = NULL;
-       const char *leftover = NULL;
-       bool print_run_args = false;
-       bool print_run_args_0 = false;
-       bool print_ctf_metadata = false;
-       bt_value *run_args = NULL;
-       bt_value *all_names = NULL;
-       GList *source_names = NULL;
-       GList *filter_names = NULL;
-       GList *sink_names = NULL;
-       bt_value *leftovers = NULL;
-       struct implicit_component_args implicit_ctf_input_args = { 0 };
-       struct implicit_component_args implicit_ctf_output_args = { 0 };
-       struct implicit_component_args implicit_lttng_live_args = { 0 };
-       struct implicit_component_args implicit_dummy_args = { 0 };
-       struct implicit_component_args implicit_text_args = { 0 };
-       struct implicit_component_args implicit_debug_info_args = { 0 };
-       struct implicit_component_args implicit_muxer_args = { 0 };
-       struct implicit_component_args implicit_trimmer_args = { 0 };
-       bt_value *plugin_paths;
-       char error_buf[256] = { 0 };
-       size_t i;
-       struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
-       char *output = NULL;
-
-       (void) bt_value_copy(initial_plugin_paths, &plugin_paths);
-
-       *retcode = 0;
-
-       if (argc <= 1) {
-               print_convert_usage(stdout);
-               *retcode = -1;
-               goto end;
-       }
-
-       if (init_implicit_component_args(&implicit_ctf_input_args,
-                       "source.ctf.fs", false)) {
-               goto error;
-       }
-
-       if (init_implicit_component_args(&implicit_ctf_output_args,
-                       "sink.ctf.fs", false)) {
-               goto error;
-       }
-
-       if (init_implicit_component_args(&implicit_lttng_live_args,
-                       "source.ctf.lttng-live", false)) {
-               goto error;
-       }
-
-       if (init_implicit_component_args(&implicit_text_args,
-                       "sink.text.pretty", false)) {
-               goto error;
-       }
-
-       if (init_implicit_component_args(&implicit_dummy_args,
-                       "sink.utils.dummy", false)) {
-               goto error;
-       }
-
-       if (init_implicit_component_args(&implicit_debug_info_args,
-                       "filter.lttng-utils.debug-info", false)) {
-               goto error;
-       }
-
-       if (init_implicit_component_args(&implicit_muxer_args,
-                       "filter.utils.muxer", true)) {
-               goto error;
-       }
-
-       if (init_implicit_component_args(&implicit_trimmer_args,
-                       "filter.utils.trimmer", false)) {
-               goto error;
-       }
-
-       all_names = bt_value_map_create();
-       if (!all_names) {
-               print_err_oom();
-               goto error;
-       }
-
-       run_args = bt_value_array_create();
-       if (!run_args) {
-               print_err_oom();
-               goto error;
-       }
-
-       cur_name = g_string_new(NULL);
-       if (!cur_name) {
-               print_err_oom();
-               goto error;
-       }
-
-       cur_name_prefix = g_string_new(NULL);
-       if (!cur_name_prefix) {
-               print_err_oom();
-               goto error;
-       }
-
-       ret = append_env_var_plugin_paths(plugin_paths);
-       if (ret) {
-               goto error;
-       }
-
-       leftovers = bt_value_array_create();
-       if (!leftovers) {
-               print_err_oom();
-               goto error;
-       }
-
-       /*
-        * First pass: collect all arguments which need to be passed
-        * as is to the run command. This pass can also add --name
-        * arguments if needed to automatically name unnamed component
-        * instances. Also it does the following transformations:
-        *
-        *     --path=PATH -> --params=path="PATH"
-        *     --url=URL   -> --params=url="URL"
-        *
-        * Also it appends the plugin paths of --plugin-path to
-        * `plugin_paths`.
-        */
-       pc = poptGetContext(NULL, argc, (const char **) argv,
-               convert_long_options, 0);
-       if (!pc) {
-               printf_err("Cannot get popt context\n");
-               goto error;
-       }
-
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) > 0) {
-               char *name = NULL;
-               char *plugin_name = NULL;
-               char *comp_cls_name = NULL;
-
-               arg = poptGetOptArg(pc);
-
-               switch (opt) {
-               case OPT_COMPONENT:
-               {
-                       bt_component_class_type type;
-                       const char *type_prefix;
-
-                       /* Append current component's name if needed */
-                       ret = convert_append_name_param(cur_comp_dest, cur_name,
-                               cur_name_prefix, run_args, all_names,
-                               &source_names, &filter_names, &sink_names);
-                       if (ret) {
-                               goto error;
-                       }
-
-                       /* Parse the argument */
-                       plugin_comp_cls_names(arg, &name, &plugin_name,
-                               &comp_cls_name, &type);
-                       if (!plugin_name || !comp_cls_name) {
-                               printf_err("Invalid format for --component option's argument:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       if (name) {
-                               g_string_assign(cur_name, name);
-                       } else {
-                               g_string_assign(cur_name, "");
-                       }
-
-                       switch (type) {
-                       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                               cur_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
-                               type_prefix = "source";
-                               break;
-                       case BT_COMPONENT_CLASS_TYPE_FILTER:
-                               cur_comp_dest = BT_CONFIG_COMPONENT_DEST_FILTER;
-                               type_prefix = "filter";
-                               break;
-                       case BT_COMPONENT_CLASS_TYPE_SINK:
-                               cur_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
-                               type_prefix = "sink";
-                               break;
-                       default:
-                               abort();
-                       }
-
-                       if (bt_value_array_append_string_element(run_args,
-                                       "--component")) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       g_string_assign(cur_name_prefix, "");
-                       g_string_append_printf(cur_name_prefix, "%s.%s.%s",
-                               type_prefix, plugin_name, comp_cls_name);
-                       free(name);
-                       free(plugin_name);
-                       free(comp_cls_name);
-                       name = NULL;
-                       plugin_name = NULL;
-                       comp_cls_name = NULL;
-                       break;
-               }
-               case OPT_PARAMS:
-                       if (cur_name_prefix->len == 0) {
-                               printf_err("No current component of which to set parameters:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args,
-                                       "--params")) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
-                               goto error;
-                       }
-                       break;
-               case OPT_PATH:
-                       if (cur_name_prefix->len == 0) {
-                               printf_err("No current component of which to set `path` parameter:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       if (append_string_parameter_to_args(run_args, "path", arg)) {
-                               goto error;
-                       }
-                       break;
-               case OPT_URL:
-                       if (cur_name_prefix->len == 0) {
-                               printf_err("No current component of which to set `url` parameter:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-
-                       if (append_string_parameter_to_args(run_args, "url", arg)) {
-                               goto error;
-                       }
-                       break;
-               case OPT_NAME:
-                       if (cur_name_prefix->len == 0) {
-                               printf_err("No current component to name:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args, "--name")) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       g_string_assign(cur_name, arg);
-                       break;
-               case OPT_OMIT_HOME_PLUGIN_PATH:
-                       force_omit_home_plugin_path = true;
-
-                       if (bt_value_array_append_string_element(run_args,
-                                       "--omit-home-plugin-path")) {
-                               print_err_oom();
-                               goto error;
-                       }
-                       break;
-               case OPT_RETRY_DURATION:
-                       if (bt_value_array_append_string_element(run_args,
-                                       "--retry-duration")) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
-                               goto error;
-                       }
-                       break;
-               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
-                       force_omit_system_plugin_path = true;
-
-                       if (bt_value_array_append_string_element(run_args,
-                                       "--omit-system-plugin-path")) {
-                               print_err_oom();
-                               goto error;
-                       }
-                       break;
-               case OPT_PLUGIN_PATH:
-                       if (bt_config_append_plugin_paths_check_setuid_setgid(
-                                       plugin_paths, arg)) {
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args,
-                                       "--plugin-path")) {
-                               print_err_oom();
-                               goto error;
-                       }
-
-                       if (bt_value_array_append_string_element(run_args, arg)) {
-                               print_err_oom();
-                               goto error;
-                       }
-                       break;
-               case OPT_HELP:
-                       print_convert_usage(stdout);
-                       *retcode = -1;
-                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-                       goto end;
-               case OPT_BEGIN:
-               case OPT_CLOCK_CYCLES:
-               case OPT_CLOCK_DATE:
-               case OPT_CLOCK_FORCE_CORRELATE:
-               case OPT_CLOCK_GMT:
-               case OPT_CLOCK_OFFSET:
-               case OPT_CLOCK_OFFSET_NS:
-               case OPT_CLOCK_SECONDS:
-               case OPT_COLOR:
-               case OPT_DEBUG:
-               case OPT_DEBUG_INFO:
-               case OPT_DEBUG_INFO_DIR:
-               case OPT_DEBUG_INFO_FULL_PATH:
-               case OPT_DEBUG_INFO_TARGET_PREFIX:
-               case OPT_END:
-               case OPT_FIELDS:
-               case OPT_INPUT_FORMAT:
-               case OPT_NAMES:
-               case OPT_NO_DELTA:
-               case OPT_OUTPUT_FORMAT:
-               case OPT_OUTPUT:
-               case OPT_RUN_ARGS:
-               case OPT_RUN_ARGS_0:
-               case OPT_STREAM_INTERSECTION:
-               case OPT_TIMERANGE:
-               case OPT_VERBOSE:
-                       /* Ignore in this pass */
-                       break;
-               default:
-                       printf_err("Unknown command-line option specified (option code %d)\n",
-                               opt);
-                       goto error;
-               }
-
-               free(arg);
-               arg = NULL;
-       }
-
-       /* Append current component's name if needed */
-       ret = convert_append_name_param(cur_comp_dest, cur_name,
-               cur_name_prefix, run_args, all_names, &source_names,
-               &filter_names, &sink_names);
-       if (ret) {
-               goto error;
-       }
-
-       /* Check for option parsing error */
-       if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
-                       poptBadOption(pc, 0), poptStrerror(opt));
-               goto error;
-       }
-
-       poptFreeContext(pc);
-       free(arg);
-       arg = NULL;
-
-       /*
-        * Second pass: transform the convert-specific options and
-        * arguments into implicit component instances for the run
-        * command.
-        */
-       pc = poptGetContext(NULL, argc, (const char **) argv,
-               convert_long_options, 0);
-       if (!pc) {
-               printf_err("Cannot get popt context\n");
-               goto error;
-       }
-
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) > 0) {
-               arg = poptGetOptArg(pc);
-
-               switch (opt) {
-               case OPT_BEGIN:
-                       if (trimmer_has_begin) {
-                               printf("At --begin option: --begin or --timerange option already specified\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       trimmer_has_begin = true;
-                       ret = append_implicit_component_extra_param(
-                               &implicit_trimmer_args, "begin", arg);
-                       implicit_trimmer_args.exists = true;
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               case OPT_END:
-                       if (trimmer_has_end) {
-                               printf("At --end option: --end or --timerange option already specified\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       trimmer_has_end = true;
-                       ret = append_implicit_component_extra_param(
-                               &implicit_trimmer_args, "end", arg);
-                       implicit_trimmer_args.exists = true;
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               case OPT_TIMERANGE:
-               {
-                       char *begin;
-                       char *end;
-
-                       if (trimmer_has_begin || trimmer_has_end) {
-                               printf("At --timerange option: --begin, --end, or --timerange option already specified\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       ret = split_timerange(arg, &begin, &end);
-                       if (ret) {
-                               printf_err("Invalid --timerange option's argument: expecting BEGIN,END or [BEGIN,END]:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-
-                       ret = append_implicit_component_extra_param(
-                               &implicit_trimmer_args, "begin", begin);
-                       ret |= append_implicit_component_extra_param(
-                               &implicit_trimmer_args, "end", end);
-                       implicit_trimmer_args.exists = true;
-                       free(begin);
-                       free(end);
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               }
-               case OPT_CLOCK_CYCLES:
-                       append_implicit_component_param(
-                               &implicit_text_args, "clock-cycles", "yes");
-                       implicit_text_args.exists = true;
-                       break;
-               case OPT_CLOCK_DATE:
-                       append_implicit_component_param(
-                               &implicit_text_args, "clock-date", "yes");
-                       implicit_text_args.exists = true;
-                       break;
-               case OPT_CLOCK_FORCE_CORRELATE:
-                       append_implicit_component_param(
-                               &implicit_muxer_args,
-                               "assume-absolute-clock-classes", "yes");
-                       break;
-               case OPT_CLOCK_GMT:
-                       append_implicit_component_param(
-                               &implicit_text_args, "clock-gmt", "yes");
-                       append_implicit_component_param(
-                               &implicit_trimmer_args, "gmt", "yes");
-                       implicit_text_args.exists = true;
-                       break;
-               case OPT_CLOCK_OFFSET:
-                       implicit_ctf_input_args.exists = true;
-                       append_implicit_component_param(
-                                       &implicit_ctf_input_args,
-                                       "clock-class-offset-s", arg);
-                       break;
-               case OPT_CLOCK_OFFSET_NS:
-                       implicit_ctf_input_args.exists = true;
-                       append_implicit_component_param(
-                                       &implicit_ctf_input_args,
-                                       "clock-class-offset-ns", arg);
-                       break;
-               case OPT_CLOCK_SECONDS:
-                       append_implicit_component_param(
-                               &implicit_text_args, "clock-seconds", "yes");
-                       implicit_text_args.exists = true;
-                       break;
-               case OPT_COLOR:
-                       implicit_text_args.exists = true;
-                       ret = append_implicit_component_extra_param(
-                               &implicit_text_args, "color", arg);
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               case OPT_DEBUG_INFO:
-                       implicit_debug_info_args.exists = true;
-                       break;
-               case OPT_DEBUG_INFO_DIR:
-                       implicit_debug_info_args.exists = true;
-                       ret = append_implicit_component_extra_param(
-                               &implicit_debug_info_args, "debug-info-dir", arg);
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               case OPT_DEBUG_INFO_FULL_PATH:
-                       implicit_debug_info_args.exists = true;
-                       append_implicit_component_param(
-                               &implicit_debug_info_args, "full-path", "yes");
-                       break;
-               case OPT_DEBUG_INFO_TARGET_PREFIX:
-                       implicit_debug_info_args.exists = true;
-                       ret = append_implicit_component_extra_param(
-                               &implicit_debug_info_args,
-                               "target-prefix", arg);
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               case OPT_FIELDS:
-               {
-                       bt_value *fields = fields_from_arg(arg);
-
-                       if (!fields) {
-                               goto error;
-                       }
-
-                       implicit_text_args.exists = true;
-                       ret = insert_flat_params_from_array(
-                               implicit_text_args.params_arg,
-                               fields, "field");
-                       bt_value_put_ref(fields);
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               }
-               case OPT_NAMES:
-               {
-                       bt_value *names = names_from_arg(arg);
-
-                       if (!names) {
-                               goto error;
-                       }
-
-                       implicit_text_args.exists = true;
-                       ret = insert_flat_params_from_array(
-                               implicit_text_args.params_arg,
-                               names, "name");
-                       bt_value_put_ref(names);
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               }
-               case OPT_NO_DELTA:
-                       append_implicit_component_param(
-                               &implicit_text_args, "no-delta", "yes");
-                       implicit_text_args.exists = true;
-                       break;
-               case OPT_INPUT_FORMAT:
-                       if (got_input_format_opt) {
-                               printf_err("Duplicate --input-format option\n");
-                               goto error;
-                       }
-
-                       got_input_format_opt = true;
-
-                       if (strcmp(arg, "ctf") == 0) {
-                               implicit_ctf_input_args.exists = true;
-                       } else if (strcmp(arg, "lttng-live") == 0) {
-                               implicit_lttng_live_args.exists = true;
-                       } else {
-                               printf_err("Unknown legacy input format:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-                       break;
-               case OPT_OUTPUT_FORMAT:
-                       if (got_output_format_opt) {
-                               printf_err("Duplicate --output-format option\n");
-                               goto error;
-                       }
-
-                       got_output_format_opt = true;
-
-                       if (strcmp(arg, "text") == 0) {
-                               implicit_text_args.exists = true;
-                       } else if (strcmp(arg, "ctf") == 0) {
-                               implicit_ctf_output_args.exists = true;
-                       } else if (strcmp(arg, "dummy") == 0) {
-                               implicit_dummy_args.exists = true;
-                       } else if (strcmp(arg, "ctf-metadata") == 0) {
-                               print_ctf_metadata = true;
-                       } else {
-                               printf_err("Unknown legacy output format:\n    %s\n",
-                                       arg);
-                               goto error;
-                       }
-                       break;
-               case OPT_OUTPUT:
-                       if (output) {
-                               printf_err("Duplicate --output option\n");
-                               goto error;
-                       }
-
-                       output = strdup(arg);
-                       if (!output) {
-                               print_err_oom();
-                               goto error;
-                       }
-                       break;
-               case OPT_RUN_ARGS:
-                       if (print_run_args_0) {
-                               printf_err("Cannot specify --run-args and --run-args-0\n");
-                               goto error;
-                       }
-
-                       print_run_args = true;
-                       break;
-               case OPT_RUN_ARGS_0:
-                       if (print_run_args) {
-                               printf_err("Cannot specify --run-args and --run-args-0\n");
-                               goto error;
-                       }
-
-                       print_run_args_0 = true;
-                       break;
-               case OPT_STREAM_INTERSECTION:
-                       /*
-                        * Applies to all traces implementing the trace-info
-                        * query.
-                        */
-                       stream_intersection_mode = true;
-                       break;
-               case OPT_VERBOSE:
-                       if (*log_level != 'V' && *log_level != 'D') {
-                               *log_level = 'I';
-                       }
-                       break;
-               case OPT_DEBUG:
-                       *log_level = 'V';
-                       break;
-               }
-
-               free(arg);
-               arg = NULL;
-       }
-
-       /* Check for option parsing error */
-       if (opt < -1) {
-               printf_err("While parsing command-line options, at option %s: %s\n",
-                       poptBadOption(pc, 0), poptStrerror(opt));
-               goto error;
-       }
-
-       /*
-        * Legacy behaviour: --verbose used to make the `text` output
-        * format print more information. --verbose is now equivalent to
-        * the INFO log level, which is why we compare to 'I' here.
-        */
-       if (*log_level == 'I') {
-               append_implicit_component_param(&implicit_text_args,
-                       "verbose", "yes");
-       }
-
-       /*
-        * Append home and system plugin paths now that we possibly got
-        * --plugin-path.
-        */
-       if (append_home_and_system_plugin_paths(plugin_paths,
-                       force_omit_system_plugin_path,
-                       force_omit_home_plugin_path)) {
-               goto error;
-       }
-
-       /* Consume and keep leftover arguments */
-       while ((leftover = poptGetArg(pc))) {
-               bt_value_status status = bt_value_array_append_string_element(leftovers, leftover);
-               if (status != BT_VALUE_STATUS_OK) {
-                       print_err_oom();
-                       goto error;
-               }
-       }
-
-       /* Print CTF metadata or print LTTng live sessions */
-       if (print_ctf_metadata) {
-               const bt_value *bt_val_leftover;
-
-               if (bt_value_array_is_empty(leftovers)) {
-                       printf_err("--output-format=ctf-metadata specified without a path\n");
-                       goto error;
-               }
-
-               if (bt_value_array_get_size(leftovers) > 1) {
-                       printf_err("Too many paths specified for --output-format=ctf-metadata\n");
-                       goto error;
-               }
-
-               cfg = bt_config_print_ctf_metadata_create(plugin_paths);
-               if (!cfg) {
-                       goto error;
-               }
-
-               bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0);
-               g_string_assign(cfg->cmd_data.print_ctf_metadata.path,
-                               bt_value_string_get(bt_val_leftover));
-
-               if (output) {
-                       g_string_assign(
-                               cfg->cmd_data.print_ctf_metadata.output_path,
-                               output);
-               }
-
-               goto end;
-       }
-
-       /*
-        * If -o ctf was specified, make sure an output path (--output)
-        * was also specified. --output does not imply -o ctf because
-        * it's also used for the default, implicit -o text if -o ctf
-        * is not specified.
-        */
-       if (implicit_ctf_output_args.exists) {
-               if (!output) {
-                       printf_err("--output-format=ctf specified without --output (trace output path)\n");
-                       goto error;
-               }
-
-               /*
-                * At this point we know that -o ctf AND --output were
-                * specified. Make sure that no options were specified
-                * which would imply -o text because --output would be
-                * ambiguous in this case. For example, this is wrong:
-                *
-                *     babeltrace2 --names=all -o ctf --output=/tmp/path my-trace
-                *
-                * because --names=all implies -o text, and --output
-                * could apply to both the sink.text.pretty and
-                * sink.ctf.fs implicit components.
-                */
-               if (implicit_text_args.exists) {
-                       printf_err("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text\n");
-                       goto error;
-               }
-       }
-
-       /*
-        * If -o dummy and -o ctf were not specified, and if there are
-        * no explicit sink components, then use an implicit
-        * `sink.text.pretty` component.
-        */
-       if (!implicit_dummy_args.exists && !implicit_ctf_output_args.exists &&
-                       !sink_names) {
-               implicit_text_args.exists = true;
-       }
-
-       /*
-        * Set implicit `sink.text.pretty` or `sink.ctf.fs` component's
-        * `path` parameter if --output was specified.
-        */
-       if (output) {
-               if (implicit_text_args.exists) {
-                       append_implicit_component_extra_param(&implicit_text_args,
-                               "path", output);
-               } else if (implicit_ctf_output_args.exists) {
-                       append_implicit_component_extra_param(&implicit_ctf_output_args,
-                               "path", output);
-               }
-       }
-
-       /* Decide where the leftover argument(s) go */
-       if (bt_value_array_get_size(leftovers) > 0) {
-               if (implicit_lttng_live_args.exists) {
-                       const bt_value *bt_val_leftover;
-
-                       if (bt_value_array_get_size(leftovers) > 1) {
-                               printf_err("Too many URLs specified for --output-format=lttng-live\n");
-                               goto error;
-                       }
-
-                       bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0);
-                       lttng_live_url_parts =
-                               bt_common_parse_lttng_live_url(bt_value_string_get(bt_val_leftover),
-                                       error_buf, sizeof(error_buf));
-                       if (!lttng_live_url_parts.proto) {
-                               printf_err("Invalid LTTng live URL format: %s\n",
-                                       error_buf);
-                               goto error;
-                       }
-
-                       if (!lttng_live_url_parts.session_name) {
-                               /* Print LTTng live sessions */
-                               cfg = bt_config_print_lttng_live_sessions_create(
-                                       plugin_paths);
-                               if (!cfg) {
-                                       goto error;
-                               }
-
-                               g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url,
-                                       bt_value_string_get(bt_val_leftover));
-
-                               if (output) {
-                                       g_string_assign(
-                                               cfg->cmd_data.print_lttng_live_sessions.output_path,
-                                               output);
-                               }
-
-                               goto end;
-                       }
-
-                       ret = append_implicit_component_extra_param(
-                               &implicit_lttng_live_args, "url",
-                               bt_value_string_get(bt_val_leftover));
-                       if (ret) {
-                               goto error;
-                       }
-
-                       ret = append_implicit_component_extra_param(
-                               &implicit_lttng_live_args,
-                               "session-not-found-action", "end");
-                       if (ret) {
-                               goto error;
-                       }
-               } else {
-                       /*
-                        * Create one source.ctf.fs component, pass it an array
-                        * with the leftovers.
-                        * Note that it still has to be named later.
-                        */
-                       implicit_ctf_input_args.exists = true;
-                       ret = append_parameter_to_args(implicit_ctf_input_args.extra_params,
-                                       "paths", leftovers);
-                       if (ret) {
-                               goto error;
-                       }
-               }
-       }
-
-       /*
-        * Ensure mutual exclusion between implicit `source.ctf.fs` and
-        * `source.ctf.lttng-live` components.
-        */
-       if (implicit_ctf_input_args.exists && implicit_lttng_live_args.exists) {
-               printf_err("Cannot create both implicit `%s` and `%s` components\n",
-                       implicit_ctf_input_args.comp_arg->str,
-                       implicit_lttng_live_args.comp_arg->str);
-               goto error;
-       }
-
-       /*
-        * If the implicit `source.ctf.fs` or `source.ctf.lttng-live`
-        * components exists, make sure there's at least one leftover
-        * (which is the path or URL).
-        */
-       if (implicit_ctf_input_args.exists && bt_value_array_is_empty(leftovers)) {
-               printf_err("Missing path for implicit `%s` component\n",
-                       implicit_ctf_input_args.comp_arg->str);
-               goto error;
-       }
-
-       if (implicit_lttng_live_args.exists && bt_value_array_is_empty(leftovers)) {
-               printf_err("Missing URL for implicit `%s` component\n",
-                       implicit_lttng_live_args.comp_arg->str);
-               goto error;
-       }
-
-       /* Assign names to implicit components */
-       ret = assign_name_to_implicit_component(&implicit_ctf_input_args,
-               "source-ctf-fs", all_names, &source_names, true);
-       if (ret) {
-               goto error;
-       }
-
-       ret = assign_name_to_implicit_component(&implicit_lttng_live_args,
-               "lttng-live", all_names, &source_names, true);
-       if (ret) {
-               goto error;
-       }
-
-       ret = assign_name_to_implicit_component(&implicit_text_args,
-               "pretty", all_names, &sink_names, true);
-       if (ret) {
-               goto error;
-       }
-
-       ret = assign_name_to_implicit_component(&implicit_ctf_output_args,
-               "sink-ctf-fs", all_names, &sink_names, true);
-       if (ret) {
-               goto error;
-       }
-
-       ret = assign_name_to_implicit_component(&implicit_dummy_args,
-               "dummy", all_names, &sink_names, true);
-       if (ret) {
-               goto error;
-       }
-
-       ret = assign_name_to_implicit_component(&implicit_muxer_args,
-               "muxer", all_names, NULL, false);
-       if (ret) {
-               goto error;
-       }
-
-       ret = assign_name_to_implicit_component(&implicit_trimmer_args,
-               "trimmer", all_names, NULL, false);
-       if (ret) {
-               goto error;
-       }
-
-       ret = assign_name_to_implicit_component(&implicit_debug_info_args,
-               "debug-info", all_names, NULL, false);
-       if (ret) {
-               goto error;
-       }
-
-       /* Make sure there's at least one source and one sink */
-       if (!source_names) {
-               printf_err("No source component\n");
-               goto error;
-       }
-
-       if (!sink_names) {
-               printf_err("No sink component\n");
-               goto error;
-       }
-
-       /*
-        * Prepend the muxer, the trimmer, and the debug info to the
-        * filter chain so that we have:
-        *
-        *     sources -> muxer -> [trimmer] -> [debug info] ->
-        *                [user filters] -> sinks
-        */
-       if (implicit_debug_info_args.exists) {
-               if (g_list_prepend_gstring(&filter_names,
-                               implicit_debug_info_args.name_arg->str)) {
-                       goto error;
-               }
-       }
-
-       if (implicit_trimmer_args.exists) {
-               if (g_list_prepend_gstring(&filter_names,
-                               implicit_trimmer_args.name_arg->str)) {
-                       goto error;
-               }
-       }
-
-       if (g_list_prepend_gstring(&filter_names,
-                       implicit_muxer_args.name_arg->str)) {
-               goto error;
-       }
-
-       /*
-        * Append the equivalent run arguments for the implicit
-        * components.
-        */
-       ret = append_run_args_for_implicit_component(&implicit_ctf_input_args, run_args);
-       if (ret) {
-               goto error;
-       }
-
-       ret = append_run_args_for_implicit_component(&implicit_lttng_live_args,
-               run_args);
-       if (ret) {
-               goto error;
-       }
-
-       ret = append_run_args_for_implicit_component(&implicit_text_args,
-               run_args);
-       if (ret) {
-               goto error;
-       }
-
-       ret = append_run_args_for_implicit_component(&implicit_ctf_output_args,
-               run_args);
-       if (ret) {
-               goto error;
-       }
-
-       ret = append_run_args_for_implicit_component(&implicit_dummy_args,
-               run_args);
-       if (ret) {
-               goto error;
-       }
-
-       ret = append_run_args_for_implicit_component(&implicit_muxer_args,
-               run_args);
-       if (ret) {
-               goto error;
-       }
-
-       ret = append_run_args_for_implicit_component(&implicit_trimmer_args,
-               run_args);
-       if (ret) {
-               goto error;
-       }
-
-       ret = append_run_args_for_implicit_component(&implicit_debug_info_args,
-               run_args);
-       if (ret) {
-               goto error;
-       }
-
-       /* Auto-connect components */
-       ret = convert_auto_connect(run_args, source_names, filter_names,
-                       sink_names);
-       if (ret) {
-               printf_err("Cannot auto-connect components\n");
-               goto error;
-       }
-
-       /*
-        * We have all the run command arguments now. Depending on
-        * --run-args, we pass this to the run command or print them
-        * here.
-        */
-       if (print_run_args || print_run_args_0) {
-               if (stream_intersection_mode) {
-                       printf_err("Cannot specify --stream-intersection with --run-args or --run-args-0\n");
-                       goto error;
-               }
-
-               for (i = 0; i < bt_value_array_get_size(run_args); i++) {
-                       const bt_value *arg_value =
-                               bt_value_array_borrow_element_by_index(run_args,
-                                                                      i);
-                       const char *arg;
-                       GString *quoted = NULL;
-                       const char *arg_to_print;
-
-                       BT_ASSERT(arg_value);
-                       arg = bt_value_string_get(arg_value);
-
-                       if (print_run_args) {
-                               quoted = bt_common_shell_quote(arg, true);
-                               if (!quoted) {
-                                       goto error;
-                               }
-
-                               arg_to_print = quoted->str;
-                       } else {
-                               arg_to_print = arg;
-                       }
-
-                       printf("%s", arg_to_print);
-
-                       if (quoted) {
-                               g_string_free(quoted, TRUE);
-                       }
-
-                       if (i < bt_value_array_get_size(run_args) - 1) {
-                               if (print_run_args) {
-                                       putchar(' ');
-                               } else {
-                                       putchar('\0');
-                               }
-                       }
-               }
-
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
-       }
-
-       cfg = bt_config_run_from_args_array(run_args, retcode,
-                                           force_omit_system_plugin_path,
-                                           force_omit_home_plugin_path,
-                                           initial_plugin_paths);
-       if (!cfg) {
-               goto error;
-       }
-
-       cfg->cmd_data.run.stream_intersection_mode = stream_intersection_mode;
-       goto end;
-
-error:
-       *retcode = 1;
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-
-end:
-       if (pc) {
-               poptFreeContext(pc);
-       }
-
-       free(arg);
-       free(output);
-
-       if (cur_name) {
-               g_string_free(cur_name, TRUE);
-       }
-
-       if (cur_name_prefix) {
-               g_string_free(cur_name_prefix, TRUE);
-       }
-
-       bt_value_put_ref(run_args);
-       bt_value_put_ref(all_names);
-       destroy_glist_of_gstring(source_names);
-       destroy_glist_of_gstring(filter_names);
-       destroy_glist_of_gstring(sink_names);
-       bt_value_put_ref(leftovers);
-       finalize_implicit_component_args(&implicit_ctf_input_args);
-       finalize_implicit_component_args(&implicit_ctf_output_args);
-       finalize_implicit_component_args(&implicit_lttng_live_args);
-       finalize_implicit_component_args(&implicit_dummy_args);
-       finalize_implicit_component_args(&implicit_text_args);
-       finalize_implicit_component_args(&implicit_debug_info_args);
-       finalize_implicit_component_args(&implicit_muxer_args);
-       finalize_implicit_component_args(&implicit_trimmer_args);
-       bt_value_put_ref(plugin_paths);
-       bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
-       return cfg;
-}
-
-/*
- * Prints the Babeltrace 2.x general usage.
- */
-static
-void print_gen_usage(FILE *fp)
-{
-       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [COMMAND] [COMMAND ARGUMENTS]\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "General options:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "  -d, --debug          Enable debug mode (same as --log-level=V)\n");
-       fprintf(fp, "  -h, --help           Show this help and quit\n");
-       fprintf(fp, "  -l, --log-level=LVL  Set all log levels to LVL (`N`, `V`, `D`,\n");
-       fprintf(fp, "                       `I`, `W` (default), `E`, or `F`)\n");
-       fprintf(fp, "  -v, --verbose        Enable verbose mode (same as --log-level=I)\n");
-       fprintf(fp, "  -V, --version        Show version and quit\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Available commands:\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "    convert       Convert and trim traces (default)\n");
-       fprintf(fp, "    help          Get help for a plugin or a component class\n");
-       fprintf(fp, "    list-plugins  List available plugins and their content\n");
-       fprintf(fp, "    query         Query objects from a component class\n");
-       fprintf(fp, "    run           Build a processing graph and run it\n");
-       fprintf(fp, "\n");
-       fprintf(fp, "Use `babeltrace2 COMMAND --help` to show the help of COMMAND.\n");
-}
-
-static
-char log_level_from_arg(const char *arg)
-{
-       char level = 'U';
-
-       if (strcmp(arg, "VERBOSE") == 0 ||
-                       strcmp(arg, "V") == 0) {
-               level = 'V';
-       } else if (strcmp(arg, "DEBUG") == 0 ||
-                       strcmp(arg, "D") == 0) {
-               level = 'D';
-       } else if (strcmp(arg, "INFO") == 0 ||
-                       strcmp(arg, "I") == 0) {
-               level = 'I';
-       } else if (strcmp(arg, "WARN") == 0 ||
-                       strcmp(arg, "WARNING") == 0 ||
-                       strcmp(arg, "W") == 0) {
-               level = 'W';
-       } else if (strcmp(arg, "ERROR") == 0 ||
-                       strcmp(arg, "E") == 0) {
-               level = 'E';
-       } else if (strcmp(arg, "FATAL") == 0 ||
-                       strcmp(arg, "F") == 0) {
-               level = 'F';
-       } else if (strcmp(arg, "NONE") == 0 ||
-                       strcmp(arg, "N") == 0) {
-               level = 'N';
-       }
-
-       return level;
-}
-
-struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
-               int *retcode, bool force_omit_system_plugin_path,
-               bool force_omit_home_plugin_path,
-               const bt_value *initial_plugin_paths)
-{
-       struct bt_config *config = NULL;
-       int i;
-       const char **command_argv = NULL;
-       int command_argc = -1;
-       const char *command_name = NULL;
-       char log_level = 'U';
-
-       enum command_type {
-               COMMAND_TYPE_NONE = -1,
-               COMMAND_TYPE_RUN = 0,
-               COMMAND_TYPE_CONVERT,
-               COMMAND_TYPE_LIST_PLUGINS,
-               COMMAND_TYPE_HELP,
-               COMMAND_TYPE_QUERY,
-       } command_type = COMMAND_TYPE_NONE;
-
-       *retcode = -1;
-
-       if (!initial_plugin_paths) {
-               initial_plugin_paths = bt_value_array_create();
-               if (!initial_plugin_paths) {
-                       *retcode = 1;
-                       goto end;
-               }
-       } else {
-               bt_value_get_ref(initial_plugin_paths);
-       }
-
-       if (argc <= 1) {
-               print_version();
-               puts("");
-               print_gen_usage(stdout);
-               goto end;
-       }
-
-       for (i = 1; i < argc; i++) {
-               const char *cur_arg = argv[i];
-               const char *next_arg = i == (argc - 1) ? NULL : argv[i + 1];
-
-               if (strcmp(cur_arg, "-d") == 0 ||
-                               strcmp(cur_arg, "--debug") == 0) {
-                       log_level = 'V';
-               } else if (strcmp(cur_arg, "-v") == 0 ||
-                               strcmp(cur_arg, "--verbose") == 0) {
-                       if (log_level != 'V' && log_level != 'D') {
-                               /*
-                                * Legacy: do not override a previous
-                                * --debug because --verbose and --debug
-                                * can be specified together (in this
-                                * case we want the lowest log level to
-                                * apply, VERBOSE).
-                                */
-                               log_level = 'I';
-                       }
-               } else if (strcmp(cur_arg, "--log-level") == 0 ||
-                               strcmp(cur_arg, "-l") == 0) {
-                       if (!next_arg) {
-                               printf_err("Missing log level value for --log-level option\n");
-                               *retcode = 1;
-                               goto end;
-                       }
-
-                       log_level = log_level_from_arg(next_arg);
-                       if (log_level == 'U') {
-                               printf_err("Invalid argument for --log-level option:\n    %s\n",
-                                       next_arg);
-                               *retcode = 1;
-                               goto end;
-                       }
-
-                       i++;
-               } else if (strncmp(cur_arg, "--log-level=", 12) == 0) {
-                       const char *arg = &cur_arg[12];
-
-                       log_level = log_level_from_arg(arg);
-                       if (log_level == 'U') {
-                               printf_err("Invalid argument for --log-level option:\n    %s\n",
-                                       arg);
-                               *retcode = 1;
-                               goto end;
-                       }
-               } else if (strncmp(cur_arg, "-l", 2) == 0) {
-                       const char *arg = &cur_arg[2];
-
-                       log_level = log_level_from_arg(arg);
-                       if (log_level == 'U') {
-                               printf_err("Invalid argument for --log-level option:\n    %s\n",
-                                       arg);
-                               *retcode = 1;
-                               goto end;
-                       }
-               } else if (strcmp(cur_arg, "-V") == 0 ||
-                               strcmp(cur_arg, "--version") == 0) {
-                       print_version();
-                       goto end;
-               } else if (strcmp(cur_arg, "-h") == 0 ||
-                               strcmp(cur_arg, "--help") == 0) {
-                       print_gen_usage(stdout);
-                       goto end;
-               } else {
-                       /*
-                        * First unknown argument: is it a known command
-                        * name?
-                        */
-                       command_argv = &argv[i];
-                       command_argc = argc - i;
-
-                       if (strcmp(cur_arg, "convert") == 0) {
-                               command_type = COMMAND_TYPE_CONVERT;
-                       } else if (strcmp(cur_arg, "list-plugins") == 0) {
-                               command_type = COMMAND_TYPE_LIST_PLUGINS;
-                       } else if (strcmp(cur_arg, "help") == 0) {
-                               command_type = COMMAND_TYPE_HELP;
-                       } else if (strcmp(cur_arg, "query") == 0) {
-                               command_type = COMMAND_TYPE_QUERY;
-                       } else if (strcmp(cur_arg, "run") == 0) {
-                               command_type = COMMAND_TYPE_RUN;
-                       } else {
-                               /*
-                                * Unknown argument, but not a known
-                                * command name: assume the default
-                                * `convert` command.
-                                */
-                               command_type = COMMAND_TYPE_CONVERT;
-                               command_name = "convert";
-                               command_argv = &argv[i - 1];
-                               command_argc = argc - i + 1;
-                       }
-                       break;
-               }
-       }
-
-       if (command_type == COMMAND_TYPE_NONE) {
-               /*
-                * We only got non-help, non-version general options
-                * like --verbose and --debug, without any other
-                * arguments, so we can't do anything useful: print the
-                * usage and quit.
-                */
-               print_gen_usage(stdout);
-               goto end;
-       }
-
-       BT_ASSERT(command_argv);
-       BT_ASSERT(command_argc >= 0);
-
-       switch (command_type) {
-       case COMMAND_TYPE_RUN:
-               config = bt_config_run_from_args(command_argc, command_argv,
-                       retcode, force_omit_system_plugin_path,
-                       force_omit_home_plugin_path, initial_plugin_paths);
-               break;
-       case COMMAND_TYPE_CONVERT:
-               config = bt_config_convert_from_args(command_argc, command_argv,
-                       retcode, force_omit_system_plugin_path,
-                       force_omit_home_plugin_path,
-                       initial_plugin_paths, &log_level);
-               break;
-       case COMMAND_TYPE_LIST_PLUGINS:
-               config = bt_config_list_plugins_from_args(command_argc,
-                       command_argv, retcode, force_omit_system_plugin_path,
-                       force_omit_home_plugin_path, initial_plugin_paths);
-               break;
-       case COMMAND_TYPE_HELP:
-               config = bt_config_help_from_args(command_argc,
-                       command_argv, retcode, force_omit_system_plugin_path,
-                       force_omit_home_plugin_path, initial_plugin_paths);
-               break;
-       case COMMAND_TYPE_QUERY:
-               config = bt_config_query_from_args(command_argc,
-                       command_argv, retcode, force_omit_system_plugin_path,
-                       force_omit_home_plugin_path, initial_plugin_paths);
-               break;
-       default:
-               abort();
-       }
-
-       if (config) {
-               if (log_level == 'U') {
-                       log_level = 'W';
-               }
-
-               config->log_level = log_level;
-               config->command_name = command_name;
-       }
-
-end:
-       bt_value_put_ref(initial_plugin_paths);
-       return config;
-}
diff --git a/cli/babeltrace2-cfg-cli-args.h b/cli/babeltrace2-cfg-cli-args.h
deleted file mode 100644 (file)
index 7f1fd00..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef CLI_BABELTRACE_CFG_CLI_ARGS_H
-#define CLI_BABELTRACE_CFG_CLI_ARGS_H
-
-/*
- * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/graph/component-class.h>
-#include <glib.h>
-
-#include "babeltrace2-cfg.h"
-
-struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
-               int *retcode, bool force_omit_system_plugin_path,
-               bool force_omit_home_plugin_path,
-               const bt_value *initial_plugin_paths);
-
-#endif /* CLI_BABELTRACE_CFG_CLI_ARGS_H */
diff --git a/cli/babeltrace2-cfg.c b/cli/babeltrace2-cfg.c
deleted file mode 100644 (file)
index 4704efb..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Babeltrace trace converter - parameter parsing
- *
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <glib.h>
-#include "babeltrace2-cfg.h"
-
-static
-void destroy_gstring(void *data)
-{
-       g_string_free(data, TRUE);
-}
-
-/*
- * Extracts the various paths from the string arg, delimited by ':',
- * and appends them to the array value object plugin_paths.
- */
-int bt_config_append_plugin_paths(
-               bt_value *plugin_paths, const char *arg)
-{
-       int ret = 0;
-       GPtrArray *dirs = g_ptr_array_new_with_free_func(destroy_gstring);
-       size_t i;
-
-       if (!dirs) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_common_append_plugin_path_dirs(arg, dirs);
-       if (ret) {
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; i < dirs->len; i++) {
-               GString *dir = g_ptr_array_index(dirs, i);
-
-               ret = bt_value_array_append_string_element(
-                       plugin_paths, dir->str);
-               if (ret != BT_VALUE_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-end:
-       g_ptr_array_free(dirs, TRUE);
-       return ret;
-}
-
-void bt_config_connection_destroy(struct bt_config_connection *connection)
-{
-       if (!connection) {
-               return;
-       }
-
-       if (connection->upstream_comp_name) {
-               g_string_free(connection->upstream_comp_name, TRUE);
-       }
-
-       if (connection->downstream_comp_name) {
-               g_string_free(connection->downstream_comp_name, TRUE);
-       }
-
-       if (connection->upstream_port_glob) {
-               g_string_free(connection->upstream_port_glob, TRUE);
-       }
-
-       if (connection->downstream_port_glob) {
-               g_string_free(connection->downstream_port_glob, TRUE);
-       }
-
-       if (connection->arg) {
-               g_string_free(connection->arg, TRUE);
-       }
-
-       g_free(connection);
-}
diff --git a/cli/babeltrace2-cfg.h b/cli/babeltrace2-cfg.h
deleted file mode 100644 (file)
index 0608e36..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-#ifndef CLI_BABELTRACE_CFG_H
-#define CLI_BABELTRACE_CFG_H
-
-/*
- * Babeltrace trace converter - CLI tool's configuration
- *
- * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/graph/component-class.h>
-#include <glib.h>
-
-enum bt_config_command {
-       BT_CONFIG_COMMAND_RUN,
-       BT_CONFIG_COMMAND_PRINT_CTF_METADATA,
-       BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS,
-       BT_CONFIG_COMMAND_LIST_PLUGINS,
-       BT_CONFIG_COMMAND_HELP,
-       BT_CONFIG_COMMAND_QUERY,
-};
-
-struct bt_config_component {
-       bt_object base;
-       bt_component_class_type type;
-       GString *plugin_name;
-       GString *comp_cls_name;
-       bt_value *params;
-       GString *instance_name;
-};
-
-struct bt_config_connection {
-       GString *upstream_comp_name;
-       GString *downstream_comp_name;
-       GString *upstream_port_glob;
-       GString *downstream_port_glob;
-       GString *arg;
-};
-
-struct bt_config {
-       bt_object base;
-       bool debug;
-       bool verbose;
-       bt_value *plugin_paths;
-       bool omit_system_plugin_path;
-       bool omit_home_plugin_path;
-       bool command_needs_plugins;
-       const char *command_name;
-       char log_level;
-       enum bt_config_command command;
-       union {
-               /* BT_CONFIG_COMMAND_RUN */
-               struct {
-                       /* Array of pointers to struct bt_config_component */
-                       GPtrArray *sources;
-
-                       /* Array of pointers to struct bt_config_component */
-                       GPtrArray *filters;
-
-                       /* Array of pointers to struct bt_config_component */
-                       GPtrArray *sinks;
-
-                       /* Array of pointers to struct bt_config_connection */
-                       GPtrArray *connections;
-
-                       /*
-                        * Number of microseconds to sleep when we need
-                        * to retry to run the graph.
-                        */
-                       uint64_t retry_duration_us;
-
-                       /*
-                        * Whether or not to trim the source trace to the
-                        * intersection of its streams.
-                        */
-                       bool stream_intersection_mode;
-               } run;
-
-               /* BT_CONFIG_COMMAND_HELP */
-               struct {
-                       struct bt_config_component *cfg_component;
-               } help;
-
-               /* BT_CONFIG_COMMAND_QUERY */
-               struct {
-                       GString *object;
-                       struct bt_config_component *cfg_component;
-               } query;
-
-               /* BT_CONFIG_COMMAND_PRINT_CTF_METADATA */
-               struct {
-                       GString *path;
-                       GString *output_path;
-               } print_ctf_metadata;
-
-               /* BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS */
-               struct {
-                       GString *url;
-                       GString *output_path;
-               } print_lttng_live_sessions;
-       } cmd_data;
-};
-
-static inline
-struct bt_config_component *bt_config_get_component(GPtrArray *array,
-               size_t index)
-{
-       struct bt_config_component *comp = g_ptr_array_index(array, index);
-
-       bt_object_get_ref(comp);
-       return comp;
-}
-
-int bt_config_append_plugin_paths(bt_value *plugin_paths,
-               const char *arg);
-
-void bt_config_connection_destroy(struct bt_config_connection *connection);
-
-#endif /* CLI_BABELTRACE_CFG_H */
diff --git a/cli/babeltrace2-log.c b/cli/babeltrace2-log.c
deleted file mode 100644 (file)
index 7d6021d..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <popt.h>
-#include <glib.h>
-
-static
-void print_usage(FILE *fp)
-{
-       fprintf(stderr, "Usage: babeltrace2-log [OPTIONS] OUTPUT-PATH\n");
-       fprintf(stderr, "\n");
-       fprintf(stderr, "Options:\n");
-       fprintf(stderr, "\n");
-       fprintf(stderr, "  -t, --with-timestamps  Extract timestamps from lines and map them to\n");
-       fprintf(stderr, "                         a CTF clock class\n");
-}
-
-static
-int parse_params(int argc, char *argv[], char **output_path,
-               bool *no_extract_ts)
-{
-       enum {
-               OPT_WITH_TIMESTAMPS = 1,
-               OPT_HELP = 2,
-       };
-       static struct poptOption opts[] = {
-               { "with-timestamps", 't', POPT_ARG_NONE, NULL, OPT_WITH_TIMESTAMPS, NULL, NULL },
-               { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
-               { NULL, '\0', 0, NULL, 0, NULL, NULL },
-       };
-       poptContext pc = NULL;
-       int opt;
-       int ret = 0;
-       const char *leftover;
-
-       *no_extract_ts = true;
-       pc = poptGetContext(NULL, argc, (const char **) argv, opts, 0);
-       if (!pc) {
-               fprintf(stderr, "Cannot get popt context\n");
-               goto error;
-       }
-
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) > 0) {
-               switch (opt) {
-               case OPT_HELP:
-                       print_usage(stdout);
-                       goto end;
-               case OPT_WITH_TIMESTAMPS:
-                       *no_extract_ts = false;
-                       break;
-               default:
-                       fprintf(stderr, "Unknown command-line option specified (option code %d)\n",
-                               opt);
-                       goto error;
-               }
-       }
-
-       if (opt < -1) {
-               fprintf(stderr, "While parsing command-line options, at option %s: %s\n",
-                       poptBadOption(pc, 0), poptStrerror(opt));
-               goto error;
-       }
-
-       leftover = poptGetArg(pc);
-       if (!leftover) {
-               fprintf(stderr, "Command line error: Missing output path\n");
-               print_usage(stderr);
-               goto error;
-       }
-
-       *output_path = strdup(leftover);
-       BT_ASSERT(*output_path);
-       goto end;
-
-error:
-       ret = 1;
-
-end:
-       if (pc) {
-               poptFreeContext(pc);
-       }
-
-       return ret;
-}
-
-int main(int argc, char *argv[])
-{
-       char *output_path = NULL;
-       bool no_extract_ts;
-       int retcode;
-       GError *error = NULL;
-       gchar *bt_argv[] = {
-               BT_CLI_PATH,
-               "run",
-               "--component",
-               "dmesg:src.text.dmesg",
-               "--params",
-               NULL, /* no-extract-timestamp=? placeholder */
-               "--component",
-               "ctf:sink.ctf.fs",
-               "--key",
-               "path",
-               "--value",
-               NULL, /* output path placeholder */
-               "--params",
-               "single-trace=yes",
-               "--connect",
-               "dmesg:ctf",
-               NULL, /* sentinel */
-       };
-
-       retcode = parse_params(argc, argv, &output_path, &no_extract_ts);
-       if (retcode) {
-               goto end;
-       }
-
-       if (no_extract_ts) {
-               bt_argv[5] = "no-extract-timestamp=yes";
-       } else {
-               bt_argv[5] = "no-extract-timestamp=no";
-       }
-
-       bt_argv[11] = output_path;
-       (void) g_spawn_sync(NULL, bt_argv, NULL,
-               G_SPAWN_CHILD_INHERITS_STDIN, NULL, NULL,
-               NULL, NULL, &retcode, &error);
-
-       if (error) {
-               fprintf(stderr, "Failed to execute \"%s\": %s (%d)\n",
-                       bt_argv[0], error->message, error->code);
-       }
-
-end:
-       free(output_path);
-
-       if (error) {
-               g_error_free(error);
-       }
-
-       return retcode;
-}
diff --git a/cli/babeltrace2.c b/cli/babeltrace2.c
deleted file mode 100644 (file)
index 91dc1ce..0000000
+++ /dev/null
@@ -1,2950 +0,0 @@
-/*
- * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
- *
- * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CLI"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/common-internal.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <popt.h>
-#include <string.h>
-#include <stdio.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <signal.h>
-#include "babeltrace2-cfg.h"
-#include "babeltrace2-cfg-cli-args.h"
-#include "babeltrace2-cfg-cli-args-default.h"
-
-#define ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH "BABELTRACE_CLI_WARN_COMMAND_NAME_DIRECTORY_CLASH"
-#define ENV_BABELTRACE_CLI_LOG_LEVEL "BABELTRACE_CLI_LOG_LEVEL"
-#define NSEC_PER_SEC   1000000000LL
-
-/*
- * Known environment variable names for the log levels of the project's
- * modules.
- */
-static const char* log_level_env_var_names[] = {
-       "BABELTRACE_COMMON_LOG_LEVEL",
-       "BABELTRACE_COMPAT_LOG_LEVEL",
-       "BABELTRACE_CTFSER_LOG_LEVEL",
-       "BABELTRACE_FD_CACHE_LOG_LEVEL",
-       "BABELTRACE_FLT_LTTNG_UTILS_DEBUG_INFO_LOG_LEVEL",
-       "BABELTRACE_FLT_UTILS_COUNTER_LOG_LEVEL",
-       "BABELTRACE_FLT_UTILS_MUXER_LOG_LEVEL",
-       "BABELTRACE_FLT_UTILS_TRIMMER_LOG_LEVEL",
-       "BABELTRACE_PLUGIN_CTF_BFCR_LOG_LEVEL",
-       "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL",
-       "BABELTRACE_PLUGIN_CTF_MSG_ITER_LOG_LEVEL",
-       "BABELTRACE_PLUGIN_CTF_UTILS_LOG_LEVEL",
-       "BABELTRACE_PYTHON_BT2_LOG_LEVEL",
-       "BABELTRACE_SINK_CTF_FS_LOG_LEVEL",
-       "BABELTRACE_SINK_TEXT_PRETTY_LOG_LEVEL",
-       "BABELTRACE_SRC_CTF_FS_LOG_LEVEL",
-       "BABELTRACE_SRC_CTF_LTTNG_LIVE_LOG_LEVEL",
-       "BABELTRACE_SRC_TEXT_DMESG_LOG_LEVEL",
-       NULL,
-};
-
-/* Application's processing graph (weak) */
-static bt_graph *the_graph;
-static bt_query_executor *the_query_executor;
-static bool canceled = false;
-
-GPtrArray *loaded_plugins;
-
-#ifdef __MINGW32__
-
-#include <windows.h>
-
-static
-BOOL WINAPI signal_handler(DWORD signal) {
-       if (the_graph) {
-               bt_graph_cancel(the_graph);
-       }
-
-       canceled = true;
-
-       return TRUE;
-}
-
-static
-void set_signal_handler(void)
-{
-       if (!SetConsoleCtrlHandler(signal_handler, TRUE)) {
-               BT_LOGE("Failed to set the ctrl+c handler.");
-       }
-}
-
-#else /* __MINGW32__ */
-
-static
-void signal_handler(int signum)
-{
-       if (signum != SIGINT) {
-               return;
-       }
-
-       if (the_graph) {
-               bt_graph_cancel(the_graph);
-       }
-
-       if (the_query_executor) {
-               bt_query_executor_cancel(the_query_executor);
-       }
-
-       canceled = true;
-}
-
-static
-void set_signal_handler(void)
-{
-       struct sigaction new_action, old_action;
-
-       new_action.sa_handler = signal_handler;
-       sigemptyset(&new_action.sa_mask);
-       new_action.sa_flags = 0;
-       sigaction(SIGINT, NULL, &old_action);
-
-       if (old_action.sa_handler != SIG_IGN) {
-               sigaction(SIGINT, &new_action, NULL);
-       }
-}
-
-#endif /* __MINGW32__ */
-
-static
-void init_static_data(void)
-{
-       loaded_plugins = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_put_ref);
-}
-
-static
-void fini_static_data(void)
-{
-       g_ptr_array_free(loaded_plugins, TRUE);
-}
-
-static
-int create_the_query_executor(void)
-{
-       int ret = 0;
-
-       the_query_executor = bt_query_executor_create();
-       if (!the_query_executor) {
-               BT_LOGE_STR("Cannot create a query executor.");
-               ret = -1;
-       }
-
-       return ret;
-}
-
-static
-void destroy_the_query_executor(void)
-{
-       BT_QUERY_EXECUTOR_PUT_REF_AND_RESET(the_query_executor);
-}
-
-static
-int query(const bt_component_class *comp_cls, const char *obj,
-               const bt_value *params, const bt_value **user_result,
-               const char **fail_reason)
-{
-       const bt_value *result = NULL;
-       bt_query_executor_status status;
-       *fail_reason = "unknown error";
-       int ret = 0;
-
-       BT_ASSERT(fail_reason);
-       BT_ASSERT(user_result);
-       ret = create_the_query_executor();
-       if (ret) {
-               /* create_the_query_executor() logs errors */
-               goto end;
-       }
-
-       if (canceled) {
-               BT_LOGI("Canceled by user before executing the query: "
-                       "comp-cls-addr=%p, comp-cls-name=\"%s\", "
-                       "query-obj=\"%s\"", comp_cls,
-                       bt_component_class_get_name(comp_cls), obj);
-               *fail_reason = "canceled by user";
-               goto error;
-       }
-
-       while (true) {
-               status = bt_query_executor_query(the_query_executor,
-                       comp_cls, obj, params, &result);
-               switch (status) {
-               case BT_QUERY_EXECUTOR_STATUS_OK:
-                       goto ok;
-               case BT_QUERY_EXECUTOR_STATUS_AGAIN:
-               {
-                       const uint64_t sleep_time_us = 100000;
-
-                       /* Wait 100 ms and retry */
-                       BT_LOGV("Got BT_QUERY_EXECUTOR_STATUS_AGAIN: sleeping: "
-                               "time-us=%" PRIu64, sleep_time_us);
-
-                       if (usleep(sleep_time_us)) {
-                               if (bt_query_executor_is_canceled(the_query_executor)) {
-                                       BT_LOGI("Query was canceled by user: "
-                                               "comp-cls-addr=%p, comp-cls-name=\"%s\", "
-                                               "query-obj=\"%s\"", comp_cls,
-                                               bt_component_class_get_name(comp_cls),
-                                               obj);
-                                       *fail_reason = "canceled by user";
-                                       goto error;
-                               }
-                       }
-
-                       continue;
-               }
-               case BT_QUERY_EXECUTOR_STATUS_CANCELED:
-                       *fail_reason = "canceled by user";
-                       goto error;
-               case BT_QUERY_EXECUTOR_STATUS_ERROR:
-                       goto error;
-               case BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT:
-                       *fail_reason = "invalid or unknown query object";
-                       goto error;
-               case BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS:
-                       *fail_reason = "invalid query parameters";
-                       goto error;
-               case BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED:
-                       *fail_reason = "unsupported action";
-                       goto error;
-               case BT_QUERY_EXECUTOR_STATUS_NOMEM:
-                       *fail_reason = "not enough memory";
-                       goto error;
-               default:
-                       BT_LOGF("Unknown query status: status=%d", status);
-                       abort();
-               }
-       }
-
-ok:
-       *user_result = result;
-       result = NULL;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       destroy_the_query_executor();
-       bt_value_put_ref(result);
-       return ret;
-}
-
-static
-const bt_plugin *find_plugin(const char *name)
-{
-       int i;
-       const bt_plugin *plugin = NULL;
-
-       BT_ASSERT(name);
-       BT_LOGD("Finding plugin: name=\"%s\"", name);
-
-       for (i = 0; i < loaded_plugins->len; i++) {
-               plugin = g_ptr_array_index(loaded_plugins, i);
-
-               if (strcmp(name, bt_plugin_get_name(plugin)) == 0) {
-                       break;
-               }
-
-               plugin = NULL;
-       }
-
-       if (BT_LOG_ON_DEBUG) {
-               if (plugin) {
-                       BT_LOGD("Found plugin: plugin-addr=%p", plugin);
-               } else {
-                       BT_LOGD("Cannot find plugin.");
-               }
-       }
-
-       bt_plugin_get_ref(plugin);
-       return plugin;
-}
-
-typedef const void *(*plugin_borrow_comp_cls_func_t)(
-               const bt_plugin *, const char *);
-
-static
-const void *find_component_class_from_plugin(const char *plugin_name,
-               const char *comp_class_name,
-               plugin_borrow_comp_cls_func_t plugin_borrow_comp_cls_func)
-{
-       const void *comp_class = NULL;
-       const bt_plugin *plugin;
-
-       BT_LOGD("Finding component class: plugin-name=\"%s\", "
-               "comp-cls-name=\"%s\"", plugin_name, comp_class_name);
-
-       plugin = find_plugin(plugin_name);
-       if (!plugin) {
-               goto end;
-       }
-
-       comp_class = plugin_borrow_comp_cls_func(plugin, comp_class_name);
-       bt_object_get_ref(comp_class);
-       BT_PLUGIN_PUT_REF_AND_RESET(plugin);
-
-end:
-       if (BT_LOG_ON_DEBUG) {
-               if (comp_class) {
-                       BT_LOGD("Found component class: comp-cls-addr=%p",
-                               comp_class);
-               } else {
-                       BT_LOGD("Cannot find source component class.");
-               }
-       }
-
-       return comp_class;
-}
-
-static
-const bt_component_class_source *find_source_component_class(
-               const char *plugin_name, const char *comp_class_name)
-{
-       return (const void *) find_component_class_from_plugin(
-               plugin_name, comp_class_name,
-               (plugin_borrow_comp_cls_func_t)
-                       bt_plugin_borrow_source_component_class_by_name_const);
-}
-
-static
-const bt_component_class_filter *find_filter_component_class(
-               const char *plugin_name, const char *comp_class_name)
-{
-       return (const void *) find_component_class_from_plugin(
-               plugin_name, comp_class_name,
-               (plugin_borrow_comp_cls_func_t)
-                       bt_plugin_borrow_filter_component_class_by_name_const);
-}
-
-static
-const bt_component_class_sink *find_sink_component_class(
-               const char *plugin_name, const char *comp_class_name)
-{
-       return (const void *) find_component_class_from_plugin(plugin_name,
-               comp_class_name,
-               (plugin_borrow_comp_cls_func_t)
-                       bt_plugin_borrow_sink_component_class_by_name_const);
-}
-
-static
-const bt_component_class *find_component_class(const char *plugin_name,
-               const char *comp_class_name,
-               bt_component_class_type comp_class_type)
-{
-       const bt_component_class *comp_cls = NULL;
-
-       switch (comp_class_type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-               comp_cls = bt_component_class_source_as_component_class_const(find_source_component_class(plugin_name, comp_class_name));
-               break;
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-               comp_cls = bt_component_class_filter_as_component_class_const(find_filter_component_class(plugin_name, comp_class_name));
-               break;
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-               comp_cls = bt_component_class_sink_as_component_class_const(find_sink_component_class(plugin_name, comp_class_name));
-               break;
-       default:
-               abort();
-       }
-
-       return comp_cls;
-}
-
-static
-void print_indent(FILE *fp, size_t indent)
-{
-       size_t i;
-
-       for (i = 0; i < indent; i++) {
-               fprintf(fp, " ");
-       }
-}
-
-static
-const char *component_type_str(bt_component_class_type type)
-{
-       switch (type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-               return "source";
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-               return "sink";
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-               return "filter";
-       default:
-               return "(unknown)";
-       }
-}
-
-static
-void print_plugin_comp_cls_opt(FILE *fh, const char *plugin_name,
-               const char *comp_cls_name, bt_component_class_type type)
-{
-       GString *shell_plugin_name = NULL;
-       GString *shell_comp_cls_name = NULL;
-
-       shell_plugin_name = bt_common_shell_quote(plugin_name, false);
-       if (!shell_plugin_name) {
-               goto end;
-       }
-
-       shell_comp_cls_name = bt_common_shell_quote(comp_cls_name, false);
-       if (!shell_comp_cls_name) {
-               goto end;
-       }
-
-       fprintf(fh, "'%s%s%s%s.%s%s%s.%s%s%s'",
-               bt_common_color_bold(),
-               bt_common_color_fg_cyan(),
-               component_type_str(type),
-               bt_common_color_fg_default(),
-               bt_common_color_fg_blue(),
-               shell_plugin_name->str,
-               bt_common_color_fg_default(),
-               bt_common_color_fg_yellow(),
-               shell_comp_cls_name->str,
-               bt_common_color_reset());
-
-end:
-       if (shell_plugin_name) {
-               g_string_free(shell_plugin_name, TRUE);
-       }
-
-       if (shell_comp_cls_name) {
-               g_string_free(shell_comp_cls_name, TRUE);
-       }
-}
-
-static
-void print_value(FILE *, const bt_value *, size_t);
-
-static
-void print_value_rec(FILE *, const bt_value *, size_t);
-
-struct print_map_value_data {
-       size_t indent;
-       FILE *fp;
-};
-
-static
-bt_bool print_map_value(const char *key, const bt_value *object,
-               void *data)
-{
-       struct print_map_value_data *print_map_value_data = data;
-
-       print_indent(print_map_value_data->fp, print_map_value_data->indent);
-       fprintf(print_map_value_data->fp, "%s: ", key);
-       BT_ASSERT(object);
-
-       if (bt_value_is_array(object) &&
-                       bt_value_array_is_empty(object)) {
-               fprintf(print_map_value_data->fp, "[ ]\n");
-               return true;
-       }
-
-       if (bt_value_is_map(object) &&
-                       bt_value_map_is_empty(object)) {
-               fprintf(print_map_value_data->fp, "{ }\n");
-               return true;
-       }
-
-       if (bt_value_is_array(object) ||
-                       bt_value_is_map(object)) {
-               fprintf(print_map_value_data->fp, "\n");
-       }
-
-       print_value_rec(print_map_value_data->fp, object,
-               print_map_value_data->indent + 2);
-       return BT_TRUE;
-}
-
-static
-void print_value_rec(FILE *fp, const bt_value *value, size_t indent)
-{
-       bt_bool bool_val;
-       int64_t int_val;
-       uint64_t uint_val;
-       double dbl_val;
-       const char *str_val;
-       int size;
-       int i;
-
-       if (!value) {
-               return;
-       }
-
-       switch (bt_value_get_type(value)) {
-       case BT_VALUE_TYPE_NULL:
-               fprintf(fp, "%snull%s\n", bt_common_color_bold(),
-                       bt_common_color_reset());
-               break;
-       case BT_VALUE_TYPE_BOOL:
-               bool_val = bt_value_bool_get(value);
-               fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
-                       bt_common_color_fg_cyan(), bool_val ? "yes" : "no",
-                       bt_common_color_reset());
-               break;
-       case BT_VALUE_TYPE_UNSIGNED_INTEGER:
-               uint_val = bt_value_unsigned_integer_get(value);
-               fprintf(fp, "%s%s%" PRIu64 "%s\n", bt_common_color_bold(),
-                       bt_common_color_fg_red(), uint_val,
-                       bt_common_color_reset());
-               break;
-       case BT_VALUE_TYPE_SIGNED_INTEGER:
-               int_val = bt_value_signed_integer_get(value);
-               fprintf(fp, "%s%s%" PRId64 "%s\n", bt_common_color_bold(),
-                       bt_common_color_fg_red(), int_val,
-                       bt_common_color_reset());
-               break;
-       case BT_VALUE_TYPE_REAL:
-               dbl_val = bt_value_real_get(value);
-               fprintf(fp, "%s%s%lf%s\n", bt_common_color_bold(),
-                       bt_common_color_fg_red(), dbl_val,
-                       bt_common_color_reset());
-               break;
-       case BT_VALUE_TYPE_STRING:
-               str_val = bt_value_string_get(value);
-               fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
-                       bt_common_color_fg_green(), str_val,
-                       bt_common_color_reset());
-               break;
-       case BT_VALUE_TYPE_ARRAY:
-               size = bt_value_array_get_size(value);
-               if (size < 0) {
-                       goto error;
-               }
-
-               if (size == 0) {
-                       print_indent(fp, indent);
-                       fprintf(fp, "[ ]\n");
-                       break;
-               }
-
-               for (i = 0; i < size; i++) {
-                       const bt_value *element =
-                               bt_value_array_borrow_element_by_index_const(
-                                       value, i);
-
-                       if (!element) {
-                               goto error;
-                       }
-                       print_indent(fp, indent);
-                       fprintf(fp, "- ");
-
-                       if (bt_value_is_array(element) &&
-                                       bt_value_array_is_empty(element)) {
-                               fprintf(fp, "[ ]\n");
-                               continue;
-                       }
-
-                       if (bt_value_is_map(element) &&
-                                       bt_value_map_is_empty(element)) {
-                               fprintf(fp, "{ }\n");
-                               continue;
-                       }
-
-                       if (bt_value_is_array(element) ||
-                                       bt_value_is_map(element)) {
-                               fprintf(fp, "\n");
-                       }
-
-                       print_value_rec(fp, element, indent + 2);
-               }
-               break;
-       case BT_VALUE_TYPE_MAP:
-       {
-               struct print_map_value_data data = {
-                       .indent = indent,
-                       .fp = fp,
-               };
-
-               if (bt_value_map_is_empty(value)) {
-                       print_indent(fp, indent);
-                       fprintf(fp, "{ }\n");
-                       break;
-               }
-
-               bt_value_map_foreach_entry_const(value, print_map_value, &data);
-               break;
-       }
-       default:
-               abort();
-       }
-       return;
-
-error:
-       BT_LOGE("Error printing value of type %s.",
-               bt_common_value_type_string(bt_value_get_type(value)));
-}
-
-static
-void print_value(FILE *fp, const bt_value *value, size_t indent)
-{
-       if (!bt_value_is_array(value) && !bt_value_is_map(value)) {
-               print_indent(fp, indent);
-       }
-
-       print_value_rec(fp, value, indent);
-}
-
-static
-void print_bt_config_component(struct bt_config_component *bt_config_component)
-{
-       fprintf(stderr, "    ");
-       print_plugin_comp_cls_opt(stderr, bt_config_component->plugin_name->str,
-               bt_config_component->comp_cls_name->str,
-               bt_config_component->type);
-       fprintf(stderr, ":\n");
-
-       if (bt_config_component->instance_name->len > 0) {
-               fprintf(stderr, "      Name: %s\n",
-                       bt_config_component->instance_name->str);
-       }
-
-       fprintf(stderr, "      Parameters:\n");
-       print_value(stderr, bt_config_component->params, 8);
-}
-
-static
-void print_bt_config_components(GPtrArray *array)
-{
-       size_t i;
-
-       for (i = 0; i < array->len; i++) {
-               struct bt_config_component *cfg_component =
-                               bt_config_get_component(array, i);
-               print_bt_config_component(cfg_component);
-               BT_OBJECT_PUT_REF_AND_RESET(cfg_component);
-       }
-}
-
-static
-void print_plugin_paths(const bt_value *plugin_paths)
-{
-       fprintf(stderr, "  Plugin paths:\n");
-       print_value(stderr, plugin_paths, 4);
-}
-
-static
-void print_cfg_run(struct bt_config *cfg)
-{
-       size_t i;
-
-       print_plugin_paths(cfg->plugin_paths);
-       fprintf(stderr, "  Source component instances:\n");
-       print_bt_config_components(cfg->cmd_data.run.sources);
-
-       if (cfg->cmd_data.run.filters->len > 0) {
-               fprintf(stderr, "  Filter component instances:\n");
-               print_bt_config_components(cfg->cmd_data.run.filters);
-       }
-
-       fprintf(stderr, "  Sink component instances:\n");
-       print_bt_config_components(cfg->cmd_data.run.sinks);
-       fprintf(stderr, "  Connections:\n");
-
-       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
-               struct bt_config_connection *cfg_connection =
-                       g_ptr_array_index(cfg->cmd_data.run.connections,
-                               i);
-
-               fprintf(stderr, "    %s%s%s -> %s%s%s\n",
-                       cfg_connection->upstream_comp_name->str,
-                       cfg_connection->upstream_port_glob->len > 0 ? "." : "",
-                       cfg_connection->upstream_port_glob->str,
-                       cfg_connection->downstream_comp_name->str,
-                       cfg_connection->downstream_port_glob->len > 0 ? "." : "",
-                       cfg_connection->downstream_port_glob->str);
-       }
-}
-
-static
-void print_cfg_list_plugins(struct bt_config *cfg)
-{
-       print_plugin_paths(cfg->plugin_paths);
-}
-
-static
-void print_cfg_help(struct bt_config *cfg)
-{
-       print_plugin_paths(cfg->plugin_paths);
-}
-
-static
-void print_cfg_print_ctf_metadata(struct bt_config *cfg)
-{
-       print_plugin_paths(cfg->plugin_paths);
-       fprintf(stderr, "  Path: %s\n",
-               cfg->cmd_data.print_ctf_metadata.path->str);
-}
-
-static
-void print_cfg_print_lttng_live_sessions(struct bt_config *cfg)
-{
-       print_plugin_paths(cfg->plugin_paths);
-       fprintf(stderr, "  URL: %s\n",
-               cfg->cmd_data.print_lttng_live_sessions.url->str);
-}
-
-static
-void print_cfg_query(struct bt_config *cfg)
-{
-       print_plugin_paths(cfg->plugin_paths);
-       fprintf(stderr, "  Object: `%s`\n", cfg->cmd_data.query.object->str);
-       fprintf(stderr, "  Component class:\n");
-       print_bt_config_component(cfg->cmd_data.query.cfg_component);
-}
-
-static
-void print_cfg(struct bt_config *cfg)
-{
-       if (!BT_LOG_ON_INFO) {
-               return;
-       }
-
-       BT_LOGI_STR("Configuration:");
-       fprintf(stderr, "  Debug mode: %s\n", cfg->debug ? "yes" : "no");
-       fprintf(stderr, "  Verbose mode: %s\n", cfg->verbose ? "yes" : "no");
-
-       switch (cfg->command) {
-       case BT_CONFIG_COMMAND_RUN:
-               print_cfg_run(cfg);
-               break;
-       case BT_CONFIG_COMMAND_LIST_PLUGINS:
-               print_cfg_list_plugins(cfg);
-               break;
-       case BT_CONFIG_COMMAND_HELP:
-               print_cfg_help(cfg);
-               break;
-       case BT_CONFIG_COMMAND_QUERY:
-               print_cfg_query(cfg);
-               break;
-       case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
-               print_cfg_print_ctf_metadata(cfg);
-               break;
-       case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
-               print_cfg_print_lttng_live_sessions(cfg);
-               break;
-       default:
-               abort();
-       }
-}
-
-static
-void add_to_loaded_plugins(const bt_plugin_set *plugin_set)
-{
-       int64_t i;
-       int64_t count;
-
-       count = bt_plugin_set_get_plugin_count(plugin_set);
-       BT_ASSERT(count >= 0);
-
-       for (i = 0; i < count; i++) {
-               const bt_plugin *plugin =
-                       bt_plugin_set_borrow_plugin_by_index_const(plugin_set, i);
-               const bt_plugin *loaded_plugin =
-                       find_plugin(bt_plugin_get_name(plugin));
-
-               BT_ASSERT(plugin);
-
-               if (loaded_plugin) {
-                       BT_LOGI("Not using plugin: another one already exists with the same name: "
-                               "plugin-name=\"%s\", plugin-path=\"%s\", "
-                               "existing-plugin-path=\"%s\"",
-                               bt_plugin_get_name(plugin),
-                               bt_plugin_get_path(plugin),
-                               bt_plugin_get_path(loaded_plugin));
-                       bt_plugin_put_ref(loaded_plugin);
-               } else {
-                       /* Add to global array. */
-                       BT_LOGD("Adding plugin to loaded plugins: plugin-path=\"%s\"",
-                               bt_plugin_get_name(plugin));
-                       bt_plugin_get_ref(plugin);
-                       g_ptr_array_add(loaded_plugins, (void *) plugin);
-               }
-       }
-}
-
-static
-int load_dynamic_plugins(const bt_value *plugin_paths)
-{
-       int nr_paths, i, ret = 0;
-
-       nr_paths = bt_value_array_get_size(plugin_paths);
-       if (nr_paths < 0) {
-               BT_LOGE_STR("Cannot load dynamic plugins: no plugin path.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGI("Loading dynamic plugins.");
-
-       for (i = 0; i < nr_paths; i++) {
-               const bt_value *plugin_path_value = NULL;
-               const char *plugin_path;
-               const bt_plugin_set *plugin_set;
-
-               plugin_path_value =
-                       bt_value_array_borrow_element_by_index_const(
-                               plugin_paths, i);
-               plugin_path = bt_value_string_get(plugin_path_value);
-
-               /*
-                * Skip this if the directory does not exist because
-                * bt_plugin_find_all_from_dir() expects an existing
-                * directory.
-                */
-               if (!g_file_test(plugin_path, G_FILE_TEST_IS_DIR)) {
-                       BT_LOGV("Skipping nonexistent directory path: "
-                               "path=\"%s\"", plugin_path);
-                       continue;
-               }
-
-               plugin_set = bt_plugin_find_all_from_dir(plugin_path, false);
-               if (!plugin_set) {
-                       BT_LOGD("Unable to load dynamic plugins: path=\"%s\"",
-                               plugin_path);
-                       continue;
-               }
-
-               add_to_loaded_plugins(plugin_set);
-               bt_plugin_set_put_ref(plugin_set);
-       }
-end:
-       return ret;
-}
-
-static
-int load_static_plugins(void)
-{
-       int ret = 0;
-       const bt_plugin_set *plugin_set;
-
-       BT_LOGI("Loading static plugins.");
-       plugin_set = bt_plugin_find_all_from_static();
-       if (!plugin_set) {
-               BT_LOGE("Unable to load static plugins.");
-               ret = -1;
-               goto end;
-       }
-
-       add_to_loaded_plugins(plugin_set);
-       bt_plugin_set_put_ref(plugin_set);
-end:
-       return ret;
-}
-
-static
-int load_all_plugins(const bt_value *plugin_paths)
-{
-       int ret = 0;
-
-       if (load_dynamic_plugins(plugin_paths)) {
-               ret = -1;
-               goto end;
-       }
-
-       if (load_static_plugins()) {
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGI("Loaded all plugins: count=%u", loaded_plugins->len);
-
-end:
-       return ret;
-}
-
-static
-void print_plugin_info(const bt_plugin *plugin)
-{
-       unsigned int major, minor, patch;
-       const char *extra;
-       bt_property_availability version_avail;
-       const char *plugin_name;
-       const char *path;
-       const char *author;
-       const char *license;
-       const char *plugin_description;
-
-       plugin_name = bt_plugin_get_name(plugin);
-       path = bt_plugin_get_path(plugin);
-       author = bt_plugin_get_author(plugin);
-       license = bt_plugin_get_license(plugin);
-       plugin_description = bt_plugin_get_description(plugin);
-       version_avail = bt_plugin_get_version(plugin, &major, &minor,
-               &patch, &extra);
-       printf("%s%s%s%s:\n", bt_common_color_bold(),
-               bt_common_color_fg_blue(), plugin_name,
-               bt_common_color_reset());
-       if (path) {
-               printf("  %sPath%s: %s\n", bt_common_color_bold(),
-                       bt_common_color_reset(), path);
-       } else {
-               puts("  Built-in");
-       }
-
-       if (version_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
-               printf("  %sVersion%s: %u.%u.%u",
-                       bt_common_color_bold(), bt_common_color_reset(),
-                       major, minor, patch);
-
-               if (extra) {
-                       printf("%s", extra);
-               }
-
-               printf("\n");
-       }
-
-       printf("  %sDescription%s: %s\n", bt_common_color_bold(),
-               bt_common_color_reset(),
-               plugin_description ? plugin_description : "(None)");
-       printf("  %sAuthor%s: %s\n", bt_common_color_bold(),
-               bt_common_color_reset(), author ? author : "(Unknown)");
-       printf("  %sLicense%s: %s\n", bt_common_color_bold(),
-               bt_common_color_reset(),
-               license ? license : "(Unknown)");
-}
-
-static
-int cmd_query(struct bt_config *cfg)
-{
-       int ret = 0;
-       const bt_component_class *comp_cls = NULL;
-       const bt_value *results = NULL;
-       const char *fail_reason = NULL;
-
-       comp_cls = find_component_class(
-               cfg->cmd_data.query.cfg_component->plugin_name->str,
-               cfg->cmd_data.query.cfg_component->comp_cls_name->str,
-               cfg->cmd_data.query.cfg_component->type);
-       if (!comp_cls) {
-               BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
-                       "comp-cls-name=\"%s\", comp-cls-type=%d",
-                       cfg->cmd_data.query.cfg_component->plugin_name->str,
-                       cfg->cmd_data.query.cfg_component->comp_cls_name->str,
-                       cfg->cmd_data.query.cfg_component->type);
-               fprintf(stderr, "%s%sCannot find component class %s",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       bt_common_color_reset());
-               print_plugin_comp_cls_opt(stderr,
-                       cfg->cmd_data.query.cfg_component->plugin_name->str,
-                       cfg->cmd_data.query.cfg_component->comp_cls_name->str,
-                       cfg->cmd_data.query.cfg_component->type);
-               fprintf(stderr, "\n");
-               ret = -1;
-               goto end;
-       }
-
-       ret = query(comp_cls, cfg->cmd_data.query.object->str,
-               cfg->cmd_data.query.cfg_component->params,
-               &results, &fail_reason);
-       if (ret) {
-               goto failed;
-       }
-
-       print_value(stdout, results, 0);
-       goto end;
-
-failed:
-       BT_LOGE("Failed to query component class: %s: plugin-name=\"%s\", "
-               "comp-cls-name=\"%s\", comp-cls-type=%d "
-               "object=\"%s\"", fail_reason,
-               cfg->cmd_data.query.cfg_component->plugin_name->str,
-               cfg->cmd_data.query.cfg_component->comp_cls_name->str,
-               cfg->cmd_data.query.cfg_component->type,
-               cfg->cmd_data.query.object->str);
-       fprintf(stderr, "%s%sFailed to query info to %s",
-               bt_common_color_bold(),
-               bt_common_color_fg_red(),
-               bt_common_color_reset());
-       print_plugin_comp_cls_opt(stderr,
-               cfg->cmd_data.query.cfg_component->plugin_name->str,
-               cfg->cmd_data.query.cfg_component->comp_cls_name->str,
-               cfg->cmd_data.query.cfg_component->type);
-       fprintf(stderr, "%s%s with object `%s`: %s%s\n",
-               bt_common_color_bold(),
-               bt_common_color_fg_red(),
-               cfg->cmd_data.query.object->str,
-               fail_reason,
-               bt_common_color_reset());
-       ret = -1;
-
-end:
-       bt_component_class_put_ref(comp_cls);
-       bt_value_put_ref(results);
-       return ret;
-}
-
-static
-void print_component_class_help(const char *plugin_name,
-               const bt_component_class *comp_cls)
-{
-       const char *comp_class_name =
-               bt_component_class_get_name(comp_cls);
-       const char *comp_class_description =
-               bt_component_class_get_description(comp_cls);
-       const char *comp_class_help =
-               bt_component_class_get_help(comp_cls);
-       bt_component_class_type type =
-               bt_component_class_get_type(comp_cls);
-
-       print_plugin_comp_cls_opt(stdout, plugin_name, comp_class_name, type);
-       printf("\n");
-       printf("  %sDescription%s: %s\n", bt_common_color_bold(),
-               bt_common_color_reset(),
-               comp_class_description ? comp_class_description : "(None)");
-
-       if (comp_class_help) {
-               printf("\n%s\n", comp_class_help);
-       }
-}
-
-static
-int cmd_help(struct bt_config *cfg)
-{
-       int ret = 0;
-       const bt_plugin *plugin = NULL;
-       const bt_component_class *needed_comp_cls = NULL;
-
-       plugin = find_plugin(cfg->cmd_data.help.cfg_component->plugin_name->str);
-       if (!plugin) {
-               BT_LOGE("Cannot find plugin: plugin-name=\"%s\"",
-                       cfg->cmd_data.help.cfg_component->plugin_name->str);
-               fprintf(stderr, "%s%sCannot find plugin %s%s%s\n",
-                       bt_common_color_bold(), bt_common_color_fg_red(),
-                       bt_common_color_fg_blue(),
-                       cfg->cmd_data.help.cfg_component->plugin_name->str,
-                       bt_common_color_reset());
-               ret = -1;
-               goto end;
-       }
-
-       print_plugin_info(plugin);
-       printf("  %sSource component classes%s: %d\n",
-                       bt_common_color_bold(),
-                       bt_common_color_reset(),
-                       (int) bt_plugin_get_source_component_class_count(plugin));
-       printf("  %sFilter component classes%s: %d\n",
-                       bt_common_color_bold(),
-                       bt_common_color_reset(),
-                       (int) bt_plugin_get_filter_component_class_count(plugin));
-       printf("  %sSink component classes%s: %d\n",
-                       bt_common_color_bold(),
-                       bt_common_color_reset(),
-                       (int) bt_plugin_get_sink_component_class_count(plugin));
-
-       if (strlen(cfg->cmd_data.help.cfg_component->comp_cls_name->str) == 0) {
-               /* Plugin help only */
-               goto end;
-       }
-
-       needed_comp_cls = find_component_class(
-               cfg->cmd_data.help.cfg_component->plugin_name->str,
-               cfg->cmd_data.help.cfg_component->comp_cls_name->str,
-               cfg->cmd_data.help.cfg_component->type);
-       if (!needed_comp_cls) {
-               BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
-                       "comp-cls-name=\"%s\", comp-cls-type=%d",
-                       cfg->cmd_data.help.cfg_component->plugin_name->str,
-                       cfg->cmd_data.help.cfg_component->comp_cls_name->str,
-                       cfg->cmd_data.help.cfg_component->type);
-               fprintf(stderr, "\n%s%sCannot find component class %s",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       bt_common_color_reset());
-               print_plugin_comp_cls_opt(stderr,
-                       cfg->cmd_data.help.cfg_component->plugin_name->str,
-                       cfg->cmd_data.help.cfg_component->comp_cls_name->str,
-                       cfg->cmd_data.help.cfg_component->type);
-               fprintf(stderr, "\n");
-               ret = -1;
-               goto end;
-       }
-
-       printf("\n");
-       print_component_class_help(
-               cfg->cmd_data.help.cfg_component->plugin_name->str,
-               needed_comp_cls);
-
-end:
-       bt_component_class_put_ref(needed_comp_cls);
-       bt_plugin_put_ref(plugin);
-       return ret;
-}
-
-typedef void *(* plugin_borrow_comp_cls_by_index_func_t)(const bt_plugin *,
-       uint64_t);
-typedef const bt_component_class *(* spec_comp_cls_borrow_comp_cls_func_t)(
-       void *);
-
-void cmd_list_plugins_print_component_classes(const bt_plugin *plugin,
-               const char *cc_type_name, uint64_t count,
-               plugin_borrow_comp_cls_by_index_func_t borrow_comp_cls_by_index_func,
-               spec_comp_cls_borrow_comp_cls_func_t spec_comp_cls_borrow_comp_cls_func)
-{
-       uint64_t i;
-
-       if (count == 0) {
-               printf("  %s%s component classes%s: (none)\n",
-                       bt_common_color_bold(),
-                       cc_type_name,
-                       bt_common_color_reset());
-               goto end;
-       } else {
-               printf("  %s%s component classes%s:\n",
-                       bt_common_color_bold(),
-                       cc_type_name,
-                       bt_common_color_reset());
-       }
-
-       for (i = 0; i < count; i++) {
-               const bt_component_class *comp_class =
-                       spec_comp_cls_borrow_comp_cls_func(
-                               borrow_comp_cls_by_index_func(plugin, i));
-               const char *comp_class_name =
-                       bt_component_class_get_name(comp_class);
-               const char *comp_class_description =
-                       bt_component_class_get_description(comp_class);
-               bt_component_class_type type =
-                       bt_component_class_get_type(comp_class);
-
-               printf("    ");
-               print_plugin_comp_cls_opt(stdout,
-                       bt_plugin_get_name(plugin), comp_class_name,
-                       type);
-
-               if (comp_class_description) {
-                       printf(": %s", comp_class_description);
-               }
-
-               printf("\n");
-       }
-
-end:
-       return;
-}
-
-static
-int cmd_list_plugins(struct bt_config *cfg)
-{
-       int ret = 0;
-       int plugins_count, component_classes_count = 0, i;
-
-       printf("From the following plugin paths:\n\n");
-       print_value(stdout, cfg->plugin_paths, 2);
-       printf("\n");
-       plugins_count = loaded_plugins->len;
-       if (plugins_count == 0) {
-               printf("No plugins found.\n");
-               goto end;
-       }
-
-       for (i = 0; i < plugins_count; i++) {
-               const bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
-
-               component_classes_count +=
-                       bt_plugin_get_source_component_class_count(plugin) +
-                       bt_plugin_get_filter_component_class_count(plugin) +
-                       bt_plugin_get_sink_component_class_count(plugin);
-       }
-
-       printf("Found %s%d%s component classes in %s%d%s plugins.\n",
-               bt_common_color_bold(),
-               component_classes_count,
-               bt_common_color_reset(),
-               bt_common_color_bold(),
-               plugins_count,
-               bt_common_color_reset());
-
-       for (i = 0; i < plugins_count; i++) {
-               const bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
-
-               printf("\n");
-               print_plugin_info(plugin);
-               cmd_list_plugins_print_component_classes(plugin, "Source",
-                       bt_plugin_get_source_component_class_count(plugin),
-                       (plugin_borrow_comp_cls_by_index_func_t)
-                               bt_plugin_borrow_source_component_class_by_index_const,
-                       (spec_comp_cls_borrow_comp_cls_func_t)
-                               bt_component_class_source_as_component_class);
-               cmd_list_plugins_print_component_classes(plugin, "Filter",
-                       bt_plugin_get_filter_component_class_count(plugin),
-                       (plugin_borrow_comp_cls_by_index_func_t)
-                               bt_plugin_borrow_filter_component_class_by_index_const,
-                       (spec_comp_cls_borrow_comp_cls_func_t)
-                               bt_component_class_filter_as_component_class);
-               cmd_list_plugins_print_component_classes(plugin, "Sink",
-                       bt_plugin_get_sink_component_class_count(plugin),
-                       (plugin_borrow_comp_cls_by_index_func_t)
-                               bt_plugin_borrow_sink_component_class_by_index_const,
-                       (spec_comp_cls_borrow_comp_cls_func_t)
-                               bt_component_class_sink_as_component_class);
-       }
-
-end:
-       return ret;
-}
-
-static
-int cmd_print_lttng_live_sessions(struct bt_config *cfg)
-{
-       int ret = 0;
-       const bt_component_class *comp_cls = NULL;
-       const bt_value *results = NULL;
-       bt_value *params = NULL;
-       const bt_value *map = NULL;
-       const bt_value *v = NULL;
-       static const char * const plugin_name = "ctf";
-       static const char * const comp_cls_name = "lttng-live";
-       static const bt_component_class_type comp_cls_type =
-               BT_COMPONENT_CLASS_TYPE_SOURCE;
-       int64_t array_size, i;
-       const char *fail_reason = NULL;
-       FILE *out_stream = stdout;
-
-       BT_ASSERT(cfg->cmd_data.print_lttng_live_sessions.url);
-       comp_cls = find_component_class(plugin_name, comp_cls_name,
-               comp_cls_type);
-       if (!comp_cls) {
-               BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
-                       "comp-cls-name=\"%s\", comp-cls-type=%d",
-                       plugin_name, comp_cls_name,
-                       BT_COMPONENT_CLASS_TYPE_SOURCE);
-               fprintf(stderr, "%s%sCannot find component class %s",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       bt_common_color_reset());
-               print_plugin_comp_cls_opt(stderr, plugin_name,
-                       comp_cls_name, comp_cls_type);
-               fprintf(stderr, "\n");
-               goto error;
-       }
-
-       params = bt_value_map_create();
-       if (!params) {
-               goto error;
-       }
-
-       ret = bt_value_map_insert_string_entry(params, "url",
-               cfg->cmd_data.print_lttng_live_sessions.url->str);
-       if (ret) {
-               goto error;
-       }
-
-       ret = query(comp_cls, "sessions", params,
-                   &results, &fail_reason);
-       if (ret) {
-               goto failed;
-       }
-
-       BT_ASSERT(results);
-
-       if (!bt_value_is_array(results)) {
-               BT_LOGE_STR("Expecting an array for sessions query.");
-               fprintf(stderr, "%s%sUnexpected type returned by session query%s\n",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       bt_common_color_reset());
-               goto error;
-       }
-
-       if (cfg->cmd_data.print_lttng_live_sessions.output_path->len > 0) {
-               out_stream =
-                       fopen(cfg->cmd_data.print_lttng_live_sessions.output_path->str,
-                               "w");
-               if (!out_stream) {
-                       ret = -1;
-                       BT_LOGE_ERRNO("Cannot open file for writing",
-                               ": path=\"%s\"",
-                               cfg->cmd_data.print_lttng_live_sessions.output_path->str);
-                       goto end;
-               }
-       }
-
-       array_size = bt_value_array_get_size(results);
-       for (i = 0; i < array_size; i++) {
-               const char *url_text;
-               int64_t timer_us, streams, clients;
-
-               map = bt_value_array_borrow_element_by_index_const(results, i);
-               if (!map) {
-                       BT_LOGE_STR("Unexpected empty array entry.");
-                       goto error;
-               }
-               if (!bt_value_is_map(map)) {
-                       BT_LOGE_STR("Unexpected entry type.");
-                       goto error;
-               }
-
-               v = bt_value_map_borrow_entry_value_const(map, "url");
-               if (!v) {
-                       BT_LOGE_STR("Unexpected empty array \"url\" entry.");
-                       goto error;
-               }
-               url_text = bt_value_string_get(v);
-               fprintf(out_stream, "%s", url_text);
-               v = bt_value_map_borrow_entry_value_const(map, "timer-us");
-               if (!v) {
-                       BT_LOGE_STR("Unexpected empty array \"timer-us\" entry.");
-                       goto error;
-               }
-               timer_us = bt_value_signed_integer_get(v);
-               fprintf(out_stream, " (timer = %" PRIu64 ", ", timer_us);
-               v = bt_value_map_borrow_entry_value_const(map, "stream-count");
-               if (!v) {
-                       BT_LOGE_STR("Unexpected empty array \"stream-count\" entry.");
-                       goto error;
-               }
-               streams = bt_value_signed_integer_get(v);
-               fprintf(out_stream, "%" PRIu64 " stream(s), ", streams);
-               v = bt_value_map_borrow_entry_value_const(map, "client-count");
-               if (!v) {
-                       BT_LOGE_STR("Unexpected empty array \"client-count\" entry.");
-                       goto error;
-               }
-               clients = bt_value_signed_integer_get(v);
-               fprintf(out_stream, "%" PRIu64 " client(s) connected)\n", clients);
-       }
-
-       goto end;
-
-failed:
-       BT_LOGE("Failed to query for sessions: %s", fail_reason);
-       fprintf(stderr, "%s%sFailed to request sessions: %s%s\n",
-               bt_common_color_bold(),
-               bt_common_color_fg_red(),
-               fail_reason,
-               bt_common_color_reset());
-
-error:
-       ret = -1;
-
-end:
-       bt_value_put_ref(results);
-       bt_value_put_ref(params);
-       bt_component_class_put_ref(comp_cls);
-
-       if (out_stream && out_stream != stdout) {
-               int fclose_ret = fclose(out_stream);
-
-               if (fclose_ret) {
-                       BT_LOGE_ERRNO("Cannot close file stream",
-                               ": path=\"%s\"",
-                               cfg->cmd_data.print_lttng_live_sessions.output_path->str);
-               }
-       }
-
-       return ret;
-}
-
-static
-int cmd_print_ctf_metadata(struct bt_config *cfg)
-{
-       int ret = 0;
-       const bt_component_class *comp_cls = NULL;
-       const bt_value *results = NULL;
-       bt_value *params = NULL;
-       const bt_value *metadata_text_value = NULL;
-       const char *metadata_text = NULL;
-       static const char * const plugin_name = "ctf";
-       static const char * const comp_cls_name = "fs";
-       static const bt_component_class_type comp_cls_type =
-               BT_COMPONENT_CLASS_TYPE_SOURCE;
-       const char *fail_reason = NULL;
-       FILE *out_stream = stdout;
-
-       BT_ASSERT(cfg->cmd_data.print_ctf_metadata.path);
-       comp_cls = find_component_class(plugin_name, comp_cls_name,
-               comp_cls_type);
-       if (!comp_cls) {
-               BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
-                       "comp-cls-name=\"%s\", comp-cls-type=%d",
-                       plugin_name, comp_cls_name,
-                       BT_COMPONENT_CLASS_TYPE_SOURCE);
-               fprintf(stderr, "%s%sCannot find component class %s",
-                       bt_common_color_bold(),
-                       bt_common_color_fg_red(),
-                       bt_common_color_reset());
-               print_plugin_comp_cls_opt(stderr, plugin_name,
-                       comp_cls_name, comp_cls_type);
-               fprintf(stderr, "\n");
-               ret = -1;
-               goto end;
-       }
-
-       params = bt_value_map_create();
-       if (!params) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_value_map_insert_string_entry(params, "path",
-               cfg->cmd_data.print_ctf_metadata.path->str);
-       if (ret) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = query(comp_cls, "metadata-info",
-               params, &results, &fail_reason);
-       if (ret) {
-               goto failed;
-       }
-
-       metadata_text_value = bt_value_map_borrow_entry_value_const(results,
-                                                                   "text");
-       if (!metadata_text_value) {
-               BT_LOGE_STR("Cannot find `text` string value in the resulting metadata info object.");
-               ret = -1;
-               goto end;
-       }
-
-       metadata_text = bt_value_string_get(metadata_text_value);
-
-       if (cfg->cmd_data.print_ctf_metadata.output_path->len > 0) {
-               out_stream =
-                       fopen(cfg->cmd_data.print_ctf_metadata.output_path->str,
-                               "w");
-               if (!out_stream) {
-                       ret = -1;
-                       BT_LOGE_ERRNO("Cannot open file for writing",
-                               ": path=\"%s\"",
-                               cfg->cmd_data.print_ctf_metadata.output_path->str);
-                       goto end;
-               }
-       }
-
-       ret = fprintf(out_stream, "%s\n", metadata_text);
-       if (ret < 0) {
-               BT_LOGE("Cannot write whole metadata text to output stream: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       ret = 0;
-
-       goto end;
-
-failed:
-       ret = -1;
-       BT_LOGE("Failed to query for metadata info: %s", fail_reason);
-       fprintf(stderr, "%s%sFailed to request metadata info: %s%s\n",
-               bt_common_color_bold(),
-               bt_common_color_fg_red(),
-               fail_reason,
-               bt_common_color_reset());
-
-end:
-       bt_value_put_ref(results);
-       bt_value_put_ref(params);
-       bt_component_class_put_ref(comp_cls);
-
-       if (out_stream && out_stream != stdout) {
-               int fclose_ret = fclose(out_stream);
-
-               if (fclose_ret) {
-                       BT_LOGE_ERRNO("Cannot close file stream",
-                               ": path=\"%s\"",
-                               cfg->cmd_data.print_ctf_metadata.output_path->str);
-               }
-       }
-
-       return ret;
-}
-
-struct port_id {
-       char *instance_name;
-       char *port_name;
-};
-
-struct trace_range {
-       uint64_t intersection_range_begin_ns;
-       uint64_t intersection_range_end_ns;
-};
-
-static
-guint port_id_hash(gconstpointer v)
-{
-       const struct port_id *id = v;
-
-       BT_ASSERT(id->instance_name);
-       BT_ASSERT(id->port_name);
-
-       return g_str_hash(id->instance_name) ^ g_str_hash(id->port_name);
-}
-
-static
-gboolean port_id_equal(gconstpointer v1, gconstpointer v2)
-{
-       const struct port_id *id1 = v1;
-       const struct port_id *id2 = v2;
-
-       return !strcmp(id1->instance_name, id2->instance_name) &&
-               !strcmp(id1->port_name, id2->port_name);
-}
-
-static
-void port_id_destroy(gpointer data)
-{
-       struct port_id *id = data;
-
-       free(id->instance_name);
-       free(id->port_name);
-       free(id);
-}
-
-static
-void trace_range_destroy(gpointer data)
-{
-       free(data);
-}
-
-struct cmd_run_ctx {
-       /* Owned by this */
-       GHashTable *src_components;
-
-       /* Owned by this */
-       GHashTable *flt_components;
-
-       /* Owned by this */
-       GHashTable *sink_components;
-
-       /* Owned by this */
-       bt_graph *graph;
-
-       /* Weak */
-       struct bt_config *cfg;
-
-       bool connect_ports;
-
-       bool stream_intersection_mode;
-
-       /*
-        * Association of struct port_id -> struct trace_range.
-        */
-       GHashTable *intersections;
-};
-
-/* Returns a timestamp of the form "(-)s.ns" */
-static
-char *s_from_ns(int64_t ns)
-{
-       int ret;
-       char *s_ret = NULL;
-       bool is_negative;
-       int64_t ts_sec_abs, ts_nsec_abs;
-       int64_t ts_sec = ns / NSEC_PER_SEC;
-       int64_t ts_nsec = ns % NSEC_PER_SEC;
-
-       if (ts_sec >= 0 && ts_nsec >= 0) {
-               is_negative = false;
-               ts_sec_abs = ts_sec;
-               ts_nsec_abs = ts_nsec;
-       } else if (ts_sec > 0 && ts_nsec < 0) {
-               is_negative = false;
-               ts_sec_abs = ts_sec - 1;
-               ts_nsec_abs = NSEC_PER_SEC + ts_nsec;
-       } else if (ts_sec == 0 && ts_nsec < 0) {
-               is_negative = true;
-               ts_sec_abs = ts_sec;
-               ts_nsec_abs = -ts_nsec;
-       } else if (ts_sec < 0 && ts_nsec > 0) {
-               is_negative = true;
-               ts_sec_abs = -(ts_sec + 1);
-               ts_nsec_abs = NSEC_PER_SEC - ts_nsec;
-       } else if (ts_sec < 0 && ts_nsec == 0) {
-               is_negative = true;
-               ts_sec_abs = -ts_sec;
-               ts_nsec_abs = ts_nsec;
-       } else {        /* (ts_sec < 0 && ts_nsec < 0) */
-               is_negative = true;
-               ts_sec_abs = -ts_sec;
-               ts_nsec_abs = -ts_nsec;
-       }
-
-       ret = asprintf(&s_ret, "%s%" PRId64 ".%09" PRId64,
-               is_negative ? "-" : "", ts_sec_abs, ts_nsec_abs);
-       if (ret < 0) {
-               s_ret = NULL;
-       }
-       return s_ret;
-}
-
-static
-int cmd_run_ctx_connect_upstream_port_to_downstream_component(
-               struct cmd_run_ctx *ctx,
-               const bt_component *upstream_comp,
-               const bt_port_output *out_upstream_port,
-               struct bt_config_connection *cfg_conn)
-{
-       typedef uint64_t (*input_port_count_func_t)(void *);
-       typedef const bt_port_input *(*borrow_input_port_by_index_func_t)(
-               const void *, uint64_t);
-       const bt_port *upstream_port =
-               bt_port_output_as_port_const(out_upstream_port);
-
-       int ret = 0;
-       GQuark downstreamp_comp_name_quark;
-       void *downstream_comp;
-       uint64_t downstream_port_count;
-       uint64_t i;
-       input_port_count_func_t port_count_fn;
-       borrow_input_port_by_index_func_t port_by_index_fn;
-       bt_graph_status status = BT_GRAPH_STATUS_ERROR;
-       bool insert_trimmer = false;
-       bt_value *trimmer_params = NULL;
-       char *intersection_begin = NULL;
-       char *intersection_end = NULL;
-       const bt_component_filter *trimmer = NULL;
-       const bt_component_class_filter *trimmer_class = NULL;
-       const bt_port_input *trimmer_input = NULL;
-       const bt_port_output *trimmer_output = NULL;
-
-       if (ctx->intersections &&
-               bt_component_get_class_type(upstream_comp) ==
-                       BT_COMPONENT_CLASS_TYPE_SOURCE) {
-               struct trace_range *range;
-               struct port_id port_id = {
-                       .instance_name = (char *) bt_component_get_name(upstream_comp),
-                       .port_name = (char *) bt_port_get_name(upstream_port)
-               };
-
-               if (!port_id.instance_name || !port_id.port_name) {
-                       goto error;
-               }
-
-               range = (struct trace_range *) g_hash_table_lookup(
-                       ctx->intersections, &port_id);
-               if (range) {
-                       bt_value_status status;
-
-                       intersection_begin = s_from_ns(
-                               range->intersection_range_begin_ns);
-                       intersection_end = s_from_ns(
-                               range->intersection_range_end_ns);
-                       if (!intersection_begin || !intersection_end) {
-                               BT_LOGE_STR("Cannot create trimmer argument timestamp string.");
-                               goto error;
-                       }
-
-                       insert_trimmer = true;
-                       trimmer_params = bt_value_map_create();
-                       if (!trimmer_params) {
-                               goto error;
-                       }
-
-                       status = bt_value_map_insert_string_entry(
-                               trimmer_params, "begin", intersection_begin);
-                       if (status != BT_VALUE_STATUS_OK) {
-                               goto error;
-                       }
-                       status = bt_value_map_insert_string_entry(
-                               trimmer_params,
-                               "end", intersection_end);
-                       if (status != BT_VALUE_STATUS_OK) {
-                               goto error;
-                       }
-               }
-
-               trimmer_class = find_filter_component_class("utils", "trimmer");
-               if (!trimmer_class) {
-                       goto error;
-               }
-       }
-
-       BT_LOGI("Connecting upstream port to the next available downstream port: "
-               "upstream-port-addr=%p, upstream-port-name=\"%s\", "
-               "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
-               upstream_port, bt_port_get_name(upstream_port),
-               cfg_conn->downstream_comp_name->str,
-               cfg_conn->arg->str);
-       downstreamp_comp_name_quark = g_quark_from_string(
-               cfg_conn->downstream_comp_name->str);
-       BT_ASSERT(downstreamp_comp_name_quark > 0);
-       downstream_comp = g_hash_table_lookup(ctx->flt_components,
-               GUINT_TO_POINTER(downstreamp_comp_name_quark));
-       port_count_fn = (input_port_count_func_t)
-               bt_component_filter_get_input_port_count;
-       port_by_index_fn = (borrow_input_port_by_index_func_t)
-               bt_component_filter_borrow_input_port_by_index_const;
-
-       if (!downstream_comp) {
-               downstream_comp = g_hash_table_lookup(ctx->sink_components,
-                       GUINT_TO_POINTER(downstreamp_comp_name_quark));
-               port_count_fn = (input_port_count_func_t)
-                       bt_component_sink_get_input_port_count;
-               port_by_index_fn = (borrow_input_port_by_index_func_t)
-                       bt_component_sink_borrow_input_port_by_index_const;
-       }
-
-       if (!downstream_comp) {
-               BT_LOGE("Cannot find downstream component:  comp-name=\"%s\", "
-                       "conn-arg=\"%s\"", cfg_conn->downstream_comp_name->str,
-                       cfg_conn->arg->str);
-               fprintf(stderr, "Cannot create connection: cannot find downstream component: %s\n",
-                       cfg_conn->arg->str);
-               goto error;
-       }
-
-       downstream_port_count = port_count_fn(downstream_comp);
-
-       for (i = 0; i < downstream_port_count; i++) {
-               const bt_port_input *in_downstream_port =
-                       port_by_index_fn(downstream_comp, i);
-               const bt_port *downstream_port =
-                       bt_port_input_as_port_const(in_downstream_port);
-               const char *upstream_port_name;
-               const char *downstream_port_name;
-
-               BT_ASSERT(downstream_port);
-
-               /* Skip port if it's already connected. */
-               if (bt_port_is_connected(downstream_port)) {
-                       BT_LOGD("Skipping downstream port: already connected: "
-                               "port-addr=%p, port-name=\"%s\"",
-                               downstream_port,
-                               bt_port_get_name(downstream_port));
-                       continue;
-               }
-
-               downstream_port_name = bt_port_get_name(downstream_port);
-               BT_ASSERT(downstream_port_name);
-               upstream_port_name = bt_port_get_name(upstream_port);
-               BT_ASSERT(upstream_port_name);
-
-               if (!bt_common_star_glob_match(
-                               cfg_conn->downstream_port_glob->str, SIZE_MAX,
-                               downstream_port_name, SIZE_MAX)) {
-                       continue;
-               }
-
-               if (insert_trimmer) {
-                       /*
-                        * In order to insert the trimmer between the
-                        * two components that were being connected, we
-                        * create a connection configuration entry which
-                        * describes a connection from the trimmer's
-                        * output to the original input that was being
-                        * connected.
-                        *
-                        * Hence, the creation of the trimmer will cause
-                        * the graph "new port" listener to establish
-                        * all downstream connections as its output port
-                        * is connected. We will then establish the
-                        * connection between the original upstream
-                        * source and the trimmer.
-                        */
-                       char *trimmer_name = NULL;
-                       bt_graph_status graph_status;
-
-                       ret = asprintf(&trimmer_name,
-                               "stream-intersection-trimmer-%s",
-                               upstream_port_name);
-                       if (ret < 0) {
-                               goto error;
-                       }
-                       ret = 0;
-
-                       ctx->connect_ports = false;
-                       graph_status = bt_graph_add_filter_component(
-                               ctx->graph, trimmer_class, trimmer_name,
-                               trimmer_params, &trimmer);
-                       free(trimmer_name);
-                       if (graph_status != BT_GRAPH_STATUS_OK) {
-                               goto error;
-                       }
-                       BT_ASSERT(trimmer);
-
-                       trimmer_input =
-                               bt_component_filter_borrow_input_port_by_index_const(
-                                       trimmer, 0);
-                       if (!trimmer_input) {
-                               goto error;
-                       }
-                       trimmer_output =
-                               bt_component_filter_borrow_output_port_by_index_const(
-                                       trimmer, 0);
-                       if (!trimmer_output) {
-                               goto error;
-                       }
-
-                       /*
-                        * Replace the current downstream port by the trimmer's
-                        * upstream port.
-                        */
-                       in_downstream_port = trimmer_input;
-                       downstream_port =
-                               bt_port_input_as_port_const(in_downstream_port);
-                       downstream_port_name = bt_port_get_name(
-                               downstream_port);
-                       BT_ASSERT(downstream_port_name);
-               }
-
-               /* We have a winner! */
-               status = bt_graph_connect_ports(ctx->graph,
-                       out_upstream_port, in_downstream_port, NULL);
-               downstream_port = NULL;
-               switch (status) {
-               case BT_GRAPH_STATUS_OK:
-                       break;
-               case BT_GRAPH_STATUS_CANCELED:
-                       BT_LOGI_STR("Graph was canceled by user.");
-                       status = BT_GRAPH_STATUS_OK;
-                       break;
-               case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
-                       BT_LOGE("A component refused a connection to one of its ports: "
-                               "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
-                               "upstream-port-addr=%p, upstream-port-name=\"%s\", "
-                               "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
-                               "downstream-port-addr=%p, downstream-port-name=\"%s\", "
-                               "conn-arg=\"%s\"",
-                               upstream_comp, bt_component_get_name(upstream_comp),
-                               upstream_port, bt_port_get_name(upstream_port),
-                               downstream_comp, cfg_conn->downstream_comp_name->str,
-                               downstream_port, downstream_port_name,
-                               cfg_conn->arg->str);
-                       fprintf(stderr,
-                               "A component refused a connection to one of its ports (`%s` to `%s`): %s\n",
-                               bt_port_get_name(upstream_port),
-                               downstream_port_name,
-                               cfg_conn->arg->str);
-                       break;
-               default:
-                       BT_LOGE("Cannot create connection: graph refuses to connect ports: "
-                               "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
-                               "upstream-port-addr=%p, upstream-port-name=\"%s\", "
-                               "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
-                               "downstream-port-addr=%p, downstream-port-name=\"%s\", "
-                               "conn-arg=\"%s\"",
-                               upstream_comp, bt_component_get_name(upstream_comp),
-                               upstream_port, bt_port_get_name(upstream_port),
-                               downstream_comp, cfg_conn->downstream_comp_name->str,
-                               downstream_port, downstream_port_name,
-                               cfg_conn->arg->str);
-                       fprintf(stderr,
-                               "Cannot create connection: graph refuses to connect ports (`%s` to `%s`): %s\n",
-                               bt_port_get_name(upstream_port),
-                               downstream_port_name,
-                               cfg_conn->arg->str);
-                       goto error;
-               }
-
-               BT_LOGI("Connected component ports: "
-                       "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
-                       "upstream-port-addr=%p, upstream-port-name=\"%s\", "
-                       "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
-                       "downstream-port-addr=%p, downstream-port-name=\"%s\", "
-                       "conn-arg=\"%s\"",
-                       upstream_comp, bt_component_get_name(upstream_comp),
-                       upstream_port, bt_port_get_name(upstream_port),
-                       downstream_comp, cfg_conn->downstream_comp_name->str,
-                       downstream_port, downstream_port_name,
-                       cfg_conn->arg->str);
-
-               if (insert_trimmer) {
-                       /*
-                        * The first connection, from the source to the trimmer,
-                        * has been done. We now connect the trimmer to the
-                        * original downstream port.
-                        */
-                       ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
-                               ctx,
-                               bt_component_filter_as_component_const(trimmer),
-                               trimmer_output, cfg_conn);
-                       if (ret) {
-                               goto error;
-                       }
-                       ctx->connect_ports = true;
-               }
-
-               /*
-                * We found a matching downstream port: the search is
-                * over.
-                */
-               goto end;
-       }
-
-       /* No downstream port found */
-       BT_LOGE("Cannot create connection: cannot find a matching downstream port for upstream port: "
-               "upstream-port-addr=%p, upstream-port-name=\"%s\", "
-               "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
-               upstream_port, bt_port_get_name(upstream_port),
-               cfg_conn->downstream_comp_name->str,
-               cfg_conn->arg->str);
-       fprintf(stderr,
-               "Cannot create connection: cannot find a matching downstream port for upstream port `%s`: %s\n",
-               bt_port_get_name(upstream_port), cfg_conn->arg->str);
-
-error:
-       ret = -1;
-
-end:
-       free(intersection_begin);
-       free(intersection_end);
-       BT_VALUE_PUT_REF_AND_RESET(trimmer_params);
-       BT_COMPONENT_CLASS_FILTER_PUT_REF_AND_RESET(trimmer_class);
-       BT_COMPONENT_FILTER_PUT_REF_AND_RESET(trimmer);
-       return ret;
-}
-
-static
-int cmd_run_ctx_connect_upstream_port(struct cmd_run_ctx *ctx,
-               const bt_port_output *upstream_port)
-{
-       int ret = 0;
-       const char *upstream_port_name;
-       const char *upstream_comp_name;
-       const bt_component *upstream_comp = NULL;
-       size_t i;
-
-       BT_ASSERT(ctx);
-       BT_ASSERT(upstream_port);
-       upstream_port_name = bt_port_get_name(
-               bt_port_output_as_port_const(upstream_port));
-       BT_ASSERT(upstream_port_name);
-       upstream_comp = bt_port_borrow_component_const(
-               bt_port_output_as_port_const(upstream_port));
-       if (!upstream_comp) {
-               BT_LOGW("Upstream port to connect is not part of a component: "
-                       "port-addr=%p, port-name=\"%s\"",
-                       upstream_port, upstream_port_name);
-               ret = -1;
-               goto end;
-       }
-
-       upstream_comp_name = bt_component_get_name(upstream_comp);
-       BT_ASSERT(upstream_comp_name);
-       BT_LOGI("Connecting upstream port: comp-addr=%p, comp-name=\"%s\", "
-               "port-addr=%p, port-name=\"%s\"",
-               upstream_comp, upstream_comp_name,
-               upstream_port, upstream_port_name);
-
-       for (i = 0; i < ctx->cfg->cmd_data.run.connections->len; i++) {
-               struct bt_config_connection *cfg_conn =
-                       g_ptr_array_index(
-                               ctx->cfg->cmd_data.run.connections, i);
-
-               if (strcmp(cfg_conn->upstream_comp_name->str,
-                               upstream_comp_name)) {
-                       continue;
-               }
-
-               if (!bt_common_star_glob_match(
-                           cfg_conn->upstream_port_glob->str,
-                           SIZE_MAX, upstream_port_name, SIZE_MAX)) {
-                       continue;
-               }
-
-               ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
-                       ctx, upstream_comp, upstream_port, cfg_conn);
-               if (ret) {
-                       BT_LOGE("Cannot connect upstream port: "
-                               "port-addr=%p, port-name=\"%s\"",
-                               upstream_port,
-                               upstream_port_name);
-                       fprintf(stderr,
-                               "Cannot connect port `%s` of component `%s` to a downstream port: %s\n",
-                               upstream_port_name,
-                               upstream_comp_name,
-                               cfg_conn->arg->str);
-                       goto error;
-               }
-               goto end;
-       }
-
-       BT_LOGE("Cannot connect upstream port: port does not match any connection argument: "
-               "port-addr=%p, port-name=\"%s\"", upstream_port,
-               upstream_port_name);
-       fprintf(stderr,
-               "Cannot create connection: upstream port `%s` does not match any connection\n",
-               upstream_port_name);
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-bt_graph_listener_status
-graph_output_port_added_listener(struct cmd_run_ctx *ctx,
-               const bt_port_output *out_port)
-{
-       const bt_component *comp;
-       const bt_port *port = bt_port_output_as_port_const(out_port);
-       bt_graph_listener_status ret = BT_GRAPH_LISTENER_STATUS_OK;
-
-       comp = bt_port_borrow_component_const(port);
-       BT_LOGI("Port added to a graph's component: comp-addr=%p, "
-               "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
-               comp, comp ? bt_component_get_name(comp) : "",
-               port, bt_port_get_name(port));
-
-       if (!ctx->connect_ports) {
-               goto end;
-       }
-
-       if (!comp) {
-               BT_LOGW_STR("Port has no component.");
-               goto end;
-       }
-
-       if (bt_port_is_connected(port)) {
-               BT_LOGW_STR("Port is already connected.");
-               goto end;
-       }
-
-       if (cmd_run_ctx_connect_upstream_port(ctx, out_port)) {
-               BT_LOGF_STR("Cannot connect upstream port.");
-               fprintf(stderr, "Added port could not be connected: aborting\n");
-               ret = BT_GRAPH_LISTENER_STATUS_ERROR;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_graph_listener_status graph_source_output_port_added_listener(
-               const bt_component_source *component,
-               const bt_port_output *port, void *data)
-{
-       return graph_output_port_added_listener(data, port);
-}
-
-static
-bt_graph_listener_status graph_filter_output_port_added_listener(
-               const bt_component_filter *component,
-               const bt_port_output *port, void *data)
-{
-       return graph_output_port_added_listener(data, port);
-}
-
-static
-void cmd_run_ctx_destroy(struct cmd_run_ctx *ctx)
-{
-       if (!ctx) {
-               return;
-       }
-
-       if (ctx->src_components) {
-               g_hash_table_destroy(ctx->src_components);
-               ctx->src_components = NULL;
-       }
-
-       if (ctx->flt_components) {
-               g_hash_table_destroy(ctx->flt_components);
-               ctx->flt_components = NULL;
-       }
-
-       if (ctx->sink_components) {
-               g_hash_table_destroy(ctx->sink_components);
-               ctx->sink_components = NULL;
-       }
-
-       if (ctx->intersections) {
-               g_hash_table_destroy(ctx->intersections);
-               ctx->intersections = NULL;
-       }
-
-       BT_GRAPH_PUT_REF_AND_RESET(ctx->graph);
-       the_graph = NULL;
-       ctx->cfg = NULL;
-}
-
-static
-int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg)
-{
-       int ret = 0;
-       bt_graph_status status;
-
-       ctx->cfg = cfg;
-       ctx->connect_ports = false;
-       ctx->src_components = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
-       if (!ctx->src_components) {
-               goto error;
-       }
-
-       ctx->flt_components = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
-       if (!ctx->flt_components) {
-               goto error;
-       }
-
-       ctx->sink_components = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
-       if (!ctx->sink_components) {
-               goto error;
-       }
-
-       if (cfg->cmd_data.run.stream_intersection_mode) {
-               ctx->stream_intersection_mode = true;
-               ctx->intersections = g_hash_table_new_full(port_id_hash,
-                       port_id_equal, port_id_destroy, trace_range_destroy);
-               if (!ctx->intersections) {
-                       goto error;
-               }
-       }
-
-       ctx->graph = bt_graph_create();
-       if (!ctx->graph) {
-               goto error;
-       }
-
-       the_graph = ctx->graph;
-       status = bt_graph_add_source_component_output_port_added_listener(
-               ctx->graph, graph_source_output_port_added_listener, NULL, ctx,
-               NULL);
-       if (status != BT_GRAPH_STATUS_OK) {
-               BT_LOGE_STR("Cannot add \"port added\" listener to graph.");
-               goto error;
-       }
-
-       status = bt_graph_add_filter_component_output_port_added_listener(
-               ctx->graph, graph_filter_output_port_added_listener, NULL, ctx,
-               NULL);
-       if (status != BT_GRAPH_STATUS_OK) {
-               BT_LOGE_STR("Cannot add \"port added\" listener to graph.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       cmd_run_ctx_destroy(ctx);
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int set_stream_intersections(struct cmd_run_ctx *ctx,
-               struct bt_config_component *cfg_comp,
-               const bt_component_class_source *src_comp_cls)
-{
-       int ret = 0;
-       uint64_t trace_idx;
-       int64_t trace_count;
-       const char *path = NULL;
-       const bt_value *query_result = NULL;
-       const bt_value *trace_info = NULL;
-       const bt_value *intersection_range = NULL;
-       const bt_value *intersection_begin = NULL;
-       const bt_value *intersection_end = NULL;
-       const bt_value *stream_infos = NULL;
-       const bt_value *stream_info = NULL;
-       struct port_id *port_id = NULL;
-       struct trace_range *trace_range = NULL;
-       const char *fail_reason = NULL;
-       const bt_component_class *comp_cls =
-               bt_component_class_source_as_component_class_const(src_comp_cls);
-
-       ret = query(comp_cls, "trace-info",
-               cfg_comp->params, &query_result,
-               &fail_reason);
-       if (ret) {
-               BT_LOGD("Component class does not support the `trace-info` query: %s: "
-                       "comp-class-name=\"%s\"", fail_reason,
-                       bt_component_class_get_name(comp_cls));
-               ret = -1;
-               goto error;
-       }
-
-       BT_ASSERT(query_result);
-
-       if (!bt_value_is_array(query_result)) {
-               BT_LOGD("Unexpected format of \'trace-info\' query result: "
-                       "component-class-name=%s",
-                       bt_component_class_get_name(comp_cls));
-               ret = -1;
-               goto error;
-       }
-
-       trace_count = bt_value_array_get_size(query_result);
-       if (trace_count < 0) {
-               ret = -1;
-               goto error;
-       }
-
-       for (trace_idx = 0; trace_idx < trace_count; trace_idx++) {
-               int64_t begin, end;
-               uint64_t stream_idx;
-               int64_t stream_count;
-
-               trace_info = bt_value_array_borrow_element_by_index_const(
-                       query_result, trace_idx);
-               if (!trace_info || !bt_value_is_map(trace_info)) {
-                       ret = -1;
-                       BT_LOGD_STR("Cannot retrieve trace from query result.");
-                       goto error;
-               }
-
-               intersection_range = bt_value_map_borrow_entry_value_const(
-                       trace_info, "intersection-range-ns");
-               if (!intersection_range) {
-                       ret = -1;
-                       BT_LOGD_STR("Cannot retrieve \'intersetion-range-ns\' field from query result.");
-                       goto error;
-               }
-
-               intersection_begin = bt_value_map_borrow_entry_value_const(intersection_range,
-                                                                          "begin");
-               if (!intersection_begin) {
-                       ret = -1;
-                       BT_LOGD_STR("Cannot retrieve intersection-range-ns \'begin\' field from query result.");
-                       goto error;
-               }
-
-               intersection_end = bt_value_map_borrow_entry_value_const(intersection_range,
-                                                                        "end");
-               if (!intersection_end) {
-                       ret = -1;
-                       BT_LOGD_STR("Cannot retrieve intersection-range-ns \'end\' field from query result.");
-                       goto error;
-               }
-
-               begin = bt_value_signed_integer_get(intersection_begin);
-               end = bt_value_signed_integer_get(intersection_end);
-
-               if (begin < 0 || end < 0 || end < begin) {
-                       BT_LOGW("Invalid trace stream intersection values: "
-                               "intersection-range-ns:begin=%" PRId64
-                               ", intersection-range-ns:end=%" PRId64,
-                               begin, end);
-                       ret = -1;
-                       goto error;
-               }
-
-               stream_infos = bt_value_map_borrow_entry_value_const(trace_info,
-                                                                    "streams");
-               if (!stream_infos || !bt_value_is_array(stream_infos)) {
-                       ret = -1;
-                       BT_LOGD_STR("Cannot retrieve stream information from trace in query result.");
-                       goto error;
-               }
-
-               stream_count = bt_value_array_get_size(stream_infos);
-               if (stream_count < 0) {
-                       ret = -1;
-                       goto error;
-               }
-
-               for (stream_idx = 0; stream_idx < stream_count; stream_idx++) {
-                       const bt_value *port_name;
-
-                       port_id = g_new0(struct port_id, 1);
-                       if (!port_id) {
-                               ret = -1;
-                               BT_LOGE_STR("Cannot allocate memory for port_id structure.");
-                               goto error;
-                       }
-                       port_id->instance_name = strdup(cfg_comp->instance_name->str);
-                       if (!port_id->instance_name) {
-                               ret = -1;
-                               BT_LOGE_STR("Cannot allocate memory for port_id component instance name.");
-                               goto error;
-                       }
-
-                       trace_range = g_new0(struct trace_range, 1);
-                       if (!trace_range) {
-                               ret = -1;
-                               BT_LOGE_STR("Cannot allocate memory for trace_range structure.");
-                               goto error;
-                       }
-                       trace_range->intersection_range_begin_ns = begin;
-                       trace_range->intersection_range_end_ns = end;
-
-                       stream_info = bt_value_array_borrow_element_by_index_const(
-                               stream_infos, stream_idx);
-                       if (!stream_info || !bt_value_is_map(stream_info)) {
-                               ret = -1;
-                               BT_LOGD_STR("Cannot retrieve stream informations from trace in query result.");
-                               goto error;
-                       }
-
-                       port_name = bt_value_map_borrow_entry_value_const(stream_info, "port-name");
-                       if (!port_name || !bt_value_is_string(port_name)) {
-                               ret = -1;
-                               BT_LOGD_STR("Cannot retrieve port name in query result.");
-                               goto error;
-                       }
-
-                       port_id->port_name = g_strdup(bt_value_string_get(port_name));
-                       if (!port_id->port_name) {
-                               ret = -1;
-                               BT_LOGE_STR("Cannot allocate memory for port_id port_name.");
-                               goto error;
-                       }
-
-                       BT_LOGD("Inserting stream intersection ");
-
-                       g_hash_table_insert(ctx->intersections, port_id, trace_range);
-
-                       port_id = NULL;
-                       trace_range = NULL;
-               }
-       }
-
-       goto end;
-
-error:
-       fprintf(stderr, "%s%sCannot determine stream intersection of trace at path \'%s\'.%s\n",
-               bt_common_color_bold(),
-               bt_common_color_fg_yellow(),
-               path ? path : "(unknown)",
-               bt_common_color_reset());
-end:
-       bt_value_put_ref(query_result);
-       g_free(port_id);
-       g_free(trace_range);
-       return ret;
-}
-
-static
-int cmd_run_ctx_create_components_from_config_components(
-               struct cmd_run_ctx *ctx, GPtrArray *cfg_components)
-{
-       size_t i;
-       const void *comp_cls = NULL;
-       const void *comp = NULL;
-       int ret = 0;
-
-       for (i = 0; i < cfg_components->len; i++) {
-               struct bt_config_component *cfg_comp =
-                       g_ptr_array_index(cfg_components, i);
-               GQuark quark;
-
-               switch (cfg_comp->type) {
-               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                       comp_cls = find_source_component_class(
-                               cfg_comp->plugin_name->str,
-                               cfg_comp->comp_cls_name->str);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       comp_cls = find_filter_component_class(
-                               cfg_comp->plugin_name->str,
-                               cfg_comp->comp_cls_name->str);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       comp_cls = find_sink_component_class(
-                               cfg_comp->plugin_name->str,
-                               cfg_comp->comp_cls_name->str);
-                       break;
-               default:
-                       abort();
-               }
-
-               if (!comp_cls) {
-                       BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
-                               "comp-cls-name=\"%s\", comp-cls-type=%d",
-                               cfg_comp->plugin_name->str,
-                               cfg_comp->comp_cls_name->str,
-                               cfg_comp->type);
-                       fprintf(stderr, "%s%sCannot find component class %s",
-                               bt_common_color_bold(),
-                               bt_common_color_fg_red(),
-                               bt_common_color_reset());
-                       print_plugin_comp_cls_opt(stderr,
-                               cfg_comp->plugin_name->str,
-                               cfg_comp->comp_cls_name->str,
-                               cfg_comp->type);
-                       fprintf(stderr, "\n");
-                       goto error;
-               }
-
-               switch (cfg_comp->type) {
-               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                       ret = bt_graph_add_source_component(ctx->graph,
-                               comp_cls, cfg_comp->instance_name->str,
-                               cfg_comp->params,
-                               (void *) &comp);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       ret = bt_graph_add_filter_component(ctx->graph,
-                               comp_cls, cfg_comp->instance_name->str,
-                               cfg_comp->params,
-                               (void *) &comp);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       ret = bt_graph_add_sink_component(ctx->graph,
-                               comp_cls, cfg_comp->instance_name->str,
-                               cfg_comp->params,
-                               (void *) &comp);
-                       break;
-               default:
-                       abort();
-               }
-
-               if (ret) {
-                       BT_LOGE("Cannot create component: plugin-name=\"%s\", "
-                               "comp-cls-name=\"%s\", comp-cls-type=%d, "
-                               "comp-name=\"%s\"",
-                               cfg_comp->plugin_name->str,
-                               cfg_comp->comp_cls_name->str,
-                               cfg_comp->type, cfg_comp->instance_name->str);
-                       fprintf(stderr, "%s%sCannot create component `%s`%s\n",
-                               bt_common_color_bold(),
-                               bt_common_color_fg_red(),
-                               cfg_comp->instance_name->str,
-                               bt_common_color_reset());
-                       goto error;
-               }
-
-               if (ctx->stream_intersection_mode &&
-                               cfg_comp->type == BT_COMPONENT_CLASS_TYPE_SOURCE) {
-                       ret = set_stream_intersections(ctx, cfg_comp, comp_cls);
-                       if (ret) {
-                               goto error;
-                       }
-               }
-
-               BT_LOGI("Created and inserted component: comp-addr=%p, comp-name=\"%s\"",
-                       comp, cfg_comp->instance_name->str);
-               quark = g_quark_from_string(cfg_comp->instance_name->str);
-               BT_ASSERT(quark > 0);
-
-               switch (cfg_comp->type) {
-               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                       g_hash_table_insert(ctx->src_components,
-                               GUINT_TO_POINTER(quark), (void *) comp);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       g_hash_table_insert(ctx->flt_components,
-                               GUINT_TO_POINTER(quark), (void *) comp);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       g_hash_table_insert(ctx->sink_components,
-                               GUINT_TO_POINTER(quark), (void *) comp);
-                       break;
-               default:
-                       abort();
-               }
-
-               comp = NULL;
-               BT_OBJECT_PUT_REF_AND_RESET(comp_cls);
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       bt_object_put_ref(comp);
-       bt_object_put_ref(comp_cls);
-       return ret;
-}
-
-static
-int cmd_run_ctx_create_components(struct cmd_run_ctx *ctx)
-{
-       int ret = 0;
-
-       /*
-        * Make sure that, during this phase, our graph's "port added"
-        * listener does not connect ports while we are creating the
-        * components because we have a special, initial phase for
-        * this.
-        */
-       ctx->connect_ports = false;
-
-       ret = cmd_run_ctx_create_components_from_config_components(
-               ctx, ctx->cfg->cmd_data.run.sources);
-       if (ret) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = cmd_run_ctx_create_components_from_config_components(
-               ctx, ctx->cfg->cmd_data.run.filters);
-       if (ret) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = cmd_run_ctx_create_components_from_config_components(
-               ctx, ctx->cfg->cmd_data.run.sinks);
-       if (ret) {
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-typedef uint64_t (*output_port_count_func_t)(const void *);
-typedef const bt_port_output *(*borrow_output_port_by_index_func_t)(
-       const void *, uint64_t);
-
-static
-int cmd_run_ctx_connect_comp_ports(struct cmd_run_ctx *ctx,
-               void *comp, output_port_count_func_t port_count_fn,
-               borrow_output_port_by_index_func_t port_by_index_fn)
-{
-       int ret = 0;
-       uint64_t count;
-       uint64_t i;
-
-       count = port_count_fn(comp);
-
-       for (i = 0; i < count; i++) {
-               const bt_port_output *upstream_port = port_by_index_fn(comp, i);
-
-               BT_ASSERT(upstream_port);
-               ret = cmd_run_ctx_connect_upstream_port(ctx, upstream_port);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int cmd_run_ctx_connect_ports(struct cmd_run_ctx *ctx)
-{
-       int ret = 0;
-       GHashTableIter iter;
-       gpointer g_name_quark, g_comp;
-
-       ctx->connect_ports = true;
-       g_hash_table_iter_init(&iter, ctx->src_components);
-
-       while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
-               ret = cmd_run_ctx_connect_comp_ports(ctx, g_comp,
-                       (output_port_count_func_t)
-                               bt_component_source_get_output_port_count,
-                       (borrow_output_port_by_index_func_t)
-                               bt_component_source_borrow_output_port_by_index_const);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       g_hash_table_iter_init(&iter, ctx->flt_components);
-
-       while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
-               ret = cmd_run_ctx_connect_comp_ports(ctx, g_comp,
-                       (output_port_count_func_t)
-                               bt_component_filter_get_output_port_count,
-                       (borrow_output_port_by_index_func_t)
-                               bt_component_filter_borrow_output_port_by_index_const);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static inline
-const char *bt_graph_status_str(bt_graph_status status)
-{
-       switch (status) {
-       case BT_GRAPH_STATUS_OK:
-               return "BT_GRAPH_STATUS_OK";
-       case BT_GRAPH_STATUS_END:
-               return "BT_GRAPH_STATUS_END";
-       case BT_GRAPH_STATUS_AGAIN:
-               return "BT_GRAPH_STATUS_AGAIN";
-       case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
-               return "BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION";
-       case BT_GRAPH_STATUS_CANCELED:
-               return "BT_GRAPH_STATUS_CANCELED";
-       case BT_GRAPH_STATUS_ERROR:
-               return "BT_GRAPH_STATUS_ERROR";
-       case BT_GRAPH_STATUS_NOMEM:
-               return "BT_GRAPH_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-}
-
-static
-int cmd_run(struct bt_config *cfg)
-{
-       int ret = 0;
-       struct cmd_run_ctx ctx = { 0 };
-
-       /* Initialize the command's context and the graph object */
-       if (cmd_run_ctx_init(&ctx, cfg)) {
-               BT_LOGE_STR("Cannot initialize the command's context.");
-               fprintf(stderr, "Cannot initialize the command's context\n");
-               goto error;
-       }
-
-       if (canceled) {
-               BT_LOGI_STR("Canceled by user before creating components.");
-               goto error;
-       }
-
-       BT_LOGI_STR("Creating components.");
-
-       /* Create the requested component instances */
-       if (cmd_run_ctx_create_components(&ctx)) {
-               BT_LOGE_STR("Cannot create components.");
-               fprintf(stderr, "Cannot create components\n");
-               goto error;
-       }
-
-       if (canceled) {
-               BT_LOGI_STR("Canceled by user before connecting components.");
-               goto error;
-       }
-
-       BT_LOGI_STR("Connecting components.");
-
-       /* Connect the initially visible component ports */
-       if (cmd_run_ctx_connect_ports(&ctx)) {
-               BT_LOGE_STR("Cannot connect initial component ports.");
-               fprintf(stderr, "Cannot connect initial component ports\n");
-               goto error;
-       }
-
-       if (canceled) {
-               BT_LOGI_STR("Canceled by user before running the graph.");
-               goto error;
-       }
-
-       BT_LOGI_STR("Running the graph.");
-
-       /* Run the graph */
-       while (true) {
-               bt_graph_status graph_status = bt_graph_run(ctx.graph);
-
-               /*
-                * Reset console in case something messed with console
-                * codes during the graph's execution.
-                */
-               printf("%s", bt_common_color_reset());
-               fflush(stdout);
-               fprintf(stderr, "%s", bt_common_color_reset());
-               BT_LOGV("bt_graph_run() returned: status=%s",
-                       bt_graph_status_str(graph_status));
-
-               switch (graph_status) {
-               case BT_GRAPH_STATUS_OK:
-                       break;
-               case BT_GRAPH_STATUS_CANCELED:
-                       BT_LOGI_STR("Graph was canceled by user.");
-                       goto error;
-               case BT_GRAPH_STATUS_AGAIN:
-                       if (bt_graph_is_canceled(ctx.graph)) {
-                               BT_LOGI_STR("Graph was canceled by user.");
-                               goto error;
-                       }
-
-                       if (cfg->cmd_data.run.retry_duration_us > 0) {
-                               BT_LOGV("Got BT_GRAPH_STATUS_AGAIN: sleeping: "
-                                       "time-us=%" PRIu64,
-                                       cfg->cmd_data.run.retry_duration_us);
-
-                               if (usleep(cfg->cmd_data.run.retry_duration_us)) {
-                                       if (bt_graph_is_canceled(ctx.graph)) {
-                                               BT_LOGI_STR("Graph was canceled by user.");
-                                               goto error;
-                                       }
-                               }
-                       }
-                       break;
-               case BT_GRAPH_STATUS_END:
-                       goto end;
-               default:
-                       BT_LOGE_STR("Graph failed to complete successfully");
-                       fprintf(stderr, "Graph failed to complete successfully\n");
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       if (ret == 0) {
-               ret = -1;
-       }
-
-end:
-       cmd_run_ctx_destroy(&ctx);
-       return ret;
-}
-
-static
-void warn_command_name_and_directory_clash(struct bt_config *cfg)
-{
-       const char *env_clash;
-
-       if (!cfg->command_name) {
-               return;
-       }
-
-       env_clash = getenv(ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH);
-       if (env_clash && strcmp(env_clash, "0") == 0) {
-               return;
-       }
-
-       if (g_file_test(cfg->command_name,
-                       G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
-               fprintf(stderr, "\nNOTE: The `%s` command was executed. If you meant to convert a\n",
-                       cfg->command_name);
-               fprintf(stderr, "trace located in the local `%s` directory, please use:\n",
-                       cfg->command_name);
-               fprintf(stderr, "\n");
-               fprintf(stderr, "    babeltrace2 convert %s [OPTIONS]\n",
-                       cfg->command_name);
-       }
-}
-
-static
-void init_log_level(void)
-{
-       bt_cli_log_level = bt_log_get_level_from_env(ENV_BABELTRACE_CLI_LOG_LEVEL);
-}
-
-static
-void set_auto_log_levels(struct bt_config *cfg)
-{
-       const char **env_var_name;
-
-       /*
-        * Override the configuration's default log level if
-        * BABELTRACE_VERBOSE or BABELTRACE_DEBUG environment variables
-        * are found for backward compatibility with legacy Babetrace 1.
-        */
-       if (getenv("BABELTRACE_DEBUG") &&
-                       strcmp(getenv("BABELTRACE_DEBUG"), "1") == 0) {
-               cfg->log_level = 'V';
-       } else if (getenv("BABELTRACE_VERBOSE") &&
-                       strcmp(getenv("BABELTRACE_VERBOSE"), "1") == 0) {
-               cfg->log_level = 'I';
-       }
-
-       /*
-        * Set log levels according to --debug or --verbose. For
-        * backward compatibility, --debug is more verbose than
-        * --verbose. So:
-        *
-        *     --verbose: INFO log level
-        *     --debug:   VERBOSE log level (includes DEBUG, which is
-        *                is less verbose than VERBOSE in the internal
-        *                logging framework)
-        */
-       if (!getenv("BABELTRACE_LOGGING_GLOBAL_LEVEL")) {
-               if (cfg->verbose) {
-                       bt_logging_set_global_level(BT_LOGGING_LEVEL_INFO);
-               } else if (cfg->debug) {
-                       bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE);
-               } else {
-                       /*
-                        * Set library's default log level if not
-                        * explicitly specified.
-                        */
-                       switch (cfg->log_level) {
-                       case 'N':
-                               bt_logging_set_global_level(BT_LOGGING_LEVEL_NONE);
-                               break;
-                       case 'V':
-                               bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE);
-                               break;
-                       case 'D':
-                               bt_logging_set_global_level(BT_LOGGING_LEVEL_DEBUG);
-                               break;
-                       case 'I':
-                               bt_logging_set_global_level(BT_LOGGING_LEVEL_INFO);
-                               break;
-                       case 'W':
-                               bt_logging_set_global_level(BT_LOGGING_LEVEL_WARN);
-                               break;
-                       case 'E':
-                               bt_logging_set_global_level(BT_LOGGING_LEVEL_ERROR);
-                               break;
-                       case 'F':
-                               bt_logging_set_global_level(BT_LOGGING_LEVEL_FATAL);
-                               break;
-                       default:
-                               abort();
-                       }
-               }
-       }
-
-       if (!getenv(ENV_BABELTRACE_CLI_LOG_LEVEL)) {
-               if (cfg->verbose) {
-                       bt_cli_log_level = BT_LOG_INFO;
-               } else if (cfg->debug) {
-                       bt_cli_log_level = BT_LOG_VERBOSE;
-               } else {
-                       /*
-                        * Set CLI's default log level if not explicitly
-                        * specified.
-                        */
-                       switch (cfg->log_level) {
-                       case 'N':
-                               bt_cli_log_level = BT_LOG_NONE;
-                               break;
-                       case 'V':
-                               bt_cli_log_level = BT_LOG_VERBOSE;
-                               break;
-                       case 'D':
-                               bt_cli_log_level = BT_LOG_DEBUG;
-                               break;
-                       case 'I':
-                               bt_cli_log_level = BT_LOG_INFO;
-                               break;
-                       case 'W':
-                               bt_cli_log_level = BT_LOG_WARN;
-                               break;
-                       case 'E':
-                               bt_cli_log_level = BT_LOG_ERROR;
-                               break;
-                       case 'F':
-                               bt_cli_log_level = BT_LOG_FATAL;
-                               break;
-                       default:
-                               abort();
-                       }
-               }
-       }
-
-       env_var_name = log_level_env_var_names;
-
-       while (*env_var_name) {
-               if (!getenv(*env_var_name)) {
-                       if (cfg->verbose) {
-                               g_setenv(*env_var_name, "I", 1);
-                       } else if (cfg->debug) {
-                               g_setenv(*env_var_name, "V", 1);
-                       } else {
-                               char val[2] = { 0 };
-
-                               /*
-                                * Set module's default log level if not
-                                * explicitly specified.
-                                */
-                               val[0] = cfg->log_level;
-                               g_setenv(*env_var_name, val, 1);
-                       }
-               }
-
-               env_var_name++;
-       }
-}
-
-int main(int argc, const char **argv)
-{
-       int ret;
-       int retcode;
-       struct bt_config *cfg;
-
-       init_log_level();
-       set_signal_handler();
-       init_static_data();
-       cfg = bt_config_cli_args_create_with_default(argc, argv, &retcode);
-
-       if (retcode < 0) {
-               /* Quit without errors; typically usage/version */
-               retcode = 0;
-               BT_LOGI_STR("Quitting without errors.");
-               goto end;
-       }
-
-       if (retcode > 0) {
-               BT_LOGE("Command-line error: retcode=%d", retcode);
-               goto end;
-       }
-
-       if (!cfg) {
-               BT_LOGE_STR("Failed to create a valid Babeltrace configuration.");
-               fprintf(stderr, "Failed to create Babeltrace configuration\n");
-               retcode = 1;
-               goto end;
-       }
-
-       set_auto_log_levels(cfg);
-       print_cfg(cfg);
-
-       if (cfg->command_needs_plugins) {
-               ret = load_all_plugins(cfg->plugin_paths);
-               if (ret) {
-                       BT_LOGE("Failed to load plugins: ret=%d", ret);
-                       retcode = 1;
-                       goto end;
-               }
-       }
-
-       BT_LOGI("Executing command: cmd=%d, command-name=\"%s\"",
-               cfg->command, cfg->command_name);
-
-       switch (cfg->command) {
-       case BT_CONFIG_COMMAND_RUN:
-               ret = cmd_run(cfg);
-               break;
-       case BT_CONFIG_COMMAND_LIST_PLUGINS:
-               ret = cmd_list_plugins(cfg);
-               break;
-       case BT_CONFIG_COMMAND_HELP:
-               ret = cmd_help(cfg);
-               break;
-       case BT_CONFIG_COMMAND_QUERY:
-               ret = cmd_query(cfg);
-               break;
-       case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
-               ret = cmd_print_ctf_metadata(cfg);
-               break;
-       case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
-               ret = cmd_print_lttng_live_sessions(cfg);
-               break;
-       default:
-               BT_LOGF("Invalid/unknown command: cmd=%d", cfg->command);
-               abort();
-       }
-
-       BT_LOGI("Command completed: cmd=%d, command-name=\"%s\", ret=%d",
-               cfg->command, cfg->command_name, ret);
-       warn_command_name_and_directory_clash(cfg);
-       retcode = ret ? 1 : 0;
-
-end:
-       BT_OBJECT_PUT_REF_AND_RESET(cfg);
-       fini_static_data();
-       return retcode;
-}
diff --git a/cli/logging.c b/cli/logging.c
deleted file mode 100644 (file)
index a2a522b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_cli_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_cli_log_level, "BABELTRACE_CLI_LOG_LEVEL");
diff --git a/cli/logging.h b/cli/logging.h
deleted file mode 100644 (file)
index 6e5dc9f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef CLI_LOGGING_H
-#define CLI_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_cli_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_cli_log_level);
-
-#endif /* CLI_LOGGING_H */
diff --git a/common/Makefile.am b/common/Makefile.am
deleted file mode 100644 (file)
index 75247fc..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-AM_CPPFLAGS += -DINSTALL_LIBDIR=\"$(libdir)\"
-
-
-noinst_LTLIBRARIES = libbabeltrace2-common.la
-
-libbabeltrace2_common_la_SOURCES = assert.c common.c logging.c logging.h
diff --git a/common/assert.c b/common/assert.c
deleted file mode 100644 (file)
index 1e28219..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2019 EfficiOS Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/common-internal.h>
-
-void bt_common_assert_failed(const char *file, int line, const char *func,
-               const char *assertion)
-{
-       fprintf(stderr,
-               "%s\n%s%s%s (╯°□°)╯︵ ┻━┻ %s %s%s%s%s:%s%d%s: %s%s()%s: "
-               "%sAssertion %s`%s`%s%s failed.%s\n",
-               bt_common_color_reset(),
-               bt_common_color_bold(),
-               bt_common_color_bg_yellow(),
-               bt_common_color_fg_red(),
-               bt_common_color_reset(),
-               bt_common_color_bold(),
-               bt_common_color_fg_magenta(),
-               file,
-               bt_common_color_reset(),
-               bt_common_color_fg_green(),
-               line,
-               bt_common_color_reset(),
-               bt_common_color_fg_cyan(),
-               func,
-               bt_common_color_reset(),
-               bt_common_color_fg_red(),
-               bt_common_color_bold(),
-               assertion,
-               bt_common_color_reset(),
-               bt_common_color_fg_red(),
-               bt_common_color_reset());
-       abort();
-}
diff --git a/common/common.c b/common/common.c
deleted file mode 100644 (file)
index f2fd0b8..0000000
+++ /dev/null
@@ -1,1569 +0,0 @@
-/*
- * Babeltrace common functions
- *
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COMMON"
-#include "logging.h"
-
-#include <unistd.h>
-#include <string.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <glib.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <wchar.h>
-#include <stdbool.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/compat/unistd-internal.h>
-
-#ifndef __MINGW32__
-#include <pwd.h>
-#endif
-
-#define SYSTEM_PLUGIN_PATH     INSTALL_LIBDIR "/babeltrace2/plugins"
-#define HOME_ENV_VAR           "HOME"
-#define HOME_PLUGIN_SUBPATH    "/.local/lib/babeltrace2/plugins"
-
-static const char *bt_common_color_code_reset = "";
-static const char *bt_common_color_code_bold = "";
-static const char *bt_common_color_code_fg_default = "";
-static const char *bt_common_color_code_fg_red = "";
-static const char *bt_common_color_code_fg_green = "";
-static const char *bt_common_color_code_fg_yellow = "";
-static const char *bt_common_color_code_fg_blue = "";
-static const char *bt_common_color_code_fg_magenta = "";
-static const char *bt_common_color_code_fg_cyan = "";
-static const char *bt_common_color_code_fg_light_gray = "";
-static const char *bt_common_color_code_bg_default = "";
-static const char *bt_common_color_code_bg_red = "";
-static const char *bt_common_color_code_bg_green = "";
-static const char *bt_common_color_code_bg_yellow = "";
-static const char *bt_common_color_code_bg_blue = "";
-static const char *bt_common_color_code_bg_magenta = "";
-static const char *bt_common_color_code_bg_cyan = "";
-static const char *bt_common_color_code_bg_light_gray = "";
-
-static
-void __attribute__((constructor)) bt_common_color_ctor(void)
-{
-       if (bt_common_colors_supported()) {
-               bt_common_color_code_reset = BT_COMMON_COLOR_RESET;
-               bt_common_color_code_bold = BT_COMMON_COLOR_BOLD;
-               bt_common_color_code_fg_default = BT_COMMON_COLOR_FG_DEFAULT;
-               bt_common_color_code_fg_red = BT_COMMON_COLOR_FG_RED;
-               bt_common_color_code_fg_green = BT_COMMON_COLOR_FG_GREEN;
-               bt_common_color_code_fg_yellow = BT_COMMON_COLOR_FG_YELLOW;
-               bt_common_color_code_fg_blue = BT_COMMON_COLOR_FG_BLUE;
-               bt_common_color_code_fg_magenta = BT_COMMON_COLOR_FG_MAGENTA;
-               bt_common_color_code_fg_cyan = BT_COMMON_COLOR_FG_CYAN;
-               bt_common_color_code_fg_light_gray = BT_COMMON_COLOR_FG_LIGHT_GRAY;
-               bt_common_color_code_bg_default = BT_COMMON_COLOR_BG_DEFAULT;
-               bt_common_color_code_bg_red = BT_COMMON_COLOR_BG_RED;
-               bt_common_color_code_bg_green = BT_COMMON_COLOR_BG_GREEN;
-               bt_common_color_code_bg_yellow = BT_COMMON_COLOR_BG_YELLOW;
-               bt_common_color_code_bg_blue = BT_COMMON_COLOR_BG_BLUE;
-               bt_common_color_code_bg_magenta = BT_COMMON_COLOR_BG_MAGENTA;
-               bt_common_color_code_bg_cyan = BT_COMMON_COLOR_BG_CYAN;
-               bt_common_color_code_bg_light_gray = BT_COMMON_COLOR_BG_LIGHT_GRAY;
-       }
-}
-
-BT_HIDDEN
-const char *bt_common_get_system_plugin_path(void)
-{
-       return SYSTEM_PLUGIN_PATH;
-}
-
-#ifdef __MINGW32__
-BT_HIDDEN
-bool bt_common_is_setuid_setgid(void)
-{
-       return false;
-}
-#else /* __MINGW32__ */
-BT_HIDDEN
-bool bt_common_is_setuid_setgid(void)
-{
-       return (geteuid() != getuid() || getegid() != getgid());
-}
-#endif /* __MINGW32__ */
-
-static
-char *bt_secure_getenv(const char *name)
-{
-       if (bt_common_is_setuid_setgid()) {
-               BT_LOGD("Disregarding environment variable for setuid/setgid binary: "
-                       "name=\"%s\"", name);
-               return NULL;
-       }
-       return getenv(name);
-}
-
-#ifdef __MINGW32__
-static
-const char *bt_get_home_dir(void)
-{
-       return g_get_home_dir();
-}
-#else /* __MINGW32__ */
-static
-const char *bt_get_home_dir(void)
-{
-       char *val = NULL;
-       struct passwd *pwd;
-
-       val = bt_secure_getenv(HOME_ENV_VAR);
-       if (val) {
-               goto end;
-       }
-       /* Fallback on password file. */
-       pwd = getpwuid(getuid());
-       if (!pwd) {
-               goto end;
-       }
-       val = pwd->pw_dir;
-end:
-       return val;
-}
-#endif /* __MINGW32__ */
-
-BT_HIDDEN
-char *bt_common_get_home_plugin_path(void)
-{
-       char *path = NULL;
-       const char *home_dir;
-       size_t length;
-
-       home_dir = bt_get_home_dir();
-       if (!home_dir) {
-               goto end;
-       }
-
-       length = strlen(home_dir) + strlen(HOME_PLUGIN_SUBPATH) + 1;
-
-       if (length >= PATH_MAX) {
-               BT_LOGW("Home directory path is too long: length=%zu",
-                       length);
-               goto end;
-       }
-
-       path = malloc(PATH_MAX);
-       if (!path) {
-               goto end;
-       }
-
-       strcpy(path, home_dir);
-       strcat(path, HOME_PLUGIN_SUBPATH);
-
-end:
-       return path;
-}
-
-BT_HIDDEN
-int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs)
-{
-       int ret = 0;
-       const char *at;
-       const char *end;
-       size_t init_dirs_len;
-
-       BT_ASSERT(dirs);
-       init_dirs_len = dirs->len;
-
-       if (!paths) {
-               /* Nothing to append */
-               goto end;
-       }
-
-       at = paths;
-       end = paths + strlen(paths);
-
-       while (at < end) {
-               GString *path;
-               const char *next_sep;
-
-               next_sep = strchr(at, G_SEARCHPATH_SEPARATOR);
-               if (next_sep == at) {
-                       /*
-                        * Empty path: try next character (supported
-                        * to conform to the typical parsing of $PATH).
-                        */
-                       at++;
-                       continue;
-               } else if (!next_sep) {
-                       /* No more separator: use the remaining */
-                       next_sep = paths + strlen(paths);
-               }
-
-               path = g_string_new(NULL);
-               if (!path) {
-                       goto error;
-               }
-
-               g_string_append_len(path, at, next_sep - at);
-               at = next_sep + 1;
-               g_ptr_array_add(dirs, path);
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-       /* Remove the new entries in dirs */
-       while (dirs->len > init_dirs_len) {
-               g_ptr_array_remove_index(dirs, init_dirs_len);
-       }
-
-end:
-       return ret;
-}
-
-static
-bool isarealtty(int fd)
-{
-       bool istty = false;
-       struct stat tty_stats;
-
-       if (!isatty(fd)) {
-               /* Not a TTY */
-               goto end;
-       }
-
-       if (fstat(fd, &tty_stats) == 0) {
-               if (!S_ISCHR(tty_stats.st_mode)) {
-                       /* Not a character device: not a TTY */
-                       goto end;
-               }
-       }
-
-       istty = true;
-
-end:
-       return istty;
-}
-
-BT_HIDDEN
-bool bt_common_colors_supported(void)
-{
-       static bool supports_colors = false;
-       static bool supports_colors_set = false;
-       const char *term_env_var;
-       const char *term_color_env_var;
-
-       if (supports_colors_set) {
-               goto end;
-       }
-
-       supports_colors_set = true;
-
-       /*
-        * `BABELTRACE_TERM_COLOR` environment variable always overrides
-        * the automatic color support detection.
-        */
-       term_color_env_var = getenv("BABELTRACE_TERM_COLOR");
-       if (term_color_env_var) {
-               if (g_ascii_strcasecmp(term_color_env_var, "always") == 0) {
-                       /* Force colors */
-                       supports_colors = true;
-               } else if (g_ascii_strcasecmp(term_color_env_var, "never") == 0) {
-                       /* Force no colors */
-                       goto end;
-               }
-       }
-
-       /* We need a compatible, known terminal */
-       term_env_var = getenv("TERM");
-       if (!term_env_var) {
-               goto end;
-       }
-
-       if (strncmp(term_env_var, "xterm", 5) != 0 &&
-                       strncmp(term_env_var, "rxvt", 4) != 0 &&
-                       strncmp(term_env_var, "konsole", 7) != 0 &&
-                       strncmp(term_env_var, "gnome", 5) != 0 &&
-                       strncmp(term_env_var, "screen", 5) != 0 &&
-                       strncmp(term_env_var, "tmux", 4) != 0 &&
-                       strncmp(term_env_var, "putty", 5) != 0) {
-               goto end;
-       }
-
-       /* Both standard output and error streams need to be TTYs */
-       if (!isarealtty(STDOUT_FILENO) || !isarealtty(STDERR_FILENO)) {
-               goto end;
-       }
-
-       supports_colors = true;
-
-end:
-       return supports_colors;
-}
-
-BT_HIDDEN
-const char *bt_common_color_reset(void)
-{
-       return bt_common_color_code_reset;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bold(void)
-{
-       return bt_common_color_code_bold;
-}
-
-BT_HIDDEN
-const char *bt_common_color_fg_default(void)
-{
-       return bt_common_color_code_fg_default;
-}
-
-BT_HIDDEN
-const char *bt_common_color_fg_red(void)
-{
-       return bt_common_color_code_fg_red;
-}
-
-BT_HIDDEN
-const char *bt_common_color_fg_green(void)
-{
-       return bt_common_color_code_fg_green;
-}
-
-BT_HIDDEN
-const char *bt_common_color_fg_yellow(void)
-{
-       return bt_common_color_code_fg_yellow;
-}
-
-BT_HIDDEN
-const char *bt_common_color_fg_blue(void)
-{
-       return bt_common_color_code_fg_blue;
-}
-
-BT_HIDDEN
-const char *bt_common_color_fg_magenta(void)
-{
-       return bt_common_color_code_fg_magenta;
-}
-
-BT_HIDDEN
-const char *bt_common_color_fg_cyan(void)
-{
-       return bt_common_color_code_fg_cyan;
-}
-
-BT_HIDDEN
-const char *bt_common_color_fg_light_gray(void)
-{
-       return bt_common_color_code_fg_light_gray;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bg_default(void)
-{
-       return bt_common_color_code_bg_default;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bg_red(void)
-{
-       return bt_common_color_code_bg_red;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bg_green(void)
-{
-       return bt_common_color_code_bg_green;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bg_yellow(void)
-{
-       return bt_common_color_code_bg_yellow;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bg_blue(void)
-{
-       return bt_common_color_code_bg_blue;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bg_magenta(void)
-{
-       return bt_common_color_code_bg_magenta;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bg_cyan(void)
-{
-       return bt_common_color_code_bg_cyan;
-}
-
-BT_HIDDEN
-const char *bt_common_color_bg_light_gray(void)
-{
-       return bt_common_color_code_bg_light_gray;
-}
-
-BT_HIDDEN
-GString *bt_common_string_until(const char *input, const char *escapable_chars,
-               const char *end_chars, size_t *end_pos)
-{
-       GString *output = g_string_new(NULL);
-       const char *ch;
-       const char *es_char;
-       const char *end_char;
-
-       if (!output) {
-               goto error;
-       }
-
-       for (ch = input; *ch != '\0'; ch++) {
-               if (*ch == '\\') {
-                       bool continue_loop = false;
-
-                       if (ch[1] == '\0') {
-                               /* `\` at the end of the string: append `\` */
-                               g_string_append_c(output, *ch);
-                               ch++;
-                               goto set_end_pos;
-                       }
-
-                       for (es_char = escapable_chars; *es_char != '\0'; es_char++) {
-                               if (ch[1] == *es_char) {
-                                       /*
-                                        * `\` followed by an escapable
-                                        * character: append the escaped
-                                        * character only.
-                                        */
-                                       g_string_append_c(output, ch[1]);
-                                       ch++;
-                                       continue_loop = true;
-                                       break;
-                               }
-                       }
-
-                       if (continue_loop) {
-                               continue;
-                       }
-
-                       /*
-                        * `\` followed by a non-escapable character:
-                        * append `\` and the character.
-                        */
-                       g_string_append_c(output, *ch);
-                       g_string_append_c(output, ch[1]);
-                       ch++;
-                       continue;
-               } else {
-                       for (end_char = end_chars; *end_char != '\0'; end_char++) {
-                               if (*ch == *end_char) {
-                                       /*
-                                        * End character found:
-                                        * terminate this loop.
-                                        */
-                                       goto set_end_pos;
-                               }
-                       }
-
-                       /* Normal character: append */
-                       g_string_append_c(output, *ch);
-               }
-       }
-
-set_end_pos:
-       if (end_pos) {
-               *end_pos = ch - input;
-       }
-
-       goto end;
-
-error:
-       if (output) {
-               g_string_free(output, TRUE);
-       }
-
-end:
-       return output;
-}
-
-BT_HIDDEN
-GString *bt_common_shell_quote(const char *input, bool with_single_quotes)
-{
-       GString *output = g_string_new(NULL);
-       const char *ch;
-       bool no_quote = true;
-
-       if (!output) {
-               goto end;
-       }
-
-       if (strlen(input) == 0) {
-               if (with_single_quotes) {
-                       g_string_assign(output, "''");
-               }
-
-               goto end;
-       }
-
-       for (ch = input; *ch != '\0'; ch++) {
-               const char c = *ch;
-
-               if (!g_ascii_isalpha(c) && !g_ascii_isdigit(c) && c != '_' &&
-                               c != '@' && c != '%' && c != '+' && c != '=' &&
-                               c != ':' && c != ',' && c != '.' && c != '/' &&
-                               c != '-') {
-                       no_quote = false;
-                       break;
-               }
-       }
-
-       if (no_quote) {
-               g_string_assign(output, input);
-               goto end;
-       }
-
-       if (with_single_quotes) {
-               g_string_assign(output, "'");
-       }
-
-       for (ch = input; *ch != '\0'; ch++) {
-               if (*ch == '\'') {
-                       g_string_append(output, "'\"'\"'");
-               } else {
-                       g_string_append_c(output, *ch);
-               }
-       }
-
-       if (with_single_quotes) {
-               g_string_append_c(output, '\'');
-       }
-
-end:
-       return output;
-}
-
-BT_HIDDEN
-bool bt_common_string_is_printable(const char *input)
-{
-       const char *ch;
-       bool printable = true;
-       BT_ASSERT(input);
-
-       for (ch = input; *ch != '\0'; ch++) {
-               if (!isprint(*ch) && *ch != '\n' && *ch != '\r' &&
-                               *ch != '\t' && *ch != '\v') {
-                       printable = false;
-                       goto end;
-               }
-       }
-
-end:
-       return printable;
-}
-
-BT_HIDDEN
-void bt_common_destroy_lttng_live_url_parts(
-               struct bt_common_lttng_live_url_parts *parts)
-{
-       if (!parts) {
-               goto end;
-       }
-
-       if (parts->proto) {
-               g_string_free(parts->proto, TRUE);
-               parts->proto = NULL;
-       }
-
-       if (parts->hostname) {
-               g_string_free(parts->hostname, TRUE);
-               parts->hostname = NULL;
-       }
-
-       if (parts->target_hostname) {
-               g_string_free(parts->target_hostname, TRUE);
-               parts->target_hostname = NULL;
-       }
-
-       if (parts->session_name) {
-               g_string_free(parts->session_name, TRUE);
-               parts->session_name = NULL;
-       }
-
-end:
-       return;
-}
-
-BT_HIDDEN
-struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
-               const char *url, char *error_buf, size_t error_buf_size)
-{
-       struct bt_common_lttng_live_url_parts parts;
-       const char *at = url;
-       size_t end_pos;
-
-       BT_ASSERT(url);
-       memset(&parts, 0, sizeof(parts));
-       parts.port = -1;
-
-       /* Protocol */
-       parts.proto = bt_common_string_until(at, "", ":", &end_pos);
-       if (!parts.proto || parts.proto->len == 0) {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size, "Missing protocol");
-               }
-
-               goto error;
-       }
-
-       if (strcmp(parts.proto->str, "net") == 0) {
-               g_string_assign(parts.proto, "net4");
-       }
-
-       if (strcmp(parts.proto->str, "net4") != 0 &&
-                       strcmp(parts.proto->str, "net6") != 0) {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size,
-                               "Unknown protocol: `%s`", parts.proto->str);
-               }
-
-               goto error;
-       }
-
-       if (at[end_pos] != ':') {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size,
-                               "Expecting `:` after `%s`", parts.proto->str);
-               }
-
-               goto error;
-       }
-
-       at += end_pos;
-
-       /* :// */
-       if (strncmp(at, "://", 3) != 0) {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size,
-                               "Expecting `://` after protocol");
-               }
-
-               goto error;
-       }
-
-       at += 3;
-
-       /* Hostname */
-       parts.hostname = bt_common_string_until(at, "", ":/", &end_pos);
-       if (!parts.hostname || parts.hostname->len == 0) {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size, "Missing hostname");
-               }
-
-               goto error;
-       }
-
-       if (at[end_pos] == ':') {
-               /* Port */
-               GString *port;
-
-               at += end_pos + 1;
-               port = bt_common_string_until(at, "", "/", &end_pos);
-               if (!port || port->len == 0) {
-                       if (error_buf) {
-                               snprintf(error_buf, error_buf_size, "Missing port");
-                       }
-
-                       goto error;
-               }
-
-               if (sscanf(port->str, "%d", &parts.port) != 1) {
-                       if (error_buf) {
-                               snprintf(error_buf, error_buf_size,
-                                       "Invalid port: `%s`", port->str);
-                       }
-
-                       g_string_free(port, TRUE);
-                       goto error;
-               }
-
-               g_string_free(port, TRUE);
-
-               if (parts.port < 0 || parts.port >= 65536) {
-                       if (error_buf) {
-                               snprintf(error_buf, error_buf_size,
-                                       "Invalid port: %d", parts.port);
-                       }
-
-                       goto error;
-               }
-       }
-
-       if (at[end_pos] == '\0') {
-               goto end;
-       }
-
-       at += end_pos;
-
-       /* /host/ */
-       if (strncmp(at, "/host/", 6) != 0) {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size,
-                               "Expecting `/host/` after hostname or port");
-               }
-
-               goto error;
-       }
-
-       at += 6;
-
-       /* Target hostname */
-       parts.target_hostname = bt_common_string_until(at, "", "/", &end_pos);
-       if (!parts.target_hostname || parts.target_hostname->len == 0) {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size,
-                               "Missing target hostname");
-               }
-
-               goto error;
-       }
-
-       if (at[end_pos] == '\0') {
-               goto end;
-       }
-
-       at += end_pos + 1;
-
-       /* Session name */
-       parts.session_name = bt_common_string_until(at, "", "/", &end_pos);
-       if (!parts.session_name || parts.session_name->len == 0) {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size,
-                               "Missing session name");
-               }
-
-               goto error;
-       }
-
-       if (at[end_pos] == '/') {
-               if (error_buf) {
-                       snprintf(error_buf, error_buf_size,
-                               "Unexpected `/` after session name (`%s`)",
-                               parts.session_name->str);
-               }
-
-               goto error;
-       }
-
-       goto end;
-
-error:
-       bt_common_destroy_lttng_live_url_parts(&parts);
-
-end:
-       return parts;
-}
-
-BT_HIDDEN
-void bt_common_normalize_star_glob_pattern(char *pattern)
-{
-       const char *p;
-       char *np;
-       bool got_star = false;
-
-       BT_ASSERT(pattern);
-
-       for (p = pattern, np = pattern; *p != '\0'; p++) {
-               switch (*p) {
-               case '*':
-                       if (got_star) {
-                               /* Avoid consecutive stars. */
-                               continue;
-                       }
-
-                       got_star = true;
-                       break;
-               case '\\':
-                       /* Copy backslash character. */
-                       *np = *p;
-                       np++;
-                       p++;
-
-                       if (*p == '\0') {
-                               goto end;
-                       }
-
-                       /* fall-through */
-               default:
-                       got_star = false;
-                       break;
-               }
-
-               /* Copy single character. */
-               *np = *p;
-               np++;
-       }
-
-end:
-       *np = '\0';
-}
-
-static inline
-bool at_end_of_pattern(const char *p, const char *pattern, size_t pattern_len)
-{
-       return (p - pattern) == pattern_len || *p == '\0';
-}
-
-/*
- * Globbing matching function with the star feature only (`?` and
- * character sets are not supported). This matches `candidate` (plain
- * string) against `pattern`. A literal star can be escaped with `\` in
- * `pattern`.
- *
- * `pattern_len` or `candidate_len` can be greater than the actual
- * string length of `pattern` or `candidate` if the string is
- * null-terminated.
- */
-BT_HIDDEN
-bool bt_common_star_glob_match(const char *pattern, size_t pattern_len,
-               const char *candidate, size_t candidate_len) {
-       const char *retry_c = candidate, *retry_p = pattern, *c, *p;
-       bool got_a_star = false;
-
-retry:
-       c = retry_c;
-       p = retry_p;
-
-       /*
-        * The concept here is to retry a match in the specific case
-        * where we already got a star. The retry position for the
-        * pattern is just after the most recent star, and the retry
-        * position for the candidate is the character following the
-        * last try's first character.
-        *
-        * Example:
-        *
-        *     candidate: hi ev every onyx one
-        *                ^
-        *     pattern:   hi*every*one
-        *                ^
-        *
-        *     candidate: hi ev every onyx one
-        *                 ^
-        *     pattern:   hi*every*one
-        *                 ^
-        *
-        *     candidate: hi ev every onyx one
-        *                  ^
-        *     pattern:   hi*every*one
-        *                  ^
-        *
-        *     candidate: hi ev every onyx one
-        *                  ^
-        *     pattern:   hi*every*one
-        *                   ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                   ^
-        *     pattern:   hi*every*one
-        *                   ^
-        *
-        *     candidate: hi ev every onyx one
-        *                   ^^
-        *     pattern:   hi*every*one
-        *                   ^^
-        *
-        *     candidate: hi ev every onyx one
-        *                   ^ ^
-        *     pattern:   hi*every*one
-        *                   ^ ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                    ^
-        *     pattern:   hi*every*one
-        *                   ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                     ^
-        *     pattern:   hi*every*one
-        *                   ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                      ^
-        *     pattern:   hi*every*one
-        *                   ^
-        *
-        *     candidate: hi ev every onyx one
-        *                      ^^
-        *     pattern:   hi*every*one
-        *                   ^^
-        *
-        *     candidate: hi ev every onyx one
-        *                      ^ ^
-        *     pattern:   hi*every*one
-        *                   ^ ^
-        *
-        *     candidate: hi ev every onyx one
-        *                      ^  ^
-        *     pattern:   hi*every*one
-        *                   ^  ^
-        *
-        *     candidate: hi ev every onyx one
-        *                      ^   ^
-        *     pattern:   hi*every*one
-        *                   ^   ^
-        *
-        *     candidate: hi ev every onyx one
-        *                           ^
-        *     pattern:   hi*every*one
-        *                        ^
-        *
-        *     candidate: hi ev every onyx one
-        *                           ^
-        *     pattern:   hi*every*one
-        *                         ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                            ^
-        *     pattern:   hi*every*one
-        *                         ^
-        *
-        *     candidate: hi ev every onyx one
-        *                            ^^
-        *     pattern:   hi*every*one
-        *                         ^^
-        *
-        *     candidate: hi ev every onyx one
-        *                            ^ ^
-        *     pattern:   hi*every*one
-        *                         ^ ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                             ^
-        *     pattern:   hi*every*one
-        *                         ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                              ^
-        *     pattern:   hi*every*one
-        *                         ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                               ^
-        *     pattern:   hi*every*one
-        *                         ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                                ^
-        *     pattern:   hi*every*one
-        *                         ^ MISMATCH
-        *
-        *     candidate: hi ev every onyx one
-        *                                 ^
-        *     pattern:   hi*every*one
-        *                         ^
-        *
-        *     candidate: hi ev every onyx one
-        *                                 ^^
-        *     pattern:   hi*every*one
-        *                         ^^
-        *
-        *     candidate: hi ev every onyx one
-        *                                 ^ ^
-        *     pattern:   hi*every*one
-        *                         ^ ^
-        *
-        *     candidate: hi ev every onyx one
-        *                                 ^  ^
-        *     pattern:   hi*every*one
-        *                         ^  ^ SUCCESS
-        */
-       while ((c - candidate) < candidate_len && *c != '\0') {
-               BT_ASSERT(*c);
-
-               if (at_end_of_pattern(p, pattern, pattern_len)) {
-                       goto end_of_pattern;
-               }
-
-               switch (*p) {
-               case '*':
-                       got_a_star = true;
-
-                       /*
-                        * Our first try starts at the current candidate
-                        * character and after the star in the pattern.
-                        */
-                       retry_c = c;
-                       retry_p = p + 1;
-
-                       if (at_end_of_pattern(retry_p, pattern, pattern_len)) {
-                               /*
-                                * Star at the end of the pattern at
-                                * this point: automatic match.
-                                */
-                               return true;
-                       }
-
-                       goto retry;
-               case '\\':
-                       /* Go to escaped character. */
-                       p++;
-
-                       /*
-                        * Fall through the default case which compares
-                        * the escaped character now.
-                        */
-                       /* fall-through */
-               default:
-                       if (at_end_of_pattern(p, pattern, pattern_len) ||
-                                       *c != *p) {
-end_of_pattern:
-                               /* Character mismatch OR end of pattern. */
-                               if (!got_a_star) {
-                                       /*
-                                        * We didn't get any star yet,
-                                        * so this first mismatch
-                                        * automatically makes the whole
-                                        * test fail.
-                                        */
-                                       return false;
-                               }
-
-                               /*
-                                * Next try: next candidate character,
-                                * original pattern character (following
-                                * the most recent star).
-                                */
-                               retry_c++;
-                               goto retry;
-                       }
-                       break;
-               }
-
-               /* Next pattern and candidate characters. */
-               c++;
-               p++;
-       }
-
-       /*
-        * We checked every candidate character and we're still in a
-        * success state: the only pattern character allowed to remain
-        * is a star.
-        */
-       if (at_end_of_pattern(p, pattern, pattern_len)) {
-               return true;
-       }
-
-       p++;
-       return p[-1] == '*' && at_end_of_pattern(p, pattern, pattern_len);
-}
-
-static
-void append_path_parts(const char *path, GPtrArray *parts)
-{
-       const char *ch = path;
-       const char *last = path;
-
-       while (true) {
-               if (*ch == G_DIR_SEPARATOR || *ch == '\0') {
-                       if (ch - last > 0) {
-                               GString *part = g_string_new(NULL);
-
-                               BT_ASSERT(part);
-                               g_string_append_len(part, last, ch - last);
-                               g_ptr_array_add(parts, part);
-                       }
-
-                       if (*ch == '\0') {
-                               break;
-                       }
-
-                       last = ch + 1;
-               }
-
-               ch++;
-       }
-}
-
-static
-void destroy_gstring(void *gstring)
-{
-       (void) g_string_free(gstring, TRUE);
-}
-
-#ifdef __MINGW32__
-BT_HIDDEN
-GString *bt_common_normalize_path(const char *path, const char *wd)
-{
-       char *tmp;
-       GString *norm_path = NULL;
-
-       BT_ASSERT(path);
-
-       tmp = _fullpath(NULL, path, PATH_MAX);
-       if (!tmp) {
-               goto error;
-       }
-
-       norm_path = g_string_new(tmp);
-       if (!norm_path) {
-               goto error;
-       }
-
-       goto end;
-error:
-       if (norm_path) {
-               g_string_free(norm_path, TRUE);
-               norm_path = NULL;
-       }
-end:
-       if (tmp) {
-               free(tmp);
-       }
-       return norm_path;
-}
-#else
-BT_HIDDEN
-GString *bt_common_normalize_path(const char *path, const char *wd)
-{
-       size_t i;
-       GString *norm_path;
-       GPtrArray *parts = NULL;
-
-       BT_ASSERT(path);
-       norm_path = g_string_new(G_DIR_SEPARATOR_S);
-       if (!norm_path) {
-               goto error;
-       }
-
-       parts = g_ptr_array_new_with_free_func(destroy_gstring);
-       if (!parts) {
-               goto error;
-       }
-
-       if (path[0] != G_DIR_SEPARATOR) {
-               /* Relative path: start with working directory */
-               if (wd) {
-                       append_path_parts(wd, parts);
-               } else {
-                       gchar *cd = g_get_current_dir();
-
-                       append_path_parts(cd, parts);
-                       g_free(cd);
-               }
-       }
-
-       /* Append parts of the path parameter */
-       append_path_parts(path, parts);
-
-       /* Resolve special `..` and `.` parts */
-       for (i = 0; i < parts->len; i++) {
-               GString *part = g_ptr_array_index(parts, i);
-
-               if (strcmp(part->str, "..") == 0) {
-                       if (i == 0) {
-                               /*
-                                * First part of absolute path is `..`:
-                                * this is invalid.
-                                */
-                               goto error;
-                       }
-
-                       /* Remove `..` and previous part */
-                       g_ptr_array_remove_index(parts, i - 1);
-                       g_ptr_array_remove_index(parts, i - 1);
-                       i -= 2;
-               } else if (strcmp(part->str, ".") == 0) {
-                       /* Remove `.` */
-                       g_ptr_array_remove_index(parts, i);
-                       i -= 1;
-               }
-       }
-
-       /* Create normalized path with what's left */
-       for (i = 0; i < parts->len; i++) {
-               GString *part = g_ptr_array_index(parts, i);
-
-               g_string_append(norm_path, part->str);
-
-               if (i < parts->len - 1) {
-                       g_string_append_c(norm_path, G_DIR_SEPARATOR);
-               }
-       }
-
-       goto end;
-
-error:
-       if (norm_path) {
-               g_string_free(norm_path, TRUE);
-               norm_path = NULL;
-       }
-
-end:
-       if (parts) {
-               g_ptr_array_free(parts, TRUE);
-       }
-
-       return norm_path;
-}
-#endif
-
-BT_HIDDEN
-size_t bt_common_get_page_size(void)
-{
-       int page_size;
-
-       page_size = bt_sysconf(_SC_PAGESIZE);
-       if (page_size < 0) {
-               BT_LOGF("Cannot get system's page size: ret=%d",
-                       page_size);
-               abort();
-       }
-
-       return page_size;
-}
-
-#define BUF_STD_APPEND(...)                                            \
-       do {                                                            \
-               char _tmp_fmt[64];                                      \
-               int _count;                                             \
-               size_t _size = buf_size - (size_t) (*buf_ch - buf);     \
-               size_t _tmp_fmt_size = (size_t) (fmt_ch - *out_fmt_ch); \
-               strncpy(_tmp_fmt, *out_fmt_ch, _tmp_fmt_size);          \
-               _tmp_fmt[_tmp_fmt_size] = '\0';                         \
-               _count = snprintf(*buf_ch, _size, _tmp_fmt, __VA_ARGS__); \
-               BT_ASSERT(_count >= 0);                                 \
-               *buf_ch += MIN(_count, _size);                          \
-       } while (0)
-
-#define BUF_STD_APPEND_SINGLE_ARG(_type)                               \
-       do {                                                            \
-               _type _arg = va_arg(*args, _type);                      \
-               BUF_STD_APPEND(_arg);                                   \
-       } while (0)
-
-static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
-               size_t buf_size, const char **out_fmt_ch, va_list *args)
-{
-       const char *fmt_ch = *out_fmt_ch;
-       enum LENGTH_MODIFIER {
-               LENGTH_MOD_H,
-               LENGTH_MOD_HH,
-               LENGTH_MOD_NONE,
-               LENGTH_MOD_LOW_L,
-               LENGTH_MOD_LOW_LL,
-               LENGTH_MOD_UP_L,
-               LENGTH_MOD_Z,
-       } length_mod = LENGTH_MOD_NONE;
-
-       /* skip '%' */
-       fmt_ch++;
-
-       if (*fmt_ch == '%') {
-               fmt_ch++;
-               **buf_ch = '%';
-               (*buf_ch)++;
-               goto update_rw_fmt;
-       }
-
-       /* flags */
-       for (;;) {
-               switch (*fmt_ch) {
-                       case '-':
-                       case '+':
-                       case ' ':
-                       case '#':
-                       case '0':
-                       case '\'':
-                               fmt_ch++;
-                               continue;
-                       default:
-                               break;
-               }
-               break;
-       }
-
-       /* width */
-       for (;;) {
-               if (*fmt_ch < '0' || *fmt_ch > '9') {
-                       break;
-               }
-
-               fmt_ch++;
-       }
-
-       /* precision */
-       if (*fmt_ch == '.') {
-               fmt_ch++;
-
-               for (;;) {
-                       if (*fmt_ch < '0' || *fmt_ch > '9') {
-                               break;
-                       }
-
-                       fmt_ch++;
-               }
-       }
-
-       /* format (PRI*64) */
-       if (strncmp(fmt_ch, PRId64, sizeof(PRId64) - 1) == 0) {
-               fmt_ch += sizeof(PRId64) - 1;
-               BUF_STD_APPEND_SINGLE_ARG(int64_t);
-               goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIu64, sizeof(PRIu64) - 1) == 0) {
-               fmt_ch += sizeof(PRIu64) - 1;
-               BUF_STD_APPEND_SINGLE_ARG(uint64_t);
-               goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIx64, sizeof(PRIx64) - 1) == 0) {
-               fmt_ch += sizeof(PRIx64) - 1;
-               BUF_STD_APPEND_SINGLE_ARG(uint64_t);
-               goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIX64, sizeof(PRIX64) - 1) == 0) {
-               fmt_ch += sizeof(PRIX64) - 1;
-               BUF_STD_APPEND_SINGLE_ARG(uint64_t);
-               goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIo64, sizeof(PRIo64) - 1) == 0) {
-               fmt_ch += sizeof(PRIo64) - 1;
-               BUF_STD_APPEND_SINGLE_ARG(uint64_t);
-               goto update_rw_fmt;
-       } else if (strncmp(fmt_ch, PRIi64, sizeof(PRIi64) - 1) == 0) {
-               fmt_ch += sizeof(PRIi64) - 1;
-               BUF_STD_APPEND_SINGLE_ARG(int64_t);
-               goto update_rw_fmt;
-       }
-
-       // length modifier
-       switch (*fmt_ch) {
-               case 'h':
-                       length_mod = LENGTH_MOD_H;
-                       fmt_ch++;
-
-                       if (*fmt_ch == 'h') {
-                               length_mod = LENGTH_MOD_HH;
-                               fmt_ch++;
-                               break;
-                       }
-                       break;
-               case 'l':
-                       length_mod = LENGTH_MOD_LOW_L;
-                       fmt_ch++;
-
-                       if (*fmt_ch == 'l') {
-                               length_mod = LENGTH_MOD_LOW_LL;
-                               fmt_ch++;
-                               break;
-                       }
-                       break;
-               case 'L':
-                       length_mod = LENGTH_MOD_UP_L;
-                       fmt_ch++;
-                       break;
-               case 'z':
-                       length_mod = LENGTH_MOD_Z;
-                       fmt_ch++;
-                       break;
-               default:
-                       break;
-       }
-
-       // format
-       switch (*fmt_ch) {
-       case 'c':
-       {
-               fmt_ch++;
-
-               switch (length_mod) {
-               case LENGTH_MOD_NONE:
-                       BUF_STD_APPEND_SINGLE_ARG(int);
-                       break;
-               case LENGTH_MOD_LOW_L:
-                       BUF_STD_APPEND_SINGLE_ARG(wint_t);
-                       break;
-               default:
-                       abort();
-               }
-               break;
-       }
-       case 's':
-               fmt_ch++;
-
-               switch (length_mod) {
-               case LENGTH_MOD_NONE:
-                       BUF_STD_APPEND_SINGLE_ARG(char *);
-                       break;
-               case LENGTH_MOD_LOW_L:
-                       BUF_STD_APPEND_SINGLE_ARG(wchar_t *);
-                       break;
-               default:
-                       abort();
-               }
-               break;
-       case 'd':
-       case 'i':
-               fmt_ch++;
-
-               switch (length_mod) {
-               case LENGTH_MOD_NONE:
-               case LENGTH_MOD_H:
-               case LENGTH_MOD_HH:
-                       BUF_STD_APPEND_SINGLE_ARG(int);
-                       break;
-               case LENGTH_MOD_LOW_L:
-                       BUF_STD_APPEND_SINGLE_ARG(long);
-                       break;
-               case LENGTH_MOD_LOW_LL:
-                       BUF_STD_APPEND_SINGLE_ARG(long long);
-                       break;
-               case LENGTH_MOD_Z:
-                       BUF_STD_APPEND_SINGLE_ARG(size_t);
-                       break;
-               default:
-                       abort();
-               }
-               break;
-       case 'o':
-       case 'x':
-       case 'X':
-       case 'u':
-               fmt_ch++;
-
-               switch (length_mod) {
-               case LENGTH_MOD_NONE:
-               case LENGTH_MOD_H:
-               case LENGTH_MOD_HH:
-                       BUF_STD_APPEND_SINGLE_ARG(unsigned int);
-                       break;
-               case LENGTH_MOD_LOW_L:
-                       BUF_STD_APPEND_SINGLE_ARG(unsigned long);
-                       break;
-               case LENGTH_MOD_LOW_LL:
-                       BUF_STD_APPEND_SINGLE_ARG(unsigned long long);
-                       break;
-               case LENGTH_MOD_Z:
-                       BUF_STD_APPEND_SINGLE_ARG(size_t);
-                       break;
-               default:
-                       abort();
-               }
-               break;
-       case 'f':
-       case 'F':
-       case 'e':
-       case 'E':
-       case 'g':
-       case 'G':
-               fmt_ch++;
-
-               switch (length_mod) {
-               case LENGTH_MOD_NONE:
-                       BUF_STD_APPEND_SINGLE_ARG(double);
-                       break;
-               case LENGTH_MOD_UP_L:
-                       BUF_STD_APPEND_SINGLE_ARG(long double);
-                       break;
-               default:
-                       abort();
-               }
-               break;
-       case 'p':
-               fmt_ch++;
-
-               if (length_mod == LENGTH_MOD_NONE) {
-                       BUF_STD_APPEND_SINGLE_ARG(void *);
-               } else {
-                       abort();
-               }
-               break;
-       default:
-               abort();
-       }
-
-update_rw_fmt:
-       *out_fmt_ch = fmt_ch;
-}
-
-BT_HIDDEN
-void bt_common_custom_vsnprintf(char *buf, size_t buf_size,
-               char intro,
-               bt_common_handle_custom_specifier_func handle_specifier,
-               void *priv_data, const char *fmt, va_list *args)
-{
-       const char *fmt_ch = fmt;
-       char *buf_ch = buf;
-
-       BT_ASSERT(buf);
-       BT_ASSERT(fmt);
-
-       while (*fmt_ch != '\0') {
-               switch (*fmt_ch) {
-               case '%':
-                       BT_ASSERT(fmt_ch[1] != '\0');
-
-                       if (fmt_ch[1] == intro) {
-                               handle_specifier(priv_data, &buf_ch,
-                                       buf_size - (size_t) (buf_ch - buf),
-                                       &fmt_ch, args);
-                       } else {
-                               handle_conversion_specifier_std(buf, &buf_ch,
-                                       buf_size, &fmt_ch, args);
-                       }
-
-                       if (buf_ch >= buf + buf_size - 1) {
-                               fmt_ch = "";
-                       }
-                       break;
-               default:
-                       *buf_ch = *fmt_ch;
-                       buf_ch++;
-                       if (buf_ch >= buf + buf_size - 1) {
-                               fmt_ch = "";
-                       }
-
-                       fmt_ch++;
-               }
-       }
-
-       *buf_ch = '\0';
-}
-
-BT_HIDDEN
-void bt_common_custom_snprintf(char *buf, size_t buf_size,
-               char intro,
-               bt_common_handle_custom_specifier_func handle_specifier,
-               void *priv_data, const char *fmt, ...)
-{
-       va_list args;
-       va_start(args, fmt);
-       bt_common_custom_vsnprintf(buf, buf_size, intro, handle_specifier,
-               priv_data, fmt, &args);
-       va_end(args);
-}
diff --git a/common/logging.c b/common/logging.c
deleted file mode 100644 (file)
index 234ee62..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_common_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_common_log_level, "BABELTRACE_COMMON_LOG_LEVEL");
diff --git a/common/logging.h b/common/logging.h
deleted file mode 100644 (file)
index a7029dc..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef COMMON_LOGGING_H
-#define COMMON_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_common_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_common_log_level);
-
-#endif /* COMMON_LOGGING_H */
diff --git a/compat/Makefile.am b/compat/Makefile.am
deleted file mode 100644 (file)
index 91a3484..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-noinst_LTLIBRARIES = libcompat.la
-
-libcompat_la_SOURCES = compat_uuid.c \
-               compat_mman.c \
-               logging.c logging.h
-
-libcompat_la_LDFLAGS = \
-       $(LD_NO_AS_NEEDED)
-
-if BABELTRACE_BUILD_WITH_MINGW
-libcompat_la_LDFLAGS += -lrpcrt4
-endif
diff --git a/compat/compat_mman.c b/compat/compat_mman.c
deleted file mode 100644 (file)
index bef80d4..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * compat/compat_mman.h
- *
- * Copyright (C) 2013   JP Ikaheimonen <jp_ikaheimonen@mentor.com>
- *               2016   Michael Jeanson <mjeanson@efficios.com>
- *
- * These sources are based on ftp://g.oswego.edu/pub/misc/malloc.c
- * file by Doug Lea, released to the public domain.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COMPAT-MMAN"
-#include "logging.h"
-
-#ifdef __APPLE__
-/*
- * On macOS, we need a dummy symbol so that the linker won't
- * complain of an empty table of contents.
- */
-BT_HIDDEN
-int bt_mman_dummy_symbol;
-#endif /* __APPLE__ */
-
-#ifdef __MINGW32__
-
-#include <errno.h>
-#include <io.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <windows.h>
-#include <babeltrace2/compat/mman-internal.h>
-
-struct mmap_mapping {
-       /* The duplicated handle. */
-       HANDLE file_handle;
-       /* Handle returned by CreateFileMapping. */
-       HANDLE map_handle;
-};
-
-static
-GHashTable *mmap_mappings = NULL;
-
-/*
- * This mutex protects the hashtable of memory mappings.
- */
-static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static
-struct mmap_mapping *mapping_create(void)
-{
-       struct mmap_mapping *mapping;
-
-       mapping = malloc(sizeof(struct mmap_mapping));
-       if (mapping != NULL) {
-               mapping->file_handle = NULL;
-               mapping->map_handle = NULL;
-       }
-
-       return mapping;
-}
-
-static
-void mapping_clean(struct mmap_mapping *mapping)
-{
-       if (mapping) {
-               if (!CloseHandle(mapping->map_handle)) {
-                       BT_LOGF_STR("Failed to close mmap map_handle.");
-                       abort();
-               }
-               if (!CloseHandle(mapping->file_handle)) {
-                       BT_LOGF_STR("Failed to close mmap file_handle.");
-                       abort();
-               }
-               free(mapping);
-               mapping = NULL;
-       }
-}
-
-static
-void addr_clean(void *addr)
-{
-       /* Cleanup of handles should never fail. */
-       if (!UnmapViewOfFile(addr)) {
-               BT_LOGF_STR("Failed to unmap mmap mapping.");
-               abort();
-       }
-}
-
-static
-void mmap_lock(void)
-{
-       if (pthread_mutex_lock(&mmap_mutex)) {
-               BT_LOGF_STR("Failed to acquire mmap_mutex.");
-               abort();
-       }
-}
-
-static
-void mmap_unlock(void)
-{
-       if (pthread_mutex_unlock(&mmap_mutex)) {
-               BT_LOGF_STR("Failed to release mmap_mutex.");
-               abort();
-       }
-}
-
-/*
- * Convert mmap memory protection flags to CreateFileMapping page protection
- * flag and MapViewOfFile desired access flag.
- */
-static
-DWORD map_prot_flags(int prot, DWORD *dwDesiredAccess)
-{
-       if (prot & PROT_READ) {
-               if (prot & PROT_WRITE) {
-                       *dwDesiredAccess = FILE_MAP_WRITE;
-                       if (prot & PROT_EXEC) {
-                               return PAGE_EXECUTE_READWRITE;
-                       }
-                       return PAGE_READWRITE;
-               }
-               if (prot & PROT_EXEC) {
-                       *dwDesiredAccess = FILE_MAP_EXECUTE;
-                       return PAGE_EXECUTE_READ;
-               }
-               *dwDesiredAccess = FILE_MAP_READ;
-               return PAGE_READONLY;
-       }
-       if (prot & PROT_WRITE) {
-               *dwDesiredAccess = FILE_MAP_COPY;
-               return PAGE_WRITECOPY;
-       }
-       if (prot & PROT_EXEC) {
-               *dwDesiredAccess = FILE_MAP_EXECUTE;
-               return PAGE_EXECUTE_READ;
-       }
-
-       /* Mapping failed. */
-       *dwDesiredAccess = 0;
-       return 0;
-}
-
-BT_HIDDEN
-void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
-               off_t offset)
-{
-       struct mmap_mapping *mapping = NULL;
-       void *mapping_addr;
-       DWORD dwDesiredAccess;
-       DWORD flProtect;
-       HANDLE handle;
-
-       /* Check for a valid fd. */
-       if (fd == -1) {
-               _set_errno(EBADF);
-               goto error;
-       }
-
-       /* We don't support this at the moment. */
-       if (flags == MAP_FIXED) {
-               _set_errno(ENOTSUP);
-               goto error;
-       }
-
-       /* Map mmap flags to those of the Windows API. */
-       flProtect = map_prot_flags(prot, &dwDesiredAccess);
-       if (flProtect == 0) {
-               _set_errno(EINVAL);
-               goto error;
-       }
-
-       /* Allocate the mapping struct. */
-       mapping = mapping_create();
-       if (!mapping) {
-               BT_LOGE_STR("Failed to allocate mmap mapping.");
-               _set_errno(ENOMEM);
-               goto error;
-       }
-
-       /* Get a handle from the fd. */
-       handle = (HANDLE) _get_osfhandle(fd);
-
-       /* Duplicate the handle and store it in 'mapping.file_handle'. */
-       if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
-                       &mapping->file_handle, 0, FALSE,
-                       DUPLICATE_SAME_ACCESS)) {
-               _set_errno(ENOMEM);
-               goto error;
-       }
-
-       /*
-        * Create a file mapping object with a maximum size
-        * of 'offset' + 'length'.
-        */
-       mapping->map_handle = CreateFileMapping(mapping->file_handle, NULL,
-                       flProtect, 0, offset + length, NULL);
-       if (mapping->map_handle == 0) {
-               _set_errno(EACCES);
-               goto error;
-       }
-
-       /* Map the requested block starting at 'offset' for 'length' bytes. */
-       mapping_addr = MapViewOfFile(mapping->map_handle, dwDesiredAccess, 0,
-                       offset, length);
-       if (mapping_addr == 0) {
-               DWORD dwLastErr = GetLastError();
-               if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
-                       _set_errno(EINVAL);
-               } else {
-                       _set_errno(EACCES);
-               }
-               goto error;
-       }
-
-       mmap_lock();
-
-       /* If we have never done any mappings, allocate the hashtable. */
-       if (!mmap_mappings) {
-               mmap_mappings = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, (GDestroyNotify) addr_clean,
-                       (GDestroyNotify) mapping_clean);
-               if (!mmap_mappings) {
-                       BT_LOGE_STR("Failed to allocate mmap hashtable.");
-                       _set_errno(ENOMEM);
-                       goto error_mutex_unlock;
-               }
-       }
-
-       /* Add the new mapping to the hashtable. */
-       g_hash_table_insert(mmap_mappings, mapping_addr, mapping);
-
-       mmap_unlock();
-
-       return mapping_addr;
-
-error_mutex_unlock:
-       mmap_unlock();
-error:
-       mapping_clean(mapping);
-       return MAP_FAILED;
-}
-
-BT_HIDDEN
-int bt_munmap(void *addr, size_t length)
-{
-       int ret = 0;
-
-       mmap_lock();
-
-       /* Check if the mapping exists in the hashtable. */
-       if (g_hash_table_lookup(mmap_mappings, addr) == NULL) {
-               _set_errno(EINVAL);
-               ret = -1;
-               goto end;
-       }
-
-       /* Remove it. */
-       if (!g_hash_table_remove(mmap_mappings, addr)) {
-               BT_LOGF_STR("Failed to remove mapping from hashtable.");
-               abort();
-       }
-
-end:
-       mmap_unlock();
-       return ret;
-}
-
-#endif
diff --git a/compat/compat_uuid.c b/compat/compat_uuid.c
deleted file mode 100644 (file)
index b367ec1..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * compat/compat_uuid.h
- *
- * Copyright (C) 2013   Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COMPAT-UUID"
-#include "logging.h"
-
-#ifdef __APPLE__
-/*
- * On macOS, we need a dummy symbol so that the linker won't
- * complain of an empty table of contents.
- */
-BT_HIDDEN
-int bt_uuid_dummy_symbol;
-#endif /* __APPLE__ */
-
-#ifdef __MINGW32__
-
-#include <rpc.h>
-#include <stdlib.h>
-#include <babeltrace2/compat/uuid-internal.h>
-
-/* MinGW does not provide byteswap - implement our own version. */
-static
-void swap(unsigned char *ptr, unsigned int i, unsigned int j)
-{
-       unsigned char tmp;
-
-       tmp = ptr[i];
-       ptr[i] = ptr[j];
-       ptr[j] = tmp;
-}
-
-static
-void fix_uuid_endian(unsigned char * ptr)
-{
-       swap(ptr, 0, 3);
-       swap(ptr, 1, 2);
-       swap(ptr, 4, 5);
-       swap(ptr, 6, 7);
-}
-
-int bt_uuid_generate(unsigned char *uuid_out)
-{
-       RPC_STATUS status;
-
-       status = UuidCreate((UUID *) uuid_out);
-       if (status == RPC_S_OK)
-               return 0;
-       else
-               return -1;
-}
-
-int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out)
-{
-       RPC_STATUS status;
-       unsigned char *alloc_str;
-       int ret;
-       unsigned char copy_of_uuid_in[BABELTRACE_UUID_LEN];
-
-       /* make a modifyable copy of uuid_in */
-       memcpy(copy_of_uuid_in, uuid_in, BABELTRACE_UUID_LEN);
-
-       fix_uuid_endian(copy_of_uuid_in);
-       status = UuidToString((UUID *) copy_of_uuid_in, &alloc_str);
-
-       if (status == RPC_S_OK) {
-               strncpy(str_out, (char *) alloc_str, BABELTRACE_UUID_STR_LEN);
-               str_out[BABELTRACE_UUID_STR_LEN - 1] = '\0';
-               ret = 0;
-       } else {
-               ret = -1;
-       }
-       RpcStringFree(&alloc_str);
-       return ret;
-}
-
-int bt_uuid_parse(const char *str_in, unsigned char *uuid_out)
-{
-       RPC_STATUS status;
-
-       status = UuidFromString((unsigned char *) str_in,
-                       (UUID *) uuid_out);
-       fix_uuid_endian(uuid_out);
-
-       if (status == RPC_S_OK)
-               return 0;
-       else
-               return -1;
-}
-
-int bt_uuid_compare(const unsigned char *uuid_a,
-               const unsigned char *uuid_b)
-{
-       RPC_STATUS status;
-
-       return !UuidCompare((UUID *) uuid_a, (UUID *) uuid_b, &status) ? 0 : -1;
-}
-
-#endif
diff --git a/compat/logging.c b/compat/logging.c
deleted file mode 100644 (file)
index 1a35952..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 Michael Jeanson <mjeanson@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_compat_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_compat_log_level, "BABELTRACE_COMPAT_LOG_LEVEL");
diff --git a/compat/logging.h b/compat/logging.h
deleted file mode 100644 (file)
index 6e4b5d2..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef COMPAT_LOGGING_H
-#define COMPAT_LOGGING_H
-
-/*
- * Copyright (c) 2017 Michael Jeanson <mjeanson@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_compat_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_compat_log_level);
-
-#endif /* COMPAT_LOGGING_H */
index b4f1e915a68821b5b1c4e7388bdd946e9d37f958..449df8d2597aa64eb688e3f8c12c791fe2417c42 100644 (file)
@@ -43,7 +43,7 @@ m4_define([bt_lib_version], bt_lib_version_current[:]bt_lib_version_revision[:]b
 
 AC_SUBST([BABELTRACE_LIBRARY_VERSION], bt_lib_version)
 
 
 AC_SUBST([BABELTRACE_LIBRARY_VERSION], bt_lib_version)
 
-AC_CONFIG_HEADERS([include/config.h])
+AC_CONFIG_HEADERS([src/common/config.h])
 AC_CONFIG_AUX_DIR([config])
 AC_CONFIG_MACRO_DIR([m4])
 AC_REQUIRE_AUX_FILE([tap-driver.sh])
 AC_CONFIG_AUX_DIR([config])
 AC_CONFIG_MACRO_DIR([m4])
 AC_REQUIRE_AUX_FILE([tap-driver.sh])
@@ -684,7 +684,7 @@ AM_CFLAGS="-Wall -Wformat -Werror=implicit-function-declaration $PTHREAD_CFLAGS
 AC_SUBST(AM_CFLAGS)
 
 # Set global CPPFLAGS in AM_CPPFLAGS
 AC_SUBST(AM_CFLAGS)
 
 # Set global CPPFLAGS in AM_CPPFLAGS
-AM_CPPFLAGS="-I\$(top_builddir)/include -I\$(top_srcdir)/include -include config.h"
+AM_CPPFLAGS="-I\$(top_srcdir)/include -I\$(top_builddir)/src -I\$(top_srcdir)/src -include common/config.h"
 AC_SUBST(AM_CPPFLAGS)
 
 # Add glib to global link libs
 AC_SUBST(AM_CPPFLAGS)
 
 # Add glib to global link libs
@@ -725,64 +725,65 @@ program_transform_name="s&babeltrace2\.bin&babeltrace2&;s&babeltrace2-log\.bin&b
 AC_SUBST(program_transform_name)
 
 AC_CONFIG_FILES([
 AC_SUBST(program_transform_name)
 
 AC_CONFIG_FILES([
-       Makefile
-       bindings/python/Makefile
-       bindings/python/bt2/Makefile
-       bindings/python/bt2/setup.py
-       bindings/python/bt2/bt2/__init__.py
-       common/Makefile
-       ctfser/Makefile
-       ctf-writer/Makefile
-       compat/Makefile
-       cli/Makefile
-       doc/Makefile
-       doc/api/Makefile
        doc/api/Doxyfile
        doc/api/Doxyfile
+       doc/api/Makefile
        doc/bindings/Makefile
        doc/bindings/python/Makefile
        doc/contributing-images/Makefile
        doc/bindings/Makefile
        doc/bindings/python/Makefile
        doc/contributing-images/Makefile
-  doc/man/Makefile
-  doc/man/asciidoc-attrs.conf
-       fd-cache/Makefile
-       lib/Makefile
-       lib/prio_heap/Makefile
-       lib/plugin/Makefile
-       lib/graph/Makefile
-       lib/graph/message/Makefile
-       lib/trace-ir/Makefile
+       doc/Makefile
+       doc/man/asciidoc-attrs.conf
+       doc/man/Makefile
        include/Makefile
        include/Makefile
-       logging/Makefile
-       bindings/Makefile
-       tests/Makefile
+       Makefile
+       src/babeltrace2-ctf-writer.pc
+       src/babeltrace2.pc
+       src/bindings/Makefile
+       src/bindings/python/bt2/bt2/__init__.py
+       src/bindings/python/bt2/Makefile
+       src/bindings/python/bt2/setup.py
+       src/bindings/python/Makefile
+       src/cli/Makefile
+       src/common/Makefile
+       src/compat/Makefile
+       src/ctfser/Makefile
+       src/ctf-writer/Makefile
+       src/fd-cache/Makefile
+       src/lib/graph/Makefile
+       src/lib/graph/message/Makefile
+       src/lib/Makefile
+       src/lib/plugin/Makefile
+       src/lib/prio-heap/Makefile
+       src/lib/trace-ir/Makefile
+       src/logging/Makefile
+       src/Makefile
+       src/plugins/ctf/common/bfcr/Makefile
+       src/plugins/ctf/common/Makefile
+       src/plugins/ctf/common/metadata/Makefile
+       src/plugins/ctf/common/msg-iter/Makefile
+       src/plugins/ctf/common/utils/Makefile
+       src/plugins/ctf/fs-sink/Makefile
+       src/plugins/ctf/fs-src/Makefile
+       src/plugins/ctf/lttng-live/Makefile
+       src/plugins/ctf/Makefile
+       src/plugins/lttng-utils/debug-info/Makefile
+       src/plugins/lttng-utils/Makefile
+       src/plugins/Makefile
+       src/plugins/text/dmesg/Makefile
+       src/plugins/text/Makefile
+       src/plugins/text/pretty/Makefile
+       src/plugins/utils/counter/Makefile
+       src/plugins/utils/dummy/Makefile
+       src/plugins/utils/Makefile
+       src/plugins/utils/muxer/Makefile
+       src/plugins/utils/trimmer/Makefile
+       src/python-plugin-provider/Makefile
        tests/lib/Makefile
        tests/lib/test-plugin-plugins/Makefile
        tests/lib/Makefile
        tests/lib/test-plugin-plugins/Makefile
+       tests/Makefile
+       tests/plugins/Makefile
        tests/utils/common.sh
        tests/utils/Makefile
        tests/utils/tap/Makefile
        tests/utils/common.sh
        tests/utils/Makefile
        tests/utils/tap/Makefile
-       tests/plugins/Makefile
-       plugins/Makefile
-       plugins/ctf/Makefile
-       plugins/ctf/common/Makefile
-       plugins/ctf/common/bfcr/Makefile
-       plugins/ctf/common/metadata/Makefile
-       plugins/ctf/common/msg-iter/Makefile
-       plugins/ctf/common/utils/Makefile
-       plugins/ctf/fs-src/Makefile
-       plugins/ctf/fs-sink/Makefile
-       plugins/ctf/lttng-live/Makefile
-       plugins/text/Makefile
-       plugins/text/dmesg/Makefile
-       plugins/text/pretty/Makefile
-       plugins/utils/Makefile
-       plugins/utils/dummy/Makefile
-       plugins/utils/counter/Makefile
-       plugins/utils/trimmer/Makefile
-       plugins/utils/muxer/Makefile
-       python-plugin-provider/Makefile
-       plugins/lttng-utils/Makefile
-       plugins/lttng-utils/debug-info/Makefile
-       babeltrace2.pc
-       babeltrace2-ctf-writer.pc
 ])
 
 AC_CONFIG_FILES([tests/cli/test_intersection], [chmod +x tests/cli/test_intersection])
 ])
 
 AC_CONFIG_FILES([tests/cli/test_intersection], [chmod +x tests/cli/test_intersection])
diff --git a/ctf-writer/Makefile.am b/ctf-writer/Makefile.am
deleted file mode 100644 (file)
index 7c5d046..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-lib_LTLIBRARIES = libbabeltrace2-ctf-writer.la
-
-libbabeltrace2_ctf_writer_la_SOURCES = \
-       attributes.c \
-       clock.c \
-       clock-class.c \
-       event.c \
-       event-class.c \
-       field-path.c \
-       fields.c \
-       field-types.c \
-       field-wrapper.c \
-       functor.c \
-       logging.c \
-       logging.h \
-       object.c \
-       object-pool.c \
-       resolve.c \
-       stream.c \
-       stream-class.c \
-       trace.c \
-       utils.c \
-       validation.c \
-       values.c \
-       visitor.c \
-       writer.c
-
-libbabeltrace2_ctf_writer_la_LDFLAGS = $(LT_NO_UNDEFINED) \
-                       -version-info $(BABELTRACE_LIBRARY_VERSION)
-
-libbabeltrace2_ctf_writer_la_LIBADD = \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/ctfser/libbabeltrace2-ctfser.la \
-       $(top_builddir)/compat/libcompat.la \
-       $(UUID_LIBS)
diff --git a/ctf-writer/attributes.c b/ctf-writer/attributes.c
deleted file mode 100644 (file)
index fbb81a0..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * attributes.c
- *
- * Babeltrace CTF writer - Attributes
- *
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-ATTRS"
-#include "logging.h"
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compat/string-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <inttypes.h>
-
-#define BT_CTF_ATTR_NAME_INDEX         0
-#define BT_CTF_ATTR_VALUE_INDEX                1
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_create(void)
-{
-       struct bt_ctf_private_value *attr_obj;
-
-       /*
-        * Attributes: array value object of array value objects, each one
-        * containing two entries: a string value object (attributes
-        * field name), and a value object (attributes field value).
-        *
-        * Example (JSON representation):
-        *
-        *     [
-        *         ["hostname", "eeppdesk"],
-        *         ["sysname", "Linux"],
-        *         ["tracer_major", 2],
-        *         ["tracer_minor", 5]
-        *     ]
-        */
-       BT_LOGD_STR("Creating attributes object.");
-       attr_obj = bt_ctf_private_value_array_create();
-       if (!attr_obj) {
-               BT_LOGE_STR("Failed to create array value.");
-       } else {
-               BT_LOGD("Created attributes object: addr=%p",
-                       attr_obj);
-       }
-
-       return attr_obj;
-}
-
-BT_HIDDEN
-void bt_ctf_attributes_destroy(struct bt_ctf_private_value *attr_obj)
-{
-       BT_LOGD("Destroying attributes object: addr=%p", attr_obj);
-       bt_ctf_object_put_ref(attr_obj);
-}
-
-BT_HIDDEN
-int64_t bt_ctf_attributes_get_count(struct bt_ctf_private_value *attr_obj)
-{
-       return bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
-}
-
-BT_HIDDEN
-const char *bt_ctf_attributes_get_field_name(struct bt_ctf_private_value *attr_obj,
-               uint64_t index)
-{
-       const char *ret = NULL;
-       struct bt_ctf_private_value *attr_field_obj = NULL;
-       struct bt_ctf_private_value *attr_field_name_obj = NULL;
-
-       if (!attr_obj) {
-               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
-               goto end;
-       }
-
-       if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "index=%" PRIu64 ", count=%" PRId64,
-                       index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)));
-               goto end;
-       }
-
-       attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index(
-               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_ctf_private_value_array_borrow_element_by_index(
-                       attr_field_obj, BT_CTF_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_CTF_ATTR_NAME_INDEX);
-               goto end;
-       }
-
-       ret = bt_ctf_value_string_get(
-               bt_ctf_private_value_as_value(attr_field_name_obj));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value(struct bt_ctf_private_value *attr_obj,
-               uint64_t index)
-{
-       struct bt_ctf_private_value *value_obj = NULL;
-       struct bt_ctf_private_value *attr_field_obj = NULL;
-
-       if (!attr_obj) {
-               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
-               goto end;
-       }
-
-       if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "index=%" PRIu64 ", count=%" PRId64,
-                       index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)));
-               goto end;
-       }
-
-       attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index(
-               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_ctf_private_value_array_borrow_element_by_index(attr_field_obj,
-               BT_CTF_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_CTF_ATTR_VALUE_INDEX);
-       }
-
-end:
-       return value_obj;
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_by_name(
-               struct bt_ctf_private_value *attr_obj, const char *name)
-{
-       uint64_t i;
-       int64_t attr_size;
-       struct bt_ctf_private_value *value_obj = NULL;
-       struct bt_ctf_private_value *attr_field_name_obj = NULL;
-
-       attr_size = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(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) {
-               const char *field_name;
-
-               value_obj = bt_ctf_private_value_array_borrow_element_by_index(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_ctf_private_value_array_borrow_element_by_index(value_obj,
-                       BT_CTF_ATTR_NAME_INDEX);
-               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) BT_CTF_ATTR_NAME_INDEX);
-                       goto error;
-               }
-
-               field_name = bt_ctf_value_string_get(
-                       bt_ctf_private_value_as_value(attr_field_name_obj));
-
-               if (!strcmp(field_name, name)) {
-                       break;
-               }
-
-               value_obj = NULL;
-       }
-
-       return value_obj;
-
-error:
-       value_obj = NULL;
-       return value_obj;
-}
-
-BT_HIDDEN
-int bt_ctf_attributes_set_field_value(struct bt_ctf_private_value *attr_obj,
-               const char *name, struct bt_ctf_private_value *value_obj)
-{
-       int ret = 0;
-       struct bt_ctf_private_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_ctf_attributes_borrow_field_by_name(attr_obj, name);
-       if (attr_field_obj) {
-               ret = bt_ctf_private_value_array_set_element_by_index(
-                       attr_field_obj, BT_CTF_ATTR_VALUE_INDEX,
-                       bt_ctf_private_value_as_value(value_obj));
-               attr_field_obj = NULL;
-               goto end;
-       }
-
-       attr_field_obj = bt_ctf_private_value_array_create();
-       if (!attr_field_obj) {
-               BT_LOGE_STR("Failed to create empty array value.");
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_private_value_array_append_string_element(attr_field_obj, name);
-       ret |= bt_ctf_private_value_array_append_element(attr_field_obj,
-               bt_ctf_private_value_as_value(value_obj));
-       if (ret) {
-               BT_LOGE("Cannot append elements to array value: addr=%p",
-                       attr_field_obj);
-               goto end;
-       }
-
-       ret = bt_ctf_private_value_array_append_element(attr_obj,
-               bt_ctf_private_value_as_value(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_ctf_object_put_ref(attr_field_obj);
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value_by_name(
-               struct bt_ctf_private_value *attr_obj, const char *name)
-{
-       struct bt_ctf_private_value *value_obj = NULL;
-       struct bt_ctf_private_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_ctf_attributes_borrow_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_ctf_private_value_array_borrow_element_by_index(attr_field_obj,
-               BT_CTF_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_CTF_ATTR_VALUE_INDEX);
-       }
-
-end:
-       return value_obj;
-}
-
-BT_HIDDEN
-int bt_ctf_attributes_freeze(struct bt_ctf_private_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_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
-       BT_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_ctf_private_value *obj = NULL;
-
-               obj = bt_ctf_attributes_borrow_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_ctf_value_freeze(bt_ctf_private_value_as_value(obj));
-       }
-
-end:
-       return ret;
-}
diff --git a/ctf-writer/clock-class.c b/ctf-writer/clock-class.c
deleted file mode 100644 (file)
index 1c507e3..0000000
+++ /dev/null
@@ -1,704 +0,0 @@
-/*
- * clock-class.c
- *
- * Babeltrace CTF writer - Clock class
- *
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-CLOCK-CLASS"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/compat/string-internal.h>
-#include <inttypes.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-static
-void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class)
-{
-       return clock_class && clock_class->name;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class,
-               const char *name)
-{
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_identifier_is_valid(name)) {
-               BT_LOGW("Clock class's name is not a valid CTF identifier: "
-                       "addr=%p, name=\"%s\"",
-                       clock_class, name);
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->name) {
-               g_string_assign(clock_class->name, name);
-       } else {
-               clock_class->name = g_string_new(name);
-               if (!clock_class->name) {
-                       BT_LOGE_STR("Failed to allocate a GString.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       BT_LOGV("Set clock class's name: addr=%p, name=\"%s\"",
-               clock_class, name);
-
-end:
-       return ret;
-}
-
-static
-bool validate_freq(struct bt_ctf_clock_class *clock_class,
-               const char *name, uint64_t freq)
-{
-       bool is_valid = true;
-
-       if (freq == -1ULL || freq == 0) {
-               BT_LOGW("Invalid parameter: frequency is invalid: "
-                       "addr=%p, name=\"%s\", freq=%" PRIu64,
-                       clock_class, name, freq);
-               is_valid = false;
-               goto end;
-       }
-
-end:
-       return is_valid;
-}
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name,
-               uint64_t freq)
-{
-       int ret;
-       struct bt_ctf_clock_class *clock_class = NULL;
-
-       BT_LOGD("Creating default clock class object: name=\"%s\"",
-               name);
-
-       if (!validate_freq(NULL, name, freq)) {
-               /* validate_freq() logs errors */
-               goto error;
-       }
-
-       clock_class = g_new0(struct bt_ctf_clock_class, 1);
-       if (!clock_class) {
-               BT_LOGE_STR("Failed to allocate one clock class.");
-               goto error;
-       }
-
-       clock_class->precision = 1;
-       clock_class->frequency = freq;
-       bt_ctf_object_init_shared(&clock_class->base, bt_ctf_clock_class_destroy);
-
-       if (name) {
-               ret = bt_ctf_clock_class_set_name(clock_class, name);
-               if (ret) {
-                       /* bt_ctf_clock_class_set_name() logs errors */
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Created clock class object: addr=%p, name=\"%s\"",
-               clock_class, name);
-       return clock_class;
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(clock_class);
-       return clock_class;
-}
-
-BT_HIDDEN
-const char *bt_ctf_clock_class_get_name(struct bt_ctf_clock_class *clock_class)
-{
-       const char *ret = NULL;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       if (clock_class->name) {
-               ret = clock_class->name->str;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-const char *bt_ctf_clock_class_get_description(
-               struct bt_ctf_clock_class *clock_class)
-{
-       const char *ret = NULL;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       if (clock_class->description) {
-               ret = clock_class->description->str;
-       }
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class,
-               const char *desc)
-{
-       int ret = 0;
-
-       if (!clock_class || !desc) {
-               BT_LOGW("Invalid parameter: clock class or description is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", desc-addr=%p",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class),
-                       desc);
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->description = g_string_new(desc);
-       ret = clock_class->description ? 0 : -1;
-       BT_LOGV("Set clock class's description: addr=%p, "
-               "name=\"%s\", desc=\"%s\"",
-               clock_class, bt_ctf_clock_class_get_name(clock_class), desc);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-uint64_t bt_ctf_clock_class_get_frequency(
-               struct bt_ctf_clock_class *clock_class)
-{
-       uint64_t ret = -1ULL;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       ret = clock_class->frequency;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class,
-               uint64_t freq)
-{
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW("Invalid parameter: clock class is NULL or frequency is invalid: "
-                       "addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!validate_freq(clock_class, bt_ctf_clock_class_get_name(clock_class),
-                       freq)) {
-               /* validate_freq() logs errors */
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->frequency = freq;
-       BT_LOGV("Set clock class's frequency: addr=%p, name=\"%s\", freq=%" PRIu64,
-               clock_class, bt_ctf_clock_class_get_name(clock_class), freq);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-uint64_t bt_ctf_clock_class_get_precision(struct bt_ctf_clock_class *clock_class)
-{
-       uint64_t ret = -1ULL;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       ret = clock_class->precision;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_precision(struct bt_ctf_clock_class *clock_class,
-               uint64_t precision)
-{
-       int ret = 0;
-
-       if (!clock_class || precision == -1ULL) {
-               BT_LOGW("Invalid parameter: clock class is NULL or precision is invalid: "
-                       "addr=%p, name=\"%s\", precision=%" PRIu64,
-                       clock_class, bt_ctf_clock_class_get_name(clock_class),
-                       precision);
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->precision = precision;
-       BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64,
-               clock_class, bt_ctf_clock_class_get_name(clock_class),
-               precision);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class,
-               int64_t *offset_s)
-{
-       int ret = 0;
-
-       if (!clock_class || !offset_s) {
-               BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", offset-addr=%p",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class),
-                       offset_s);
-               ret = -1;
-               goto end;
-       }
-
-       *offset_s = clock_class->offset_s;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_offset_s(struct bt_ctf_clock_class *clock_class,
-               int64_t offset_s)
-{
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->offset_s = offset_s;
-       BT_LOGV("Set clock class's offset (seconds): "
-               "addr=%p, name=\"%s\", offset-s=%" PRId64,
-               clock_class, bt_ctf_clock_class_get_name(clock_class),
-               offset_s);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_clock_class *clock_class,
-               int64_t *offset)
-{
-       int ret = 0;
-
-       if (!clock_class || !offset) {
-               BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", offset-addr=%p",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class),
-                       offset);
-               ret = -1;
-               goto end;
-       }
-
-       *offset = clock_class->offset;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class,
-               int64_t offset)
-{
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->offset = offset;
-       BT_LOGV("Set clock class's offset (cycles): addr=%p, name=\"%s\", offset-cycles=%" PRId64,
-               clock_class, bt_ctf_clock_class_get_name(clock_class), offset);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_clock_class_is_absolute(struct bt_ctf_clock_class *clock_class)
-{
-       int ret = -1;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               goto end;
-       }
-
-       ret = clock_class->absolute;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_clock_class *clock_class,
-               bt_bool is_absolute)
-{
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       clock_class->absolute = !!is_absolute;
-       BT_LOGV("Set clock class's absolute flag: addr=%p, name=\"%s\", is-absolute=%d",
-               clock_class, bt_ctf_clock_class_get_name(clock_class),
-               is_absolute);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-const unsigned char *bt_ctf_clock_class_get_uuid(
-               struct bt_ctf_clock_class *clock_class)
-{
-       const unsigned char *ret;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = NULL;
-               goto end;
-       }
-
-       if (!clock_class->uuid_set) {
-               BT_LOGV("Clock class's UUID is not set: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = NULL;
-               goto end;
-       }
-
-       ret = clock_class->uuid;
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class,
-               const unsigned char *uuid)
-{
-       int ret = 0;
-
-       if (!clock_class || !uuid) {
-               BT_LOGW("Invalid parameter: clock class or UUID is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", uuid-addr=%p",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class),
-                       uuid);
-               ret = -1;
-               goto end;
-       }
-
-       if (clock_class->frozen) {
-               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       memcpy(clock_class->uuid, uuid, BABELTRACE_UUID_LEN);
-       clock_class->uuid_set = 1;
-       BT_LOGV("Set clock class's UUID: addr=%p, name=\"%s\", "
-               "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-               clock_class, bt_ctf_clock_class_get_name(clock_class),
-               (unsigned int) uuid[0],
-               (unsigned int) uuid[1],
-               (unsigned int) uuid[2],
-               (unsigned int) uuid[3],
-               (unsigned int) uuid[4],
-               (unsigned int) uuid[5],
-               (unsigned int) uuid[6],
-               (unsigned int) uuid[7],
-               (unsigned int) uuid[8],
-               (unsigned int) uuid[9],
-               (unsigned int) uuid[10],
-               (unsigned int) uuid[11],
-               (unsigned int) uuid[12],
-               (unsigned int) uuid[13],
-               (unsigned int) uuid[14],
-               (unsigned int) uuid[15]);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class)
-{
-       if (!clock_class || clock_class->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"",
-               clock_class, bt_ctf_clock_class_get_name(clock_class));
-       clock_class->frozen = 1;
-}
-
-static
-void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_clock_class *clock_class;
-
-       clock_class = container_of(obj, struct bt_ctf_clock_class, base);
-       BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"",
-               obj, bt_ctf_clock_class_get_name(clock_class));
-
-       if (clock_class->name) {
-               g_string_free(clock_class->name, TRUE);
-       }
-
-       if (clock_class->description) {
-               g_string_free(clock_class->description, TRUE);
-       }
-
-       g_free(clock_class);
-}
-
-BT_HIDDEN
-int bt_ctf_clock_class_compare(struct bt_ctf_clock_class *clock_class_a,
-               struct bt_ctf_clock_class *clock_class_b)
-{
-       int ret = 1;
-       BT_ASSERT(clock_class_a);
-       BT_ASSERT(clock_class_b);
-
-       /* Name */
-       if (strcmp(clock_class_a->name->str, clock_class_b->name->str) != 0) {
-               BT_LOGV("Clock classes differ: different names: "
-                       "cc-a-name=\"%s\", cc-b-name=\"%s\"",
-                       clock_class_a->name->str,
-                       clock_class_b->name->str);
-               goto end;
-       }
-
-       /* Description */
-       if (clock_class_a->description) {
-               if (!clock_class_b->description) {
-                       BT_LOGV_STR("Clock classes differ: clock class A has a "
-                               "description, but clock class B does not.");
-                       goto end;
-               }
-
-               if (strcmp(clock_class_a->name->str, clock_class_b->name->str)
-                               != 0) {
-                       BT_LOGV("Clock classes differ: different descriptions: "
-                               "cc-a-descr=\"%s\", cc-b-descr=\"%s\"",
-                               clock_class_a->description->str,
-                               clock_class_b->description->str);
-                       goto end;
-               }
-       } else {
-               if (clock_class_b->description) {
-                       BT_LOGV_STR("Clock classes differ: clock class A has "
-                               "no description, but clock class B has one.");
-                       goto end;
-               }
-       }
-
-       /* Frequency */
-       if (clock_class_a->frequency != clock_class_b->frequency) {
-               BT_LOGV("Clock classes differ: different frequencies: "
-                       "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64,
-                       clock_class_a->frequency,
-                       clock_class_b->frequency);
-               goto end;
-       }
-
-       /* Precision */
-       if (clock_class_a->precision != clock_class_b->precision) {
-               BT_LOGV("Clock classes differ: different precisions: "
-                       "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64,
-                       clock_class_a->precision,
-                       clock_class_b->precision);
-               goto end;
-       }
-
-       /* Offset (seconds) */
-       if (clock_class_a->offset_s != clock_class_b->offset_s) {
-               BT_LOGV("Clock classes differ: different offsets (seconds): "
-                       "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64,
-                       clock_class_a->offset_s,
-                       clock_class_b->offset_s);
-               goto end;
-       }
-
-       /* Offset (cycles) */
-       if (clock_class_a->offset != clock_class_b->offset) {
-               BT_LOGV("Clock classes differ: different offsets (cycles): "
-                       "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64,
-                       clock_class_a->offset,
-                       clock_class_b->offset);
-               goto end;
-       }
-
-       /* UUIDs */
-       if (clock_class_a->uuid_set) {
-               if (!clock_class_b->uuid_set) {
-                       BT_LOGV_STR("Clock classes differ: clock class A has a "
-                               "UUID, but clock class B does not.");
-                       goto end;
-               }
-
-               if (memcmp(clock_class_a->uuid, clock_class_b->uuid,
-                               BABELTRACE_UUID_LEN) != 0) {
-                       BT_LOGV("Clock classes differ: different UUIDs: "
-                               "cc-a-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", "
-                               "cc-b-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-                               (unsigned int) clock_class_a->uuid[0],
-                               (unsigned int) clock_class_a->uuid[1],
-                               (unsigned int) clock_class_a->uuid[2],
-                               (unsigned int) clock_class_a->uuid[3],
-                               (unsigned int) clock_class_a->uuid[4],
-                               (unsigned int) clock_class_a->uuid[5],
-                               (unsigned int) clock_class_a->uuid[6],
-                               (unsigned int) clock_class_a->uuid[7],
-                               (unsigned int) clock_class_a->uuid[8],
-                               (unsigned int) clock_class_a->uuid[9],
-                               (unsigned int) clock_class_a->uuid[10],
-                               (unsigned int) clock_class_a->uuid[11],
-                               (unsigned int) clock_class_a->uuid[12],
-                               (unsigned int) clock_class_a->uuid[13],
-                               (unsigned int) clock_class_a->uuid[14],
-                               (unsigned int) clock_class_a->uuid[15],
-                               (unsigned int) clock_class_b->uuid[0],
-                               (unsigned int) clock_class_b->uuid[1],
-                               (unsigned int) clock_class_b->uuid[2],
-                               (unsigned int) clock_class_b->uuid[3],
-                               (unsigned int) clock_class_b->uuid[4],
-                               (unsigned int) clock_class_b->uuid[5],
-                               (unsigned int) clock_class_b->uuid[6],
-                               (unsigned int) clock_class_b->uuid[7],
-                               (unsigned int) clock_class_b->uuid[8],
-                               (unsigned int) clock_class_b->uuid[9],
-                               (unsigned int) clock_class_b->uuid[10],
-                               (unsigned int) clock_class_b->uuid[11],
-                               (unsigned int) clock_class_b->uuid[12],
-                               (unsigned int) clock_class_b->uuid[13],
-                               (unsigned int) clock_class_b->uuid[14],
-                               (unsigned int) clock_class_b->uuid[15]);
-                       goto end;
-               }
-       } else {
-               if (clock_class_b->uuid_set) {
-                       BT_LOGV_STR("Clock classes differ: clock class A has "
-                               "no UUID, but clock class B has one.");
-                       goto end;
-               }
-       }
-
-       /* Absolute */
-       if (!!clock_class_a->absolute != !!clock_class_b->absolute) {
-               BT_LOGV("Clock classes differ: one is absolute, the other "
-                       "is not: cc-a-is-absolute=%d, cc-b-is-absolute=%d",
-                       !!clock_class_a->absolute,
-                       !!clock_class_b->absolute);
-               goto end;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
diff --git a/ctf-writer/clock.c b/ctf-writer/clock.c
deleted file mode 100644 (file)
index 0238c25..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * clock.c
- *
- * Babeltrace CTF writer - Clock
- *
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-CLOCK"
-#include "logging.h"
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <inttypes.h>
-
-static
-void bt_ctf_clock_destroy(struct bt_ctf_object *obj);
-
-struct bt_ctf_clock *bt_ctf_clock_create(const char *name)
-{
-       int ret;
-       struct bt_ctf_clock *clock = NULL;
-       unsigned char cc_uuid[BABELTRACE_UUID_LEN];
-
-       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
-       clock = g_new0(struct bt_ctf_clock, 1);
-       if (!clock) {
-               goto error;
-       }
-
-       bt_ctf_object_init_shared(&clock->base, bt_ctf_clock_destroy);
-       clock->value = 0;
-
-       /* Pre-2.0.0 backward compatibility: default frequency is 1 GHz */
-       clock->clock_class = (void *) bt_ctf_clock_class_create(name, 1000000000);
-       if (!clock->clock_class) {
-               goto error;
-       }
-
-       /* Automatically set clock class's UUID. */
-       ret = bt_uuid_generate(cc_uuid);
-       if (ret) {
-               goto error;
-       }
-
-       ret = bt_ctf_clock_class_set_uuid(clock->clock_class, cc_uuid);
-       BT_ASSERT(ret == 0);
-       return clock;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(clock);
-       return clock;
-}
-
-const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_name(clock->clock_class);
-}
-
-const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_description(clock->clock_class);
-}
-
-int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, const char *desc)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_description(clock->clock_class,
-               desc);
-}
-
-uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_frequency(clock->clock_class);
-}
-
-int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, uint64_t freq)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_frequency(clock->clock_class,
-               freq);
-}
-
-uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_precision(clock->clock_class);
-}
-
-int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, uint64_t precision)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_precision(clock->clock_class,
-               precision);
-}
-
-int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock, int64_t *offset_s)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_offset_s(clock->clock_class,
-               offset_s);
-}
-
-int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, int64_t offset_s)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_offset_s(clock->clock_class,
-               offset_s);
-}
-
-int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock, int64_t *offset)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_offset_cycles(clock->clock_class,
-               offset);
-}
-
-int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, int64_t offset)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_offset_cycles(clock->clock_class,
-               offset);
-}
-
-int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_is_absolute(clock->clock_class);
-}
-
-int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, int is_absolute)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_is_absolute(clock->clock_class,
-               is_absolute);
-}
-
-const unsigned char *bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_get_uuid(clock->clock_class);
-}
-
-int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock, const unsigned char *uuid)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       return bt_ctf_clock_class_set_uuid(clock->clock_class, uuid);
-}
-
-int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, int64_t time)
-{
-       int64_t value;
-       struct bt_ctf_clock_class *cc;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       cc = clock->clock_class;
-
-       /* Common case where cycles are actually nanoseconds */
-       if (cc->frequency == 1000000000) {
-               value = time;
-       } else {
-               value = (uint64_t) (((double) time *
-                       (double) cc->frequency) / 1e9);
-       }
-
-       BT_CTF_ASSERT_PRE(clock->value <= value,
-               "CTF writer clock value must be updated monotonically: "
-               "prev-value=%" PRId64 ", new-value=%" PRId64,
-               clock->value, value);
-       clock->value = value;
-       return 0;
-}
-
-BT_HIDDEN
-int bt_ctf_clock_get_value(struct bt_ctf_clock *clock, uint64_t *value)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
-       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
-       *value = clock->value;
-       return 0;
-}
-
-static
-void bt_ctf_clock_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_clock *clock;
-
-       clock = container_of(obj, struct bt_ctf_clock, base);
-       bt_ctf_object_put_ref(clock->clock_class);
-       g_free(clock);
-}
-
-BT_HIDDEN
-void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class,
-               struct metadata_context *context)
-{
-       unsigned char *uuid;
-
-       BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, "
-               "name=\"%s\", metadata-context-addr=%p", clock_class,
-               bt_ctf_clock_class_get_name(clock_class),
-               context);
-
-       if (!clock_class || !context) {
-               BT_LOGW("Invalid parameter: clock class or metadata context is NULL: "
-                       "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p",
-                       clock_class,
-                       bt_ctf_clock_class_get_name(clock_class),
-                       context);
-               return;
-       }
-
-       uuid = clock_class->uuid;
-       g_string_append(context->string, "clock {\n");
-       g_string_append_printf(context->string, "\tname = %s;\n",
-               clock_class->name->str);
-
-       if (clock_class->uuid_set) {
-               g_string_append_printf(context->string,
-                       "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
-                       uuid[0], uuid[1], uuid[2], uuid[3],
-                       uuid[4], uuid[5], uuid[6], uuid[7],
-                       uuid[8], uuid[9], uuid[10], uuid[11],
-                       uuid[12], uuid[13], uuid[14], uuid[15]);
-       }
-
-       if (clock_class->description) {
-               g_string_append_printf(context->string, "\tdescription = \"%s\";\n",
-                       clock_class->description->str);
-       }
-
-       g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n",
-               clock_class->frequency);
-       g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n",
-               clock_class->precision);
-       g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n",
-               clock_class->offset_s);
-       g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n",
-               clock_class->offset);
-       g_string_append_printf(context->string, "\tabsolute = %s;\n",
-               clock_class->absolute ? "true" : "false");
-       g_string_append(context->string, "};\n\n");
-}
diff --git a/ctf-writer/event-class.c b/ctf-writer/event-class.c
deleted file mode 100644 (file)
index 3d8c1f5..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-EVENT-CLASS"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/attributes-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-BT_HIDDEN
-void bt_ctf_event_class_common_finalize(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_event_class_common *event_class;
-
-       event_class = container_of(obj, struct bt_ctf_event_class_common, base);
-       BT_LOGD("Finalizing common event class: addr=%p, name=\"%s\", id=%" PRId64,
-               event_class, bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-
-       if (event_class->name) {
-               g_string_free(event_class->name, TRUE);
-       }
-
-       if (event_class->emf_uri) {
-               g_string_free(event_class->emf_uri, TRUE);
-       }
-
-       BT_LOGD_STR("Putting context field type.");
-       bt_ctf_object_put_ref(event_class->context_field_type);
-       BT_LOGD_STR("Putting payload field type.");
-       bt_ctf_object_put_ref(event_class->payload_field_type);
-}
-
-BT_HIDDEN
-int bt_ctf_event_class_common_initialize(struct bt_ctf_event_class_common *event_class,
-               const char *name, bt_ctf_object_release_func release_func,
-               bt_ctf_field_type_structure_create_func ft_struct_create_func)
-{
-       int ret = 0;
-
-       BT_LOGD("Initializing common event class object: name=\"%s\"",
-               name);
-       bt_ctf_object_init_shared_with_parent(&event_class->base, release_func);
-       event_class->payload_field_type = ft_struct_create_func();
-       if (!event_class->payload_field_type) {
-               BT_LOGE_STR("Cannot create event class's initial payload field type object.");
-               goto error;
-       }
-
-       event_class->id = -1;
-       event_class->name = g_string_new(name);
-       if (!event_class->name) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       event_class->emf_uri = g_string_new(NULL);
-       if (!event_class->emf_uri) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       event_class->log_level = BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED;
-       BT_LOGD("Initialized common event class object: addr=%p, name=\"%s\"",
-               event_class, bt_ctf_event_class_common_get_name(event_class));
-       return ret;
-
-error:
-       ret = -1;
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_event_class_common_freeze(struct bt_ctf_event_class_common *event_class)
-{
-       BT_ASSERT(event_class);
-
-       if (event_class->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing event class: addr=%p, name=\"%s\", id=%" PRId64,
-               event_class, bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-       event_class->frozen = 1;
-       BT_LOGD_STR("Freezing event class's context field type.");
-       bt_ctf_field_type_common_freeze(event_class->context_field_type);
-       BT_LOGD_STR("Freezing event class's payload field type.");
-       bt_ctf_field_type_common_freeze(event_class->payload_field_type);
-}
-
-BT_HIDDEN
-int bt_ctf_event_class_common_validate_single_clock_class(
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_clock_class **expected_clock_class)
-{
-       int ret = 0;
-
-       BT_ASSERT(event_class);
-       BT_ASSERT(expected_clock_class);
-       ret = bt_ctf_field_type_common_validate_single_clock_class(
-               event_class->context_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Event class's context field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       event_class,
-                       bt_ctf_event_class_common_get_name(event_class),
-                       event_class->id,
-                       event_class->context_field_type);
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_validate_single_clock_class(
-               event_class->payload_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Event class's payload field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       event_class,
-                       bt_ctf_event_class_common_get_name(event_class),
-                       event_class->id,
-                       event_class->payload_field_type);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-void bt_ctf_event_class_destroy(struct bt_ctf_object *obj)
-{
-       bt_ctf_event_class_common_finalize(obj);
-       g_free(obj);
-}
-
-struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name)
-{
-       struct bt_ctf_event_class *ctf_event_class = NULL;
-       int ret;
-
-       if (!name) {
-               BT_LOGW_STR("Invalid parameter: name is NULL.");
-               goto error;
-       }
-
-       BT_LOGD("Creating event class object: name=\"%s\"",
-               name);
-       ctf_event_class = g_new0(struct bt_ctf_event_class, 1);
-       if (!ctf_event_class) {
-               BT_LOGE_STR("Failed to allocate one event class.");
-               goto error;
-       }
-
-       ret = bt_ctf_event_class_common_initialize(BT_CTF_TO_COMMON(ctf_event_class),
-               name, bt_ctf_event_class_destroy,
-               (bt_ctf_field_type_structure_create_func)
-                       bt_ctf_field_type_structure_create);
-       if (ret) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       bt_ctf_object_put_ref(ctf_event_class);
-
-end:
-       return ctf_event_class;
-}
-
-const char *bt_ctf_event_class_get_name(struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_event_class_common_get_name(BT_CTF_TO_COMMON(event_class));
-}
-
-int64_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_event_class_common_get_id(BT_CTF_TO_COMMON(event_class));
-}
-
-int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class,
-               uint64_t id)
-{
-       return bt_ctf_event_class_common_set_id(BT_CTF_TO_COMMON(event_class), id);
-}
-
-enum bt_ctf_event_class_log_level bt_ctf_event_class_get_log_level(
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_event_class_common_get_log_level(BT_CTF_TO_COMMON(event_class));
-}
-
-int bt_ctf_event_class_set_log_level(struct bt_ctf_event_class *event_class,
-               enum bt_ctf_event_class_log_level log_level)
-{
-       return bt_ctf_event_class_common_set_log_level(BT_CTF_TO_COMMON(event_class),
-               log_level);
-}
-
-const char *bt_ctf_event_class_get_emf_uri(
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_event_class_common_get_emf_uri(BT_CTF_TO_COMMON(event_class));
-}
-
-int bt_ctf_event_class_set_emf_uri(struct bt_ctf_event_class *event_class,
-               const char *emf_uri)
-{
-       return bt_ctf_event_class_common_set_emf_uri(BT_CTF_TO_COMMON(event_class),
-               emf_uri);
-}
-
-struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class(
-               struct bt_ctf_event_class *event_class)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_stream_class(
-               BT_CTF_TO_COMMON(event_class)));
-}
-
-struct bt_ctf_field_type *bt_ctf_event_class_get_payload_field_type(
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_payload_field_type(
-               BT_CTF_TO_COMMON(event_class)));
-}
-
-int bt_ctf_event_class_set_payload_field_type(
-               struct bt_ctf_event_class *event_class,
-               struct bt_ctf_field_type *field_type)
-{
-       return bt_ctf_event_class_common_set_payload_field_type(
-               BT_CTF_TO_COMMON(event_class), (void *) field_type);
-}
-
-struct bt_ctf_field_type *bt_ctf_event_class_get_context_field_type(
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_context_field_type(
-               BT_CTF_TO_COMMON(event_class)));
-}
-
-int bt_ctf_event_class_set_context_field_type(
-               struct bt_ctf_event_class *event_class,
-               struct bt_ctf_field_type *field_type)
-{
-       return bt_ctf_event_class_common_set_context_field_type(
-               BT_CTF_TO_COMMON(event_class), (void *) field_type);
-}
-
-int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class,
-               struct bt_ctf_field_type *type,
-               const char *name)
-{
-       int ret = 0;
-
-       if (!event_class || !type) {
-               BT_LOGW("Invalid parameter: event class or field type is NULL: "
-                       "event-class-addr=%p, field-type-addr=%p",
-                       event_class, type);
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_identifier_is_valid(name)) {
-               BT_LOGW("Invalid parameter: event class's payload field type's field name is not a valid CTF identifier: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", field-name=\"%s\"",
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class),
-                       name);
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->common.frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!event_class->common.payload_field_type) {
-               BT_LOGW("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));
-               ret = -1;
-               goto end;
-       }
-
-       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
-               event_class->common.payload_field_type) ==
-               BT_CTF_FIELD_TYPE_ID_STRUCT);
-       ret = bt_ctf_field_type_structure_add_field(
-               (void *) event_class->common.payload_field_type,
-               (void *) type, name);
-       BT_LOGV("Added field to event class's payload field type: "
-               "event-class-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", field-name=\"%s\", ft-addr=%p",
-               event_class, bt_ctf_event_class_get_name(event_class),
-               bt_ctf_event_class_get_id(event_class), name, type);
-end:
-       return ret;
-}
-
-int64_t bt_ctf_event_class_get_payload_type_field_count(
-               struct bt_ctf_event_class *event_class)
-{
-       int64_t ret;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = (int64_t) -1;
-               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));
-               ret = (int64_t) -1;
-               goto end;
-       }
-
-       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
-               event_class->common.payload_field_type) ==
-                       BT_CTF_FIELD_TYPE_ID_STRUCT);
-       ret = bt_ctf_field_type_common_structure_get_field_count(
-               event_class->common.payload_field_type);
-end:
-       return ret;
-}
-
-int bt_ctf_event_class_get_payload_type_field_by_index(
-               struct bt_ctf_event_class *event_class,
-               const char **field_name, struct bt_ctf_field_type **field_type,
-               uint64_t index)
-{
-       int ret;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!event_class->common.payload_field_type) {
-               BT_LOGV("Event class has no payload field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", index=%" PRIu64,
-                       event_class, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class), index);
-               ret = -1;
-               goto end;
-       }
-
-       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
-               event_class->common.payload_field_type) ==
-                       BT_CTF_FIELD_TYPE_ID_STRUCT);
-       ret = bt_ctf_field_type_structure_get_field_by_index(
-               (void *) event_class->common.payload_field_type,
-               field_name, (void *) field_type, index);
-
-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_ctf_event_class_serialize(struct bt_ctf_event_class *event_class,
-               struct metadata_context *context)
-{
-       int ret = 0;
-       struct bt_ctf_value *attr_value = NULL;
-
-       BT_ASSERT(event_class);
-       BT_ASSERT(context);
-       BT_LOGD("Serializing event class's metadata: "
-               "event-class-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", metadata-context-addr=%p",
-               event_class, bt_ctf_event_class_get_name(event_class),
-               bt_ctf_event_class_get_id(event_class), context);
-       context->current_indentation_level = 1;
-       g_string_assign(context->field_name, "");
-       g_string_append(context->string, "event {\n");
-
-       /* Serialize attributes */
-       g_string_append_printf(context->string, "\tname = \"%s\";\n",
-               event_class->common.name->str);
-       BT_ASSERT(event_class->common.id >= 0);
-       g_string_append_printf(context->string, "\tid = %" PRId64 ";\n",
-               event_class->common.id);
-       g_string_append_printf(context->string, "\tstream_id = %" PRId64 ";\n",
-               bt_ctf_stream_class_common_get_id(
-                       bt_ctf_event_class_common_borrow_stream_class(
-                               BT_CTF_TO_COMMON(event_class))));
-
-       if (event_class->common.log_level !=
-                       BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED) {
-               g_string_append_printf(context->string, "\tloglevel = %d;\n",
-                       (int) event_class->common.log_level);
-       }
-
-       if (event_class->common.emf_uri->len > 0) {
-               g_string_append_printf(context->string, "\tmodel.emf.uri = \"%s\";\n",
-                       event_class->common.emf_uri->str);
-       }
-
-       /* Serialize context field type */
-       if (event_class->common.context_field_type) {
-               g_string_append(context->string, "\tcontext := ");
-               BT_LOGD_STR("Serializing event class's context field type metadata.");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) event_class->common.context_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event class's context field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";\n");
-       }
-
-       /* Serialize payload field type */
-       if (event_class->common.payload_field_type) {
-               g_string_append(context->string, "\tfields := ");
-               BT_LOGD_STR("Serializing event class's payload field type metadata.");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) event_class->common.payload_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event class's payload field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";\n");
-       }
-
-       g_string_append(context->string, "};\n\n");
-
-end:
-       context->current_indentation_level = 0;
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(attr_value);
-       return ret;
-}
-
-struct bt_ctf_field_type *bt_ctf_event_class_get_field_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(event_class->common.payload_field_type->id ==
-               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 = bt_ctf_object_get_ref(
-               bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-                       event_class->common.payload_field_type, name));
-
-end:
-       return field_type;
-}
diff --git a/ctf-writer/event.c b/ctf-writer/event.c
deleted file mode 100644 (file)
index b074cdb..0000000
+++ /dev/null
@@ -1,900 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-EVENT"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/attributes-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <inttypes.h>
-
-static
-int bt_ctf_event_common_validate_types_for_create(
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_validation_output *validation_output,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
-{
-       int ret;
-       enum bt_ctf_validation_flag validation_flags =
-               BT_CTF_VALIDATION_FLAG_STREAM |
-               BT_CTF_VALIDATION_FLAG_EVENT;
-       struct bt_ctf_trace_common *trace = NULL;
-       struct bt_ctf_stream_class_common *stream_class = NULL;
-       struct bt_ctf_field_type_common *packet_header_type = NULL;
-       struct bt_ctf_field_type_common *packet_context_type = NULL;
-       struct bt_ctf_field_type_common *event_header_type = NULL;
-       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
-       struct bt_ctf_field_type_common *event_context_type = NULL;
-       struct bt_ctf_field_type_common *event_payload_type = NULL;
-       int trace_valid = 0;
-       struct bt_ctf_private_value *environment = NULL;
-
-       stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
-       BT_ASSERT(stream_class);
-       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
-       if (trace) {
-               BT_LOGD_STR("Event class is part of a trace.");
-               packet_header_type =
-                       bt_ctf_trace_common_borrow_packet_header_field_type(trace);
-               trace_valid = trace->valid;
-               BT_ASSERT(trace_valid);
-               environment = trace->environment;
-       }
-
-       packet_context_type =
-               bt_ctf_stream_class_common_borrow_packet_context_field_type(
-                       stream_class);
-       event_header_type =
-               bt_ctf_stream_class_common_borrow_event_header_field_type(
-                       stream_class);
-       stream_event_ctx_type =
-               bt_ctf_stream_class_common_borrow_event_context_field_type(
-                       stream_class);
-       event_context_type =
-               bt_ctf_event_class_common_borrow_context_field_type(event_class);
-       event_payload_type =
-               bt_ctf_event_class_common_borrow_payload_field_type(event_class);
-       ret = bt_ctf_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, copy_field_type_func);
-       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;
-       }
-
-       goto end;
-
-error:
-       bt_ctf_validation_output_put_types(validation_output);
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_event_common_create_fields(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_validation_output *validation_output,
-               create_field_func create_field_func,
-               release_field_func release_field_func,
-               create_header_field_func create_header_field_func,
-               release_header_field_func release_header_field_func,
-               struct bt_ctf_field_wrapper **header_field,
-               struct bt_ctf_field_common **stream_event_context_field,
-               struct bt_ctf_field_common **context_field,
-               struct bt_ctf_field_common **payload_field)
-{
-       int ret = 0;
-
-       if (validation_output->event_header_type) {
-               BT_LOGD("Creating initial event header field: ft-addr=%p",
-                       validation_output->event_header_type);
-               *header_field =
-                       create_header_field_func(stream_class,
-                               validation_output->event_header_type);
-               if (!*header_field) {
-                       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_field = create_field_func(
-                       validation_output->stream_event_ctx_type);
-               if (!*stream_event_context_field) {
-                       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);
-               *context_field = create_field_func(
-                       validation_output->event_context_type);
-               if (!*context_field) {
-                       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);
-               *payload_field = create_field_func(
-                       validation_output->event_payload_type);
-               if (!*payload_field) {
-                       BT_LOGE_STR("Cannot create initial event payload field object.");
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       if (*header_field) {
-               release_header_field_func(*header_field, stream_class);
-       }
-
-       if (*stream_event_context_field) {
-               release_field_func(*stream_event_context_field);
-       }
-
-       if (*context_field) {
-               release_field_func(*context_field);
-       }
-
-       if (*payload_field) {
-               release_field_func(*payload_field);
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int _bt_ctf_event_common_validate(struct bt_ctf_event_common *event)
-{
-       int ret = 0;
-       struct bt_ctf_stream_class_common *stream_class;
-
-       BT_ASSERT(event);
-       if (event->header_field) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       event->header_field->field);
-               if (ret) {
-                       BT_CTF_ASSERT_PRE_MSG("Invalid event's header field: "
-                               "event-addr=%p, field-addr=%p",
-                               event, event->header_field->field);
-                       goto end;
-               }
-       }
-
-       stream_class = bt_ctf_event_class_common_borrow_stream_class(event->class);
-
-       /*
-        * We should not have been able to create the event without associating
-        * the event class to a stream class.
-        */
-       BT_ASSERT(stream_class);
-
-       if (stream_class->event_context_field_type) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       event->stream_event_context_field);
-               if (ret) {
-                       BT_CTF_ASSERT_PRE_MSG("Invalid event's stream event context field: "
-                               "event-addr=%p, field-addr=%p",
-                               event, event->stream_event_context_field);
-                       goto end;
-               }
-       }
-
-       if (event->class->context_field_type) {
-               ret = bt_ctf_field_common_validate_recursive(event->context_field);
-               if (ret) {
-                       BT_CTF_ASSERT_PRE_MSG("Invalid event's payload field: "
-                               "event-addr=%p, field-addr=%p",
-                               event, event->context_field);
-                       goto end;
-               }
-       }
-
-       ret = bt_ctf_field_common_validate_recursive(event->payload_field);
-       if (ret) {
-               BT_CTF_ASSERT_PRE_MSG("Invalid event's payload field: "
-                       "event-addr=%p, field-addr=%p",
-                       event, event->payload_field);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event,
-               bool is_frozen)
-{
-       BT_ASSERT(event);
-       BT_LOGD("Freezing event: addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event, bt_ctf_event_class_common_get_name(event->class),
-               bt_ctf_event_class_common_get_id(event->class));
-
-       if (event->header_field) {
-               BT_LOGD_STR("Freezing event's header field.");
-               bt_ctf_field_common_set_is_frozen_recursive(
-                       event->header_field->field, is_frozen);
-       }
-
-       if (event->stream_event_context_field) {
-               BT_LOGD_STR("Freezing event's stream event context field.");
-               bt_ctf_field_common_set_is_frozen_recursive(
-                       event->stream_event_context_field, is_frozen);
-       }
-
-       if (event->context_field) {
-               BT_LOGD_STR("Freezing event's context field.");
-               bt_ctf_field_common_set_is_frozen_recursive(event->context_field,
-                       is_frozen);
-       }
-
-       if (event->payload_field) {
-               BT_LOGD_STR("Freezing event's payload field.");
-               bt_ctf_field_common_set_is_frozen_recursive(event->payload_field,
-                       is_frozen);
-       }
-
-       event->frozen = is_frozen;
-}
-
-BT_HIDDEN
-int bt_ctf_event_common_initialize(struct bt_ctf_event_common *event,
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_clock_class *init_expected_clock_class,
-               bool is_shared_with_parent, bt_ctf_object_release_func release_func,
-               bt_ctf_validation_flag_copy_field_type_func field_type_copy_func,
-               bool must_be_in_trace,
-               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
-                       struct bt_ctf_field_type_common *packet_context_field_type,
-                       struct bt_ctf_field_type_common *event_header_field_type),
-               create_field_func create_field_func,
-               release_field_func release_field_func,
-               create_header_field_func create_header_field_func,
-               release_header_field_func release_header_field_func)
-{
-       int ret;
-       struct bt_ctf_trace_common *trace = NULL;
-       struct bt_ctf_stream_class_common *stream_class = NULL;
-       struct bt_ctf_field_wrapper *event_header = NULL;
-       struct bt_ctf_field_common *stream_event_context = NULL;
-       struct bt_ctf_field_common *event_context = NULL;
-       struct bt_ctf_field_common *event_payload = NULL;
-       struct bt_ctf_validation_output validation_output = { 0 };
-       struct bt_ctf_clock_class *expected_clock_class =
-               init_expected_clock_class ? bt_ctf_object_get_ref(init_expected_clock_class) :
-               NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_LOGD("Initializing common event object: event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event_class, bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-
-       stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
-       BT_CTF_ASSERT_PRE(stream_class,
-               "Event class is not part of a stream class: event-class-addr=%p",
-               event_class);
-
-       /* The event class was frozen when added to its stream class */
-       BT_ASSERT(event_class->frozen);
-       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
-
-       if (must_be_in_trace) {
-               BT_CTF_ASSERT_PRE(trace,
-                       "Event class's stream class is not part of a trace: "
-                       "ec-addr=%p, sc-addr=%p", event_class, stream_class);
-       }
-
-       /*
-        * This must be called before anything that can fail because on
-        * failure, the caller releases the reference to `event` to
-        * destroy it.
-        */
-       if (is_shared_with_parent) {
-               bt_ctf_object_init_shared_with_parent(&event->base, release_func);
-       } else {
-               bt_ctf_object_init_unique(&event->base);
-       }
-
-       if (!stream_class->frozen) {
-               /*
-                * Because this function freezes the stream class,
-                * validate that this stream class contains at most a
-                * single clock class so that we set its expected clock
-                * class for future checks.
-                */
-               ret = bt_ctf_stream_class_common_validate_single_clock_class(
-                       stream_class, &expected_clock_class);
-               if (ret) {
-                       BT_LOGW("Event class's stream class or one of its event "
-                               "classes contains a field type which is not "
-                               "recursively mapped to the expected "
-                               "clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-id=%" PRId64 ", "
-                               "stream-class-name=\"%s\", "
-                               "expected-clock-class-addr=%p, "
-                               "expected-clock-class-name=\"%s\"",
-                               stream_class,
-                               bt_ctf_stream_class_common_get_id(stream_class),
-                               bt_ctf_stream_class_common_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_ctf_clock_class_get_name(expected_clock_class) :
-                                       NULL);
-                       goto error;
-               }
-       }
-
-       /* Validate the trace, the stream class, and the event class */
-       ret = bt_ctf_event_common_validate_types_for_create(
-               event_class, &validation_output, field_type_copy_func);
-       if (ret) {
-               /* bt_ctf_event_common_validate_types_for_create() logs errors */
-               goto error;
-       }
-
-       if (map_clock_classes_func) {
-               /*
-                * Safe to automatically map selected fields to the
-                * stream's clock's class here because the stream class
-                * is about to be frozen.
-                */
-               if (map_clock_classes_func(stream_class,
-                               validation_output.packet_context_type,
-                               validation_output.event_header_type)) {
-                       BT_LOGW_STR("Cannot automatically map selected stream class's "
-                               "field types to stream class's clock's class.");
-                       goto error;
-               }
-       }
-
-       /*
-        * 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->class = bt_ctf_object_get_ref(event_class);
-
-       ret = bt_ctf_event_common_create_fields(stream_class,
-               &validation_output,
-               create_field_func, release_field_func,
-               create_header_field_func, release_header_field_func,
-               &event_header, &stream_event_context, &event_context,
-               &event_payload);
-       if (ret) {
-               /* bt_ctf_event_common_create_fields() logs errors */
-               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_ctf_validation_replace_types(trace, stream_class, event_class,
-               &validation_output,
-               BT_CTF_VALIDATION_FLAG_STREAM | BT_CTF_VALIDATION_FLAG_EVENT);
-       event->header_field = event_header;
-       event_header = NULL;
-       event->stream_event_context_field = stream_event_context;
-       stream_event_context = NULL;
-       event->context_field = event_context;
-       event_context = NULL;
-       event->payload_field = event_payload;
-       event_payload = NULL;
-
-       /*
-        * Put what was not moved in bt_ctf_validation_replace_types().
-        */
-       bt_ctf_validation_output_put_types(&validation_output);
-
-       /*
-        * Freeze the stream class since the event header must not be changed
-        * anymore.
-        */
-       bt_ctf_stream_class_common_freeze(stream_class);
-
-       /*
-        * It is safe to set the stream class's unique clock class
-        * now because the stream class is frozen.
-        */
-       if (expected_clock_class) {
-               BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_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_LOGD("Initialized event object: addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64,
-               event, bt_ctf_event_class_common_get_name(event->class),
-               bt_ctf_event_class_common_get_id(event->class));
-       goto end;
-
-error:
-       bt_ctf_validation_output_put_types(&validation_output);
-       bt_ctf_object_put_ref(expected_clock_class);
-
-       if (event_header) {
-               release_header_field_func(event_header, stream_class);
-       }
-
-       if (stream_event_context) {
-               release_field_func(stream_event_context);
-       }
-
-       if (event_context) {
-               release_field_func(event_context);
-       }
-
-       if (event_payload) {
-               release_field_func(event_payload);
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
-int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type)
-{
-       int ret = bt_ctf_stream_class_map_clock_class(
-               BT_CTF_FROM_COMMON(stream_class),
-               BT_CTF_FROM_COMMON(packet_context_type),
-               BT_CTF_FROM_COMMON(event_header_type));
-
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
-       }
-
-       return ret;
-}
-
-static
-void destroy_event_header_field(struct bt_ctf_field_wrapper *field_wrapper)
-{
-       BT_ASSERT(field_wrapper);
-       bt_ctf_object_put_ref(field_wrapper->field);
-       bt_ctf_field_wrapper_destroy(field_wrapper);
-}
-
-static
-struct bt_ctf_field_wrapper *create_event_header_field(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_wrapper *field_wrapper = NULL;
-       struct bt_ctf_field *field = bt_ctf_field_create((void *) ft);
-
-       if (!field) {
-               goto error;
-       }
-
-       field_wrapper = bt_ctf_field_wrapper_new(NULL);
-       if (!field_wrapper) {
-               goto error;
-       }
-
-       field_wrapper->field = (void *) field;
-       field = NULL;
-       goto end;
-
-error:
-       bt_ctf_object_put_ref(field);
-
-       if (field_wrapper) {
-               destroy_event_header_field(field_wrapper);
-               field_wrapper = NULL;
-       }
-
-end:
-       return field_wrapper;
-}
-
-static
-void release_event_header_field(struct bt_ctf_field_wrapper *field_wrapper,
-               struct bt_ctf_event_common *event_common)
-{
-       BT_ASSERT(field_wrapper);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_wrapper->field);
-       bt_ctf_field_wrapper_destroy(field_wrapper);
-}
-
-static
-void bt_ctf_event_destroy(struct bt_ctf_object *obj)
-{
-       bt_ctf_event_common_finalize(obj, (void *) bt_ctf_object_put_ref,
-               (void *) release_event_header_field);
-       g_free(obj);
-}
-
-struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
-{
-       int ret;
-       struct bt_ctf_event *event = NULL;
-       struct bt_ctf_clock_class *expected_clock_class = NULL;
-
-       event = g_new0(struct bt_ctf_event, 1);
-       if (!event) {
-               BT_LOGE_STR("Failed to allocate one CTF writer event.");
-               goto error;
-       }
-
-       if (event_class) {
-               struct bt_ctf_stream_class *stream_class =
-                       BT_CTF_FROM_COMMON(bt_ctf_event_class_common_borrow_stream_class(
-                               BT_CTF_TO_COMMON(event_class)));
-
-               if (stream_class && stream_class->clock) {
-                       expected_clock_class = stream_class->clock->clock_class;
-               }
-       }
-
-       ret = bt_ctf_event_common_initialize(BT_CTF_TO_COMMON(event),
-               BT_CTF_TO_COMMON(event_class), expected_clock_class,
-               true, bt_ctf_event_destroy,
-               (bt_ctf_validation_flag_copy_field_type_func)
-                       bt_ctf_field_type_copy,
-               false, map_clock_classes_func,
-               (create_field_func) bt_ctf_field_create,
-               (release_field_func) bt_ctf_object_put_ref,
-               (create_header_field_func) create_event_header_field,
-               (release_header_field_func) destroy_event_header_field);
-       if (ret) {
-               /* bt_ctf_event_common_initialize() logs errors */
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(event);
-
-end:
-       return event;
-}
-
-struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event)));
-}
-
-BT_HIDDEN
-struct bt_ctf_stream *bt_ctf_event_borrow_stream(struct bt_ctf_event *event)
-{
-       BT_ASSERT(event);
-       return (struct bt_ctf_stream *)
-               bt_ctf_object_borrow_parent(&BT_CTF_TO_COMMON(event)->base);
-}
-
-struct bt_ctf_stream *bt_ctf_event_get_stream(struct bt_ctf_event *event)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-       return bt_ctf_object_get_ref(bt_ctf_event_borrow_stream(event));
-}
-
-int bt_ctf_event_set_payload(struct bt_ctf_event *event, const char *name,
-               struct bt_ctf_field *field)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Payload field");
-       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-       return bt_ctf_field_structure_set_field_by_name(
-               (void *) event->common.payload_field, name, field);
-}
-
-struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event,
-               const char *name)
-{
-       struct bt_ctf_field *field = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (name) {
-               field = bt_ctf_field_structure_get_field_by_name(
-                       BT_CTF_FROM_COMMON(event->common.payload_field), name);
-       } else {
-               field = BT_CTF_FROM_COMMON(event->common.payload_field);
-               bt_ctf_object_get_ref(field);
-       }
-
-       return field;
-}
-
-struct bt_ctf_field *bt_ctf_event_get_payload_field(
-               struct bt_ctf_event *event)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_payload(BT_CTF_TO_COMMON(event)));
-}
-
-struct bt_ctf_field *bt_ctf_event_get_header(struct bt_ctf_event *event)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_header(BT_CTF_TO_COMMON(event)));
-}
-
-struct bt_ctf_field *bt_ctf_event_get_context(struct bt_ctf_event *event)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_context(BT_CTF_TO_COMMON(event)));
-}
-
-struct bt_ctf_field *bt_ctf_event_get_stream_event_context(
-               struct bt_ctf_event *event)
-{
-       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_stream_event_context(
-               BT_CTF_TO_COMMON(event)));
-}
-
-BT_HIDDEN
-int bt_ctf_event_serialize(struct bt_ctf_event *event,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int ret = 0;
-
-       BT_ASSERT(event);
-       BT_ASSERT(ctfser);
-
-       BT_LOGV_STR("Serializing event's context field.");
-       if (event->common.context_field) {
-               ret = bt_ctf_field_serialize_recursive(
-                       (void *) event->common.context_field, ctfser,
-                       native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event's context field: "
-                               "event-addr=%p, event-class-name=\"%s\", "
-                               "event-class-id=%" PRId64,
-                               event,
-                               bt_ctf_event_class_common_get_name(event->common.class),
-                               bt_ctf_event_class_common_get_id(event->common.class));
-                       goto end;
-               }
-       }
-
-       BT_LOGV_STR("Serializing event's payload field.");
-       if (event->common.payload_field) {
-               ret = bt_ctf_field_serialize_recursive(
-                       (void *) event->common.payload_field, ctfser,
-                       native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event's payload field: "
-                               "event-addr=%p, event-class-name=\"%s\", "
-                               "event-class-id=%" PRId64,
-                               event,
-                               bt_ctf_event_class_common_get_name(event->common.class),
-                               bt_ctf_event_class_common_get_id(event->common.class));
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void _bt_ctf_event_freeze(struct bt_ctf_event *event)
-{
-       _bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
-}
-
-int bt_ctf_event_set_header(struct bt_ctf_event *event,
-               struct bt_ctf_field *header)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-
-       /*
-        * Ensure the provided header's type matches the one registered to the
-        * stream class.
-        */
-       if (header) {
-               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
-                       ((struct bt_ctf_field_common *) header)->type,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type) == 0,
-                       "Header field's type is different from the "
-                       "expected field type: event-addr=%p, ft-addr=%p, "
-                       "expected-ft-addr=%p",
-                       event, ((struct bt_ctf_field_common *) header)->type,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
-       } else {
-               BT_CTF_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type,
-                       "Setting no event header field, "
-                       "but event header field type is not NULL: "
-                       "event-addr=%p, header-ft-addr=%p",
-                       event,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
-       }
-
-       bt_ctf_object_put_ref(event->common.header_field->field);
-       event->common.header_field->field = bt_ctf_object_get_ref(header);
-       BT_LOGV("Set event's header field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "header-field-addr=%p",
-               event, bt_ctf_event_class_common_get_name(event->common.class),
-               bt_ctf_event_class_common_get_id(event->common.class), header);
-       return 0;
-}
-
-int bt_ctf_event_common_set_payload(struct bt_ctf_event *event,
-               struct bt_ctf_field *payload)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-
-       if (payload) {
-               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
-                       ((struct bt_ctf_field_common *) payload)->type,
-                       event->common.class->payload_field_type) == 0,
-                       "Payload field's type is different from the "
-                       "expected field type: event-addr=%p, ft-addr=%p, "
-                       "expected-ft-addr=%p",
-                       event,
-                       ((struct bt_ctf_field_common *) payload)->type,
-                       event->common.class->payload_field_type);
-       } else {
-               BT_CTF_ASSERT_PRE(!event->common.class->payload_field_type,
-                       "Setting no event payload field, "
-                       "but event payload field type is not NULL: "
-                       "event-addr=%p, payload-ft-addr=%p",
-                       event, event->common.class->payload_field_type);
-       }
-
-       bt_ctf_object_put_ref(event->common.payload_field);
-       event->common.payload_field = bt_ctf_object_get_ref(payload);
-       BT_LOGV("Set event's payload field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "payload-field-addr=%p",
-               event, bt_ctf_event_class_common_get_name(event->common.class),
-               bt_ctf_event_class_common_get_id(event->common.class), payload);
-       return 0;
-}
-
-int bt_ctf_event_set_context(struct bt_ctf_event *event,
-               struct bt_ctf_field *context)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-
-       if (context) {
-               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
-                       ((struct bt_ctf_field_common *) context)->type,
-                       event->common.class->context_field_type) == 0,
-                       "Context field's type is different from the "
-                       "expected field type: event-addr=%p, ft-addr=%p, "
-                       "expected-ft-addr=%p",
-                       event, ((struct bt_ctf_field_common *) context)->type,
-                       event->common.class->context_field_type);
-       } else {
-               BT_CTF_ASSERT_PRE(!event->common.class->context_field_type,
-                       "Setting no event context field, "
-                       "but event context field type is not NULL: "
-                       "event-addr=%p, context-ft-addr=%p",
-                       event, event->common.class->context_field_type);
-       }
-
-       bt_ctf_object_put_ref(event->common.context_field);
-       event->common.context_field = bt_ctf_object_get_ref(context);
-       BT_LOGV("Set event's context field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "context-field-addr=%p",
-               event, bt_ctf_event_class_common_get_name(event->common.class),
-               bt_ctf_event_class_common_get_id(event->common.class), context);
-       return 0;
-}
-
-int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
-               struct bt_ctf_field *stream_event_context)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
-
-       if (stream_event_context) {
-               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
-                       ((struct bt_ctf_field_common *) stream_event_context)->type,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type) == 0,
-                       "Stream event context field's type is different from the "
-                       "expected field type: event-addr=%p, ft-addr=%p, "
-                       "expected-ft-addr=%p",
-                       event,
-                       ((struct bt_ctf_field_common *) stream_event_context)->type,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
-       } else {
-               BT_CTF_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type,
-                       "Setting no stream event context field, "
-                       "but stream event context field type is not NULL: "
-                       "event-addr=%p, context-ft-addr=%p",
-                       event,
-                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
-       }
-
-       bt_ctf_object_put_ref(event->common.stream_event_context_field);
-       event->common.stream_event_context_field = bt_ctf_object_get_ref(stream_event_context);
-       BT_LOGV("Set event's stream event context field: event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "stream-event-context-field-addr=%p",
-               event, bt_ctf_event_class_common_get_name(event->common.class),
-               bt_ctf_event_class_common_get_id(event->common.class),
-               stream_event_context);
-       return 0;
-}
diff --git a/ctf-writer/field-path.c b/ctf-writer/field-path.c
deleted file mode 100644 (file)
index 284e850..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * field-path.c
- *
- * Babeltrace CTF writer - Field path
- *
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-FIELD-PATH"
-#include "logging.h"
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/field-path-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdint.h>
-
-static
-void field_path_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_path *field_path = (struct bt_ctf_field_path *) obj;
-
-       BT_LOGD("Destroying field path: addr=%p", obj);
-
-       if (!field_path) {
-               return;
-       }
-
-       if (field_path->indexes) {
-               g_array_free(field_path->indexes, TRUE);
-       }
-       g_free(field_path);
-}
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_path_create(void)
-{
-       struct bt_ctf_field_path *field_path = NULL;
-
-       BT_LOGD_STR("Creating empty field path object.");
-
-       field_path = g_new0(struct bt_ctf_field_path, 1);
-       if (!field_path) {
-               BT_LOGE_STR("Failed to allocate one field path.");
-               goto error;
-       }
-
-       bt_ctf_object_init_shared(&field_path->base, field_path_destroy);
-       field_path->root = BT_CTF_SCOPE_UNKNOWN;
-       field_path->indexes = g_array_new(TRUE, FALSE, sizeof(int));
-       if (!field_path->indexes) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               goto error;
-       }
-
-       BT_LOGD("Created empty field path object: addr=%p", field_path);
-       return field_path;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path);
-       return NULL;
-}
-
-BT_HIDDEN
-void bt_ctf_field_path_clear(struct bt_ctf_field_path *field_path)
-{
-       if (field_path->indexes->len > 0) {
-               g_array_remove_range(field_path->indexes, 0,
-                       field_path->indexes->len);
-       }
-}
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_path_copy(
-               struct bt_ctf_field_path *path)
-{
-       struct bt_ctf_field_path *new_path;
-
-       BT_ASSERT(path);
-       BT_LOGD("Copying field path: addr=%p, index-count=%u",
-               path, path->indexes->len);
-       new_path = bt_ctf_field_path_create();
-       if (!new_path) {
-               BT_LOGE_STR("Cannot create empty field path.");
-               goto end;
-       }
-
-       new_path->root = path->root;
-       g_array_insert_vals(new_path->indexes, 0,
-               path->indexes->data, path->indexes->len);
-       BT_LOGD("Copied field path: original-addr=%p, copy-addr=%p",
-               path, new_path);
-end:
-       return new_path;
-}
-
-enum bt_ctf_scope bt_ctf_field_path_get_root_scope(
-               const struct bt_ctf_field_path *field_path)
-{
-       enum bt_ctf_scope scope = BT_CTF_SCOPE_UNKNOWN;
-
-       if (!field_path) {
-               BT_LOGW_STR("Invalid parameter: field path is NULL.");
-               goto end;
-       }
-
-       scope = field_path->root;
-
-end:
-       return scope;
-}
-
-int64_t bt_ctf_field_path_get_index_count(
-               const struct bt_ctf_field_path *field_path)
-{
-       int64_t count = (int64_t) -1;
-
-       if (!field_path) {
-               BT_LOGW_STR("Invalid parameter: field path is NULL.");
-               goto end;
-       }
-
-       count = (int64_t) field_path->indexes->len;
-
-end:
-       return count;
-}
-
-int bt_ctf_field_path_get_index(const struct bt_ctf_field_path *field_path,
-               uint64_t index)
-{
-       int ret = INT_MIN;
-
-       if (!field_path) {
-               BT_LOGW_STR("Invalid parameter: field path is NULL.");
-               goto end;
-       }
-
-       if (index >= field_path->indexes->len) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "addr=%p, index=%" PRIu64 ", count=%u",
-                       field_path, index, field_path->indexes->len);
-               goto end;
-       }
-
-       ret = g_array_index(field_path->indexes, int, index);
-
-end:
-       return ret;
-}
diff --git a/ctf-writer/field-types.c b/ctf-writer/field-types.c
deleted file mode 100644 (file)
index 2d18c45..0000000
+++ /dev/null
@@ -1,5564 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-FIELD-TYPES"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/field-path-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <float.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-static
-void destroy_enumeration_mapping(struct bt_ctf_enumeration_mapping *mapping)
-{
-       g_free(mapping);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_initialize(struct bt_ctf_field_type_common *ft,
-               bool init_bo, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       BT_ASSERT(ft && (ft->id > BT_CTF_FIELD_TYPE_ID_UNKNOWN) &&
-               (ft->id < BT_CTF_FIELD_TYPE_ID_NR));
-
-       bt_ctf_object_init_shared(&ft->base, release_func);
-       ft->methods = methods;
-
-       if (init_bo) {
-               int ret;
-               const enum bt_ctf_byte_order bo = BT_CTF_BYTE_ORDER_NATIVE;
-
-               BT_LOGD("Setting initial field type's byte order: bo=%s",
-                       bt_ctf_byte_order_string(bo));
-               ret = bt_ctf_field_type_common_set_byte_order(ft, bo);
-               BT_ASSERT(ret == 0);
-       }
-
-       ft->alignment = 1;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_initialize(
-               struct bt_ctf_field_type_common *ft,
-               unsigned int size, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(size > 0);
-       BT_LOGD("Initializing common integer field type object: size=%u",
-               size);
-       ft->id = BT_CTF_FIELD_TYPE_ID_INTEGER;
-       int_ft->size = size;
-       int_ft->base = BT_CTF_INTEGER_BASE_DECIMAL;
-       int_ft->encoding = BT_CTF_STRING_ENCODING_NONE;
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized common integer field type object: addr=%p, size=%u",
-               ft, size);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_LOGD_STR("Initializing common floating point number field type object.");
-       ft->id = BT_CTF_FIELD_TYPE_ID_FLOAT;
-       flt_ft->exp_dig = sizeof(float) * CHAR_BIT - FLT_MANT_DIG;
-       flt_ft->mant_dig = FLT_MANT_DIG;
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized common floating point number field type object: addr=%p, "
-               "exp-size=%u, mant-size=%u", ft, flt_ft->exp_dig,
-               flt_ft->mant_dig);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *container_ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(container_ft);
-       BT_LOGD("Initializing common enumeration field type object: int-ft-addr=%p",
-               container_ft);
-       ft->id = BT_CTF_FIELD_TYPE_ID_ENUM;
-       enum_ft->container_ft = bt_ctf_object_get_ref(container_ft);
-       enum_ft->entries = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) destroy_enumeration_mapping);
-       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized common enumeration field type object: addr=%p, "
-               "int-ft-addr=%p, int-ft-size=%u", ft, container_ft,
-               bt_ctf_field_type_common_integer_get_size(container_ft));
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_string_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_LOGD_STR("Initializing common string field type object.");
-       ft->id = BT_CTF_FIELD_TYPE_ID_STRING;
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       string_ft->encoding = BT_CTF_STRING_ENCODING_UTF8;
-       ft->alignment = CHAR_BIT;
-       BT_LOGD("Initialized common string field type object: addr=%p", ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_LOGD_STR("Initializing common structure field type object.");
-       ft->id = BT_CTF_FIELD_TYPE_ID_STRUCT;
-       struct_ft->fields = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_ctf_field_type_common_structure_field));
-       struct_ft->field_name_to_index = g_hash_table_new(NULL, NULL);
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       BT_LOGD("Initialized common structure field type object: addr=%p", ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft,
-               unsigned int length, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(element_ft);
-       BT_LOGD("Initializing common array field type object: element-ft-addr=%p, "
-               "length=%u", element_ft, length);
-       ft->id = BT_CTF_FIELD_TYPE_ID_ARRAY;
-       array_ft->element_ft = bt_ctf_object_get_ref(element_ft);
-       array_ft->length = length;
-       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized common array field type object: addr=%p, "
-               "element-ft-addr=%p, length=%u", ft, element_ft, length);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft,
-               const char *length_field_name,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(element_ft);
-       BT_ASSERT(length_field_name);
-       BT_ASSERT(bt_ctf_identifier_is_valid(length_field_name));
-       BT_LOGD("Initializing common sequence field type object: element-ft-addr=%p, "
-               "length-field-name=\"%s\"", element_ft, length_field_name);
-       ft->id = BT_CTF_FIELD_TYPE_ID_SEQUENCE;
-       seq_ft->element_ft = bt_ctf_object_get_ref(element_ft);
-       seq_ft->length_field_name = g_string_new(length_field_name);
-       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
-       BT_LOGD("Initialized common sequence field type object: addr=%p, "
-               "element-ft-addr=%p, length-field-name=\"%s\"",
-               ft, element_ft, length_field_name);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *tag_ft,
-               const char *tag_name,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(!tag_name || bt_ctf_identifier_is_valid(tag_name));
-       BT_LOGD("Initializing common variant field type object: "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               tag_ft, tag_name);
-       ft->id = BT_CTF_FIELD_TYPE_ID_VARIANT;
-       var_ft->tag_name = g_string_new(tag_name);
-       var_ft->choice_name_to_index = g_hash_table_new(NULL, NULL);
-       var_ft->choices = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_ctf_field_type_common_variant_choice));
-
-       if (tag_ft) {
-               var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft);
-       }
-
-       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
-       /* A variant's alignment is undefined */
-       ft->alignment = 0;
-       BT_LOGD("Initialized common variant field type object: addr=%p, "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               ft, tag_ft, tag_name);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_integer *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying integer field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting mapped clock class.");
-       bt_ctf_object_put_ref(ft->mapped_clock_class);
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_floating_point *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying floating point number field type object: addr=%p", ft);
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_enumeration *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying enumeration field type object: addr=%p", ft);
-       g_ptr_array_free(ft->entries, TRUE);
-       BT_LOGD_STR("Putting container field type.");
-       bt_ctf_object_put_ref(ft->container_ft);
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_string_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_string *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying string field type object: addr=%p", ft);
-       g_free(ft);
-}
-
-static
-void bt_ctf_field_type_common_structure_field_finalize(
-               struct bt_ctf_field_type_common_structure_field *field)
-{
-       if (!field) {
-               return;
-       }
-
-       BT_LOGD("Finalizing structure field type's field: "
-               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-               field, field->type, g_quark_to_string(field->name));
-       BT_LOGD_STR("Putting field type.");
-       bt_ctf_object_put_ref(field->type);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_structure *ft = (void *) obj;
-       uint64_t i;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying structure field type object: addr=%p", ft);
-
-       if (ft->fields) {
-               for (i = 0; i < ft->fields->len; i++) {
-                       bt_ctf_field_type_common_structure_field_finalize(
-                               BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                                       ft, i));
-               }
-
-               g_array_free(ft->fields, TRUE);
-       }
-
-       if (ft->field_name_to_index) {
-               g_hash_table_destroy(ft->field_name_to_index);
-       }
-
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_array *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying array field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting element field type.");
-       bt_ctf_object_put_ref(ft->element_ft);
-       g_free(ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_sequence *ft = (void *) obj;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying sequence field type object: addr=%p", ft);
-       BT_LOGD_STR("Putting element field type.");
-       bt_ctf_object_put_ref(ft->element_ft);
-       g_string_free(ft->length_field_name, TRUE);
-       BT_LOGD_STR("Putting length field path.");
-       bt_ctf_object_put_ref(ft->length_field_path);
-       g_free(ft);
-}
-
-static
-void bt_ctf_field_type_common_variant_choice_finalize(
-               struct bt_ctf_field_type_common_variant_choice *choice)
-{
-       if (!choice) {
-               return;
-       }
-
-       BT_LOGD("Finalizing variant field type's choice: "
-               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-               choice, choice->type, g_quark_to_string(choice->name));
-       BT_LOGD_STR("Putting field type.");
-       bt_ctf_object_put_ref(choice->type);
-
-       if (choice->ranges) {
-               g_array_free(choice->ranges, TRUE);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_destroy_recursive(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_common_variant *ft = (void *) obj;
-       uint64_t i;
-
-       if (!ft) {
-               return;
-       }
-
-       BT_LOGD("Destroying variant field type object: addr=%p", ft);
-
-       if (ft->choices) {
-               for (i = 0; i < ft->choices->len; i++) {
-                       bt_ctf_field_type_common_variant_choice_finalize(
-                               BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                                       ft, i));
-               }
-
-               g_array_free(ft->choices, TRUE);
-       }
-
-       if (ft->choice_name_to_index) {
-               g_hash_table_destroy(ft->choice_name_to_index);
-       }
-
-       if (ft->tag_name) {
-               g_string_free(ft->tag_name, TRUE);
-       }
-
-       BT_LOGD_STR("Putting tag field type.");
-       bt_ctf_object_put_ref(ft->tag_ft);
-       BT_LOGD_STR("Putting tag field path.");
-       bt_ctf_object_put_ref(ft->tag_field_path);
-       g_free(ft);
-}
-
-struct range_overlap_query {
-       union {
-               uint64_t _unsigned;
-               int64_t _signed;
-       } range_start;
-
-       union {
-               uint64_t _unsigned;
-               int64_t _signed;
-       } range_end;
-       int overlaps;
-       GQuark mapping_name;
-};
-
-static
-void check_ranges_overlap(gpointer element, gpointer query)
-{
-       struct bt_ctf_enumeration_mapping *mapping = element;
-       struct range_overlap_query *overlap_query = query;
-
-       if (mapping->range_start._signed <= overlap_query->range_end._signed
-                       && overlap_query->range_start._signed <=
-                       mapping->range_end._signed) {
-               overlap_query->overlaps = 1;
-               overlap_query->mapping_name = mapping->string;
-       }
-
-       overlap_query->overlaps |=
-               mapping->string == overlap_query->mapping_name;
-
-       if (overlap_query->overlaps) {
-               BT_LOGV("Overlapping enumeration field type mappings: "
-                       "mapping-name=\"%s\", "
-                       "mapping-a-range-start=%" PRId64 ", "
-                       "mapping-a-range-end=%" PRId64 ", "
-                       "mapping-b-range-start=%" PRId64 ", "
-                       "mapping-b-range-end=%" PRId64,
-                       g_quark_to_string(mapping->string),
-                       mapping->range_start._signed,
-                       mapping->range_end._signed,
-                       overlap_query->range_start._signed,
-                       overlap_query->range_end._signed);
-       }
-}
-
-static
-void check_ranges_overlap_unsigned(gpointer element, gpointer query)
-{
-       struct bt_ctf_enumeration_mapping *mapping = element;
-       struct range_overlap_query *overlap_query = query;
-
-       if (mapping->range_start._unsigned <= overlap_query->range_end._unsigned
-                       && overlap_query->range_start._unsigned <=
-                       mapping->range_end._unsigned) {
-               overlap_query->overlaps = 1;
-               overlap_query->mapping_name = mapping->string;
-       }
-
-       overlap_query->overlaps |=
-               mapping->string == overlap_query->mapping_name;
-
-       if (overlap_query->overlaps) {
-               BT_LOGW("Overlapping enumeration field type mappings: "
-                       "mapping-name=\"%s\", "
-                       "mapping-a-range-start=%" PRIu64 ", "
-                       "mapping-a-range-end=%" PRIu64 ", "
-                       "mapping-b-range-start=%" PRIu64 ", "
-                       "mapping-b-range-end=%" PRIu64,
-                       g_quark_to_string(mapping->string),
-                       mapping->range_start._unsigned,
-                       mapping->range_end._unsigned,
-                       overlap_query->range_start._unsigned,
-                       overlap_query->range_end._unsigned);
-       }
-}
-
-static
-gint compare_enumeration_mappings_signed(struct bt_ctf_enumeration_mapping **a,
-               struct bt_ctf_enumeration_mapping **b)
-{
-       return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1;
-}
-
-static
-gint compare_enumeration_mappings_unsigned(struct bt_ctf_enumeration_mapping **a,
-               struct bt_ctf_enumeration_mapping **b)
-{
-       return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1;
-}
-
-static
-int add_structure_variant_member(GArray *members,
-               GHashTable *field_name_to_index,
-               struct bt_ctf_field_type_common *field_type, const char *field_name,
-               bool is_variant)
-{
-       int ret = 0;
-       GQuark name_quark = g_quark_from_string(field_name);
-       struct bt_ctf_field_type_common **member_ft;
-       GQuark *member_name;
-
-       /* Make sure structure does not contain a field of the same name */
-       if (g_hash_table_lookup_extended(field_name_to_index,
-                       GUINT_TO_POINTER(name_quark), NULL, NULL)) {
-               BT_LOGW("Structure or variant field type already contains a field type with this name: "
-                       "field-name=\"%s\"", field_name);
-               ret = -1;
-               goto end;
-       }
-
-       g_array_set_size(members, members->len + 1);
-
-       if (is_variant) {
-               struct bt_ctf_field_type_common_variant_choice *choice =
-                       &g_array_index(members,
-                               struct bt_ctf_field_type_common_variant_choice,
-                               members->len - 1);
-
-               member_ft = &choice->type;
-               member_name = &choice->name;
-               BT_ASSERT(!choice->ranges);
-               choice->ranges = g_array_new(FALSE, TRUE,
-                       sizeof(struct bt_ctf_field_type_common_variant_choice_range));
-               BT_ASSERT(choice->ranges);
-       } else {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       &g_array_index(members,
-                               struct bt_ctf_field_type_common_structure_field,
-                               members->len - 1);
-
-               member_ft = &field->type;
-               member_name = &field->name;
-       }
-
-       *member_name = name_quark;
-       *member_ft = bt_ctf_object_get_ref(field_type);
-       g_hash_table_insert(field_name_to_index,
-               GUINT_TO_POINTER(name_quark),
-               GUINT_TO_POINTER(members->len - 1));
-       BT_LOGV("Added structure/variant field type member: member-ft-addr=%p, "
-               "member-name=\"%s\"", field_type, field_name);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_validate(struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (int_ft->mapped_clock_class && int_ft->is_signed) {
-               BT_LOGW("Invalid integer field type: cannot be signed and have a mapped clock class: "
-                       "ft-addr=%p, clock-class-addr=%p, clock-class-name=\"%s\"",
-                       ft, int_ft->mapped_clock_class,
-                       bt_ctf_clock_class_get_name(int_ft->mapped_clock_class));
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-void bt_ctf_field_type_enum_iter_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter =
-               container_of(obj,
-                       struct bt_ctf_field_type_enumeration_mapping_iterator,
-                       base);
-
-       BT_LOGD("Destroying enumeration field type mapping iterator: addr=%p",
-               obj);
-       BT_LOGD_STR("Putting parent enumeration field type.");
-       bt_ctf_object_put_ref(iter->enumeration_ft);
-       g_free(iter);
-}
-
-static
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_find_mappings_type(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_field_type_enumeration_mapping_iterator_type iterator_type)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM,
-               "Field type");
-       iter = g_new0(struct bt_ctf_field_type_enumeration_mapping_iterator, 1);
-       if (!iter) {
-               BT_LOGE_STR("Failed to allocate one enumeration field type mapping.");
-               goto end;
-       }
-
-       bt_ctf_object_init_shared(&iter->base, bt_ctf_field_type_enum_iter_destroy);
-       iter->enumeration_ft = bt_ctf_object_get_ref(ft);
-       iter->index = -1;
-       iter->type = iterator_type;
-
-end:
-       return iter;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_find_mappings_by_name(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
-                       ft, CTF_ITERATOR_BY_NAME);
-       if (!iter) {
-               BT_LOGW("Cannot create enumeration field type mapping iterator: "
-                       "ft-addr=%p, mapping-name=\"%s\"", ft, name);
-               goto error;
-       }
-
-       iter->u.name_quark = g_quark_try_string(name);
-       if (!iter->u.name_quark) {
-               /*
-                * No results are possible, set the iterator's position at the
-                * end.
-                */
-               iter->index = iter->enumeration_ft->entries->len;
-       }
-
-       return iter;
-
-error:
-       bt_ctf_object_put_ref(iter);
-       return NULL;
-}
-
-static
-struct bt_ctf_enumeration_mapping *bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-               struct bt_ctf_field_type_common *ft, uint64_t index)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_enumeration_mapping *mapping = NULL;
-
-       if (index >= enum_ft->entries->len) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "addr=%p, index=%" PRIu64 ", count=%u",
-                       ft, index, enum_ft->entries->len);
-               goto end;
-       }
-
-       mapping = g_ptr_array_index(enum_ft->entries, index);
-
-end:
-       return mapping;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_enumeration_mapping_iterator_next(
-               struct bt_ctf_field_type_enumeration_mapping_iterator *iter)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = iter->enumeration_ft;
-       int i, ret = 0, len;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
-       len = enum_ft->entries->len;
-       for (i = iter->index + 1; i < len; i++) {
-               struct bt_ctf_enumeration_mapping *mapping =
-                       bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-                               BT_CTF_TO_COMMON(enum_ft), i);
-
-               switch (iter->type) {
-               case CTF_ITERATOR_BY_NAME:
-                       if (mapping->string == iter->u.name_quark) {
-                               iter->index = i;
-                               goto end;
-                       }
-                       break;
-               case CTF_ITERATOR_BY_SIGNED_VALUE:
-               {
-                       int64_t value = iter->u.signed_value;
-
-                       if (value >= mapping->range_start._signed &&
-                                       value <= mapping->range_end._signed) {
-                               iter->index = i;
-                               goto end;
-                       }
-                       break;
-               }
-               case CTF_ITERATOR_BY_UNSIGNED_VALUE:
-               {
-                       uint64_t value = iter->u.unsigned_value;
-
-                       if (value >= mapping->range_start._unsigned &&
-                                       value <= mapping->range_end._unsigned) {
-                               iter->index = i;
-                               goto end;
-                       }
-                       break;
-               }
-               default:
-                       BT_LOGF("Invalid enumeration field type mapping iterator type: "
-                               "type=%d", iter->type);
-                       abort();
-               }
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_signed_find_mappings_by_value(
-               struct bt_ctf_field_type_common *ft, int64_t value)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
-                       ft, CTF_ITERATOR_BY_SIGNED_VALUE);
-       if (!iter) {
-               BT_LOGW("Cannot create enumeration field type mapping iterator: "
-                       "ft-addr=%p, value=%" PRId64, ft, value);
-               goto error;
-       }
-
-       if (bt_ctf_field_type_common_integer_is_signed(
-                       BT_CTF_TO_COMMON(iter->enumeration_ft->container_ft)) != 1) {
-               BT_LOGW("Invalid parameter: enumeration field type is unsigned: "
-                       "enum-ft-addr=%p, int-ft-addr=%p",
-                       ft, iter->enumeration_ft->container_ft);
-               goto error;
-       }
-
-       iter->u.signed_value = value;
-       return iter;
-
-error:
-       bt_ctf_object_put_ref(iter);
-       return NULL;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_unsigned_find_mappings_by_value(
-               struct bt_ctf_field_type_common *ft, uint64_t value)
-{
-       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
-
-       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
-                       ft, CTF_ITERATOR_BY_UNSIGNED_VALUE);
-       if (!iter) {
-               BT_LOGW("Cannot create enumeration field type mapping iterator: "
-                       "ft-addr=%p, value=%" PRIu64, ft, value);
-               goto error;
-       }
-
-       if (bt_ctf_field_type_common_integer_is_signed(
-                       BT_CTF_TO_COMMON(iter->enumeration_ft->container_ft)) != 0) {
-               BT_LOGW("Invalid parameter: enumeration field type is signed: "
-                       "enum-ft-addr=%p, int-ft-addr=%p",
-                       ft, iter->enumeration_ft->container_ft);
-               goto error;
-       }
-
-       iter->u.unsigned_value = value;
-       return iter;
-
-error:
-       bt_ctf_object_put_ref(iter);
-       return NULL;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_enumeration_mapping_iterator_signed_get(
-               struct bt_ctf_field_type_enumeration_mapping_iterator *iter,
-               const char **mapping_name, int64_t *range_begin,
-               int64_t *range_end)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
-       BT_CTF_ASSERT_PRE(iter->index != -1,
-               "Invalid enumeration field type mapping iterator access: "
-               "addr=%p, position=-1", iter);
-       return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
-                       (void *) iter->enumeration_ft, iter->index,
-                       mapping_name, range_begin, range_end);
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get(
-               struct bt_ctf_field_type_enumeration_mapping_iterator *iter,
-               const char **mapping_name, uint64_t *range_begin,
-               uint64_t *range_end)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
-       BT_CTF_ASSERT_PRE(iter->index != -1,
-               "Invalid enumeration field type mapping iterator access: "
-               "addr=%p, position=-1", iter);
-       return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
-                       (void *) iter->enumeration_ft, iter->index,
-                       mapping_name, range_begin, range_end);
-}
-
-/*
- * Note: This algorithm is O(n^2) vs number of enumeration mappings.
- * Only used when freezing an enumeration.
- */
-static
-void bt_ctf_field_type_common_enumeration_set_range_overlap(
-               struct bt_ctf_field_type_common_enumeration *ft)
-{
-       int64_t i, j, len;
-       int is_signed;
-
-       BT_LOGV("Setting enumeration field type's overlap flag: addr=%p",
-               ft);
-       len = ft->entries->len;
-       is_signed = bt_ctf_field_type_common_integer_is_signed(
-               BT_CTF_TO_COMMON(ft->container_ft));
-
-       for (i = 0; i < len; i++) {
-               for (j = i + 1; j < len; j++) {
-                       struct bt_ctf_enumeration_mapping *mapping[2];
-
-                       mapping[0] = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-                               BT_CTF_TO_COMMON(ft), i);
-                       mapping[1] = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-                               BT_CTF_TO_COMMON(ft), j);
-                       if (is_signed) {
-                               if (mapping[0]->range_start._signed
-                                                       <= mapping[1]->range_end._signed
-                                               && mapping[0]->range_end._signed
-                                                       >= mapping[1]->range_start._signed) {
-                                       ft->has_overlapping_ranges = BT_TRUE;
-                                       goto end;
-                               }
-                       } else {
-                               if (mapping[0]->range_start._unsigned
-                                                       <= mapping[1]->range_end._unsigned
-                                               && mapping[0]->range_end._unsigned
-                                                       >= mapping[1]->range_start._unsigned) {
-                                       ft->has_overlapping_ranges = BT_TRUE;
-                                       goto end;
-                               }
-                       }
-               }
-       }
-
-end:
-       if (ft->has_overlapping_ranges) {
-               BT_LOGV_STR("Enumeration field type has overlapping ranges.");
-       } else {
-               BT_LOGV_STR("Enumeration field type has no overlapping ranges.");
-       }
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       ret = bt_ctf_field_type_common_integer_validate(
-                       BT_CTF_TO_COMMON(enum_ft->container_ft));
-       if (ret) {
-               BT_LOGW("Invalid enumeration field type: container type is invalid: "
-                       "enum-ft-addr=%p, int-ft-addr=%p",
-                       ft, enum_ft->container_ft);
-               goto end;
-       }
-
-       /* Ensure enum has entries */
-       if (enum_ft->entries->len == 0) {
-               BT_LOGW("Invalid enumeration field type: no entries: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       /* Length field name should be set at this point */
-       if (seq_ft->length_field_name->len == 0) {
-               BT_LOGW("Invalid sequence field type: no length field name: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_validate(seq_ft->element_ft);
-       if (ret) {
-               BT_LOGW("Invalid sequence field type: invalid element field type: "
-                       "seq-ft-addr=%p, element-ft-add=%p",
-                       ft, seq_ft->element_ft);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       ret = bt_ctf_field_type_common_validate(array_ft->element_ft);
-       if (ret) {
-               BT_LOGW("Invalid array field type: invalid element field type: "
-                       "array-ft-addr=%p, element-ft-add=%p",
-                       ft, array_ft->element_ft);
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common *child_ft = NULL;
-       int64_t field_count =
-               bt_ctf_field_type_common_structure_get_field_count(ft);
-       int64_t i;
-
-       BT_ASSERT(field_count >= 0);
-
-       for (i = 0; i < field_count; ++i) {
-               const char *field_name;
-
-               ret = bt_ctf_field_type_common_structure_borrow_field_by_index(ft,
-                       &field_name, &child_ft, i);
-               BT_ASSERT(ret == 0);
-               ret = bt_ctf_field_type_common_validate(child_ft);
-               if (ret) {
-                       BT_LOGW("Invalid structure field type: "
-                               "a contained field type is invalid: "
-                               "struct-ft-addr=%p, field-ft-addr=%p, "
-                               "field-name=\"%s\", field-index=%" PRId64,
-                               ft, child_ft, field_name, i);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_bool bt_ctf_field_type_common_enumeration_has_overlapping_ranges(
-               struct bt_ctf_field_type_common_enumeration *enum_ft)
-{
-       if (!enum_ft->common.frozen) {
-               bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft);
-       }
-
-       return enum_ft->has_overlapping_ranges;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_validate_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-       int64_t field_count;
-       struct bt_ctf_field_type_common *child_ft = NULL;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       int64_t i;
-
-       if (var_ft->tag_name->len == 0) {
-               BT_LOGW("Invalid variant field type: no tag field name: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (!var_ft->tag_ft) {
-               BT_LOGW("Invalid variant field type: no tag field type: "
-                       "addr=%p, tag-field-name=\"%s\"", var_ft,
-                       var_ft->tag_name->str);
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_ctf_field_type_common_enumeration_has_overlapping_ranges(var_ft->tag_ft)) {
-               BT_LOGW("Invalid variant field type: enumeration tag field type has overlapping ranges: "
-                       "variant-ft-addr=%p, tag-field-name=\"%s\", "
-                       "enum-ft-addr=%p", ft, var_ft->tag_name->str,
-                       var_ft->tag_ft);
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * It is valid to have a variant field type which does not have
-        * the fields corresponding to each label in the associated
-        * enumeration.
-        *
-        * It is also valid to have variant field type fields which
-        * cannot be selected because the variant field type tag has no
-        * mapping named as such. This scenario, while not ideal, cannot
-        * cause any error.
-        *
-        * If a non-existing field happens to be selected by an
-        * enumeration while reading a variant field, an error will be
-        * generated at that point (while reading the stream).
-        */
-       field_count = bt_ctf_field_type_common_variant_get_field_count(ft);
-       if (field_count < 0) {
-               BT_LOGW("Invalid variant field type: no fields: "
-                       "addr=%p, tag-field-name=\"%s\"",
-                       ft, var_ft->tag_name->str);
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; i < field_count; ++i) {
-               const char *field_name;
-
-               ret = bt_ctf_field_type_common_variant_borrow_field_by_index(ft,
-                       &field_name, &child_ft, i);
-               BT_ASSERT(ret == 0);
-               ret = bt_ctf_field_type_common_validate(child_ft);
-               if (ret) {
-                       BT_LOGW("Invalid variant field type: "
-                               "a contained field type is invalid: "
-                               "variant-ft-addr=%p, tag-field-name=\"%s\", "
-                               "field-ft-addr=%p, field-name=\"%s\", "
-                               "field-index=%" PRId64,
-                               ft, var_ft->tag_name->str, child_ft,
-                               field_name, i);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * This function validates a given field type without considering
- * where this field type is located. It only validates the properties
- * of the given field type and the properties of its children if
- * applicable.
- */
-BT_HIDDEN
-int bt_ctf_field_type_common_validate(struct bt_ctf_field_type_common *ft)
-{
-       int ret = 0;
-
-       BT_ASSERT(ft);
-
-       if (ft->valid) {
-               /* Already marked as valid */
-               goto end;
-       }
-
-       if (ft->methods->validate) {
-               ret = ft->methods->validate(ft);
-       }
-
-       if (ret == 0 && ft->frozen) {
-               /* Field type is valid */
-               BT_LOGV("Marking field type as valid: addr=%p", ft);
-               ft->valid = 1;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_get_size(struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return (int) int_ft->size;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_type_common_integer_is_signed(struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->is_signed;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_is_signed(struct bt_ctf_field_type_common *ft,
-               bt_bool is_signed)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       int_ft->is_signed = !!is_signed;
-       BT_LOGV("Set integer field type's signedness: addr=%p, is-signed=%d",
-               ft, is_signed);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_size(struct bt_ctf_field_type_common *ft,
-               unsigned int size)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (size == 0 || size > 64) {
-               BT_LOGW("Invalid parameter: size must be between 1 and 64: "
-                       "addr=%p, size=%u", ft, size);
-               ret = -1;
-               goto end;
-       }
-
-       int_ft->size = size;
-       BT_LOGV("Set integer field type's size: addr=%p, size=%u",
-               ft, size);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_integer_base bt_ctf_field_type_common_integer_get_base(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->base;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_base(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_integer_base base)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       switch (base) {
-       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
-       case BT_CTF_INTEGER_BASE_BINARY:
-       case BT_CTF_INTEGER_BASE_OCTAL:
-       case BT_CTF_INTEGER_BASE_DECIMAL:
-       case BT_CTF_INTEGER_BASE_HEXADECIMAL:
-       {
-               int_ft->base = base;
-               break;
-       }
-       default:
-               BT_LOGW("Invalid parameter: unknown integer field type base: "
-                       "addr=%p, base=%d", ft, base);
-               ret = -1;
-       }
-
-       BT_LOGV("Set integer field type's base: addr=%p, base=%s",
-               ft, bt_ctf_integer_base_string(base));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_string_encoding bt_ctf_field_type_common_integer_get_encoding(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->encoding;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_encoding(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_string_encoding encoding)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (encoding != BT_CTF_STRING_ENCODING_UTF8 &&
-                       encoding != BT_CTF_STRING_ENCODING_ASCII &&
-                       encoding != BT_CTF_STRING_ENCODING_NONE) {
-               BT_LOGW("Invalid parameter: unknown string encoding: "
-                       "addr=%p, encoding=%d", ft, encoding);
-               ret = -1;
-               goto end;
-       }
-
-       int_ft->encoding = encoding;
-       BT_LOGV("Set integer field type's encoding: addr=%p, encoding=%s",
-               ft, bt_ctf_string_encoding_string(encoding));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
-               "Field type");
-       return int_ft->mapped_clock_class;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_clock_class *clock_class)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-       int ret = 0;
-
-       if (!clock_class) {
-               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: field type is not an integer field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               goto end;
-       }
-
-       if (!bt_ctf_clock_class_is_valid(clock_class)) {
-               BT_LOGW("Invalid parameter: clock class is invalid: ft-addr=%p"
-                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                       ft, clock_class,
-                       bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(int_ft->mapped_clock_class);
-       int_ft->mapped_clock_class = bt_ctf_object_get_ref(clock_class);
-       BT_LOGV("Set integer field type's mapped clock class: ft-addr=%p, "
-               "clock-class-addr=%p, clock-class-name=\"%s\"",
-               ft, clock_class, bt_ctf_clock_class_get_name(clock_class));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_mapped_clock_class(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_clock_class *clock_class)
-{
-       int ret = 0;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
-               ft, clock_class);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
-               struct bt_ctf_field_type_common *ft, uint64_t index,
-               const char **mapping_name, int64_t *range_begin,
-               int64_t *range_end)
-{
-       int ret = 0;
-       struct bt_ctf_enumeration_mapping *mapping;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft,
-               BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
-       mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(ft,
-               index);
-       if (!mapping) {
-               /* bt_ctf_field_type_common_enumeration_get_mapping_by_index() logs errors */
-               ret = -1;
-               goto end;
-       }
-
-       if (mapping_name) {
-               *mapping_name = g_quark_to_string(mapping->string);
-               BT_ASSERT(*mapping_name);
-       }
-
-       if (range_begin) {
-               *range_begin = mapping->range_start._signed;
-       }
-
-       if (range_end) {
-               *range_end = mapping->range_end._signed;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
-               struct bt_ctf_field_type_common *ft, uint64_t index,
-               const char **mapping_name, uint64_t *range_begin,
-               uint64_t *range_end)
-{
-       int ret = 0;
-       struct bt_ctf_enumeration_mapping *mapping;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
-       mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
-               ft, index);
-       if (!mapping) {
-               /* bt_ctf_field_type_common_enumeration_get_mapping_by_index() reports any error */
-               ret = -1;
-               goto end;
-       }
-
-       if (mapping_name) {
-               *mapping_name = g_quark_to_string(mapping->string);
-               BT_ASSERT(*mapping_name);
-       }
-
-       if (range_begin) {
-               *range_begin = mapping->range_start._unsigned;
-       }
-
-       if (range_end) {
-               *range_end = mapping->range_end._unsigned;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_enumeration_borrow_container_field_type(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
-       return BT_CTF_TO_COMMON(enum_ft->container_ft);
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_signed_add_mapping(
-               struct bt_ctf_field_type_common *ft, const char *string,
-               int64_t range_start, int64_t range_end)
-{
-       int ret = 0;
-       GQuark mapping_name;
-       struct bt_ctf_enumeration_mapping *mapping;
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-       char *escaped_string;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!string) {
-               BT_LOGW_STR("Invalid parameter: string is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) {
-               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (range_end < range_start) {
-               BT_LOGW("Invalid parameter: range's end is lesser than range's start: "
-                       "addr=%p, range-start=%" PRId64 ", range-end=%" PRId64,
-                       ft, range_start, range_end);
-               ret = -1;
-               goto end;
-       }
-
-       if (strlen(string) == 0) {
-               BT_LOGW("Invalid parameter: mapping name is an empty string: "
-                       "enum-ft-addr=%p, mapping-name-addr=%p", ft,
-                       string);
-               ret = -1;
-               goto end;
-       }
-
-       escaped_string = g_strescape(string, NULL);
-       if (!escaped_string) {
-               BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, "
-                       "mapping-name-addr=%p, mapping-name=\"%s\"",
-                       ft, string, string);
-               ret = -1;
-               goto end;
-       }
-
-       mapping = g_new(struct bt_ctf_enumeration_mapping, 1);
-       if (!mapping) {
-               BT_LOGE_STR("Failed to allocate one enumeration mapping.");
-               ret = -1;
-               goto error_free;
-       }
-       mapping_name = g_quark_from_string(escaped_string);
-       *mapping = (struct bt_ctf_enumeration_mapping) {
-               .range_start._signed = range_start,
-               .range_end._signed = range_end,
-               .string =  mapping_name,
-       };
-       g_ptr_array_add(enum_ft->entries, mapping);
-       g_ptr_array_sort(enum_ft->entries,
-               (GCompareFunc) compare_enumeration_mappings_signed);
-       BT_LOGV("Added mapping to signed enumeration field type: addr=%p, "
-               "name=\"%s\", range-start=%" PRId64 ", "
-               "range-end=%" PRId64,
-               ft, string, range_start, range_end);
-
-error_free:
-       free(escaped_string);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
-               struct bt_ctf_field_type_common *ft, const char *string,
-               uint64_t range_start, uint64_t range_end)
-{
-       int ret = 0;
-       GQuark mapping_name;
-       struct bt_ctf_enumeration_mapping *mapping;
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-       char *escaped_string;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!string) {
-               BT_LOGW_STR("Invalid parameter: string is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) {
-               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (range_end < range_start) {
-               BT_LOGW("Invalid parameter: range's end is lesser than range's start: "
-                       "addr=%p, range-start=%" PRIu64 ", range-end=%" PRIu64,
-                       ft, range_start, range_end);
-               ret = -1;
-               goto end;
-       }
-
-       if (strlen(string) == 0) {
-               BT_LOGW("Invalid parameter: mapping name is an empty string: "
-                       "enum-ft-addr=%p, mapping-name-addr=%p", ft,
-                       string);
-               ret = -1;
-               goto end;
-       }
-
-       escaped_string = g_strescape(string, NULL);
-       if (!escaped_string) {
-               BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, "
-                       "mapping-name-addr=%p, mapping-name=\"%s\"",
-                       ft, string, string);
-               ret = -1;
-               goto end;
-       }
-
-       mapping = g_new(struct bt_ctf_enumeration_mapping, 1);
-       if (!mapping) {
-               BT_LOGE_STR("Failed to allocate one enumeration mapping.");
-               ret = -1;
-               goto error_free;
-       }
-       mapping_name = g_quark_from_string(escaped_string);
-       *mapping = (struct bt_ctf_enumeration_mapping) {
-               .range_start._unsigned = range_start,
-               .range_end._unsigned = range_end,
-               .string = mapping_name,
-       };
-       g_ptr_array_add(enum_ft->entries, mapping);
-       g_ptr_array_sort(enum_ft->entries,
-               (GCompareFunc) compare_enumeration_mappings_unsigned);
-       BT_LOGV("Added mapping to unsigned enumeration field type: addr=%p, "
-               "name=\"%s\", range-start=%" PRIu64 ", "
-               "range-end=%" PRIu64,
-               ft, string, range_start, range_end);
-
-error_free:
-       free(escaped_string);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_enumeration_get_mapping_count(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
-       return (int64_t) enum_ft->entries->len;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_get_exponent_digits(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT,
-               "Field type");
-       return (int) flt_ft->exp_dig;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_set_exponent_digits(
-               struct bt_ctf_field_type_common *ft,
-               unsigned int exponent_digits)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_FLOAT) {
-               BT_LOGW("Invalid parameter: field type is not a floating point number field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) &&
-               (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) &&
-               (exponent_digits !=
-                       sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) {
-               BT_LOGW("Invalid parameter: invalid exponent size: "
-                       "addr=%p, exp-size=%u", ft, exponent_digits);
-               ret = -1;
-               goto end;
-       }
-
-       flt_ft->exp_dig = exponent_digits;
-       BT_LOGV("Set floating point number field type's exponent size: addr=%p, "
-               "exp-size=%u", ft, exponent_digits);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_get_mantissa_digits(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT,
-               "Field type");
-       return (int) flt_ft->mant_dig;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_set_mantissa_digits(
-               struct bt_ctf_field_type_common *ft, unsigned int mantissa_digits)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_FLOAT) {
-               BT_LOGW("Invalid parameter: field type is not a floating point number field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if ((mantissa_digits != FLT_MANT_DIG) &&
-               (mantissa_digits != DBL_MANT_DIG) &&
-               (mantissa_digits != LDBL_MANT_DIG)) {
-               BT_LOGW("Invalid parameter: invalid mantissa size: "
-                       "addr=%p, mant-size=%u", ft, mantissa_digits);
-               ret = -1;
-               goto end;
-       }
-
-       flt_ft->mant_dig = mantissa_digits;
-       BT_LOGV("Set floating point number field type's mantissa size: addr=%p, "
-               "mant-size=%u", ft, mantissa_digits);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_replace_field(
-               struct bt_ctf_field_type_common *ft,
-               const char *field_name,
-               struct bt_ctf_field_type_common *field_type)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-       GQuark name_quark;
-       uint64_t i;
-
-       BT_ASSERT(ft);
-       BT_ASSERT(field_name);
-       BT_ASSERT(field_type);
-       BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_STRUCT);
-       name_quark = g_quark_from_string(field_name);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i);
-
-               if (field->name == name_quark) {
-                       bt_ctf_object_put_ref(field->type);
-                       field->type = bt_ctf_object_get_ref(field_type);
-               }
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_add_field(struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *field_type,
-               const char *field_name)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       /*
-        * TODO: check that `field_type` does not contain `type`,
-        *       recursively.
-        */
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!field_name) {
-               BT_LOGW_STR("Invalid parameter: field name is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: field type is not a structure field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (ft == field_type) {
-               BT_LOGW("Invalid parameter: structure field type and field type to add are the same: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (add_structure_variant_member(struct_ft->fields,
-                       struct_ft->field_name_to_index, field_type, field_name,
-                       false)) {
-               BT_LOGW("Cannot add field to structure field type: "
-                       "struct-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-                       ft, field_type, field_name);
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Added structure field type field: struct-ft-addr=%p, "
-               "field-ft-addr=%p, field-name=\"%s\"", ft,
-               field_type, field_name);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_structure_get_field_count(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-       return (int64_t) struct_ft->fields->len;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_borrow_field_by_index(
-               struct bt_ctf_field_type_common *ft,
-               const char **field_name,
-               struct bt_ctf_field_type_common **field_type, uint64_t index)
-{
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common_structure_field *field;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-       BT_CTF_ASSERT_PRE(index < struct_ft->fields->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u, ft-addr=%p",
-               index, struct_ft->fields->len, ft);
-       field = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(struct_ft, index);
-
-       if (field_type) {
-               *field_type = field->type;
-       }
-
-       if (field_name) {
-               *field_name = g_quark_to_string(field->name);
-               BT_ASSERT(*field_name);
-       }
-
-       return 0;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       size_t index;
-       GQuark name_quark;
-       struct bt_ctf_field_type_common_structure_field *field;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-       name_quark = g_quark_try_string(name);
-       if (!name_quark) {
-               BT_LOGV("No such structure field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               goto end;
-       }
-
-       if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index,
-                       GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) {
-               BT_LOGV("No such structure field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               goto end;
-       }
-
-       field = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, index);
-       field_type = field->type;
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_tag_field_type(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common *tag_ft = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-
-       if (!var_ft->tag_ft) {
-               BT_LOGV("Variant field type has no tag field type: "
-                       "addr=%p", ft);
-               goto end;
-       }
-
-       tag_ft = BT_CTF_TO_COMMON(var_ft->tag_ft);
-
-end:
-       return tag_ft;
-}
-
-BT_HIDDEN
-const char *bt_ctf_field_type_common_variant_get_tag_name(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       const char *tag_name = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-
-       if (var_ft->tag_name->len == 0) {
-               BT_LOGV("Variant field type has no tag field name: "
-                       "addr=%p", ft);
-               goto end;
-       }
-
-       tag_name = var_ft->tag_name->str;
-
-end:
-       return tag_name;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_set_tag_name(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft, bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_identifier_is_valid(name)) {
-               BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: "
-                       "variant-ft-addr=%p, tag-field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       g_string_assign(var_ft->tag_name, name);
-       BT_LOGV("Set variant field type's tag field name: addr=%p, "
-               "tag-field-name=\"%s\"", ft, name);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_add_field(struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *field_type,
-               const char *field_name)
-{
-       size_t i;
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       GQuark field_name_quark = g_quark_from_string(field_name);
-
-       /*
-        * TODO: check that `field_type` does not contain `type`,
-        *       recursively.
-        */
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (ft == field_type) {
-               BT_LOGW("Invalid parameter: variant field type and field type to add are the same: "
-                       "addr=%p", ft);
-               ret = -1;
-               goto end;
-       }
-
-       /* The user has explicitly provided a tag; validate against it. */
-       if (var_ft->tag_ft) {
-               int name_found = 0;
-
-               /* Make sure this name is present in the enum tag */
-               for (i = 0; i < var_ft->tag_ft->entries->len; i++) {
-                       struct bt_ctf_enumeration_mapping *mapping =
-                               g_ptr_array_index(var_ft->tag_ft->entries, i);
-
-                       if (mapping->string == field_name_quark) {
-                               name_found = 1;
-                               break;
-                       }
-               }
-
-               if (!name_found) {
-                       /* Validation failed */
-                       BT_LOGW("Invalid parameter: field name does not name a tag field type's mapping: "
-                               "variant-ft-addr=%p, tag-ft-addr=%p, "
-                               "tag-field-name=\"%s\""
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               ft, var_ft->tag_ft, var_ft->tag_name->str,
-                               field_type, field_name);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       if (add_structure_variant_member(var_ft->choices,
-                       var_ft->choice_name_to_index, field_type,
-                       field_name, true)) {
-               BT_LOGW("Cannot add field to variant field type: "
-                       "variant-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"",
-                       ft, field_type, field_name);
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Added variant field type field: variant-ft-addr=%p, "
-               "field-ft-addr=%p, field-name=\"%s\"", ft,
-               field_type, field_name);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_by_name(
-               struct bt_ctf_field_type_common *ft,
-               const char *field_name)
-{
-       size_t index;
-       GQuark name_quark;
-       struct bt_ctf_field_type_common_variant_choice *choice;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_NON_NULL(field_name, "Name");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       name_quark = g_quark_try_string(field_name);
-       if (!name_quark) {
-               BT_LOGV("No such variant field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, field_name);
-               goto end;
-       }
-
-       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
-                       GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) {
-               BT_LOGV("No such variant field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, field_name);
-               goto end;
-       }
-
-       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index);
-       field_type = choice->type;
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_variant_get_field_count(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Variant field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       return (int64_t) var_ft->choices->len;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_borrow_field_by_index(
-               struct bt_ctf_field_type_common *ft,
-               const char **field_name,
-               struct bt_ctf_field_type_common **field_type, uint64_t index)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common_variant_choice *choice;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       BT_CTF_ASSERT_PRE(index < var_ft->choices->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u, ft-addr=%p",
-               index, var_ft->choices->len, ft);
-       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index);
-
-       if (field_type) {
-               *field_type = choice->type;
-       }
-
-       if (field_name) {
-               *field_name = g_quark_to_string(choice->name);
-               BT_ASSERT(*field_name);
-       }
-
-       return 0;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_variant_find_choice_index(
-               struct bt_ctf_field_type_common *ft, uint64_t uval,
-               bool is_signed)
-{
-       int64_t ret;
-       uint64_t i;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_ASSERT(ft);
-       BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_VARIANT);
-
-       if (bt_ctf_field_type_common_variant_update_choices(ft)) {
-               ret = INT64_C(-1);
-               goto end;
-       }
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               uint64_t range_i;
-               struct bt_ctf_field_type_common_variant_choice *choice =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               var_ft, i);
-
-               for (range_i = 0; range_i < choice->ranges->len; range_i++) {
-                       struct bt_ctf_field_type_common_variant_choice_range *range =
-                               &g_array_index(
-                                       choice->ranges,
-                                       struct bt_ctf_field_type_common_variant_choice_range,
-                                       range_i);
-
-                       if (is_signed) {
-                               int64_t tag_ival = (int64_t) uval;
-
-                               if (tag_ival >= range->lower.i &&
-                                               tag_ival <= range->upper.i) {
-                                       goto found;
-                               }
-                       } else {
-                               if (uval >= range->lower.u &&
-                                               uval <= range->upper.u) {
-                                       goto found;
-                               }
-                       }
-               }
-       }
-
-       /* Range not found */
-       ret = INT64_C(-1);
-       goto end;
-
-found:
-       ret = (int64_t) i;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_array_borrow_element_field_type(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY,
-               "Field type");
-       BT_ASSERT(array_ft && array_ft->element_ft);
-       return array_ft->element_ft;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_set_element_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: array field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!element_ft) {
-               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_ARRAY) {
-               BT_LOGW("Invalid parameter: field type is not an array field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (array_ft->element_ft) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(array_ft->element_ft);
-       }
-
-       array_ft->element_ft = bt_ctf_object_get_ref(element_ft);
-       BT_LOGV("Set array field type's element field type: array-ft-addr=%p, "
-               "element-ft-addr=%p", ft, element_ft);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_array_get_length(struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY,
-               "Field type");
-       return (int64_t) array_ft->length;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *bt_ctf_field_type_common_sequence_borrow_element_field_type(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->element_ft;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_set_element_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: sequence field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!element_ft) {
-               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
-               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (seq_ft->element_ft) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(seq_ft->element_ft);
-       }
-
-       seq_ft->element_ft = element_ft;
-       bt_ctf_object_get_ref(seq_ft->element_ft);
-       BT_LOGV("Set sequence field type's element field type: sequence-ft-addr=%p, "
-               "element-ft-addr=%p", ft, element_ft);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-const char *bt_ctf_field_type_common_sequence_get_length_field_name(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->length_field_name ?
-               seq_ft->length_field_name->str : NULL;
-}
-
-BT_HIDDEN
-enum bt_ctf_string_encoding bt_ctf_field_type_common_string_get_encoding(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRING,
-               "Field type");
-       return string_ft->encoding;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_string_set_encoding(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_string_encoding encoding)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_STRING) {
-               BT_LOGW("Invalid parameter: field type is not a string field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       if (encoding != BT_CTF_STRING_ENCODING_UTF8 &&
-                       encoding != BT_CTF_STRING_ENCODING_ASCII) {
-               BT_LOGW("Invalid parameter: unknown string encoding: "
-                       "addr=%p, encoding=%d", ft, encoding);
-               ret = -1;
-               goto end;
-       }
-
-       string_ft->encoding = encoding;
-       BT_LOGV("Set string field type's encoding: addr=%p, encoding=%s",
-               ft, bt_ctf_string_encoding_string(encoding));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_get_alignment(struct bt_ctf_field_type_common *ft)
-{
-       int ret;
-       enum bt_ctf_field_type_id type_id;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-
-       if (ft->frozen) {
-               ret = (int) ft->alignment;
-               goto end;
-       }
-
-       type_id = bt_ctf_field_type_common_get_type_id(ft);
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       {
-               struct bt_ctf_field_type_common *element_ft =
-                       bt_ctf_field_type_common_sequence_borrow_element_field_type(ft);
-
-               BT_ASSERT(element_ft);
-               ret = bt_ctf_field_type_common_get_alignment(element_ft);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       {
-               struct bt_ctf_field_type_common *element_ft =
-                       bt_ctf_field_type_common_array_borrow_element_field_type(ft);
-
-               BT_ASSERT(element_ft);
-               ret = bt_ctf_field_type_common_get_alignment(element_ft);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               int64_t i, element_count;
-
-               element_count = bt_ctf_field_type_common_structure_get_field_count(
-                       ft);
-               BT_ASSERT(element_count >= 0);
-
-               for (i = 0; i < element_count; i++) {
-                       struct bt_ctf_field_type_common *field = NULL;
-                       int field_alignment;
-
-                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               ft, NULL, &field, i);
-                       BT_ASSERT(ret == 0);
-                       BT_ASSERT(field);
-                       field_alignment = bt_ctf_field_type_common_get_alignment(
-                               field);
-                       if (field_alignment < 0) {
-                               ret = field_alignment;
-                               goto end;
-                       }
-
-                       ft->alignment = MAX(field_alignment, ft->alignment);
-               }
-               ret = (int) ft->alignment;
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_UNKNOWN:
-               BT_LOGW("Invalid parameter: unknown field type ID: "
-                       "addr=%p, ft-id=%d", ft, type_id);
-               ret = -1;
-               break;
-       default:
-               ret = (int) ft->alignment;
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int is_power_of_two(unsigned int value)
-{
-       return ((value & (value - 1)) == 0) && value > 0;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_set_alignment(struct bt_ctf_field_type_common *ft,
-               unsigned int alignment)
-{
-       int ret = 0;
-       enum bt_ctf_field_type_id type_id;
-
-       /* Alignment must be a power of two */
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (!is_power_of_two(alignment)) {
-               BT_LOGW("Invalid parameter: alignment is not a power of two: "
-                       "addr=%p, align=%u", ft, alignment);
-               ret = -1;
-               goto end;
-       }
-
-       type_id = bt_ctf_field_type_common_get_type_id(ft);
-       if (type_id == BT_CTF_FIELD_TYPE_ID_UNKNOWN) {
-               BT_LOGW("Invalid parameter: unknown field type ID: "
-                       "addr=%p, ft-id=%d", ft, type_id);
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id == BT_CTF_FIELD_TYPE_ID_STRING && alignment != CHAR_BIT) {
-               BT_LOGW("Invalid parameter: alignment must be %u for a string field type: "
-                       "addr=%p, align=%u", CHAR_BIT, ft, alignment);
-               ret = -1;
-               goto end;
-       }
-
-       if (type_id == BT_CTF_FIELD_TYPE_ID_VARIANT ||
-                       type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE ||
-                       type_id == BT_CTF_FIELD_TYPE_ID_ARRAY) {
-               /* Setting an alignment on these types makes no sense */
-               BT_LOGW("Invalid parameter: cannot set the alignment of this field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       ft->alignment = alignment;
-       ret = 0;
-       BT_LOGV("Set field type's alignment: addr=%p, align=%u",
-               ft, alignment);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_byte_order bt_ctf_field_type_common_get_byte_order(
-               struct bt_ctf_field_type_common *ft)
-{
-       enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_INTEGER:
-       {
-               struct bt_ctf_field_type_common_integer *integer =
-                       BT_CTF_FROM_COMMON(ft);
-
-               ret = integer->user_byte_order;
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ENUM:
-       {
-               struct bt_ctf_field_type_common_enumeration *enum_ft =
-                       BT_CTF_FROM_COMMON(ft);
-
-               ret = bt_ctf_field_type_common_get_byte_order(
-                       BT_CTF_TO_COMMON(enum_ft->container_ft));
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_FLOAT:
-       {
-               struct bt_ctf_field_type_common_floating_point *floating_point =
-                       BT_CTF_FROM_COMMON(ft);
-               ret = floating_point->user_byte_order;
-               break;
-       }
-       default:
-               BT_LOGW("Invalid parameter: cannot get the byte order of this field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               goto end;
-       }
-
-       BT_ASSERT(ret == BT_CTF_BYTE_ORDER_NATIVE ||
-               ret == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
-               ret == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
-               ret == BT_CTF_BYTE_ORDER_NETWORK);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_set_byte_order(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       int ret = 0;
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->frozen) {
-               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
-                       ft);
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order != BT_CTF_BYTE_ORDER_NATIVE &&
-                       byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
-                       byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
-                       byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
-               BT_LOGW("Invalid parameter: invalid byte order: "
-                       "addr=%p, bo=%s", ft,
-                       bt_ctf_byte_order_string(byte_order));
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->methods->set_byte_order) {
-               ft->methods->set_byte_order(ft, byte_order);
-       }
-
-       BT_LOGV("Set field type's byte order: addr=%p, bo=%s",
-               ft, bt_ctf_byte_order_string(byte_order));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_field_type_id bt_ctf_field_type_common_get_type_id(
-               struct bt_ctf_field_type_common *ft)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       return ft->id;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_freeze(struct bt_ctf_field_type_common *ft)
-{
-       if (!ft || ft->frozen) {
-               return;
-       }
-
-       BT_ASSERT(ft->methods->freeze);
-       ft->methods->freeze(ft);
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_signed(
-               struct bt_ctf_field_type_common_variant *var_ft,
-               int64_t tag_value)
-{
-       struct bt_ctf_field_type_common *field_type = NULL;
-       GQuark field_name_quark;
-       gpointer index;
-       struct bt_ctf_field_type_common_variant_choice *choice;
-       struct range_overlap_query query = {
-               .range_start._signed = tag_value,
-               .range_end._signed = tag_value,
-               .mapping_name = 0,
-               .overlaps = 0,
-       };
-
-       g_ptr_array_foreach(var_ft->tag_ft->entries, check_ranges_overlap,
-               &query);
-       if (!query.overlaps) {
-               goto end;
-       }
-
-       field_name_quark = query.mapping_name;
-       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
-                       GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
-               goto end;
-       }
-
-       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
-               (size_t) index);
-       field_type = choice->type;
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_unsigned(
-               struct bt_ctf_field_type_common_variant *var_ft,
-               uint64_t tag_value)
-{
-       struct bt_ctf_field_type_common *field_type = NULL;
-       GQuark field_name_quark;
-       gpointer index;
-       struct bt_ctf_field_type_common_variant_choice *choice;
-       struct range_overlap_query query = {
-               .range_start._unsigned = tag_value,
-               .range_end._unsigned = tag_value,
-               .mapping_name = 0,
-               .overlaps = 0,
-       };
-
-       g_ptr_array_foreach(var_ft->tag_ft->entries,
-               check_ranges_overlap_unsigned, &query);
-       if (!query.overlaps) {
-               goto end;
-       }
-
-       field_name_quark = query.mapping_name;
-       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
-               GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
-               goto end;
-       }
-
-       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
-               (size_t) index);
-       field_type = choice->type;
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *bt_ctf_field_type_common_copy(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common *ft_copy = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_ASSERT(ft->methods->copy);
-       ft_copy = ft->methods->copy(ft);
-       if (!ft_copy) {
-               BT_LOGE_STR("Cannot copy field type.");
-               goto end;
-       }
-
-       ft_copy->alignment = ft->alignment;
-
-end:
-       return ft_copy;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_get_field_name_index(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       int ret;
-       size_t index;
-       GQuark name_quark;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
-               "Field type");
-
-       name_quark = g_quark_try_string(name);
-       if (!name_quark) {
-               BT_LOGV("No such structure field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index,
-                       GUINT_TO_POINTER(name_quark),
-                       NULL, (gpointer *) &index)) {
-               BT_LOGV("No such structure field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       ret = (int) index;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_get_field_name_index(
-               struct bt_ctf_field_type_common *ft, const char *name)
-{
-       int ret;
-       size_t index;
-       GQuark name_quark;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       name_quark = g_quark_try_string(name);
-       if (!name_quark) {
-               BT_LOGV("No such variant field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
-                       GUINT_TO_POINTER(name_quark),
-                       NULL, (gpointer *) &index)) {
-               BT_LOGV("No such variant field type field name: "
-                       "ft-addr=%p, field-name=\"%s\"",
-                       ft, name);
-               ret = -1;
-               goto end;
-       }
-
-       ret = (int) index;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_set_length_field_path(
-               struct bt_ctf_field_type_common *ft, struct bt_ctf_field_path *path)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
-               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_get_ref(path);
-       BT_CTF_OBJECT_MOVE_REF(seq_ft->length_field_path, path);
-       BT_LOGV("Set sequence field type's length field path: ft-addr=%p, "
-               "field-path-addr=%p", ft, path);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_set_tag_field_path(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_path *path)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
-               BT_LOGW("Invalid parameter: field type is not a variant field type: "
-                       "addr=%p, ft-id=%s", ft,
-                       bt_ctf_field_type_id_string(ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_get_ref(path);
-       BT_CTF_OBJECT_MOVE_REF(var_ft->tag_field_path, path);
-       BT_LOGV("Set variant field type's tag field path: ft-addr=%p, "
-               "field-path-addr=%p", ft, path);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_set_tag_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *tag_ft)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       if (!ft) {
-               BT_LOGW_STR("Invalid parameter: variant field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!tag_ft) {
-               BT_LOGW_STR("Invalid parameter: tag field type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (tag_ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) {
-               BT_LOGW("Invalid parameter: tag field type is not an enumeration field type: "
-                       "addr=%p, ft-id=%s", tag_ft,
-                       bt_ctf_field_type_id_string(tag_ft->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(var_ft->tag_ft);
-       var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft);
-       BT_LOGV("Set variant field type's tag field type: variant-ft-addr=%p, "
-               "tag-ft-addr=%p", ft, tag_ft);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_generic_freeze(struct bt_ctf_field_type_common *ft)
-{
-       ft->frozen = 1;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_LOGD("Freezing enumeration field type object: addr=%p", ft);
-       bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-       BT_LOGD("Freezing enumeration field type object's container field type: int-ft-addr=%p",
-               enum_ft->container_ft);
-       bt_ctf_field_type_common_freeze(BT_CTF_TO_COMMON(enum_ft->container_ft));
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-       uint64_t i;
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing structure field type object: addr=%p", ft);
-       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i);
-
-               BT_LOGD("Freezing structure field type field: "
-                       "ft-addr=%p, name=\"%s\"",
-                       field->type, g_quark_to_string(field->name));
-               bt_ctf_field_type_common_freeze(field->type);
-       }
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_update_choices(struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       uint64_t i;
-       int ret = 0;
-       bool is_signed;
-
-       if (ft->frozen && var_ft->choices_up_to_date) {
-               goto end;
-       }
-
-       BT_ASSERT(var_ft->tag_ft);
-       is_signed = !!var_ft->tag_ft->container_ft->is_signed;
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_ctf_field_type_common_variant_choice *choice =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i);
-               const char *choice_name = g_quark_to_string(choice->name);
-               struct bt_ctf_field_type_enumeration_mapping_iterator *iter =
-                       bt_ctf_field_type_common_enumeration_find_mappings_by_name(
-                               BT_CTF_TO_COMMON(var_ft->tag_ft), choice_name);
-
-               if (!iter) {
-                       ret = -1;
-                       goto end;
-               }
-
-               BT_ASSERT(choice->ranges);
-               g_array_set_size(choice->ranges, 0);
-
-               while (bt_ctf_field_type_enumeration_mapping_iterator_next(iter) == 0) {
-                       struct bt_ctf_field_type_common_variant_choice_range range;
-
-                       if (is_signed) {
-                               ret = bt_ctf_field_type_enumeration_mapping_iterator_signed_get(
-                                       iter, NULL,
-                                       &range.lower.i, &range.upper.i);
-                       } else {
-                               ret = bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get(
-                                       iter, NULL,
-                                       &range.lower.u, &range.upper.u);
-                       }
-
-                       BT_ASSERT(ret == 0);
-                       g_array_append_val(choice->ranges, range);
-               }
-
-               bt_ctf_object_put_ref(iter);
-       }
-
-       var_ft->choices_up_to_date = true;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-       uint64_t i;
-
-       BT_LOGD("Freezing variant field type object: addr=%p", ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_ctf_field_type_common_variant_choice *choice =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i);
-
-               BT_LOGD("Freezing variant field type member: "
-                       "ft-addr=%p, name=\"%s\"",
-                       choice->type, g_quark_to_string(choice->name));
-               bt_ctf_field_type_common_freeze(choice->type);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing array field type object: addr=%p", ft);
-       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-       BT_LOGD("Freezing array field type object's element field type: element-ft-addr=%p",
-               array_ft->element_ft);
-       bt_ctf_field_type_common_freeze(array_ft->element_ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_freeze_recursive(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       /* Cache the alignment */
-       BT_LOGD("Freezing sequence field type object: addr=%p", ft);
-       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
-       bt_ctf_field_type_common_generic_freeze(ft);
-       BT_LOGD("Freezing sequence field type object's element field type: element-ft-addr=%p",
-               seq_ft->element_ft);
-       bt_ctf_field_type_common_freeze(seq_ft->element_ft);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_set_byte_order(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
-
-       int_ft->user_byte_order = byte_order;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
-
-       bt_ctf_field_type_common_set_byte_order(BT_CTF_TO_COMMON(enum_ft->container_ft),
-               byte_order);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_set_byte_order(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-
-       flt_ft->user_byte_order = byte_order;
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       int i;
-       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                               struct_ft, i);
-               struct bt_ctf_field_type_common *field_type = field->type;
-
-               bt_ctf_field_type_common_set_byte_order(field_type, byte_order);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       int i;
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_ctf_field_type_common_variant_choice *choice =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               var_ft, i);
-               struct bt_ctf_field_type_common *field_type = choice->type;
-
-               bt_ctf_field_type_common_set_byte_order(field_type, byte_order);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
-
-       bt_ctf_field_type_common_set_byte_order(array_ft->element_ft, byte_order);
-}
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       bt_ctf_field_type_common_set_byte_order(seq_ft->element_ft, byte_order);
-}
-
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       struct bt_ctf_field_type_common_integer *int_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_integer *int_ft_b = BT_CTF_FROM_COMMON(ft_b);
-
-       /* Length */
-       if (int_ft_a->size != int_ft_b->size) {
-               BT_LOGV("Integer field types differ: different sizes: "
-                       "ft-a-size=%u, ft-b-size=%u",
-                       int_ft_a->size, int_ft_b->size);
-               goto end;
-       }
-
-       /* Byte order */
-       if (int_ft_a->user_byte_order != int_ft_b->user_byte_order) {
-               BT_LOGV("Integer field types differ: different byte orders: "
-                       "ft-a-bo=%s, ft-b-bo=%s",
-                       bt_ctf_byte_order_string(int_ft_a->user_byte_order),
-                       bt_ctf_byte_order_string(int_ft_b->user_byte_order));
-               goto end;
-       }
-
-       /* Signedness */
-       if (int_ft_a->is_signed != int_ft_b->is_signed) {
-               BT_LOGV("Integer field types differ: different signedness: "
-                       "ft-a-is-signed=%d, ft-b-is-signed=%d",
-                       int_ft_a->is_signed,
-                       int_ft_b->is_signed);
-               goto end;
-       }
-
-       /* Base */
-       if (int_ft_a->base != int_ft_b->base) {
-               BT_LOGV("Integer field types differ: different bases: "
-                       "ft-a-base=%s, ft-b-base=%s",
-                       bt_ctf_integer_base_string(int_ft_a->base),
-                       bt_ctf_integer_base_string(int_ft_b->base));
-               goto end;
-       }
-
-       /* Encoding */
-       if (int_ft_a->encoding != int_ft_b->encoding) {
-               BT_LOGV("Integer field types differ: different encodings: "
-                       "ft-a-encoding=%s, ft-b-encoding=%s",
-                       bt_ctf_string_encoding_string(int_ft_a->encoding),
-                       bt_ctf_string_encoding_string(int_ft_b->encoding));
-               goto end;
-       }
-
-       /* Mapped clock class */
-       if (int_ft_a->mapped_clock_class) {
-               if (!int_ft_b->mapped_clock_class) {
-                       BT_LOGV_STR("Integer field types differ: field type A "
-                               "has a mapped clock class, but field type B "
-                               "does not.");
-                       goto end;
-               }
-
-               if (bt_ctf_clock_class_compare(int_ft_a->mapped_clock_class,
-                               int_ft_b->mapped_clock_class) != 0) {
-                       BT_LOGV_STR("Integer field types differ: different "
-                               "mapped clock classes.");
-               }
-       } else {
-               if (int_ft_b->mapped_clock_class) {
-                       BT_LOGV_STR("Integer field types differ: field type A "
-                               "has no description, but field type B has one.");
-                       goto end;
-               }
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_compare(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       struct bt_ctf_field_type_common_floating_point *flt_ft_a =
-               BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_floating_point *flt_ft_b =
-               BT_CTF_FROM_COMMON(ft_b);
-
-       /* Byte order */
-       if (flt_ft_a->user_byte_order != flt_ft_b->user_byte_order) {
-               BT_LOGV("Floating point number field types differ: different byte orders: "
-                       "ft-a-bo=%s, ft-b-bo=%s",
-                       bt_ctf_byte_order_string(flt_ft_a->user_byte_order),
-                       bt_ctf_byte_order_string(flt_ft_b->user_byte_order));
-               goto end;
-       }
-
-       /* Exponent length */
-       if (flt_ft_a->exp_dig != flt_ft_b->exp_dig) {
-               BT_LOGV("Floating point number field types differ: different exponent sizes: "
-                       "ft-a-exp-size=%u, ft-b-exp-size=%u",
-                       flt_ft_a->exp_dig, flt_ft_b->exp_dig);
-               goto end;
-       }
-
-       /* Mantissa length */
-       if (flt_ft_a->mant_dig != flt_ft_b->mant_dig) {
-               BT_LOGV("Floating point number field types differ: different mantissa sizes: "
-                       "ft-a-mant-size=%u, ft-b-mant-size=%u",
-                       flt_ft_a->mant_dig, flt_ft_b->mant_dig);
-               goto end;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int compare_enumeration_mappings(struct bt_ctf_enumeration_mapping *mapping_a,
-               struct bt_ctf_enumeration_mapping *mapping_b)
-{
-       int ret = 1;
-
-       /* Label */
-       if (mapping_a->string != mapping_b->string) {
-               BT_LOGV("Enumeration field type mappings differ: different names: "
-                       "mapping-a-name=\"%s\", mapping-b-name=\"%s\"",
-                       g_quark_to_string(mapping_a->string),
-                       g_quark_to_string(mapping_b->string));
-               goto end;
-       }
-
-       /* Range start */
-       if (mapping_a->range_start._unsigned !=
-                       mapping_b->range_start._unsigned) {
-               BT_LOGV("Enumeration field type mappings differ: different starts of range: "
-                       "mapping-a-range-start-unsigned=%" PRIu64 ", "
-                       "mapping-b-range-start-unsigned=%" PRIu64,
-                       mapping_a->range_start._unsigned,
-                       mapping_b->range_start._unsigned);
-               goto end;
-       }
-
-       /* Range end */
-       if (mapping_a->range_end._unsigned !=
-                       mapping_b->range_end._unsigned) {
-               BT_LOGV("Enumeration field type mappings differ: different ends of range: "
-                       "mapping-a-range-end-unsigned=%" PRIu64 ", "
-                       "mapping-b-range-end-unsigned=%" PRIu64,
-                       mapping_a->range_end._unsigned,
-                       mapping_b->range_end._unsigned);
-               goto end;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_ctf_field_type_common_enumeration *enum_ft_a =
-               BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_enumeration *enum_ft_b =
-               BT_CTF_FROM_COMMON(ft_b);
-
-       /* Container field type */
-       ret = bt_ctf_field_type_common_compare(
-               BT_CTF_TO_COMMON(enum_ft_a->container_ft),
-               BT_CTF_TO_COMMON(enum_ft_b->container_ft));
-       if (ret) {
-               BT_LOGV("Enumeration field types differ: different container field types: "
-                       "ft-a-container-ft-addr=%p, ft-b-container-ft-addr=%p",
-                       enum_ft_a->container_ft, enum_ft_b->container_ft);
-               goto end;
-       }
-
-       ret = 1;
-
-       /* Entries */
-       if (enum_ft_a->entries->len != enum_ft_b->entries->len) {
-               goto end;
-       }
-
-       for (i = 0; i < enum_ft_a->entries->len; ++i) {
-               struct bt_ctf_enumeration_mapping *mapping_a =
-                       g_ptr_array_index(enum_ft_a->entries, i);
-               struct bt_ctf_enumeration_mapping *mapping_b =
-                       g_ptr_array_index(enum_ft_b->entries, i);
-
-               if (compare_enumeration_mappings(mapping_a, mapping_b)) {
-                       BT_LOGV("Enumeration field types differ: different mappings: "
-                               "ft-a-mapping-addr=%p, ft-b-mapping-addr=%p, "
-                               "ft-a-mapping-name=\"%s\", ft-b-mapping-name=\"%s\"",
-                               mapping_a, mapping_b,
-                               g_quark_to_string(mapping_a->string),
-                               g_quark_to_string(mapping_b->string));
-                       goto end;
-               }
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_string_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       struct bt_ctf_field_type_common_string *string_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_string *string_ft_b = BT_CTF_FROM_COMMON(ft_b);
-
-       /* Encoding */
-       if (string_ft_a->encoding != string_ft_b->encoding) {
-               BT_LOGV("String field types differ: different encodings: "
-                       "ft-a-encoding=%s, ft-b-encoding=%s",
-                       bt_ctf_string_encoding_string(string_ft_a->encoding),
-                       bt_ctf_string_encoding_string(string_ft_b->encoding));
-               goto end;
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int compare_structure_variant_members(
-               struct bt_ctf_field_type_common *member_a_ft,
-               struct bt_ctf_field_type_common *member_b_ft,
-               GQuark member_a_name, GQuark member_b_name)
-{
-       int ret = 1;
-
-       /* Label */
-       if (member_a_name != member_b_name) {
-               BT_LOGV("Structure/variant field type fields differ: different names: "
-                       "field-a-name=%s, field-b-name=%s",
-                       g_quark_to_string(member_a_name),
-                       g_quark_to_string(member_b_name));
-               goto end;
-       }
-
-       /* Type */
-       ret = bt_ctf_field_type_common_compare(member_a_ft, member_b_ft);
-       if (ret == 1) {
-               BT_LOGV("Structure/variant field type fields differ: different field types: "
-                       "field-name=\"%s\", field-a-ft-addr=%p, field-b-ft-addr=%p",
-                       g_quark_to_string(member_a_name),
-                       member_a_ft, member_b_ft);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_ctf_field_type_common_structure *struct_ft_a =
-               BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_structure *struct_ft_b =
-               BT_CTF_FROM_COMMON(ft_b);
-
-       /* Alignment */
-       if (bt_ctf_field_type_common_get_alignment(ft_a) !=
-                       bt_ctf_field_type_common_get_alignment(ft_b)) {
-               BT_LOGV("Structure field types differ: different alignments: "
-                       "ft-a-align=%u, ft-b-align=%u",
-                       bt_ctf_field_type_common_get_alignment(ft_a),
-                       bt_ctf_field_type_common_get_alignment(ft_b));
-               goto end;
-       }
-
-       /* Fields */
-       if (struct_ft_a->fields->len != struct_ft_b->fields->len) {
-               BT_LOGV("Structure field types differ: different field counts: "
-                       "ft-a-field-count=%u, ft-b-field-count=%u",
-                       struct_ft_a->fields->len, struct_ft_b->fields->len);
-               goto end;
-       }
-
-       for (i = 0; i < struct_ft_a->fields->len; ++i) {
-               struct bt_ctf_field_type_common_structure_field *field_a =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                               struct_ft_a, i);
-               struct bt_ctf_field_type_common_structure_field *field_b =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                               struct_ft_b, i);
-
-               ret = compare_structure_variant_members(field_a->type,
-                       field_b->type, field_a->name, field_b->name);
-               if (ret) {
-                       /* compare_structure_variant_members() logs what differs */
-                       BT_LOGV_STR("Structure field types differ: different fields.");
-                       goto end;
-               }
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       int i;
-       struct bt_ctf_field_type_common_variant *var_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_variant *var_ft_b = BT_CTF_FROM_COMMON(ft_b);
-
-       /* Tag name */
-       if (strcmp(var_ft_a->tag_name->str, var_ft_b->tag_name->str)) {
-               BT_LOGV("Variant field types differ: different tag field names: "
-                       "ft-a-tag-field-name=\"%s\", ft-b-tag-field-name=\"%s\"",
-                       var_ft_a->tag_name->str, var_ft_b->tag_name->str);
-               goto end;
-       }
-
-       /* Tag type */
-       ret = bt_ctf_field_type_common_compare(BT_CTF_TO_COMMON(var_ft_a->tag_ft),
-               BT_CTF_TO_COMMON(var_ft_b->tag_ft));
-       if (ret) {
-               BT_LOGV("Variant field types differ: different tag field types: "
-                       "ft-a-tag-ft-addr=%p, ft-b-tag-ft-addr=%p",
-                       var_ft_a->tag_ft, var_ft_b->tag_ft);
-               goto end;
-       }
-
-       ret = 1;
-
-       /* Fields */
-       if (var_ft_a->choices->len != var_ft_b->choices->len) {
-               BT_LOGV("Variant field types differ: different field counts: "
-                       "ft-a-field-count=%u, ft-b-field-count=%u",
-                       var_ft_a->choices->len, var_ft_b->choices->len);
-               goto end;
-       }
-
-       for (i = 0; i < var_ft_a->choices->len; ++i) {
-               struct bt_ctf_field_type_common_variant_choice *choice_a =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               var_ft_a, i);
-               struct bt_ctf_field_type_common_variant_choice *choice_b =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               var_ft_b, i);
-
-               ret = compare_structure_variant_members(choice_a->type,
-                       choice_b->type, choice_a->name, choice_b->name);
-               if (ret) {
-                       /* compare_structure_variant_members() logs what differs */
-                       BT_LOGV_STR("Variant field types differ: different fields.");
-                       goto end;
-               }
-       }
-
-       /* Equal */
-       ret = 0;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-       struct bt_ctf_field_type_common_array *array_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_array *array_ft_b = BT_CTF_FROM_COMMON(ft_b);
-
-       /* Length */
-       if (array_ft_a->length != array_ft_b->length) {
-               BT_LOGV("Structure field types differ: different lengths: "
-                       "ft-a-length=%u, ft-b-length=%u",
-                       array_ft_a->length, array_ft_b->length);
-               goto end;
-       }
-
-       /* Element type */
-       ret = bt_ctf_field_type_common_compare(array_ft_a->element_ft,
-               array_ft_b->element_ft);
-       if (ret == 1) {
-               BT_LOGV("Array field types differ: different element field types: "
-                       "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p",
-                       array_ft_a->element_ft, array_ft_b->element_ft);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = -1;
-       struct bt_ctf_field_type_common_sequence *seq_ft_a = BT_CTF_FROM_COMMON(ft_a);
-       struct bt_ctf_field_type_common_sequence *seq_ft_b = BT_CTF_FROM_COMMON(ft_b);
-
-       /* Length name */
-       if (strcmp(seq_ft_a->length_field_name->str,
-                       seq_ft_b->length_field_name->str)) {
-               BT_LOGV("Sequence field types differ: different length field names: "
-                       "ft-a-length-field-name=\"%s\", "
-                       "ft-b-length-field-name=\"%s\"",
-                       seq_ft_a->length_field_name->str,
-                       seq_ft_b->length_field_name->str);
-               goto end;
-       }
-
-       /* Element type */
-       ret = bt_ctf_field_type_common_compare(seq_ft_a->element_ft,
-                       seq_ft_b->element_ft);
-       if (ret == 1) {
-               BT_LOGV("Sequence field types differ: different element field types: "
-                       "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p",
-                       seq_ft_a->element_ft, seq_ft_b->element_ft);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b)
-{
-       int ret = 1;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft_a, "Field type A");
-       BT_CTF_ASSERT_PRE_NON_NULL(ft_b, "Field type B");
-
-       if (ft_a == ft_b) {
-               /* Same reference: equal (even if both are NULL) */
-               ret = 0;
-               goto end;
-       }
-
-       if (!ft_a) {
-               BT_LOGW_STR("Invalid parameter: field type A is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!ft_b) {
-               BT_LOGW_STR("Invalid parameter: field type B is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (ft_a->id != ft_b->id) {
-               /* Different type IDs */
-               BT_LOGV("Field types differ: different IDs: "
-                       "ft-a-addr=%p, ft-b-addr=%p, "
-                       "ft-a-id=%s, ft-b-id=%s",
-                       ft_a, ft_b,
-                       bt_ctf_field_type_id_string(ft_a->id),
-                       bt_ctf_field_type_id_string(ft_b->id));
-               goto end;
-       }
-
-       if (ft_a->id == BT_CTF_FIELD_TYPE_ID_UNKNOWN) {
-               /* Both have unknown type IDs */
-               BT_LOGW_STR("Invalid parameter: field type IDs are unknown.");
-               goto end;
-       }
-
-       BT_ASSERT(ft_a->methods->compare);
-       ret = ft_a->methods->compare(ft_a, ft_b);
-       if (ret == 1) {
-               BT_LOGV("Field types differ: ft-a-addr=%p, ft-b-addr=%p",
-                       ft_a, ft_b);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_get_field_count(struct bt_ctf_field_type_common *ft)
-{
-       int64_t field_count = -1;
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-               field_count =
-                       bt_ctf_field_type_common_structure_get_field_count(ft);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               field_count =
-                       bt_ctf_field_type_common_variant_get_field_count(ft);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               /*
-                * Array and sequence types always contain a single member
-                * (the element type).
-                */
-               field_count = 1;
-               break;
-       default:
-               break;
-       }
-
-       return field_count;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *bt_ctf_field_type_common_borrow_field_at_index(
-               struct bt_ctf_field_type_common *ft, int index)
-{
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               int ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                       ft, NULL, &field_type, index);
-               if (ret) {
-                       field_type = NULL;
-                       goto end;
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-       {
-               int ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
-                       ft, NULL, &field_type, index);
-               if (ret) {
-                       field_type = NULL;
-                       goto end;
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-               field_type =
-                       bt_ctf_field_type_common_array_borrow_element_field_type(ft);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               field_type =
-                       bt_ctf_field_type_common_sequence_borrow_element_field_type(ft);
-               break;
-       default:
-               break;
-       }
-
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_get_field_index(struct bt_ctf_field_type_common *ft,
-               const char *name)
-{
-       int field_index = -1;
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-               field_index = bt_ctf_field_type_common_structure_get_field_name_index(
-                       ft, name);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               field_index = bt_ctf_field_type_common_variant_get_field_name_index(
-                       ft, name);
-               break;
-       default:
-               break;
-       }
-
-       return field_index;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_type_common_variant_borrow_tag_field_path(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       return var_ft->tag_field_path;
-}
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_type_common_sequence_borrow_length_field_path(
-               struct bt_ctf_field_type_common *ft)
-{
-       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
-               "Field type");
-       return seq_ft->length_field_path;
-}
-
-BT_HIDDEN
-int bt_ctf_field_type_common_validate_single_clock_class(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_clock_class **expected_clock_class)
-{
-       int ret = 0;
-
-       if (!ft) {
-               goto end;
-       }
-
-       BT_ASSERT(expected_clock_class);
-
-       switch (ft->id) {
-       case BT_CTF_FIELD_TYPE_ID_INTEGER:
-       {
-               struct bt_ctf_clock_class *mapped_clock_class =
-                       bt_ctf_field_type_common_integer_borrow_mapped_clock_class(ft);
-
-               if (!mapped_clock_class) {
-                       goto end;
-               }
-
-               if (!*expected_clock_class) {
-                       /* Move reference to output parameter */
-                       *expected_clock_class = bt_ctf_object_get_ref(mapped_clock_class);
-                       mapped_clock_class = NULL;
-                       BT_LOGV("Setting expected clock class: "
-                               "expected-clock-class-addr=%p",
-                               *expected_clock_class);
-               } else {
-                       if (mapped_clock_class != *expected_clock_class) {
-                               BT_LOGW("Integer field type is not mapped to "
-                                       "the expected clock class: "
-                                       "mapped-clock-class-addr=%p, "
-                                       "mapped-clock-class-name=\"%s\", "
-                                       "expected-clock-class-addr=%p, "
-                                       "expected-clock-class-name=\"%s\"",
-                                       mapped_clock_class,
-                                       bt_ctf_clock_class_get_name(mapped_clock_class),
-                                       *expected_clock_class,
-                                       bt_ctf_clock_class_get_name(*expected_clock_class));
-                               bt_ctf_object_put_ref(mapped_clock_class);
-                               ret = -1;
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ENUM:
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       {
-               struct bt_ctf_field_type_common *sub_ft = NULL;
-
-               switch (ft->id) {
-               case BT_CTF_FIELD_TYPE_ID_ENUM:
-                       sub_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type(
-                               ft);
-                       break;
-               case BT_CTF_FIELD_TYPE_ID_ARRAY:
-                       sub_ft = bt_ctf_field_type_common_array_borrow_element_field_type(
-                               ft);
-                       break;
-               case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-                       sub_ft = bt_ctf_field_type_common_sequence_borrow_element_field_type(
-                               ft);
-                       break;
-               default:
-                       BT_LOGF("Unexpected field type ID: id=%d", ft->id);
-                       abort();
-               }
-
-               BT_ASSERT(sub_ft);
-               ret = bt_ctf_field_type_common_validate_single_clock_class(sub_ft,
-                       expected_clock_class);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               uint64_t i;
-               int64_t count = bt_ctf_field_type_common_structure_get_field_count(
-                       ft);
-
-               for (i = 0; i < count; i++) {
-                       const char *name;
-                       struct bt_ctf_field_type_common *member_type;
-
-                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               ft, &name, &member_type, i);
-                       BT_ASSERT(ret == 0);
-                       ret = bt_ctf_field_type_common_validate_single_clock_class(
-                               member_type, expected_clock_class);
-                       if (ret) {
-                               BT_LOGW("Structure field type's field's type "
-                                       "is not recursively mapped to the "
-                                       "expected clock class: "
-                                       "field-ft-addr=%p, field-name=\"%s\"",
-                                       member_type, name);
-                               goto end;
-                       }
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-       {
-               uint64_t i;
-               int64_t count = bt_ctf_field_type_common_variant_get_field_count(
-                       ft);
-
-               for (i = 0; i < count; i++) {
-                       const char *name;
-                       struct bt_ctf_field_type_common *member_type;
-
-                       ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
-                               ft, &name, &member_type, i);
-                       BT_ASSERT(ret == 0);
-                       ret = bt_ctf_field_type_common_validate_single_clock_class(
-                               member_type, expected_clock_class);
-                       if (ret) {
-                               BT_LOGW("Variant field type's field's type "
-                                       "is not recursively mapped to the "
-                                       "expected clock class: "
-                                       "field-ft-addr=%p, field-name=\"%s\"",
-                                       member_type, name);
-                               goto end;
-                       }
-               }
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_integer_copy(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive(
-               struct bt_ctf_field_type *ft);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive(
-               struct bt_ctf_field_type *type);
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_string_copy(
-               struct bt_ctf_field_type *type);
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_integer_methods = {
-       .freeze = bt_ctf_field_type_common_generic_freeze,
-       .validate = bt_ctf_field_type_common_integer_validate,
-       .set_byte_order = bt_ctf_field_type_common_integer_set_byte_order,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_integer_copy,
-       .compare = bt_ctf_field_type_common_integer_compare,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_floating_point_methods = {
-       .freeze = bt_ctf_field_type_common_generic_freeze,
-       .validate = NULL,
-       .set_byte_order = bt_ctf_field_type_common_floating_point_set_byte_order,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_floating_point_copy,
-       .compare = bt_ctf_field_type_common_floating_point_compare,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_enumeration_methods = {
-       .freeze = bt_ctf_field_type_common_enumeration_freeze_recursive,
-       .validate = bt_ctf_field_type_common_enumeration_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_enumeration_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_enumeration_copy_recursive,
-       .compare = bt_ctf_field_type_common_enumeration_compare_recursive,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_string_methods = {
-       .freeze = bt_ctf_field_type_common_generic_freeze,
-       .validate = NULL,
-       .set_byte_order = NULL,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_string_copy,
-       .compare = bt_ctf_field_type_common_string_compare,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_array_methods = {
-       .freeze = bt_ctf_field_type_common_array_freeze_recursive,
-       .validate = bt_ctf_field_type_common_array_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_array_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_array_copy_recursive,
-       .compare = bt_ctf_field_type_common_array_compare_recursive,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_sequence_methods = {
-       .freeze = bt_ctf_field_type_common_sequence_freeze_recursive,
-       .validate = bt_ctf_field_type_common_sequence_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_sequence_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_sequence_copy_recursive,
-       .compare = bt_ctf_field_type_common_sequence_compare_recursive,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_structure_methods = {
-       .freeze = bt_ctf_field_type_common_structure_freeze_recursive,
-       .validate = bt_ctf_field_type_common_structure_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_structure_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_structure_copy_recursive,
-       .compare = bt_ctf_field_type_common_structure_compare_recursive,
-};
-
-static struct bt_ctf_field_type_common_methods bt_ctf_field_type_variant_methods = {
-       .freeze = bt_ctf_field_type_common_variant_freeze_recursive,
-       .validate = bt_ctf_field_type_common_variant_validate_recursive,
-       .set_byte_order = bt_ctf_field_type_common_variant_set_byte_order_recursive,
-       .copy = (bt_ctf_field_type_common_method_copy)
-               bt_ctf_field_type_variant_copy_recursive,
-       .compare = bt_ctf_field_type_common_variant_compare_recursive,
-};
-
-typedef int (*bt_ctf_field_type_serialize_func)(struct bt_ctf_field_type_common *,
-               struct metadata_context *);
-
-BT_HIDDEN
-int bt_ctf_field_type_serialize_recursive(struct bt_ctf_field_type *type,
-               struct metadata_context *context)
-{
-       int ret;
-       struct bt_ctf_field_type_common *type_common = (void *) type;
-       bt_ctf_field_type_serialize_func serialize_func;
-
-       BT_ASSERT(type);
-       BT_ASSERT(context);
-
-       /* Make sure field type is valid before serializing it */
-       ret = bt_ctf_field_type_common_validate((void *) type);
-       if (ret) {
-               BT_LOGW("Cannot serialize field type's metadata: field type is invalid: "
-                       "addr=%p", type);
-               goto end;
-       }
-
-       serialize_func = type_common->spec.writer.serialize_func;
-       ret = serialize_func((void *) type, context);
-
-end:
-       return ret;
-}
-
-static
-const char *get_encoding_string(enum bt_ctf_string_encoding encoding)
-{
-       const char *encoding_string;
-
-       switch (encoding) {
-       case BT_CTF_STRING_ENCODING_NONE:
-               encoding_string = "none";
-               break;
-       case BT_CTF_STRING_ENCODING_ASCII:
-               encoding_string = "ASCII";
-               break;
-       case BT_CTF_STRING_ENCODING_UTF8:
-               encoding_string = "UTF8";
-               break;
-       default:
-               encoding_string = "unknown";
-               break;
-       }
-
-       return encoding_string;
-}
-
-static
-const char *get_integer_base_string(enum bt_ctf_integer_base base)
-{
-       const char *base_string;
-
-       switch (base) {
-       case BT_CTF_INTEGER_BASE_DECIMAL:
-       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
-               base_string = "decimal";
-               break;
-       case BT_CTF_INTEGER_BASE_HEXADECIMAL:
-               base_string = "hexadecimal";
-               break;
-       case BT_CTF_INTEGER_BASE_OCTAL:
-               base_string = "octal";
-               break;
-       case BT_CTF_INTEGER_BASE_BINARY:
-               base_string = "binary";
-               break;
-       default:
-               base_string = "unknown";
-               break;
-       }
-
-       return base_string;
-}
-
-static
-void append_field_name(struct metadata_context *context,
-               const char *name)
-{
-       g_string_append_c(context->string, ' ');
-
-       if (!bt_ctf_identifier_is_valid(name) || *name == '_') {
-               g_string_append_c(context->string, '_');
-       }
-
-       g_string_append(context->string, name);
-}
-
-static
-int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       struct bt_ctf_field_type_common_integer *integer = BT_CTF_FROM_COMMON(type);
-       int ret = 0;
-
-       BT_LOGD("Serializing CTF writer integer field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       g_string_append_printf(context->string,
-               "integer { size = %u; align = %u; signed = %s; encoding = %s; base = %s; byte_order = %s",
-               integer->size, type->alignment,
-               (integer->is_signed ? "true" : "false"),
-               get_encoding_string(integer->encoding),
-               get_integer_base_string(integer->base),
-               bt_ctf_get_byte_order_string(integer->user_byte_order));
-       if (integer->mapped_clock_class) {
-               const char *clock_name = bt_ctf_clock_class_get_name(
-                       integer->mapped_clock_class);
-
-               BT_ASSERT(clock_name);
-               g_string_append_printf(context->string,
-                       "; map = clock.%s.value", clock_name);
-       }
-
-       g_string_append(context->string, "; }");
-       return ret;
-}
-
-static
-int bt_ctf_field_type_enumeration_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       size_t entry;
-       int ret;
-       struct bt_ctf_field_type_common_enumeration *enumeration =
-               BT_CTF_FROM_COMMON(type);
-       struct bt_ctf_field_type_common *container_type;
-       int container_signed;
-
-       BT_LOGD("Serializing CTF writer enumeration field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       container_type =
-               bt_ctf_field_type_common_enumeration_borrow_container_field_type(type);
-       BT_ASSERT(container_type);
-       container_signed = bt_ctf_field_type_common_integer_is_signed(
-               container_type);
-       BT_ASSERT(container_signed >= 0);
-       g_string_append(context->string, "enum : ");
-       BT_LOGD_STR("Serializing CTF writer enumeration field type's container field type's metadata.");
-       ret = bt_ctf_field_type_serialize_recursive(
-               (void *) enumeration->container_ft, context);
-       if (ret) {
-               BT_LOGW("Cannot serialize CTF writer enumeration field type's container field type's metadata: "
-                       "container-ft-addr=%p", enumeration->container_ft);
-               goto end;
-       }
-
-       g_string_append(context->string, " { ");
-       for (entry = 0; entry < enumeration->entries->len; entry++) {
-               struct bt_ctf_enumeration_mapping *mapping =
-                       enumeration->entries->pdata[entry];
-               const char *label = g_quark_to_string(mapping->string);
-
-               g_string_append(context->string, "\"");
-
-               if (!bt_ctf_identifier_is_valid(label) || label[0] == '_') {
-                       g_string_append(context->string, "_");
-               }
-
-               g_string_append_printf(context->string, "%s\" = ", label);
-
-               if (container_signed) {
-                       if (mapping->range_start._signed ==
-                               mapping->range_end._signed) {
-                               g_string_append_printf(context->string,
-                                       "%" PRId64,
-                                       mapping->range_start._signed);
-                       } else {
-                               g_string_append_printf(context->string,
-                                       "%" PRId64 " ... %" PRId64,
-                                       mapping->range_start._signed,
-                                       mapping->range_end._signed);
-                       }
-               } else {
-                       if (mapping->range_start._unsigned ==
-                               mapping->range_end._unsigned) {
-                               g_string_append_printf(context->string,
-                                       "%" PRIu64,
-                                       mapping->range_start._unsigned);
-                       } else {
-                               g_string_append_printf(context->string,
-                                       "%" PRIu64 " ... %" PRIu64,
-                                       mapping->range_start._unsigned,
-                                       mapping->range_end._unsigned);
-                       }
-               }
-
-               g_string_append(context->string,
-                       ((entry != (enumeration->entries->len - 1)) ?
-                       ", " : " }"));
-       }
-
-       if (context->field_name->len) {
-               append_field_name(context,
-                       context->field_name->str);
-               g_string_assign(context->field_name, "");
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       struct bt_ctf_field_type_common_floating_point *floating_point =
-               BT_CTF_FROM_COMMON(type);
-
-       BT_LOGD("Serializing CTF writer floating point number field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       g_string_append_printf(context->string,
-               "floating_point { exp_dig = %u; mant_dig = %u; byte_order = %s; align = %u; }",
-               floating_point->exp_dig,
-               floating_point->mant_dig,
-               bt_ctf_get_byte_order_string(floating_point->user_byte_order),
-               type->alignment);
-       return 0;
-}
-
-static
-int bt_ctf_field_type_structure_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       size_t i;
-       unsigned int indent;
-       int ret = 0;
-       struct bt_ctf_field_type_common_structure *structure = BT_CTF_FROM_COMMON(type);
-       GString *structure_field_name = context->field_name;
-
-       BT_LOGD("Serializing CTF writer structure field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       context->field_name = g_string_new("");
-
-       context->current_indentation_level++;
-       g_string_append(context->string, "struct {\n");
-
-       for (i = 0; i < structure->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *field =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                               structure, i);
-
-               BT_LOGD("Serializing CTF writer structure field type's field metadata: "
-                       "index=%zu, "
-                       "field-ft-addr=%p, field-name=\"%s\"",
-                       i, field, g_quark_to_string(field->name));
-
-               for (indent = 0; indent < context->current_indentation_level;
-                       indent++) {
-                       g_string_append_c(context->string, '\t');
-               }
-
-               g_string_assign(context->field_name,
-                       g_quark_to_string(field->name));
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) field->type, context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize CTF writer structure field type's field's metadata: "
-                               "index=%zu, "
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               i, field->type,
-                               g_quark_to_string(field->name));
-                       goto end;
-               }
-
-               if (context->field_name->len) {
-                       append_field_name(context,
-                               context->field_name->str);
-               }
-               g_string_append(context->string, ";\n");
-       }
-
-       context->current_indentation_level--;
-       for (indent = 0; indent < context->current_indentation_level;
-               indent++) {
-               g_string_append_c(context->string, '\t');
-       }
-
-       g_string_append_printf(context->string, "} align(%u)",
-                type->alignment);
-
-end:
-       g_string_free(context->field_name, TRUE);
-       context->field_name = structure_field_name;
-       return ret;
-}
-
-static
-int bt_ctf_field_type_variant_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       size_t i;
-       unsigned int indent;
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *variant = BT_CTF_FROM_COMMON(type);
-       GString *variant_field_name = context->field_name;
-
-       BT_LOGD("Serializing CTF writer variant field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       context->field_name = g_string_new("");
-       if (variant->tag_name->len > 0) {
-               g_string_append(context->string, "variant <");
-               append_field_name(context, variant->tag_name->str);
-               g_string_append(context->string, "> {\n");
-       } else {
-               g_string_append(context->string, "variant {\n");
-       }
-
-       context->current_indentation_level++;
-       for (i = 0; i < variant->choices->len; i++) {
-               struct bt_ctf_field_type_common_variant_choice *field =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               variant, i);
-
-               BT_LOGD("Serializing CTF writer variant field type's field metadata: "
-                       "index=%zu, "
-                       "field-ft-addr=%p, field-name=\"%s\"",
-                       i, field, g_quark_to_string(field->name));
-
-               g_string_assign(context->field_name,
-                       g_quark_to_string(field->name));
-               for (indent = 0; indent < context->current_indentation_level;
-                       indent++) {
-                       g_string_append_c(context->string, '\t');
-               }
-
-               g_string_assign(context->field_name,
-                       g_quark_to_string(field->name));
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) field->type, context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize CTF writer variant field type's field's metadata: "
-                               "index=%zu, "
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               i, field->type,
-                               g_quark_to_string(field->name));
-                       goto end;
-               }
-
-               if (context->field_name->len) {
-                       append_field_name(context,
-                               context->field_name->str);
-                       g_string_append_c(context->string, ';');
-               }
-
-               g_string_append_c(context->string, '\n');
-       }
-
-       context->current_indentation_level--;
-       for (indent = 0; indent < context->current_indentation_level;
-               indent++) {
-               g_string_append_c(context->string, '\t');
-       }
-
-       g_string_append(context->string, "}");
-
-end:
-       g_string_free(context->field_name, TRUE);
-       context->field_name = variant_field_name;
-       return ret;
-}
-
-static
-int bt_ctf_field_type_array_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_array *array = BT_CTF_FROM_COMMON(type);
-
-       BT_LOGD("Serializing CTF writer array field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       BT_LOGD_STR("Serializing CTF writer array field type's element field type's metadata.");
-       ret = bt_ctf_field_type_serialize_recursive(
-               (void *) array->element_ft, context);
-       if (ret) {
-               BT_LOGW("Cannot serialize CTF writer array field type's element field type's metadata: "
-                       "element-ft-addr=%p", array->element_ft);
-               goto end;
-       }
-
-       if (context->field_name->len) {
-               append_field_name(context,
-                       context->field_name->str);
-
-               g_string_append_printf(context->string, "[%u]", array->length);
-               g_string_assign(context->field_name, "");
-       } else {
-               g_string_append_printf(context->string, "[%u]", array->length);
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_type_sequence_serialize_recursive(
-               struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_sequence *sequence = BT_CTF_FROM_COMMON(type);
-
-       BT_LOGD("Serializing CTF writer sequence field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       BT_LOGD_STR("Serializing CTF writer sequence field type's element field type's metadata.");
-       ret = bt_ctf_field_type_serialize_recursive(
-               (void *) sequence->element_ft, context);
-       if (ret) {
-               BT_LOGW("Cannot serialize CTF writer sequence field type's element field type's metadata: "
-                       "element-ft-addr=%p", sequence->element_ft);
-               goto end;
-       }
-
-       if (context->field_name->len) {
-               append_field_name(context, context->field_name->str);
-               g_string_assign(context->field_name, "");
-       }
-       g_string_append(context->string, "[");
-       append_field_name(context, sequence->length_field_name->str);
-       g_string_append(context->string, "]");
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type_common *type,
-               struct metadata_context *context)
-{
-       struct bt_ctf_field_type_common_string *string = BT_CTF_FROM_COMMON(type);
-
-       BT_LOGD("Serializing CTF writer string field type's metadata: "
-               "ft-addr=%p, metadata-context-addr=%p", type, context);
-       g_string_append_printf(context->string,
-               "string { encoding = %s; }",
-               get_encoding_string(string->encoding));
-       return 0;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size)
-{
-       struct bt_ctf_field_type_common_integer *integer = NULL;
-
-       BT_LOGD("Creating CTF writer integer field type object: size=%u", size);
-
-       if (size == 0 || size > 64) {
-               BT_LOGW("Invalid parameter: size must be between 1 and 64: "
-                       "size=%u", size);
-               goto error;
-       }
-
-       integer = g_new0(struct bt_ctf_field_type_common_integer, 1);
-       if (!integer) {
-               BT_LOGE_STR("Failed to allocate one integer field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_integer_initialize(BT_CTF_TO_COMMON(integer),
-               size, bt_ctf_field_type_common_integer_destroy,
-               &bt_ctf_field_type_integer_methods);
-       integer->common.spec.writer.serialize_func =
-               bt_ctf_field_type_integer_serialize;
-       BT_LOGD("Created CTF writer integer field type object: addr=%p, size=%u",
-               integer, size);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(integer);
-
-end:
-       return (void *) integer;
-}
-
-int bt_ctf_field_type_integer_get_size(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_integer_get_size((void *) ft);
-}
-
-bt_bool bt_ctf_field_type_integer_is_signed(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_integer_is_signed((void *) ft);
-}
-
-int bt_ctf_field_type_integer_set_is_signed(struct bt_ctf_field_type *ft,
-               bt_bool is_signed)
-{
-       return bt_ctf_field_type_common_integer_set_is_signed((void *) ft,
-               is_signed);
-}
-
-int bt_ctf_field_type_integer_set_size(struct bt_ctf_field_type *ft,
-               unsigned int size)
-{
-       return bt_ctf_field_type_common_integer_set_size((void *) ft, size);
-}
-
-enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_integer_get_base((void *) ft);
-}
-
-int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *ft,
-               enum bt_ctf_integer_base base)
-{
-       return bt_ctf_field_type_common_integer_set_base((void *) ft,
-               (int) base);
-}
-
-enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_integer_get_encoding((void *) ft);
-}
-
-int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *ft,
-               enum bt_ctf_string_encoding encoding)
-{
-       return bt_ctf_field_type_common_integer_set_encoding((void *) ft,
-               (int) encoding);
-}
-
-struct bt_ctf_clock_class *bt_ctf_field_type_integer_get_mapped_clock_class(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
-               (void *) ft));
-}
-
-int bt_ctf_field_type_integer_set_mapped_clock_class(
-               struct bt_ctf_field_type *ft,
-               struct bt_ctf_clock_class *clock_class)
-{
-       return bt_ctf_field_type_common_integer_set_mapped_clock_class((void *) ft,
-               clock_class);
-}
-
-int bt_ctf_field_type_enumeration_signed_get_mapping_by_index(
-               struct bt_ctf_field_type *ft, uint64_t index,
-               const char **mapping_name, int64_t *range_begin,
-               int64_t *range_end)
-{
-       return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
-               (void *) ft, index, mapping_name, range_begin, range_end);
-}
-
-int bt_ctf_field_type_enumeration_unsigned_get_mapping_by_index(
-               struct bt_ctf_field_type *ft, uint64_t index,
-               const char **mapping_name, uint64_t *range_begin,
-               uint64_t *range_end)
-{
-       return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
-               (void *) ft, index, mapping_name, range_begin, range_end);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create(
-               struct bt_ctf_field_type *container_ft)
-{
-       struct bt_ctf_field_type_common_enumeration *enumeration = NULL;
-       struct bt_ctf_field_type_common *int_ft = (void *) container_ft;
-
-       BT_LOGD("Creating CTF writer enumeration field type object: int-ft-addr=%p",
-               container_ft);
-
-       if (!container_ft) {
-               BT_LOGW_STR("Invalid parameter: field type is NULL.");
-               goto error;
-       }
-
-       if (int_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               BT_LOGW("Invalid parameter: container field type is not an integer field type: "
-                       "container-ft-addr=%p, container-ft-id=%s",
-                       container_ft, bt_ctf_field_type_id_string(int_ft->id));
-               goto error;
-       }
-
-       enumeration = g_new0(struct bt_ctf_field_type_common_enumeration, 1);
-       if (!enumeration) {
-               BT_LOGE_STR("Failed to allocate one enumeration field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_enumeration_initialize(BT_CTF_TO_COMMON(enumeration),
-               int_ft, bt_ctf_field_type_common_enumeration_destroy_recursive,
-               &bt_ctf_field_type_enumeration_methods);
-       enumeration->common.spec.writer.serialize_func =
-               bt_ctf_field_type_enumeration_serialize_recursive;
-       BT_LOGD("Created CTF writer enumeration field type object: addr=%p, "
-               "int-ft-addr=%p, int-ft-size=%u",
-               enumeration, container_ft,
-               bt_ctf_field_type_integer_get_size(container_ft));
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration);
-
-end:
-       return (void *) enumeration;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_field_type(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_field_type_common_enumeration_borrow_container_field_type(
-                       (void *) ft));
-}
-
-int bt_ctf_field_type_enumeration_signed_add_mapping(
-               struct bt_ctf_field_type *ft, const char *string,
-               int64_t range_start, int64_t range_end)
-{
-       return bt_ctf_field_type_common_enumeration_signed_add_mapping(
-               (void *) ft, string, range_start, range_end);
-}
-
-int bt_ctf_field_type_enumeration_unsigned_add_mapping(
-               struct bt_ctf_field_type *ft, const char *string,
-               uint64_t range_start, uint64_t range_end)
-{
-       return bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
-               (void *) ft, string, range_start, range_end);
-}
-
-int64_t bt_ctf_field_type_enumeration_get_mapping_count(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_enumeration_get_mapping_count((void *) ft);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void)
-{
-       struct bt_ctf_field_type_common_floating_point *floating_point =
-               g_new0(struct bt_ctf_field_type_common_floating_point, 1);
-
-       BT_LOGD_STR("Creating CTF writer floating point number field type object.");
-
-       if (!floating_point) {
-               BT_LOGE_STR("Failed to allocate one floating point number field type.");
-               goto end;
-       }
-
-       bt_ctf_field_type_common_floating_point_initialize(
-               BT_CTF_TO_COMMON(floating_point),
-               bt_ctf_field_type_common_floating_point_destroy,
-               &bt_ctf_field_type_floating_point_methods);
-       floating_point->common.spec.writer.serialize_func =
-               bt_ctf_field_type_floating_point_serialize;
-       BT_LOGD("Created CTF writer floating point number field type object: addr=%p, "
-               "exp-size=%u, mant-size=%u", floating_point,
-               floating_point->exp_dig, floating_point->mant_dig);
-
-end:
-       return (void *) floating_point;
-}
-
-int bt_ctf_field_type_floating_point_get_exponent_digits(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_floating_point_get_exponent_digits(
-               (void *) ft);
-}
-
-int bt_ctf_field_type_floating_point_set_exponent_digits(
-               struct bt_ctf_field_type *ft, unsigned int exponent_digits)
-{
-       return bt_ctf_field_type_common_floating_point_set_exponent_digits(
-               (void *) ft, exponent_digits);
-}
-
-int bt_ctf_field_type_floating_point_get_mantissa_digits(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_floating_point_get_mantissa_digits(
-               (void *) ft);
-}
-
-int bt_ctf_field_type_floating_point_set_mantissa_digits(
-               struct bt_ctf_field_type *ft, unsigned int mantissa_digits)
-{
-       return bt_ctf_field_type_common_floating_point_set_mantissa_digits(
-               (void *) ft, mantissa_digits);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void)
-{
-       struct bt_ctf_field_type_common_structure *structure =
-               g_new0(struct bt_ctf_field_type_common_structure, 1);
-
-       BT_LOGD_STR("Creating CTF writer structure field type object.");
-
-       if (!structure) {
-               BT_LOGE_STR("Failed to allocate one structure field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_structure_initialize(BT_CTF_TO_COMMON(structure),
-               bt_ctf_field_type_common_structure_destroy_recursive,
-               &bt_ctf_field_type_structure_methods);
-       structure->common.spec.writer.serialize_func =
-               bt_ctf_field_type_structure_serialize_recursive;
-       BT_LOGD("Created CTF writer structure field type object: addr=%p",
-               structure);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(structure);
-
-end:
-       return (void *) structure;
-}
-
-int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *ft,
-               struct bt_ctf_field_type *field_type,
-               const char *field_name)
-{
-       return bt_ctf_field_type_common_structure_add_field((void *) ft,
-               (void *) field_type, field_name);
-}
-
-int64_t bt_ctf_field_type_structure_get_field_count(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_structure_get_field_count((void *) ft);
-}
-
-int bt_ctf_field_type_structure_get_field_by_index(
-               struct bt_ctf_field_type *ft,
-               const char **field_name,
-               struct bt_ctf_field_type **field_type, uint64_t index)
-{
-       int ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-               (void *) ft, field_name, (void *) field_type, index);
-
-       if (ret == 0 && field_type) {
-               bt_ctf_object_get_ref(*field_type);
-       }
-
-       return ret;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name(
-               struct bt_ctf_field_type *ft, const char *name)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               (void *) ft, name));
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_variant_create(
-       struct bt_ctf_field_type *tag_ft, const char *tag_name)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = NULL;
-
-       BT_LOGD("Creating CTF writer variant field type object: "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               tag_ft, tag_name);
-
-       if (tag_name && !bt_ctf_identifier_is_valid(tag_name)) {
-               BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: "
-                       "tag-ft-addr=%p, tag-field-name=\"%s\"",
-                       tag_ft, tag_name);
-               goto error;
-       }
-
-       var_ft = g_new0(struct bt_ctf_field_type_common_variant, 1);
-       if (!var_ft) {
-               BT_LOGE_STR("Failed to allocate one variant field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_variant_initialize(BT_CTF_TO_COMMON(var_ft),
-               (void *) tag_ft, tag_name,
-               bt_ctf_field_type_common_variant_destroy_recursive,
-               &bt_ctf_field_type_variant_methods);
-       var_ft->common.spec.writer.serialize_func =
-               bt_ctf_field_type_variant_serialize_recursive;
-       BT_LOGD("Created CTF writer variant field type object: addr=%p, "
-               "tag-ft-addr=%p, tag-field-name=\"%s\"",
-               var_ft, tag_ft, tag_name);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(var_ft);
-
-end:
-       return (void *) var_ft;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_field_type(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_tag_field_type(
-               (void *) ft));
-}
-
-const char *bt_ctf_field_type_variant_get_tag_name(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_variant_get_tag_name((void *) ft);
-}
-
-int bt_ctf_field_type_variant_set_tag_name(
-               struct bt_ctf_field_type *ft, const char *name)
-{
-       return bt_ctf_field_type_common_variant_set_tag_name((void *) ft, name);
-}
-
-int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *ft,
-               struct bt_ctf_field_type *field_type,
-               const char *field_name)
-{
-       return bt_ctf_field_type_common_variant_add_field((void *) ft,
-               (void *) field_type, field_name);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name(
-               struct bt_ctf_field_type *ft,
-               const char *field_name)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_field_type_by_name(
-               (void *) ft, field_name));
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag(
-               struct bt_ctf_field_type *ft,
-               struct bt_ctf_field *tag_field)
-{
-       int ret;
-       int64_t choice_index;
-       struct bt_ctf_field *container;
-       struct bt_ctf_field_type_common_variant *var_ft = (void *) ft;
-       struct bt_ctf_field_type *ret_ft = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
-       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
-               "Field type");
-       BT_CTF_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
-               (struct bt_ctf_field_common *) tag_field,
-               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((struct bt_ctf_field_common *) tag_field,
-               "Tag field");
-
-       container = bt_ctf_field_enumeration_borrow_container(tag_field);
-       BT_ASSERT(container);
-
-       if (var_ft->tag_ft->container_ft->is_signed) {
-               int64_t val;
-
-               ret = bt_ctf_field_integer_signed_get_value(container,
-                       &val);
-               BT_ASSERT(ret == 0);
-               choice_index = bt_ctf_field_type_common_variant_find_choice_index(
-                       (void *) ft, (uint64_t) val, true);
-       } else {
-               uint64_t val;
-
-               ret = bt_ctf_field_integer_unsigned_get_value(container,
-                       &val);
-               BT_ASSERT(ret == 0);
-               choice_index = bt_ctf_field_type_common_variant_find_choice_index(
-                       (void *) ft, val, false);
-       }
-
-       if (choice_index < 0) {
-               BT_LOGW("Cannot find variant field type's field: "
-                       "var-ft-addr=%p, tag-field-addr=%p", ft, tag_field);
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_variant_get_field_by_index(ft, NULL,
-               &ret_ft, choice_index);
-       BT_ASSERT(ret == 0);
-
-end:
-       return ret_ft;
-}
-
-int64_t bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_variant_get_field_count((void *) ft);
-}
-
-int bt_ctf_field_type_variant_get_field_by_index(struct bt_ctf_field_type *ft,
-               const char **field_name, struct bt_ctf_field_type **field_type,
-               uint64_t index)
-{
-       int ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
-               (void *) ft, field_name, (void *) field_type, index);
-
-       if (ret == 0 && field_type) {
-               bt_ctf_object_get_ref(*field_type);
-       }
-
-       return ret;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_array_create(
-               struct bt_ctf_field_type *element_ft, unsigned int length)
-{
-       struct bt_ctf_field_type_common_array *array = NULL;
-
-       BT_LOGD("Creating CTF writer array field type object: element-ft-addr=%p, "
-               "length=%u", element_ft, length);
-
-       if (!element_ft) {
-               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
-               goto error;
-       }
-
-       if (length == 0) {
-               BT_LOGW_STR("Invalid parameter: length is zero.");
-               goto error;
-       }
-
-       array = g_new0(struct bt_ctf_field_type_common_array, 1);
-       if (!array) {
-               BT_LOGE_STR("Failed to allocate one array field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_array_initialize(BT_CTF_TO_COMMON(array),
-               (void *) element_ft, length,
-               bt_ctf_field_type_common_array_destroy_recursive,
-               &bt_ctf_field_type_array_methods);
-       array->common.spec.writer.serialize_func =
-               bt_ctf_field_type_array_serialize_recursive;
-       BT_LOGD("Created CTF writer array field type object: addr=%p, "
-               "element-ft-addr=%p, length=%u",
-               array, element_ft, length);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(array);
-
-end:
-       return (void *) array;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_field_type(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_array_borrow_element_field_type(
-               (void *) ft));
-}
-
-int64_t bt_ctf_field_type_array_get_length(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_array_get_length((void *) ft);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_sequence_create(
-               struct bt_ctf_field_type *element_ft,
-               const char *length_field_name)
-{
-       struct bt_ctf_field_type_common_sequence *sequence = NULL;
-
-       BT_LOGD("Creating CTF writer sequence field type object: element-ft-addr=%p, "
-               "length-field-name=\"%s\"", element_ft, length_field_name);
-
-       if (!element_ft) {
-               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
-               goto error;
-       }
-
-       if (!bt_ctf_identifier_is_valid(length_field_name)) {
-               BT_LOGW("Invalid parameter: length field name is not a valid CTF identifier: "
-                       "length-field-name=\"%s\"", length_field_name);
-               goto error;
-       }
-
-       sequence = g_new0(struct bt_ctf_field_type_common_sequence, 1);
-       if (!sequence) {
-               BT_LOGE_STR("Failed to allocate one sequence field type.");
-               goto error;
-       }
-
-       bt_ctf_field_type_common_sequence_initialize(BT_CTF_TO_COMMON(sequence),
-               (void *) element_ft, length_field_name,
-               bt_ctf_field_type_common_sequence_destroy_recursive,
-               &bt_ctf_field_type_sequence_methods);
-       sequence->common.spec.writer.serialize_func =
-               bt_ctf_field_type_sequence_serialize_recursive;
-       BT_LOGD("Created CTF writer sequence field type object: addr=%p, "
-               "element-ft-addr=%p, length-field-name=\"%s\"",
-               sequence, element_ft, length_field_name);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(sequence);
-
-end:
-       return (void *) sequence;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_field_type(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_type_common_sequence_borrow_element_field_type(
-               (void *) ft));
-}
-
-const char *bt_ctf_field_type_sequence_get_length_field_name(
-               struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_sequence_get_length_field_name((void *) ft);
-}
-
-struct bt_ctf_field_type *bt_ctf_field_type_string_create(void)
-{
-       struct bt_ctf_field_type_common_string *string =
-               g_new0(struct bt_ctf_field_type_common_string, 1);
-
-       BT_LOGD_STR("Creating CTF writer string field type object.");
-
-       if (!string) {
-               BT_LOGE_STR("Failed to allocate one string field type.");
-               return NULL;
-       }
-
-       bt_ctf_field_type_common_string_initialize(BT_CTF_TO_COMMON(string),
-               bt_ctf_field_type_common_string_destroy,
-               &bt_ctf_field_type_string_methods);
-       string->common.spec.writer.serialize_func =
-               bt_ctf_field_type_string_serialize;
-       BT_LOGD("Created CTF writer string field type object: addr=%p", string);
-       return (void *) string;
-}
-
-enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_string_get_encoding((void *) ft);
-}
-
-int bt_ctf_field_type_string_set_encoding(struct bt_ctf_field_type *ft,
-               enum bt_ctf_string_encoding encoding)
-{
-       return bt_ctf_field_type_common_string_set_encoding((void *) ft,
-               (int) encoding);
-}
-
-int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *ft)
-{
-       return bt_ctf_field_type_common_get_alignment((void *) ft);
-}
-
-int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *ft,
-               unsigned int alignment)
-{
-       return bt_ctf_field_type_common_set_alignment((void *) ft, alignment);
-}
-
-enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_get_byte_order((void *) ft);
-}
-
-int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *ft,
-               enum bt_ctf_byte_order byte_order)
-{
-       return bt_ctf_field_type_common_set_byte_order((void *) ft,
-               (int) byte_order);
-}
-
-enum bt_ctf_field_type_id bt_ctf_field_type_get_type_id(
-               struct bt_ctf_field_type *ft)
-{
-       return (int) bt_ctf_field_type_common_get_type_id((void *) ft);
-}
-
-BT_HIDDEN
-struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *ft)
-{
-       return (void *) bt_ctf_field_type_common_copy((void *) ft);
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_integer_copy(
-               struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common_integer *int_ft = (void *) ft;
-       struct bt_ctf_field_type_common_integer *copy_ft;
-
-       BT_LOGD("Copying CTF writer integer field type's: addr=%p", ft);
-       copy_ft = (void *) bt_ctf_field_type_integer_create(int_ft->size);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer integer field type.");
-               goto end;
-       }
-
-       copy_ft->mapped_clock_class = bt_ctf_object_get_ref(int_ft->mapped_clock_class);
-       copy_ft->user_byte_order = int_ft->user_byte_order;
-       copy_ft->is_signed = int_ft->is_signed;
-       copy_ft->size = int_ft->size;
-       copy_ft->base = int_ft->base;
-       copy_ft->encoding = int_ft->encoding;
-       BT_LOGD("Copied CTF writer integer field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       size_t i;
-       struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) ft;
-       struct bt_ctf_field_type_common_enumeration *copy_ft = NULL;
-       struct bt_ctf_field_type_common_enumeration *container_copy_ft;
-
-       BT_LOGD("Copying CTF writer enumeration field type's: addr=%p", ft);
-
-       /* Copy the source enumeration's container */
-       BT_LOGD_STR("Copying CTF writer enumeration field type's container field type.");
-       container_copy_ft = BT_CTF_FROM_COMMON(bt_ctf_field_type_common_copy(
-               BT_CTF_TO_COMMON(enum_ft->container_ft)));
-       if (!container_copy_ft) {
-               BT_LOGE_STR("Cannot copy CTF writer enumeration field type's container field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_ctf_field_type_enumeration_create(
-               (void *) container_copy_ft);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer enumeration field type.");
-               goto end;
-       }
-
-       /* Copy all enumaration entries */
-       for (i = 0; i < enum_ft->entries->len; i++) {
-               struct bt_ctf_enumeration_mapping *mapping = g_ptr_array_index(
-                       enum_ft->entries, i);
-               struct bt_ctf_enumeration_mapping *copy_mapping = g_new0(
-                       struct bt_ctf_enumeration_mapping, 1);
-
-               if (!copy_mapping) {
-                       BT_LOGE_STR("Failed to allocate one enumeration mapping.");
-                       goto error;
-               }
-
-               *copy_mapping = *mapping;
-               g_ptr_array_add(copy_ft->entries, copy_mapping);
-       }
-
-       BT_LOGD("Copied CTF writer enumeration field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_ctf_object_put_ref(container_copy_ft);
-       return (void *) copy_ft;
-
-error:
-       bt_ctf_object_put_ref(container_copy_ft);
-        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
-       return (void *) copy_ft;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy(
-               struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
-       struct bt_ctf_field_type_common_floating_point *copy_ft;
-
-       BT_LOGD("Copying CTF writer floating point number field type's: addr=%p", ft);
-       copy_ft = (void *) bt_ctf_field_type_floating_point_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer floating point number field type.");
-               goto end;
-       }
-
-       copy_ft->user_byte_order = flt_ft->user_byte_order;
-       copy_ft->exp_dig = flt_ft->exp_dig;
-       copy_ft->mant_dig = flt_ft->mant_dig;
-       BT_LOGD("Copied CTF writer floating point number field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       int64_t i;
-       GHashTableIter iter;
-       gpointer key, value;
-       struct bt_ctf_field_type_common_structure *struct_ft = (void *) ft;
-       struct bt_ctf_field_type_common_structure *copy_ft;
-
-       BT_LOGD("Copying CTF writer structure field type's: addr=%p", ft);
-       copy_ft = (void *) bt_ctf_field_type_structure_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer structure field type.");
-               goto end;
-       }
-
-       /* Copy field_name_to_index */
-       g_hash_table_iter_init(&iter, struct_ft->field_name_to_index);
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               g_hash_table_insert(copy_ft->field_name_to_index,
-                       key, value);
-       }
-
-       g_array_set_size(copy_ft->fields, struct_ft->fields->len);
-
-       for (i = 0; i < struct_ft->fields->len; i++) {
-               struct bt_ctf_field_type_common_structure_field *entry, *copy_entry;
-               struct bt_ctf_field_type_common *field_ft_copy;
-
-               entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                       struct_ft, i);
-               copy_entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                       copy_ft, i);
-               BT_LOGD("Copying CTF writer structure field type's field: "
-                       "index=%" PRId64 ", "
-                       "field-ft-addr=%p, field-name=\"%s\"",
-                       i, entry, g_quark_to_string(entry->name));
-
-               field_ft_copy = (void *) bt_ctf_field_type_copy(
-                       (void *) entry->type);
-               if (!field_ft_copy) {
-                       BT_LOGE("Cannot copy CTF writer structure field type's field: "
-                               "index=%" PRId64 ", "
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               i, entry, g_quark_to_string(entry->name));
-                       goto error;
-               }
-
-               copy_entry->name = entry->name;
-               copy_entry->type = field_ft_copy;
-       }
-
-       BT_LOGD("Copied CTF writer structure field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-
-error:
-        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       int64_t i;
-       GHashTableIter iter;
-       gpointer key, value;
-       struct bt_ctf_field_type_common *tag_ft_copy = NULL;
-       struct bt_ctf_field_type_common_variant *var_ft = (void *) ft;
-       struct bt_ctf_field_type_common_variant *copy_ft = NULL;
-
-       BT_LOGD("Copying CTF writer variant field type's: addr=%p", ft);
-       if (var_ft->tag_ft) {
-               BT_LOGD_STR("Copying CTF writer variant field type's tag field type.");
-               tag_ft_copy = bt_ctf_field_type_common_copy(
-                       BT_CTF_TO_COMMON(var_ft->tag_ft));
-               if (!tag_ft_copy) {
-                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field type.");
-                       goto end;
-               }
-       }
-
-       copy_ft = (void *) bt_ctf_field_type_variant_create(
-               (void *) tag_ft_copy,
-               var_ft->tag_name->len ? var_ft->tag_name->str : NULL);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer variant field type.");
-               goto end;
-       }
-
-       /* Copy field_name_to_index */
-       g_hash_table_iter_init(&iter, var_ft->choice_name_to_index);
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               g_hash_table_insert(copy_ft->choice_name_to_index,
-                       key, value);
-       }
-
-       g_array_set_size(copy_ft->choices, var_ft->choices->len);
-
-       for (i = 0; i < var_ft->choices->len; i++) {
-               struct bt_ctf_field_type_common_variant_choice *entry, *copy_entry;
-               struct bt_ctf_field_type_common *field_ft_copy;
-               uint64_t range_i;
-
-               entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, i);
-               copy_entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                       copy_ft, i);
-               BT_LOGD("Copying CTF writer variant field type's field: "
-                       "index=%" PRId64 ", "
-                       "field-ft-addr=%p, field-name=\"%s\"",
-                       i, entry, g_quark_to_string(entry->name));
-
-               field_ft_copy = (void *) bt_ctf_field_type_copy(
-                       (void *) entry->type);
-               if (!field_ft_copy) {
-                       BT_LOGE("Cannot copy CTF writer variant field type's field: "
-                               "index=%" PRId64 ", "
-                               "field-ft-addr=%p, field-name=\"%s\"",
-                               i, entry, g_quark_to_string(entry->name));
-                       g_free(copy_entry);
-                       goto error;
-               }
-
-               copy_entry->name = entry->name;
-               copy_entry->type = field_ft_copy;
-
-               /* Copy ranges */
-               copy_entry->ranges = g_array_new(FALSE, TRUE,
-                       sizeof(struct bt_ctf_field_type_common_variant_choice_range));
-               BT_ASSERT(copy_entry->ranges);
-               g_array_set_size(copy_entry->ranges, entry->ranges->len);
-
-               for (range_i = 0; range_i < entry->ranges->len; range_i++) {
-                       copy_entry->ranges[range_i] = entry->ranges[range_i];
-               }
-       }
-
-       if (var_ft->tag_field_path) {
-               BT_LOGD_STR("Copying CTF writer variant field type's tag field path.");
-               copy_ft->tag_field_path = bt_ctf_field_path_copy(
-                       var_ft->tag_field_path);
-               if (!copy_ft->tag_field_path) {
-                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field path.");
-                       goto error;
-               }
-       }
-
-       copy_ft->choices_up_to_date = var_ft->choices_up_to_date;
-       BT_LOGD("Copied CTF writer variant field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_ctf_object_put_ref(tag_ft_copy);
-       return (void *) copy_ft;
-
-error:
-       bt_ctf_object_put_ref(tag_ft_copy);
-        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common *container_ft_copy = NULL;
-       struct bt_ctf_field_type_common_array *array_ft = (void *) ft;
-       struct bt_ctf_field_type_common_array *copy_ft = NULL;
-
-       BT_LOGD("Copying CTF writer array field type's: addr=%p", ft);
-       BT_LOGD_STR("Copying CTF writer array field type's element field type.");
-       container_ft_copy = bt_ctf_field_type_common_copy(array_ft->element_ft);
-       if (!container_ft_copy) {
-               BT_LOGE_STR("Cannot copy CTF writer array field type's element field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_ctf_field_type_array_create(
-               (void *) container_ft_copy, array_ft->length);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer array field type.");
-               goto end;
-       }
-
-       BT_LOGD("Copied CTF writer array field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_ctf_object_put_ref(container_ft_copy);
-       return (void *) copy_ft;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive(
-               struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common *container_ft_copy = NULL;
-       struct bt_ctf_field_type_common_sequence *seq_ft = (void *) ft;
-       struct bt_ctf_field_type_common_sequence *copy_ft = NULL;
-
-       BT_LOGD("Copying CTF writer sequence field type's: addr=%p", ft);
-       BT_LOGD_STR("Copying CTF writer sequence field type's element field type.");
-       container_ft_copy = bt_ctf_field_type_common_copy(seq_ft->element_ft);
-       if (!container_ft_copy) {
-               BT_LOGE_STR("Cannot copy CTF writer sequence field type's element field type.");
-               goto end;
-       }
-
-       copy_ft = (void *) bt_ctf_field_type_sequence_create(
-               (void *) container_ft_copy,
-               seq_ft->length_field_name->len ?
-                       seq_ft->length_field_name->str : NULL);
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer sequence field type.");
-               goto end;
-       }
-
-       if (seq_ft->length_field_path) {
-               BT_LOGD_STR("Copying CTF writer sequence field type's length field path.");
-               copy_ft->length_field_path = bt_ctf_field_path_copy(
-                       seq_ft->length_field_path);
-               if (!copy_ft->length_field_path) {
-                       BT_LOGE_STR("Cannot copy CTF writer sequence field type's length field path.");
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Copied CTF writer sequence field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       bt_ctf_object_put_ref(container_ft_copy);
-       return (void *) copy_ft;
-error:
-       bt_ctf_object_put_ref(container_ft_copy);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
-       return NULL;
-}
-
-static
-struct bt_ctf_field_type *bt_ctf_field_type_string_copy(struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_type_common_string *string_ft = (void *) ft;
-       struct bt_ctf_field_type_common_string *copy_ft = NULL;
-
-       BT_LOGD("Copying CTF writer string field type's: addr=%p", ft);
-       copy_ft = (void *) bt_ctf_field_type_string_create();
-       if (!copy_ft) {
-               BT_LOGE_STR("Cannot create CTF writer string field type.");
-               goto end;
-       }
-
-       copy_ft->encoding = string_ft->encoding;
-       BT_LOGD("Copied CTF writer string field type: original-ft-addr=%p, copy-ft-addr=%p",
-               ft, copy_ft);
-
-end:
-       return (void *) copy_ft;
-}
diff --git a/ctf-writer/field-wrapper.c b/ctf-writer/field-wrapper.c
deleted file mode 100644 (file)
index a5a3b46..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-FIELD-WRAPPER"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <glib.h>
-
-BT_HIDDEN
-struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_new(void *data)
-{
-       struct bt_ctf_field_wrapper *field_wrapper =
-               g_new0(struct bt_ctf_field_wrapper, 1);
-
-       BT_LOGD_STR("Creating empty field wrapper object.");
-
-       if (!field_wrapper) {
-               BT_LOGE("Failed to allocate one field wrapper.");
-               goto end;
-       }
-
-       bt_ctf_object_init_unique(&field_wrapper->base);
-       BT_LOGD("Created empty field wrapper object: addr=%p",
-               field_wrapper);
-
-end:
-       return field_wrapper;
-}
-
-BT_HIDDEN
-void bt_ctf_field_wrapper_destroy(struct bt_ctf_field_wrapper *field_wrapper)
-{
-       BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper);
-       BT_ASSERT(!field_wrapper->field);
-       BT_LOGD_STR("Putting stream class.");
-       g_free(field_wrapper);
-}
-
-BT_HIDDEN
-struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_create(
-               struct bt_ctf_object_pool *pool, struct bt_ctf_field_type *ft)
-{
-       struct bt_ctf_field_wrapper *field_wrapper = NULL;
-
-       BT_ASSERT(pool);
-       BT_ASSERT(ft);
-       field_wrapper = bt_ctf_object_pool_create_object(pool);
-       if (!field_wrapper) {
-               BT_LOGE("Cannot allocate one field wrapper");
-               goto error;
-       }
-
-       BT_ASSERT(field_wrapper->field);
-       goto end;
-
-error:
-       if (field_wrapper) {
-               bt_ctf_field_wrapper_destroy(field_wrapper);
-               field_wrapper = NULL;
-       }
-
-end:
-       return field_wrapper;
-}
diff --git a/ctf-writer/fields.c b/ctf-writer/fields.c
deleted file mode 100644 (file)
index 327f62e..0000000
+++ /dev/null
@@ -1,1860 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-FIELDS"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/fcntl-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <float.h>
-#include <inttypes.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-#define BT_CTF_ASSERT_PRE_CTF_FIELD_IS_INT_OR_ENUM(_field, _name)              \
-       BT_CTF_ASSERT_PRE((_field)->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER || \
-               (_field)->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,        \
-               _name " is not an integer or an enumeration field: "    \
-               "field-addr=%p", (_field))
-
-BT_HIDDEN
-struct bt_ctf_field_common *bt_ctf_field_common_copy(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common *copy = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT(field_type_common_has_known_id(field->type));
-       BT_ASSERT(field->methods->copy);
-       copy = field->methods->copy(field);
-       if (!copy) {
-               BT_LOGW("Cannot create field: ft-addr=%p", field->type);
-               goto end;
-       }
-
-       bt_ctf_field_common_set(copy, field->payload_set);
-
-end:
-       return copy;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_structure_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_release_func)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_structure *structure_type =
-               BT_CTF_FROM_COMMON(type);
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-       size_t i;
-
-       BT_LOGD("Initializing common structure field object: ft-addr=%p", type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       structure->fields = g_ptr_array_new_with_free_func(field_release_func);
-       g_ptr_array_set_size(structure->fields, structure_type->fields->len);
-
-       /* Create all fields contained in the structure field. */
-       for (i = 0; i < structure_type->fields->len; i++) {
-               struct bt_ctf_field_common *field;
-               struct bt_ctf_field_type_common_structure_field *struct_field =
-                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
-                               structure_type, i);
-               field = field_create_func(struct_field->type);
-               if (!field) {
-                       BT_LOGE("Failed to create structure field's member: name=\"%s\", index=%zu",
-                               g_quark_to_string(struct_field->name), i);
-                       ret = -1;
-                       goto end;
-               }
-
-               g_ptr_array_index(structure->fields, i) = field;
-       }
-
-       BT_LOGD("Initialized common structure field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_variant_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_release_func)
-{
-       int ret = 0;
-       struct bt_ctf_field_type_common_variant *variant_type =
-               BT_CTF_FROM_COMMON(type);
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-       size_t i;
-
-       BT_LOGD("Initializing common variant field object: ft-addr=%p", type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       ret = bt_ctf_field_type_common_variant_update_choices(type);
-       if (ret) {
-               BT_LOGE("Cannot update common variant field type choices: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       variant->fields = g_ptr_array_new_with_free_func(field_release_func);
-       g_ptr_array_set_size(variant->fields, variant_type->choices->len);
-
-       /* Create all fields contained in the variant field. */
-       for (i = 0; i < variant_type->choices->len; i++) {
-               struct bt_ctf_field_common *field;
-               struct bt_ctf_field_type_common_variant_choice *var_choice =
-                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
-                               variant_type, i);
-
-               field = field_create_func(var_choice->type);
-               if (!field) {
-                       BT_LOGE("Failed to create variant field's member: name=\"%s\", index=%zu",
-                               g_quark_to_string(var_choice->name), i);
-                       ret = -1;
-                       goto end;
-               }
-
-               g_ptr_array_index(variant->fields, i) = field;
-       }
-
-       BT_LOGD("Initialized common variant field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_string_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods)
-{
-       int ret = 0;
-       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Initializing common string field object: ft-addr=%p", type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       string->buf = g_array_sized_new(FALSE, FALSE, sizeof(char), 1);
-       if (!string->buf) {
-               ret = -1;
-               goto end;
-       }
-
-       g_array_index(string->buf, char, 0) = '\0';
-       BT_LOGD("Initialized common string field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_array_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_destroy_func)
-{
-       struct bt_ctf_field_type_common_array *array_type = BT_CTF_FROM_COMMON(type);
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-       unsigned int array_length;
-       int ret = 0;
-       uint64_t i;
-
-       BT_LOGD("Initializing common array field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       array_length = array_type->length;
-       array->elements = g_ptr_array_sized_new(array_length);
-       if (!array->elements) {
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_set_free_func(array->elements, field_destroy_func);
-       g_ptr_array_set_size(array->elements, array_length);
-
-       for (i = 0; i < array_length; i++) {
-               array->elements->pdata[i] = field_create_func(
-                       array_type->element_ft);
-               if (!array->elements->pdata[i]) {
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       BT_LOGD("Initialized common array field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_sequence_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               GDestroyNotify field_destroy_func)
-{
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-       int ret = 0;
-
-       BT_LOGD("Initializing common sequence field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-       bt_ctf_field_common_initialize(field, type, is_shared,
-               release_func, methods);
-       sequence->elements = g_ptr_array_new();
-       if (!sequence->elements) {
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_set_free_func(sequence->elements, field_destroy_func);
-       BT_LOGD("Initialized common sequence field object: addr=%p, ft-addr=%p",
-               field, type);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_generic_validate(struct bt_ctf_field_common *field)
-{
-       return (field && field->payload_set) ? 0 : -1;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_structure_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < structure->fields->len; i++) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       (void *) structure->fields->pdata[i]);
-
-               if (ret) {
-                       int this_ret;
-                       const char *name;
-
-                       this_ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               field->type, &name, NULL, i);
-                       BT_ASSERT(this_ret == 0);
-                       BT_CTF_ASSERT_PRE_MSG("Invalid structure field's field: "
-                               "struct-field-addr=%p, field-name=\"%s\", "
-                               "index=%" PRId64 ", field-addr=%p",
-                               field, name, i, structure->fields->pdata[i]);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_variant_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int ret = 0;
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       if (!variant->current_field) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_common_validate_recursive(variant->current_field);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_array_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < array->elements->len; i++) {
-               ret = bt_ctf_field_common_validate_recursive((void *) array->elements->pdata[i]);
-               if (ret) {
-                       BT_CTF_ASSERT_PRE_MSG("Invalid array field's element field: "
-                               "array-field-addr=%p, %" PRId64 ", "
-                               "elem-field-addr=%p",
-                               field, i, array->elements->pdata[i]);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_common_sequence_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       (void *) sequence->elements->pdata[i]);
-               if (ret) {
-                       BT_CTF_ASSERT_PRE_MSG("Invalid sequence field's element field: "
-                               "seq-field-addr=%p, %" PRId64 ", "
-                               "elem-field-addr=%p",
-                               field, i, sequence->elements->pdata[i]);
-                       goto end;
-               }
-       }
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_generic_reset(struct bt_ctf_field_common *field)
-{
-       BT_ASSERT(field);
-       field->payload_set = false;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_structure_reset_recursive(struct bt_ctf_field_common *field)
-{
-       int64_t i;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < structure->fields->len; i++) {
-               struct bt_ctf_field_common *member = structure->fields->pdata[i];
-
-               if (!member) {
-                       /*
-                        * Structure members are lazily initialized;
-                        * skip if this member has not been allocated
-                        * yet.
-                        */
-                       continue;
-               }
-
-               bt_ctf_field_common_reset_recursive(member);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_variant_reset_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-       variant->current_field = NULL;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_array_reset_recursive(struct bt_ctf_field_common *field)
-{
-       size_t i;
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < array->elements->len; i++) {
-               struct bt_ctf_field_common *member = array->elements->pdata[i];
-
-               if (!member) {
-                       /*
-                        * Array elements are lazily initialized; skip
-                        * if this member has not been allocated yet.
-                        */
-                       continue;
-               }
-
-               bt_ctf_field_common_reset_recursive(member);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_sequence_reset_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-       uint64_t i;
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               if (sequence->elements->pdata[i]) {
-                       bt_ctf_field_common_reset_recursive(
-                               sequence->elements->pdata[i]);
-               }
-       }
-
-       sequence->length = 0;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_generic_set_is_frozen(struct bt_ctf_field_common *field,
-               bool is_frozen)
-{
-       field->frozen = is_frozen;
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_structure_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       uint64_t i;
-       struct bt_ctf_field_common_structure *structure_field =
-               BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Freezing structure field object: addr=%p", field);
-
-       for (i = 0; i < structure_field->fields->len; i++) {
-               struct bt_ctf_field_common *struct_field =
-                       g_ptr_array_index(structure_field->fields, i);
-
-               BT_LOGD("Freezing structure field's field: field-addr=%p, index=%" PRId64,
-                       struct_field, i);
-               bt_ctf_field_common_set_is_frozen_recursive(struct_field,
-                       is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_variant_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       uint64_t i;
-       struct bt_ctf_field_common_variant *variant_field = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Freezing variant field object: addr=%p", field);
-
-       for (i = 0; i < variant_field->fields->len; i++) {
-               struct bt_ctf_field_common *var_field =
-                       g_ptr_array_index(variant_field->fields, i);
-
-               BT_LOGD("Freezing variant field's field: field-addr=%p, index=%" PRId64,
-                       var_field, i);
-               bt_ctf_field_common_set_is_frozen_recursive(var_field, is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_array_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       int64_t i;
-       struct bt_ctf_field_common_array *array_field = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Freezing array field object: addr=%p", field);
-
-       for (i = 0; i < array_field->elements->len; i++) {
-               struct bt_ctf_field_common *elem_field =
-                       g_ptr_array_index(array_field->elements, i);
-
-               BT_LOGD("Freezing array field object's element field: "
-                       "element-field-addr=%p, index=%" PRId64,
-                       elem_field, i);
-               bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void bt_ctf_field_common_sequence_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       int64_t i;
-       struct bt_ctf_field_common_sequence *sequence_field =
-               BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Freezing sequence field object: addr=%p", field);
-
-       for (i = 0; i < sequence_field->length; i++) {
-               struct bt_ctf_field_common *elem_field =
-                       g_ptr_array_index(sequence_field->elements, i);
-
-               BT_LOGD("Freezing sequence field object's element field: "
-                       "element-field-addr=%p, index=%" PRId64,
-                       elem_field, i);
-               bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void _bt_ctf_field_common_set_is_frozen_recursive(struct bt_ctf_field_common *field,
-               bool is_frozen)
-{
-       if (!field) {
-               goto end;
-       }
-
-       BT_LOGD("Setting field object's frozen state: addr=%p, is-frozen=%d",
-               field, is_frozen);
-       BT_ASSERT(field_type_common_has_known_id(field->type));
-       BT_ASSERT(field->methods->set_is_frozen);
-       field->methods->set_is_frozen(field, is_frozen);
-
-end:
-       return;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_generic_is_set(struct bt_ctf_field_common *field)
-{
-       return field && field->payload_set;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_structure_is_set_recursive(
-               struct bt_ctf_field_common *field)
-{
-       bt_bool is_set = BT_FALSE;
-       size_t i;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < structure->fields->len; i++) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       structure->fields->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
-       }
-
-end:
-       return is_set;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_variant_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-       bt_bool is_set = BT_FALSE;
-
-       BT_ASSERT(field);
-
-       if (variant->current_field) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       variant->current_field);
-       }
-
-       return is_set;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_array_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       size_t i;
-       bt_bool is_set = BT_FALSE;
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < array->elements->len; i++) {
-               is_set = bt_ctf_field_common_is_set_recursive(array->elements->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
-       }
-
-end:
-       return is_set;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_sequence_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       size_t i;
-       bt_bool is_set = BT_FALSE;
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-
-       if (!sequence->elements) {
-               goto end;
-       }
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       sequence->elements->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
-       }
-
-end:
-       return is_set;
-}
-
-static struct bt_ctf_field_common_methods bt_ctf_field_integer_methods = {
-       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
-       .validate = bt_ctf_field_common_generic_validate,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_generic_is_set,
-       .reset = bt_ctf_field_common_generic_reset,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_floating_point_methods = {
-       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
-       .validate = bt_ctf_field_common_generic_validate,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_generic_is_set,
-       .reset = bt_ctf_field_common_generic_reset,
-};
-
-static
-void bt_ctf_field_enumeration_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen);
-
-static
-int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field);
-
-static
-bt_bool bt_ctf_field_enumeration_is_set_recursive(
-               struct bt_ctf_field_common *field);
-
-static
-void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field);
-
-static struct bt_ctf_field_common_methods bt_ctf_field_enumeration_methods = {
-       .set_is_frozen = bt_ctf_field_enumeration_set_is_frozen_recursive,
-       .validate = bt_ctf_field_enumeration_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_enumeration_is_set_recursive,
-       .reset = bt_ctf_field_enumeration_reset_recursive,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_string_methods = {
-       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
-       .validate = bt_ctf_field_common_generic_validate,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_generic_is_set,
-       .reset = bt_ctf_field_common_generic_reset,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_structure_methods = {
-       .set_is_frozen = bt_ctf_field_common_structure_set_is_frozen_recursive,
-       .validate = bt_ctf_field_common_structure_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_structure_is_set_recursive,
-       .reset = bt_ctf_field_common_structure_reset_recursive,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_sequence_methods = {
-       .set_is_frozen = bt_ctf_field_common_sequence_set_is_frozen_recursive,
-       .validate = bt_ctf_field_common_sequence_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_sequence_is_set_recursive,
-       .reset = bt_ctf_field_common_sequence_reset_recursive,
-};
-
-static struct bt_ctf_field_common_methods bt_ctf_field_array_methods = {
-       .set_is_frozen = bt_ctf_field_common_array_set_is_frozen_recursive,
-       .validate = bt_ctf_field_common_array_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_common_array_is_set_recursive,
-       .reset = bt_ctf_field_common_array_reset_recursive,
-};
-
-static
-void bt_ctf_field_variant_set_is_frozen_recursive(struct bt_ctf_field_common *field,
-               bool is_frozen);
-
-static
-int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field);
-
-static
-bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field);
-
-static
-void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field);
-
-static struct bt_ctf_field_common_methods bt_ctf_field_variant_methods = {
-       .set_is_frozen = bt_ctf_field_variant_set_is_frozen_recursive,
-       .validate = bt_ctf_field_variant_validate_recursive,
-       .copy = NULL,
-       .is_set = bt_ctf_field_variant_is_set_recursive,
-       .reset = bt_ctf_field_variant_reset_recursive,
-};
-
-static
-struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_enumeration_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_floating_point_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_structure_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *);
-
-static
-struct bt_ctf_field *(* const field_create_funcs[])(struct bt_ctf_field_type *) = {
-       [BT_CTF_FIELD_TYPE_ID_INTEGER] =        bt_ctf_field_integer_create,
-       [BT_CTF_FIELD_TYPE_ID_ENUM] =           bt_ctf_field_enumeration_create,
-       [BT_CTF_FIELD_TYPE_ID_FLOAT] =          bt_ctf_field_floating_point_create,
-       [BT_CTF_FIELD_TYPE_ID_STRUCT] =         bt_ctf_field_structure_create,
-       [BT_CTF_FIELD_TYPE_ID_VARIANT] =        bt_ctf_field_variant_create,
-       [BT_CTF_FIELD_TYPE_ID_ARRAY] =          bt_ctf_field_array_create,
-       [BT_CTF_FIELD_TYPE_ID_SEQUENCE] =       bt_ctf_field_sequence_create,
-       [BT_CTF_FIELD_TYPE_ID_STRING] =         bt_ctf_field_string_create,
-};
-
-typedef int (*bt_ctf_field_serialize_recursive_func)(
-               struct bt_ctf_field_common *, struct bt_ctfser *,
-               enum bt_ctf_byte_order);
-
-static
-void bt_ctf_field_integer_destroy(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer integer field object: addr=%p", field);
-       bt_ctf_field_common_integer_finalize((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer floating point field object: addr=%p",
-               field);
-       bt_ctf_field_common_floating_point_finalize((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_enumeration_destroy_recursive(struct bt_ctf_field *field)
-{
-       struct bt_ctf_field_enumeration *enumeration = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Destroying CTF writer enumeration field object: addr=%p",
-               field);
-       BT_LOGD_STR("Putting container field.");
-       bt_ctf_object_put_ref(enumeration->container);
-       bt_ctf_field_common_finalize((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_structure_destroy_recursive(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer structure field object: addr=%p", field);
-       bt_ctf_field_common_structure_finalize_recursive((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_variant_destroy_recursive(struct bt_ctf_field *field)
-{
-       struct bt_ctf_field_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGD("Destroying CTF writer variant field object: addr=%p", field);
-       BT_LOGD_STR("Putting tag field.");
-       bt_ctf_object_put_ref(variant->tag);
-       bt_ctf_field_common_variant_finalize_recursive((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_array_destroy_recursive(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer array field object: addr=%p", field);
-       bt_ctf_field_common_array_finalize_recursive((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_sequence_destroy_recursive(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer sequence field object: addr=%p", field);
-       bt_ctf_field_common_sequence_finalize_recursive((void *) field);
-       g_free(field);
-}
-
-static
-void bt_ctf_field_string_destroy(struct bt_ctf_field *field)
-{
-       BT_LOGD("Destroying CTF writer string field object: addr=%p", field);
-       bt_ctf_field_common_string_finalize((void *) field);
-       g_free(field);
-}
-
-BT_HIDDEN
-int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       struct bt_ctf_field_common *field_common = (void *) field;
-       bt_ctf_field_serialize_recursive_func serialize_func;
-
-       BT_ASSERT(ctfser);
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT(field_common->spec.writer.serialize_func);
-       serialize_func = field_common->spec.writer.serialize_func;
-       return serialize_func(field_common, ctfser,
-               native_byte_order);
-}
-
-static
-int bt_ctf_field_integer_serialize(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int ret;
-       struct bt_ctf_field_type_common_integer *int_type =
-               BT_CTF_FROM_COMMON(field->type);
-       struct bt_ctf_field_common_integer *int_field =
-               BT_CTF_FROM_COMMON(field);
-       enum bt_ctf_byte_order byte_order;
-
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Integer field");
-       BT_LOGV("Serializing CTF writer integer field: addr=%p, native-bo=%s",
-               field,
-               bt_ctf_byte_order_string(native_byte_order));
-       byte_order = int_type->user_byte_order;
-       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
-               byte_order = native_byte_order;
-       }
-
-       if (int_type->is_signed) {
-               ret = bt_ctfser_write_signed_int(ctfser,
-                       int_field->payload.signd, int_type->common.alignment,
-                       int_type->size,
-                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN);
-       } else {
-               ret = bt_ctfser_write_unsigned_int(ctfser,
-                       int_field->payload.unsignd, int_type->common.alignment,
-                       int_type->size,
-                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN);
-       }
-
-       if (unlikely(ret)) {
-               BT_LOGE("Cannot serialize integer field: ret=%d", ret);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_enumeration_serialize_recursive(
-               struct bt_ctf_field_common *field, struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       BT_LOGV("Serializing enumeration field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-       BT_LOGV_STR("Serializing enumeration field's payload field.");
-       return bt_ctf_field_serialize_recursive(
-               (void *) enumeration->container, ctfser, native_byte_order);
-}
-
-static
-int bt_ctf_field_floating_point_serialize(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int ret = -1;
-       struct bt_ctf_field_type_common_floating_point *flt_type =
-               BT_CTF_FROM_COMMON(field->type);
-       struct bt_ctf_field_common_floating_point *flt_field = BT_CTF_FROM_COMMON(field);
-       enum bt_ctf_byte_order byte_order;
-
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
-       BT_LOGV("Serializing floating point number field: "
-               "addr=%p, native-bo=%s", field,
-               bt_ctf_byte_order_string(native_byte_order));
-
-       byte_order = flt_type->user_byte_order;
-       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
-               byte_order = native_byte_order;
-       }
-
-       if (flt_type->mant_dig == FLT_MANT_DIG) {
-               ret = bt_ctfser_write_float32(ctfser, flt_field->payload,
-                       flt_type->common.alignment,
-                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN);
-       } else if (flt_type->mant_dig == DBL_MANT_DIG) {
-               ret = bt_ctfser_write_float64(ctfser, flt_field->payload,
-                       flt_type->common.alignment,
-                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN);
-       } else {
-               abort();
-       }
-
-       if (unlikely(ret)) {
-               BT_LOGE("Cannot serialize floating point number field: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_structure_serialize_recursive(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int64_t i;
-       int ret;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGV("Serializing structure field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-       ret = bt_ctfser_align_offset_in_current_packet(ctfser,
-               field->type->alignment);
-       if (unlikely(ret)) {
-               BT_LOGE("Cannot align offset before serializing structure field: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       for (i = 0; i < structure->fields->len; i++) {
-               struct bt_ctf_field_common *member = g_ptr_array_index(
-                       structure->fields, i);
-               const char *field_name = NULL;
-
-               BT_LOGV("Serializing structure field's field: ser-offset=%" PRIu64 ", "
-                       "field-addr=%p, index=%" PRIu64,
-                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
-                       member, i);
-
-               if (unlikely(!member)) {
-                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               field->type, &field_name, NULL, i);
-                       BT_ASSERT(ret == 0);
-                       BT_LOGW("Cannot serialize structure field's field: field is not set: "
-                               "struct-field-addr=%p, "
-                               "field-name=\"%s\", index=%" PRId64,
-                               field, field_name, i);
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = bt_ctf_field_serialize_recursive((void *) member, ctfser,
-                       native_byte_order);
-               if (unlikely(ret)) {
-                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                               field->type, &field_name, NULL, i);
-                       BT_ASSERT(ret == 0);
-                       BT_LOGW("Cannot serialize structure field's field: "
-                               "struct-field-addr=%p, field-addr=%p, "
-                               "field-name=\"%s\", index=%" PRId64,
-                               field->type, member, field_name, i);
-                       break;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_variant_serialize_recursive(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGV("Serializing variant field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-       BT_LOGV_STR("Serializing variant field's payload field.");
-       return bt_ctf_field_serialize_recursive(
-               (void *) variant->current_field, ctfser, native_byte_order);
-}
-
-static
-int bt_ctf_field_array_serialize_recursive(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGV("Serializing array field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-
-       for (i = 0; i < array->elements->len; i++) {
-               struct bt_ctf_field_common *elem_field =
-                       g_ptr_array_index(array->elements, i);
-
-               BT_LOGV("Serializing array field's element field: "
-                       "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
-                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
-                       elem_field, i);
-               ret = bt_ctf_field_serialize_recursive(
-                       (void *) elem_field, ctfser, native_byte_order);
-               if (unlikely(ret)) {
-                       BT_LOGW("Cannot serialize array field's element field: "
-                               "array-field-addr=%p, field-addr=%p, "
-                               "index=%" PRId64, field, elem_field, i);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_sequence_serialize_recursive(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int64_t i;
-       int ret = 0;
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_LOGV("Serializing sequence field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string(native_byte_order));
-
-       for (i = 0; i < sequence->elements->len; i++) {
-               struct bt_ctf_field_common *elem_field =
-                       g_ptr_array_index(sequence->elements, i);
-
-               BT_LOGV("Serializing sequence field's element field: "
-                       "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
-                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
-                       elem_field, i);
-               ret = bt_ctf_field_serialize_recursive(
-                       (void *) elem_field, ctfser, native_byte_order);
-               if (unlikely(ret)) {
-                       BT_LOGW("Cannot serialize sequence field's element field: "
-                               "sequence-field-addr=%p, field-addr=%p, "
-                               "index=%" PRId64, field, elem_field, i);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int bt_ctf_field_string_serialize(struct bt_ctf_field_common *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order)
-{
-       int ret;
-       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
-       BT_LOGV("Serializing string field: addr=%p, native-bo=%s",
-               field, bt_ctf_byte_order_string((int) native_byte_order));
-       ret = bt_ctfser_write_string(ctfser, (const char *) string->buf->data);
-       if (unlikely(ret)) {
-               BT_LOGE("Cannot serialize string field: ret=%d", ret);
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field *field = NULL;
-       enum bt_ctf_field_type_id type_id;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(type, "Field type");
-       BT_ASSERT(field_type_common_has_known_id((void *) type));
-       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_validate((void *) type) == 0,
-               "Field type is invalid: ft-addr=%p", type);
-       type_id = bt_ctf_field_type_get_type_id(type);
-       field = field_create_funcs[type_id](type);
-       if (!field) {
-               goto end;
-       }
-
-       bt_ctf_field_type_common_freeze((void *) type);
-
-end:
-       return field;
-}
-
-struct bt_ctf_field_type *bt_ctf_field_get_type(struct bt_ctf_field *field)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_common_borrow_type((void *) field));
-}
-
-enum bt_ctf_field_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field)
-{
-       struct bt_ctf_field_common *field_common = (void *) field;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
-       return (int) field_common->type->id;
-}
-
-int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field,
-               struct bt_ctf_field *length_field)
-{
-       int ret;
-       struct bt_ctf_field_common *common_length_field = (void *) length_field;
-       uint64_t length;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(length_field, "Length field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) length_field, "Length field");
-       BT_CTF_ASSERT_PRE(common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER ||
-                       common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,
-               "Length field must be an integer or enumeration field: field-addr=%p",
-               length_field);
-
-       if (common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
-               struct bt_ctf_field_enumeration *enumeration = (void *)
-                       length_field;
-
-               length_field = (void *) enumeration->container;
-       }
-
-       ret = bt_ctf_field_integer_unsigned_get_value(length_field, &length);
-       BT_ASSERT(ret == 0);
-       return bt_ctf_field_common_sequence_set_length((void *) field,
-               length, (bt_ctf_field_common_create_func) bt_ctf_field_create);
-}
-
-struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index(
-               struct bt_ctf_field *field, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_index(
-               (void *) field, index));
-}
-
-struct bt_ctf_field *bt_ctf_field_structure_get_field_by_name(
-               struct bt_ctf_field *field, const char *name)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_name(
-               (void *) field, name));
-}
-
-struct bt_ctf_field *bt_ctf_field_array_get_field(
-               struct bt_ctf_field *field, uint64_t index)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_field_common_array_borrow_field((void *) field, index));
-}
-
-struct bt_ctf_field *bt_ctf_field_sequence_get_field(
-               struct bt_ctf_field *field, uint64_t index)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_field_common_sequence_borrow_field((void *) field, index));
-}
-
-struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field,
-               struct bt_ctf_field *tag_field)
-{
-       struct bt_ctf_field_variant *variant_field = (void *) field;
-       struct bt_ctf_field_enumeration *enum_field = (void *) tag_field;
-       struct bt_ctf_field_type_common_variant *variant_ft;
-       struct bt_ctf_field_type_common_enumeration *tag_ft;
-       struct bt_ctf_field *current_field = NULL;
-       bt_bool is_signed;
-       uint64_t tag_uval;
-       int ret;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Variant field");
-       BT_CTF_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) tag_field, "Tag field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
-               (struct bt_ctf_field_common *) tag_field,
-               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
-               (struct bt_ctf_field_common *) field,
-               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_CTF_ASSERT_PRE(
-               bt_ctf_field_common_validate_recursive((void *) tag_field) == 0,
-               "Tag field is invalid: field-addr=%p", tag_field);
-       variant_ft = BT_CTF_FROM_COMMON(variant_field->common.common.type);
-       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
-               BT_CTF_TO_COMMON(variant_ft->tag_ft), enum_field->common.type) == 0,
-               "Unexpected tag field's type: expected-ft-addr=%p, "
-               "tag-ft-addr=%p", variant_ft->tag_ft,
-               enum_field->common.type);
-       tag_ft = BT_CTF_FROM_COMMON(enum_field->common.type);
-       is_signed = tag_ft->container_ft->is_signed;
-
-       if (is_signed) {
-               int64_t tag_ival;
-
-               ret = bt_ctf_field_integer_signed_get_value(
-                       (void *) enum_field->container, &tag_ival);
-               tag_uval = (uint64_t) tag_ival;
-       } else {
-               ret = bt_ctf_field_integer_unsigned_get_value(
-                       (void *) enum_field->container, &tag_uval);
-       }
-
-       BT_ASSERT(ret == 0);
-       ret = bt_ctf_field_common_variant_set_tag((void *) field, tag_uval,
-               is_signed);
-       if (ret) {
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(variant_field->tag);
-       variant_field->tag = bt_ctf_object_get_ref(tag_field);
-       current_field = bt_ctf_field_variant_get_current_field(field);
-       BT_ASSERT(current_field);
-
-end:
-       return current_field;
-}
-
-struct bt_ctf_field *bt_ctf_field_variant_get_current_field(
-               struct bt_ctf_field *variant_field)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_common_variant_borrow_current_field(
-               (void *) variant_field));
-}
-
-BT_HIDDEN
-struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container(
-               struct bt_ctf_field *field)
-{
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Enumeration field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID((struct bt_ctf_field_common *) field,
-               BT_CTF_FIELD_TYPE_ID_ENUM, "Field");
-       BT_ASSERT(enumeration->container);
-       return (void *) enumeration->container;
-}
-
-struct bt_ctf_field *bt_ctf_field_enumeration_get_container(
-               struct bt_ctf_field *field)
-{
-       return bt_ctf_object_get_ref(bt_ctf_field_enumeration_borrow_container(field));
-}
-
-int bt_ctf_field_integer_signed_get_value(struct bt_ctf_field *field,
-               int64_t *value)
-{
-       struct bt_ctf_field_common_integer *integer = (void *) field;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
-               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
-       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_integer_is_signed(
-               integer->common.type),
-               "Field's type is unsigned: field-addr=%p", field);
-       *value = integer->payload.signd;
-       return 0;
-}
-
-int bt_ctf_field_integer_signed_set_value(struct bt_ctf_field *field,
-               int64_t value)
-{
-       int ret = 0;
-       struct bt_ctf_field_common_integer *integer = (void *) field;
-       struct bt_ctf_field_type_common_integer *integer_type;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
-               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
-       integer_type = BT_CTF_FROM_COMMON(integer->common.type);
-       BT_CTF_ASSERT_PRE(
-               bt_ctf_field_type_common_integer_is_signed(integer->common.type),
-               "Field's type is unsigned: field-addr=%p", field);
-       BT_CTF_ASSERT_PRE(value_is_in_range_signed(integer_type->size, value),
-               "Value is out of bounds: value=%" PRId64 ", field-addr=%p",
-               value, field);
-       integer->payload.signd = value;
-       bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true);
-       return ret;
-}
-
-int bt_ctf_field_integer_unsigned_get_value(struct bt_ctf_field *field,
-               uint64_t *value)
-{
-       struct bt_ctf_field_common_integer *integer = (void *) field;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
-               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
-       BT_CTF_ASSERT_PRE(
-               !bt_ctf_field_type_common_integer_is_signed(integer->common.type),
-               "Field's type is signed: field-addr=%p", field);
-       *value = integer->payload.unsignd;
-       return 0;
-}
-
-int bt_ctf_field_integer_unsigned_set_value(struct bt_ctf_field *field,
-               uint64_t value)
-{
-       struct bt_ctf_field_common_integer *integer = (void *) field;
-       struct bt_ctf_field_type_common_integer *integer_type;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
-               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
-       integer_type = BT_CTF_FROM_COMMON(integer->common.type);
-       BT_CTF_ASSERT_PRE(
-               !bt_ctf_field_type_common_integer_is_signed(integer->common.type),
-               "Field's type is signed: field-addr=%p", field);
-       BT_CTF_ASSERT_PRE(value_is_in_range_unsigned(integer_type->size, value),
-               "Value is out of bounds: value=%" PRIu64 ", field-addr=%p",
-               value, field);
-       integer->payload.unsignd = value;
-       bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true);
-       return 0;
-}
-
-int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field,
-               double *value)
-{
-       return bt_ctf_field_common_floating_point_get_value((void *) field, value);
-}
-
-int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field,
-               double value)
-{
-       return bt_ctf_field_common_floating_point_set_value((void *) field, value);
-}
-
-const char *bt_ctf_field_string_get_value(struct bt_ctf_field *field)
-{
-       return bt_ctf_field_common_string_get_value((void *) field);
-}
-
-int bt_ctf_field_string_set_value(struct bt_ctf_field *field, const char *value)
-{
-       return bt_ctf_field_common_string_set_value((void *) field, value);
-}
-
-int bt_ctf_field_string_append(struct bt_ctf_field *field, const char *value)
-{
-       return bt_ctf_field_common_string_append((void *) field, value);
-}
-
-int bt_ctf_field_string_append_len(struct bt_ctf_field *field,
-               const char *value, unsigned int length)
-{
-       return bt_ctf_field_common_string_append_len((void *) field, value, length);
-}
-
-struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field)
-{
-       return (void *) bt_ctf_field_common_copy((void *) field);
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_integer *integer =
-               g_new0(struct bt_ctf_field_common_integer, 1);
-
-       BT_LOGD("Creating CTF writer integer field object: ft-addr=%p", type);
-
-       if (integer) {
-               bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(integer), (void *) type,
-                       true,
-                       (bt_ctf_object_release_func) bt_ctf_field_integer_destroy,
-                       &bt_ctf_field_integer_methods);
-               integer->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_integer_serialize;
-               BT_LOGD("Created CTF writer integer field object: addr=%p, ft-addr=%p",
-                       integer, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one integer field.");
-       }
-
-       return (void *) integer;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_enumeration_create(
-               struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) type;
-       struct bt_ctf_field_enumeration *enumeration = g_new0(
-               struct bt_ctf_field_enumeration, 1);
-
-       BT_LOGD("Creating CTF writer enumeration field object: ft-addr=%p", type);
-
-       if (!enumeration) {
-               BT_LOGE_STR("Failed to allocate one enumeration field.");
-               goto end;
-       }
-
-       bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(enumeration),
-               (void *) type,
-               true, (bt_ctf_object_release_func)
-                       bt_ctf_field_enumeration_destroy_recursive,
-               &bt_ctf_field_enumeration_methods);
-       enumeration->container = (void *) bt_ctf_field_create(
-               BT_CTF_FROM_COMMON(enum_ft->container_ft));
-       if (!enumeration->container) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration);
-               goto end;
-       }
-
-       enumeration->common.spec.writer.serialize_func =
-               (bt_ctf_field_serialize_recursive_func)
-                       bt_ctf_field_enumeration_serialize_recursive;
-       BT_LOGD("Created CTF writer enumeration field object: addr=%p, ft-addr=%p",
-               enumeration, type);
-
-end:
-       return (void *) enumeration;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_floating_point_create(
-               struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_floating_point *floating_point;
-
-       BT_LOGD("Creating CTF writer floating point number field object: ft-addr=%p", type);
-       floating_point = g_new0(struct bt_ctf_field_common_floating_point, 1);
-
-       if (floating_point) {
-               bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(floating_point),
-                       (void *) type,
-                       true, (bt_ctf_object_release_func)
-                               bt_ctf_field_floating_point_destroy,
-                       &bt_ctf_field_floating_point_methods);
-               floating_point->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_floating_point_serialize;
-               BT_LOGD("Created CTF writer floating point number field object: addr=%p, ft-addr=%p",
-                       floating_point, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one floating point number field.");
-       }
-
-       return (void *) floating_point;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_structure_create(
-               struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_structure *structure = g_new0(
-               struct bt_ctf_field_common_structure, 1);
-       int iret;
-
-       BT_LOGD("Creating CTF writer structure field object: ft-addr=%p", type);
-
-       if (!structure) {
-               BT_LOGE_STR("Failed to allocate one structure field.");
-               goto end;
-       }
-
-       iret = bt_ctf_field_common_structure_initialize(BT_CTF_TO_COMMON(structure),
-               (void *) type,
-               true, (bt_ctf_object_release_func)
-                       bt_ctf_field_structure_destroy_recursive,
-               &bt_ctf_field_structure_methods,
-               (bt_ctf_field_common_create_func) bt_ctf_field_create,
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       structure->common.spec.writer.serialize_func =
-               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_structure_serialize_recursive;
-       if (iret) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(structure);
-               goto end;
-       }
-
-       BT_LOGD("Created CTF writer structure field object: addr=%p, ft-addr=%p",
-               structure, type);
-
-end:
-       return (void *) structure;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_type_common_variant *var_ft = (void *) type;
-       struct bt_ctf_field_variant *variant = g_new0(
-               struct bt_ctf_field_variant, 1);
-
-       BT_LOGD("Creating CTF writer variant field object: ft-addr=%p", type);
-
-       if (!variant) {
-               BT_LOGE_STR("Failed to allocate one variant field.");
-               goto end;
-       }
-
-       bt_ctf_field_common_variant_initialize(BT_CTF_TO_COMMON(BT_CTF_TO_COMMON(variant)),
-               (void *) type,
-               true, (bt_ctf_object_release_func)
-                       bt_ctf_field_variant_destroy_recursive,
-               &bt_ctf_field_variant_methods,
-               (bt_ctf_field_common_create_func) bt_ctf_field_create,
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       variant->tag = (void *) bt_ctf_field_create(
-               BT_CTF_FROM_COMMON(var_ft->tag_ft));
-       variant->common.common.spec.writer.serialize_func =
-               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_variant_serialize_recursive;
-       BT_LOGD("Created CTF writer variant field object: addr=%p, ft-addr=%p",
-               variant, type);
-
-end:
-       return (void *) variant;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_array *array =
-               g_new0(struct bt_ctf_field_common_array, 1);
-       int ret;
-
-       BT_LOGD("Creating CTF writer array field object: ft-addr=%p", type);
-       BT_ASSERT(type);
-
-       if (!array) {
-               BT_LOGE_STR("Failed to allocate one array field.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_common_array_initialize(BT_CTF_TO_COMMON(array),
-               (void *) type,
-               true, (bt_ctf_object_release_func)
-                       bt_ctf_field_array_destroy_recursive,
-               &bt_ctf_field_array_methods,
-               (bt_ctf_field_common_create_func) bt_ctf_field_create,
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       array->common.spec.writer.serialize_func =
-               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_array_serialize_recursive;
-       if (ret) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(array);
-               goto end;
-       }
-
-       BT_LOGD("Created CTF writer array field object: addr=%p, ft-addr=%p",
-               array, type);
-
-end:
-       return (void *) array;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_sequence *sequence = g_new0(
-               struct bt_ctf_field_common_sequence, 1);
-
-       BT_LOGD("Creating CTF writer sequence field object: ft-addr=%p", type);
-
-       if (sequence) {
-               bt_ctf_field_common_sequence_initialize(BT_CTF_TO_COMMON(sequence),
-                       (void *) type,
-                       true, (bt_ctf_object_release_func)
-                               bt_ctf_field_sequence_destroy_recursive,
-                       &bt_ctf_field_sequence_methods,
-                       (GDestroyNotify) bt_ctf_object_put_ref);
-               sequence->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_sequence_serialize_recursive;
-               BT_LOGD("Created CTF writer sequence field object: addr=%p, ft-addr=%p",
-                       sequence, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one sequence field.");
-       }
-
-       return (void *) sequence;
-}
-
-static
-struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type)
-{
-       struct bt_ctf_field_common_string *string = g_new0(
-               struct bt_ctf_field_common_string, 1);
-
-       BT_LOGD("Creating CTF writer string field object: ft-addr=%p", type);
-
-       if (string) {
-               bt_ctf_field_common_string_initialize(BT_CTF_TO_COMMON(string),
-                       (void *) type,
-                       true, (bt_ctf_object_release_func)
-                               bt_ctf_field_string_destroy,
-                       &bt_ctf_field_string_methods);
-               string->common.spec.writer.serialize_func =
-                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_string_serialize;
-               BT_LOGD("Created CTF writer string field object: addr=%p, ft-addr=%p",
-                       string, type);
-       } else {
-               BT_LOGE_STR("Failed to allocate one string field.");
-       }
-
-       return (void *) string;
-}
-
-static
-void bt_ctf_field_enumeration_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       if (enumeration->container) {
-               bt_ctf_field_common_set_is_frozen_recursive(
-                       (void *) enumeration->container, is_frozen);
-       }
-
-       bt_ctf_field_common_generic_set_is_frozen((void *) field, is_frozen);
-}
-
-static
-int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int ret = -1;
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       if (enumeration->container) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       (void *) enumeration->container);
-       }
-
-       return ret;
-}
-
-static
-bt_bool bt_ctf_field_enumeration_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       bt_bool is_set = BT_FALSE;
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       if (enumeration->container) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       (void *) enumeration->container);
-       }
-
-       return is_set;
-}
-
-static
-void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_enumeration *enumeration = (void *) field;
-
-       if (enumeration->container) {
-               bt_ctf_field_common_reset_recursive(
-                       (void *) enumeration->container);
-       }
-
-       bt_ctf_field_common_generic_reset((void *) field);
-}
-
-static
-void bt_ctf_field_variant_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen)
-{
-       struct bt_ctf_field_variant *variant = (void *) field;
-
-       if (variant->tag) {
-               bt_ctf_field_common_set_is_frozen_recursive(
-                       (void *) variant->tag, is_frozen);
-       }
-
-       bt_ctf_field_common_variant_set_is_frozen_recursive((void *) field,
-               is_frozen);
-}
-
-static
-int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int ret;
-       struct bt_ctf_field_variant *variant = (void *) field;
-
-       if (variant->tag) {
-               ret = bt_ctf_field_common_validate_recursive(
-                       (void *) variant->tag);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       ret = bt_ctf_field_common_variant_validate_recursive((void *) field);
-
-end:
-       return ret;
-}
-
-static
-bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       bt_bool is_set;
-       struct bt_ctf_field_variant *variant = (void *) field;
-
-       if (variant->tag) {
-               is_set = bt_ctf_field_common_is_set_recursive(
-                       (void *) variant->tag);
-               if (is_set) {
-                       goto end;
-               }
-       }
-
-       is_set = bt_ctf_field_common_variant_is_set_recursive((void *) field);
-
-end:
-       return is_set;
-}
-
-static
-void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_variant *variant = (void *) field;
-
-       if (variant->tag) {
-               bt_ctf_field_common_reset_recursive(
-                       (void *) variant->tag);
-       }
-
-       bt_ctf_field_common_variant_reset_recursive((void *) field);
-}
-
-BT_CTF_ASSERT_PRE_FUNC
-static inline bool field_to_set_has_expected_type(
-               struct bt_ctf_field_common *struct_field,
-               const char *name, struct bt_ctf_field_common *value)
-{
-       bool ret = true;
-       struct bt_ctf_field_type_common *expected_field_type = NULL;
-
-       expected_field_type =
-               bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-                       struct_field->type, name);
-
-       if (bt_ctf_field_type_common_compare(expected_field_type, value->type)) {
-               BT_CTF_ASSERT_PRE_MSG("Value field's type is different from the expected field type: "
-                       "value-ft-addr=%p, expected-ft-addr=%p", value->type,
-                       expected_field_type);
-               ret = false;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
-               const char *name, struct bt_ctf_field *value)
-{
-       int ret = 0;
-       GQuark field_quark;
-       struct bt_ctf_field_common *common_field = (void *) field;
-       struct bt_ctf_field_common_structure *structure =
-               BT_CTF_FROM_COMMON(common_field);
-       struct bt_ctf_field_common *common_value = (void *) value;
-       size_t index;
-       GHashTable *field_name_to_index;
-       struct bt_ctf_field_type_common_structure *structure_ft;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Parent field");
-       BT_CTF_ASSERT_PRE_NON_NULL(name, "Field name");
-       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(common_field,
-               BT_CTF_FIELD_TYPE_ID_STRUCT, "Parent field");
-       BT_CTF_ASSERT_PRE(field_to_set_has_expected_type(common_field,
-               name, common_value),
-               "Value field's type is different from the expected field type.");
-       field_quark = g_quark_from_string(name);
-       structure_ft = BT_CTF_FROM_COMMON(common_field->type);
-       field_name_to_index = structure_ft->field_name_to_index;
-       if (!g_hash_table_lookup_extended(field_name_to_index,
-                       GUINT_TO_POINTER(field_quark), NULL,
-                       (gpointer *) &index)) {
-               BT_LOGV("Invalid parameter: no such field in structure field's type: "
-                       "struct-field-addr=%p, struct-ft-addr=%p, "
-                       "field-ft-addr=%p, name=\"%s\"",
-                       field, common_field->type, common_value->type, name);
-               ret = -1;
-               goto end;
-       }
-       bt_ctf_object_get_ref(value);
-       BT_CTF_OBJECT_MOVE_REF(structure->fields->pdata[index], value);
-
-end:
-       return ret;
-}
diff --git a/ctf-writer/functor.c b/ctf-writer/functor.c
deleted file mode 100644 (file)
index e8ad20f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * functor.c
- *
- * Babeltrace CTF Writer
- *
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include <babeltrace2/ctf-writer/functor-internal.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-
-BT_HIDDEN
-void value_exists(gpointer element, gpointer search_query)
-{
-       if (element == ((struct bt_ctf_search_query *)search_query)->value) {
-               ((struct bt_ctf_search_query *)search_query)->found = 1;
-       }
-}
diff --git a/ctf-writer/logging.c b/ctf-writer/logging.c
deleted file mode 100644 (file)
index 641d5d9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_lib_ctf_writer_log_level
-#include "logging.h"
-
-BT_LOG_INIT_LOG_LEVEL(bt_lib_ctf_writer_log_level,
-       "BABELTRACE_CTF_WRITER_LOG_LEVEL");
diff --git a/ctf-writer/logging.h b/ctf-writer/logging.h
deleted file mode 100644 (file)
index a6cf543..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_LOGGING_H
-#define BABELTRACE_CTF_WRITER_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_lib_ctf_writer_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_lib_ctf_writer_log_level);
-
-#endif /* BABELTRACE_CTF_WRITER_LOGGING_H */
diff --git a/ctf-writer/object-pool.c b/ctf-writer/object-pool.c
deleted file mode 100644 (file)
index 2d932ac..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "OBJECT-POOL"
-#include "logging.h"
-
-#include <stdint.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/object-pool-internal.h>
-
-int bt_ctf_object_pool_initialize(struct bt_ctf_object_pool *pool,
-               bt_ctf_object_pool_new_object_func new_object_func,
-               bt_ctf_object_pool_destroy_object_func destroy_object_func,
-               void *data)
-{
-       int ret = 0;
-
-       BT_ASSERT(new_object_func);
-       BT_ASSERT(destroy_object_func);
-       BT_LOGD("Initializing object pool: addr=%p, data-addr=%p",
-               pool, data);
-       pool->objects = g_ptr_array_new();
-       if (!pool->objects) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       pool->funcs.new_object = new_object_func;
-       pool->funcs.destroy_object = destroy_object_func;
-       pool->data = data;
-       pool->size = 0;
-       BT_LOGD("Initialized object pool.");
-       goto end;
-
-error:
-       if (pool) {
-               bt_ctf_object_pool_finalize(pool);
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
-void bt_ctf_object_pool_finalize(struct bt_ctf_object_pool *pool)
-{
-       uint64_t i;
-
-       BT_ASSERT(pool);
-       BT_LOGD("Finalizing object pool.");
-
-       if (pool->objects) {
-               for (i = 0; i < pool->size; i++) {
-                       void *obj = pool->objects->pdata[i];
-
-                       if (obj) {
-                               pool->funcs.destroy_object(obj, pool->data);
-                       }
-               }
-
-               g_ptr_array_free(pool->objects, TRUE);
-               pool->objects = NULL;
-       }
-}
diff --git a/ctf-writer/object.c b/ctf-writer/object.c
deleted file mode 100644 (file)
index b618512..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/ctf-writer/object-internal.h>
-
-void *bt_ctf_object_get_ref(void *obj)
-{
-       if (unlikely(!obj)) {
-               goto end;
-       }
-
-       bt_ctf_object_get_no_null_check(obj);
-
-end:
-       return obj;
-}
-
-void bt_ctf_object_put_ref(void *obj)
-{
-       if (unlikely(!obj)) {
-               return;
-       }
-
-       bt_ctf_object_put_no_null_check(obj);
-}
diff --git a/ctf-writer/resolve.c b/ctf-writer/resolve.c
deleted file mode 100644 (file)
index b0a5e15..0000000
+++ /dev/null
@@ -1,1339 +0,0 @@
-/*
- * resolve.c
- *
- * Babeltrace - CTF writer: Type resolving internal
- *
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Authors: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *          Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-RESOLVE"
-#include "logging.h"
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/field-path-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/resolve-internal.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.h>
-
-typedef GPtrArray type_stack;
-
-/*
- * A stack frame.
- *
- * `type` contains a compound field type (structure, variant, array,
- * or sequence) and `index` indicates the index of the field type in
- * the upper frame (-1 for array and sequence field types).
- *
- * `type` is owned by the stack frame.
- */
-struct type_stack_frame {
-       struct bt_ctf_field_type_common *type;
-       int index;
-};
-
-/*
- * The current context of the resolving engine.
- *
- * `scopes` contain the 6 CTF scope field types (see CTF, sect. 7.3.2)
- * in the following order:
- *
- *   * Packet header
- *   * Packet context
- *   * Event header
- *   * Stream event context
- *   * Event context
- *   * Event payload
- */
-struct resolve_context {
-       struct bt_ctf_private_value *environment;
-       struct bt_ctf_field_type_common *scopes[6];
-
-       /* Root scope being visited */
-       enum bt_ctf_scope root_scope;
-       type_stack *type_stack;
-       struct bt_ctf_field_type_common *cur_field_type;
-};
-
-/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
-static const char * const absolute_path_prefixes[] = {
-       [BT_CTF_SCOPE_ENV]                              = "env.",
-       [BT_CTF_SCOPE_TRACE_PACKET_HEADER]              = "trace.packet.header.",
-       [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT]    = "stream.packet.context.",
-       [BT_CTF_SCOPE_STREAM_EVENT_HEADER]              = "stream.event.header.",
-       [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT]             = "stream.event.context.",
-       [BT_CTF_SCOPE_EVENT_CONTEXT]            = "event.context.",
-       [BT_CTF_SCOPE_EVENT_FIELDS]                     = "event.fields.",
-};
-
-/* Number of path tokens used for the absolute prefixes */
-static const int absolute_path_prefix_ptoken_counts[] = {
-       [BT_CTF_SCOPE_ENV]                      = 1,
-       [BT_CTF_SCOPE_TRACE_PACKET_HEADER]      = 3,
-       [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT]    = 3,
-       [BT_CTF_SCOPE_STREAM_EVENT_HEADER]      = 3,
-       [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT]     = 3,
-       [BT_CTF_SCOPE_EVENT_CONTEXT]            = 2,
-       [BT_CTF_SCOPE_EVENT_FIELDS]             = 2,
-};
-
-/*
- * Destroys a type stack frame.
- */
-static
-void type_stack_destroy_notify(gpointer data)
-{
-       struct type_stack_frame *frame = data;
-
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(frame->type);
-       g_free(frame);
-}
-
-/*
- * Creates a type stack.
- *
- * Return value is owned by the caller.
- */
-static
-type_stack *type_stack_create(void)
-{
-       return g_ptr_array_new_with_free_func(type_stack_destroy_notify);
-}
-
-/*
- * Destroys a type stack.
- */
-static
-void type_stack_destroy(type_stack *stack)
-{
-       g_ptr_array_free(stack, TRUE);
-}
-
-/*
- * Pushes a field type onto a type stack.
- *
- * `type` is owned by the caller (stack frame gets a new reference).
- */
-static
-int type_stack_push(type_stack *stack, struct bt_ctf_field_type_common *type)
-{
-       int ret = 0;
-       struct type_stack_frame *frame = NULL;
-
-       if (!stack || !type) {
-               BT_LOGW("Invalid parameter: stack or type is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       frame = g_new0(struct type_stack_frame, 1);
-       if (!frame) {
-               BT_LOGE_STR("Failed to allocate one field type stack frame.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Pushing field type on context's stack: "
-               "ft-addr=%p, stack-size-before=%u", type, stack->len);
-       frame->type = bt_ctf_object_get_ref(type);
-       g_ptr_array_add(stack, frame);
-
-end:
-       return ret;
-}
-
-/*
- * Checks whether or not `stack` is empty.
- */
-static
-bt_bool type_stack_empty(type_stack *stack)
-{
-       return stack->len == 0;
-}
-
-/*
- * Returns the number of frames in `stack`.
- */
-static
-size_t type_stack_size(type_stack *stack)
-{
-       return stack->len;
-}
-
-/*
- * Returns the top frame of `stack`.
- *
- * Return value is owned by `stack`.
- */
-static
-struct type_stack_frame *type_stack_peek(type_stack *stack)
-{
-       struct type_stack_frame *entry = NULL;
-
-       if (!stack || type_stack_empty(stack)) {
-               goto end;
-       }
-
-       entry = g_ptr_array_index(stack, stack->len - 1);
-end:
-       return entry;
-}
-
-/*
- * Returns the frame at index `index` in `stack`.
- *
- * Return value is owned by `stack`.
- */
-static
-struct type_stack_frame *type_stack_at(type_stack *stack,
-               size_t index)
-{
-       struct type_stack_frame *entry = NULL;
-
-       if (!stack || index >= stack->len) {
-               goto end;
-       }
-
-       entry = g_ptr_array_index(stack, index);
-
-end:
-       return entry;
-}
-
-/*
- * Removes the top frame of `stack`.
- */
-static
-void type_stack_pop(type_stack *stack)
-{
-       if (!type_stack_empty(stack)) {
-               /*
-                * This will call the frame's destructor and free it, as
-                * well as put its contained field type.
-                */
-               BT_LOGV("Popping context's stack: stack-size-before=%u",
-                       stack->len);
-               g_ptr_array_set_size(stack, stack->len - 1);
-       }
-}
-
-/*
- * Returns the scope field type of `scope` in the context `ctx`.
- *
- * Return value is owned by `ctx` on success.
- */
-static
-struct bt_ctf_field_type_common *get_type_from_ctx(struct resolve_context *ctx,
-               enum bt_ctf_scope scope)
-{
-       BT_ASSERT(scope >= BT_CTF_SCOPE_TRACE_PACKET_HEADER &&
-               scope <= BT_CTF_SCOPE_EVENT_FIELDS);
-
-       return ctx->scopes[scope - BT_CTF_SCOPE_TRACE_PACKET_HEADER];
-}
-
-/*
- * Returns the CTF scope from a path string. May return
- * CTF_NODE_UNKNOWN if the path is found to be relative.
- */
-static
-enum bt_ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
-{
-       enum bt_ctf_scope scope;
-       enum bt_ctf_scope ret = BT_CTF_SCOPE_UNKNOWN;
-       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
-               sizeof(*absolute_path_prefixes);
-
-       for (scope = BT_CTF_SCOPE_ENV; scope < BT_CTF_SCOPE_ENV +
-                       prefixes_count; scope++) {
-               /*
-                * Chech if path string starts with a known absolute
-                * path prefix.
-                *
-                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
-                */
-               if (strncmp(pathstr, absolute_path_prefixes[scope],
-                               strlen(absolute_path_prefixes[scope]))) {
-                       /* Prefix does not match: try the next one */
-                       BT_LOGV("Prefix does not match: trying the next one: "
-                               "path=\"%s\", path-prefix=\"%s\", scope=%s",
-                               pathstr, absolute_path_prefixes[scope],
-                               bt_ctf_scope_string(scope));
-                       continue;
-               }
-
-               /* Found it! */
-               ret = scope;
-               BT_LOGV("Found root scope from absolute path: "
-                       "path=\"%s\", scope=%s", pathstr,
-                       bt_ctf_scope_string(scope));
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Destroys a path token.
- */
-static
-void ptokens_destroy_func(gpointer ptoken, gpointer data)
-{
-       g_string_free(ptoken, TRUE);
-}
-
-/*
- * Destroys a path token list.
- */
-static
-void ptokens_destroy(GList *ptokens)
-{
-       if (!ptokens) {
-               return;
-       }
-
-       g_list_foreach(ptokens, ptokens_destroy_func, NULL);
-       g_list_free(ptokens);
-}
-
-/*
- * Returns the string contained in a path token.
- */
-static
-const char *ptoken_get_string(GList *ptoken)
-{
-       GString *tokenstr = (GString *) ptoken->data;
-
-       return tokenstr->str;
-}
-
-/*
- * Converts a path string to a path token list, that is, splits the
- * individual words of a path string into a list of individual
- * strings.
- *
- * Return value is owned by the caller on success.
- */
-static
-GList *pathstr_to_ptokens(const char *pathstr)
-{
-       const char *at = pathstr;
-       const char *last = at;
-       GList *ptokens = NULL;
-
-       for (;;) {
-               if (*at == '.' || *at == '\0') {
-                       GString *tokenstr;
-
-                       if (at == last) {
-                               /* Error: empty token */
-                               BT_LOGW("Empty path token: path=\"%s\", pos=%u",
-                                       pathstr, (int) (at - pathstr));
-                               goto error;
-                       }
-
-                       tokenstr = g_string_new(NULL);
-                       g_string_append_len(tokenstr, last, at - last);
-                       ptokens = g_list_append(ptokens, tokenstr);
-                       last = at + 1;
-               }
-
-               if (*at == '\0') {
-                       break;
-               }
-
-               at++;
-       }
-
-       return ptokens;
-
-error:
-       ptokens_destroy(ptokens);
-       return NULL;
-}
-
-/*
- * Converts a path token list to a field path object. The path token
- * list is relative from `type`. The index of the source looking for
- * its target within `type` is indicated by `src_index`. This can be
- * `INT_MAX` if the source is contained in `type`.
- *
- * `ptokens` is owned by the caller. `field_path` is an output parameter
- * owned by the caller that must be filled here. `type` is owned by the
- * caller.
- */
-static
-int ptokens_to_field_path(GList *ptokens, struct bt_ctf_field_path *field_path,
-               struct bt_ctf_field_type_common *type, int src_index)
-{
-       int ret = 0;
-       GList *cur_ptoken = ptokens;
-       bt_bool first_level_done = BT_FALSE;
-
-       /* Get our own reference */
-       bt_ctf_object_get_ref(type);
-
-       /* Locate target */
-       while (cur_ptoken) {
-               int child_index;
-               struct bt_ctf_field_type_common *child_type;
-               const char *field_name = ptoken_get_string(cur_ptoken);
-               enum bt_ctf_field_type_id type_id =
-                       bt_ctf_field_type_common_get_type_id(type);
-
-               BT_LOGV("Current path token: token=\"%s\"", field_name);
-
-               /* Find to which index corresponds the current path token */
-               if (type_id == BT_CTF_FIELD_TYPE_ID_ARRAY ||
-                               type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
-                       child_index = -1;
-               } else {
-                       child_index = bt_ctf_field_type_common_get_field_index(type,
-                               field_name);
-                       if (child_index < 0) {
-                               /*
-                                * Error: field name does not exist or
-                                * wrong current type.
-                                */
-                               BT_LOGW("Cannot get index of field type: "
-                                       "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
-                                       field_name, src_index, child_index, first_level_done);
-                               ret = -1;
-                               goto end;
-                       } else if (child_index > src_index &&
-                                       !first_level_done) {
-                               BT_LOGW("Child field type is located after source field type: "
-                                       "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
-                                       field_name, src_index, child_index, first_level_done);
-                               ret = -1;
-                               goto end;
-                       }
-
-                       /* Next path token */
-                       cur_ptoken = g_list_next(cur_ptoken);
-                       first_level_done = BT_TRUE;
-               }
-
-               /* Create new field path entry */
-               g_array_append_val(field_path->indexes, child_index);
-
-               /* Get child field type */
-               child_type = bt_ctf_field_type_common_borrow_field_at_index(type,
-                       child_index);
-               if (!child_type) {
-                       BT_LOGW("Cannot get child field type: "
-                               "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
-                               field_name, src_index, child_index, first_level_done);
-                       ret = -1;
-                       goto end;
-               }
-
-               /* Move child type to current type */
-               bt_ctf_object_get_ref(child_type);
-               BT_CTF_OBJECT_MOVE_REF(type, child_type);
-       }
-
-end:
-       bt_ctf_object_put_ref(type);
-       return ret;
-}
-
-/*
- * Converts a known absolute path token list to a field path object
- * within the resolving context `ctx`.
- *
- * `ptokens` is owned by the caller. `field_path` is an output parameter
- * owned by the caller that must be filled here.
- */
-static
-int absolute_ptokens_to_field_path(GList *ptokens,
-               struct bt_ctf_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       GList *cur_ptoken;
-       struct bt_ctf_field_type_common *type;
-
-       /* Skip absolute path tokens */
-       cur_ptoken = g_list_nth(ptokens,
-               absolute_path_prefix_ptoken_counts[field_path->root]);
-
-       /* Start with root type */
-       type = get_type_from_ctx(ctx, field_path->root);
-       if (!type) {
-               /* Error: root type is not available */
-               BT_LOGW("Root field type is not available: "
-                       "root-scope=%s",
-                       bt_ctf_scope_string(field_path->root));
-               ret = -1;
-               goto end;
-       }
-
-       /* Locate target */
-       ret = ptokens_to_field_path(cur_ptoken, field_path, type, INT_MAX);
-
-end:
-       return ret;
-}
-
-/*
- * Converts a known relative path token list to a field path object
- * within the resolving context `ctx`.
- *
- * `ptokens` is owned by the caller. `field_path` is an output parameter
- * owned by the caller that must be filled here.
- */
-static
-int relative_ptokens_to_field_path(GList *ptokens,
-               struct bt_ctf_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       int parent_pos_in_stack;
-       struct bt_ctf_field_path *tail_field_path = bt_ctf_field_path_create();
-
-       if (!tail_field_path) {
-               BT_LOGE_STR("Cannot create empty field path.");
-               ret = -1;
-               goto end;
-       }
-
-       parent_pos_in_stack = type_stack_size(ctx->type_stack) - 1;
-
-       while (parent_pos_in_stack >= 0) {
-               struct bt_ctf_field_type_common *parent_type =
-                       type_stack_at(ctx->type_stack,
-                               parent_pos_in_stack)->type;
-               int cur_index = type_stack_at(ctx->type_stack,
-                       parent_pos_in_stack)->index;
-
-               BT_LOGV("Locating target field type from current parent field type: "
-                       "parent-pos=%d, parent-ft-addr=%p, cur-index=%d",
-                       parent_pos_in_stack, parent_type, cur_index);
-
-               /* Locate target from current parent type */
-               ret = ptokens_to_field_path(ptokens, tail_field_path,
-                       parent_type, cur_index);
-               if (ret) {
-                       /* Not found... yet */
-                       BT_LOGV_STR("Not found at this point.");
-                       bt_ctf_field_path_clear(tail_field_path);
-               } else {
-                       /* Found: stitch tail field path to head field path */
-                       int i = 0;
-                       int tail_field_path_len =
-                               tail_field_path->indexes->len;
-
-                       while (BT_TRUE) {
-                               struct bt_ctf_field_type_common *cur_type =
-                                       type_stack_at(ctx->type_stack, i)->type;
-                               int index = type_stack_at(
-                                       ctx->type_stack, i)->index;
-
-                               if (cur_type == parent_type) {
-                                       break;
-                               }
-
-                               g_array_append_val(field_path->indexes,
-                                       index);
-                               i++;
-                       }
-
-                       for (i = 0; i < tail_field_path_len; i++) {
-                               int index = g_array_index(
-                                       tail_field_path->indexes,
-                                       int, i);
-
-                               g_array_append_val(field_path->indexes,
-                                       index);
-                       }
-                       break;
-               }
-
-               parent_pos_in_stack--;
-       }
-
-       if (parent_pos_in_stack < 0) {
-               /* Not found: look in previous scopes */
-               field_path->root--;
-
-               while (field_path->root >= BT_CTF_SCOPE_TRACE_PACKET_HEADER) {
-                       struct bt_ctf_field_type_common *root_type;
-                       bt_ctf_field_path_clear(field_path);
-
-                       BT_LOGV("Looking into potential root scope: scope=%s",
-                               bt_ctf_scope_string(field_path->root));
-                       root_type = get_type_from_ctx(ctx, field_path->root);
-                       if (!root_type) {
-                               field_path->root--;
-                               continue;
-                       }
-
-                       /* Locate target in previous scope */
-                       ret = ptokens_to_field_path(ptokens, field_path,
-                               root_type, INT_MAX);
-                       if (ret) {
-                               /* Not found yet */
-                               BT_LOGV_STR("Not found in this scope.");
-                               field_path->root--;
-                               continue;
-                       }
-
-                       /* Found */
-                       BT_LOGV_STR("Found in this scope.");
-                       break;
-               }
-       }
-
-end:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(tail_field_path);
-       return ret;
-}
-
-/*
- * Converts a path string to a field path object within the resolving
- * context `ctx`.
- *
- * Return value is owned by the caller on success.
- */
-static
-struct bt_ctf_field_path *pathstr_to_field_path(const char *pathstr,
-               struct resolve_context *ctx)
-{
-       int ret;
-       enum bt_ctf_scope root_scope;
-       GList *ptokens = NULL;
-       struct bt_ctf_field_path *field_path = NULL;
-
-       /* Create field path */
-       field_path = bt_ctf_field_path_create();
-       if (!field_path) {
-               BT_LOGE_STR("Cannot create empty field path.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Convert path string to path tokens */
-       ptokens = pathstr_to_ptokens(pathstr);
-       if (!ptokens) {
-               BT_LOGW("Cannot convert path string to path tokens: "
-                       "path=\"%s\"", pathstr);
-               ret = -1;
-               goto end;
-       }
-
-       /* Absolute or relative path? */
-       root_scope = get_root_scope_from_absolute_pathstr(pathstr);
-
-       if (root_scope == BT_CTF_SCOPE_UNKNOWN) {
-               /* Relative path: start with current root scope */
-               field_path->root = ctx->root_scope;
-               BT_LOGV("Detected relative path: starting with current root scope: "
-                       "scope=%s", bt_ctf_scope_string(field_path->root));
-               ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
-               if (ret) {
-                       BT_LOGW("Cannot get relative field path of path string: "
-                               "path=\"%s\", start-scope=%s, end-scope=%s",
-                               pathstr, bt_ctf_scope_string(ctx->root_scope),
-                               bt_ctf_scope_string(field_path->root));
-                       goto end;
-               }
-       } else if (root_scope == BT_CTF_SCOPE_ENV) {
-               BT_LOGW("Sequence field types referring the trace environment are not supported as of this version: "
-                       "path=\"%s\"", pathstr);
-               ret = -1;
-               goto end;
-       } else {
-               /* Absolute path: use found root scope */
-               field_path->root = root_scope;
-               BT_LOGV("Detected absolute path: using root scope: "
-                       "scope=%s", bt_ctf_scope_string(field_path->root));
-               ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
-               if (ret) {
-                       BT_LOGW("Cannot get absolute field path of path string: "
-                               "path=\"%s\", root-scope=%s",
-                               pathstr, bt_ctf_scope_string(root_scope));
-                       goto end;
-               }
-       }
-
-       if (ret == 0) {
-               GString *field_path_pretty =
-                       bt_ctf_field_path_string(field_path);
-               const char *field_path_pretty_str =
-                       field_path_pretty ? field_path_pretty->str : NULL;
-
-               BT_LOGV("Found field path: path=\"%s\", field-path=\"%s\"",
-                       pathstr, field_path_pretty_str);
-
-               if (field_path_pretty) {
-                       g_string_free(field_path_pretty, TRUE);
-               }
-       }
-
-end:
-       if (ret) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path);
-       }
-
-       ptokens_destroy(ptokens);
-       return field_path;
-}
-
-/*
- * Retrieves a field type by following the field path `field_path` in
- * the resolving context `ctx`.
- *
- * Return value is owned by the caller on success.
- */
-static
-struct bt_ctf_field_type_common *field_path_to_field_type(
-               struct bt_ctf_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int i;
-       struct bt_ctf_field_type_common *type;
-
-       /* Start with root type */
-       type = get_type_from_ctx(ctx, field_path->root);
-       bt_ctf_object_get_ref(type);
-       if (!type) {
-               /* Error: root type is not available */
-               BT_LOGW("Root field type is not available: root-scope=%s",
-                       bt_ctf_scope_string(field_path->root));
-               goto error;
-       }
-
-       /* Locate target */
-       for (i = 0; i < field_path->indexes->len; i++) {
-               struct bt_ctf_field_type_common *child_type;
-               int child_index =
-                       g_array_index(field_path->indexes, int, i);
-
-               /* Get child field type */
-               child_type = bt_ctf_field_type_common_borrow_field_at_index(type,
-                       child_index);
-               if (!child_type) {
-                       BT_LOGW("Cannot get field type: "
-                               "parent-ft-addr=%p, index=%d", type, i);
-                       goto error;
-               }
-
-               /* Move child type to current type */
-               bt_ctf_object_get_ref(child_type);
-               BT_CTF_OBJECT_MOVE_REF(type, child_type);
-       }
-
-       return type;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(type);
-       return type;
-}
-
-/*
- * Returns the equivalent field path object of the context type stack.
- *
- * Return value is owned by the caller on success.
- */
-static
-struct bt_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx)
-{
-       int i;
-       struct bt_ctf_field_path *field_path;
-
-       /* Create field path */
-       field_path = bt_ctf_field_path_create();
-       if (!field_path) {
-               BT_LOGE_STR("Cannot create empty field path.");
-               goto error;
-       }
-
-       field_path->root = ctx->root_scope;
-
-       for (i = 0; i < type_stack_size(ctx->type_stack); i++) {
-               struct type_stack_frame *frame;
-
-               frame = type_stack_at(ctx->type_stack, i);
-               g_array_append_val(field_path->indexes, frame->index);
-       }
-
-       return field_path;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path);
-       return field_path;
-}
-
-/*
- * Returns the lowest common ancestor of two field path objects
- * having the same root scope.
- *
- * `field_path1` and `field_path2` are owned by the caller.
- */
-static
-int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1,
-               struct bt_ctf_field_path *field_path2)
-{
-       int lca_index = 0;
-       int field_path1_len, field_path2_len;
-
-       if (BT_LOG_ON_VERBOSE) {
-               GString *field_path1_pretty =
-                       bt_ctf_field_path_string(field_path1);
-               GString *field_path2_pretty =
-                       bt_ctf_field_path_string(field_path2);
-               const char *field_path1_pretty_str =
-                       field_path1_pretty ? field_path1_pretty->str : NULL;
-               const char *field_path2_pretty_str =
-                       field_path2_pretty ? field_path2_pretty->str : NULL;
-
-               BT_LOGV("Finding lowest common ancestor (LCA) between two field paths: "
-                       "field-path-1=\"%s\", field-path-2=\"%s\"",
-                       field_path1_pretty_str, field_path2_pretty_str);
-
-               if (field_path1_pretty) {
-                       g_string_free(field_path1_pretty, TRUE);
-               }
-
-               if (field_path2_pretty) {
-                       g_string_free(field_path2_pretty, TRUE);
-               }
-       }
-
-       /*
-        * Start from both roots and find the first mismatch.
-        */
-       BT_ASSERT(field_path1->root == field_path2->root);
-       field_path1_len = field_path1->indexes->len;
-       field_path2_len = field_path2->indexes->len;
-
-       while (BT_TRUE) {
-               int target_index, ctx_index;
-
-               if (lca_index == field_path2_len ||
-                               lca_index == field_path1_len) {
-                       /*
-                        * This means that both field paths never split.
-                        * This is invalid because the target cannot be
-                        * an ancestor of the source.
-                        */
-                       BT_LOGW("Source field type is an ancestor of target field type or vice versa: "
-                               "lca-index=%d, field-path-1-len=%d, "
-                               "field-path-2-len=%d",
-                               lca_index, field_path1_len, field_path2_len);
-                       lca_index = -1;
-                       break;
-               }
-
-               target_index = g_array_index(field_path1->indexes, int,
-                       lca_index);
-               ctx_index = g_array_index(field_path2->indexes, int,
-                       lca_index);
-
-               if (target_index != ctx_index) {
-                       /* LCA index is the previous */
-                       break;
-               }
-
-               lca_index++;
-       }
-
-       BT_LOGV("Found LCA: lca-index=%d", lca_index);
-       return lca_index;
-}
-
-/*
- * Validates a target field path.
- *
- * `target_field_path` and `target_type` are owned by the caller.
- */
-static
-int validate_target_field_path(struct bt_ctf_field_path *target_field_path,
-               struct bt_ctf_field_type_common *target_type,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       struct bt_ctf_field_path *ctx_field_path;
-       int target_field_path_len = target_field_path->indexes->len;
-       int lca_index;
-       enum bt_ctf_field_type_id ctx_cur_field_type_id;
-       enum bt_ctf_field_type_id target_type_id;
-
-       /* Get context field path */
-       ctx_field_path = get_ctx_stack_field_path(ctx);
-       if (!ctx_field_path) {
-               BT_LOGW_STR("Cannot get field path from context's stack.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Make sure the target is not a root.
-        */
-       if (target_field_path_len == 0) {
-               BT_LOGW_STR("Target field path's length is 0 (targeting the root).");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Make sure the root of the target field path is not located
-        * after the context field path's root.
-        */
-       if (target_field_path->root > ctx_field_path->root) {
-               BT_LOGW("Target field type is located after source field type: "
-                       "target-root=%s, source-root=%s",
-                       bt_ctf_scope_string(target_field_path->root),
-                       bt_ctf_scope_string(ctx_field_path->root));
-               ret = -1;
-               goto end;
-       }
-
-       if (target_field_path->root == ctx_field_path->root) {
-               int target_index, ctx_index;
-
-               /*
-                * Find the index of the lowest common ancestor of both field
-                * paths.
-                */
-               lca_index = get_field_paths_lca_index(target_field_path,
-                       ctx_field_path);
-               if (lca_index < 0) {
-                       BT_LOGW_STR("Cannot get least common ancestor.");
-                       ret = -1;
-                       goto end;
-               }
-
-               /*
-                * Make sure the target field path is located before the
-                * context field path.
-                */
-               target_index = g_array_index(target_field_path->indexes,
-                       int, lca_index);
-               ctx_index = g_array_index(ctx_field_path->indexes,
-                       int, lca_index);
-
-               if (target_index >= ctx_index) {
-                       BT_LOGW("Target field type's index is greater than or equal to source field type's index in LCA: "
-                               "lca-index=%d, target-index=%d, source-index=%d",
-                               lca_index, target_index, ctx_index);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /*
-        * Make sure the target type has the right type and properties.
-        */
-       ctx_cur_field_type_id = bt_ctf_field_type_common_get_type_id(
-               ctx->cur_field_type);
-       target_type_id = bt_ctf_field_type_common_get_type_id(target_type);
-
-       switch (ctx_cur_field_type_id) {
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               if (target_type_id != BT_CTF_FIELD_TYPE_ID_ENUM) {
-                       BT_LOGW("Variant field type's tag field type is not an enumeration field type: "
-                               "tag-ft-addr=%p, tag-ft-id=%s",
-                               target_type,
-                               bt_ctf_field_type_id_string(target_type_id));
-                       ret = -1;
-                       goto end;
-               }
-               break;
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               if (target_type_id != BT_CTF_FIELD_TYPE_ID_INTEGER ||
-                               bt_ctf_field_type_common_integer_is_signed(target_type)) {
-                       BT_LOGW("Sequence field type's length field type is not an unsigned integer field type: "
-                               "length-ft-addr=%p, length-ft-id=%s",
-                               target_type,
-                               bt_ctf_field_type_id_string(target_type_id));
-                       ret = -1;
-                       goto end;
-               }
-               break;
-       default:
-               abort();
-       }
-
-end:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(ctx_field_path);
-       return ret;
-}
-
-/*
- * Resolves a variant or sequence field type `type`.
- *
- * `type` is owned by the caller.
- */
-static
-int resolve_sequence_or_variant_type(struct bt_ctf_field_type_common *type,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       const char *pathstr;
-       enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type);
-       struct bt_ctf_field_path *target_field_path = NULL;
-       struct bt_ctf_field_type_common *target_type = NULL;
-       GString *target_field_path_pretty = NULL;
-       const char *target_field_path_pretty_str;
-
-
-       /* Get path string */
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               pathstr =
-                       bt_ctf_field_type_common_sequence_get_length_field_name(type);
-               break;
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               pathstr =
-                       bt_ctf_field_type_common_variant_get_tag_name(type);
-               break;
-       default:
-               abort();
-       }
-
-       if (!pathstr) {
-               BT_LOGW_STR("Cannot get path string.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Get target field path out of path string */
-       target_field_path = pathstr_to_field_path(pathstr, ctx);
-       if (!target_field_path) {
-               BT_LOGW("Cannot get target field path for path string: "
-                       "path=\"%s\"", pathstr);
-               ret = -1;
-               goto end;
-       }
-
-       target_field_path_pretty = bt_ctf_field_path_string(target_field_path);
-       target_field_path_pretty_str =
-               target_field_path_pretty ? target_field_path_pretty->str : NULL;
-
-       /* Get target field type */
-       target_type = field_path_to_field_type(target_field_path, ctx);
-       if (!target_type) {
-               BT_LOGW("Cannot get target field type for path string: "
-                       "path=\"%s\", target-field-path=\"%s\"",
-                       pathstr, target_field_path_pretty_str);
-               ret = -1;
-               goto end;
-       }
-
-       ret = validate_target_field_path(target_field_path, target_type, ctx);
-       if (ret) {
-               BT_LOGW("Invalid target field path for path string: "
-                       "path=\"%s\", target-field-path=\"%s\"",
-                       pathstr, target_field_path_pretty_str);
-               goto end;
-       }
-
-       /* Set target field path and target field type */
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               ret = bt_ctf_field_type_common_sequence_set_length_field_path(
-                       type, target_field_path);
-               if (ret) {
-                       BT_LOGW("Cannot set sequence field type's length field path: "
-                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
-                               ret, type, pathstr,
-                               target_field_path_pretty_str);
-                       goto end;
-               }
-               break;
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               ret = bt_ctf_field_type_common_variant_set_tag_field_path(
-                       type, target_field_path);
-               if (ret) {
-                       BT_LOGW("Cannot set varaint field type's tag field path: "
-                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
-                               ret, type, pathstr,
-                               target_field_path_pretty_str);
-                       goto end;
-               }
-
-               ret = bt_ctf_field_type_common_variant_set_tag_field_type(
-                       type, target_type);
-               if (ret) {
-                       BT_LOGW("Cannot set varaint field type's tag field type: "
-                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
-                               ret, type, pathstr,
-                               target_field_path_pretty_str);
-                       goto end;
-               }
-               break;
-       default:
-               abort();
-       }
-
-end:
-       if (target_field_path_pretty) {
-               g_string_free(target_field_path_pretty, TRUE);
-       }
-
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(target_field_path);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(target_type);
-       return ret;
-}
-
-/*
- * Resolves a field type `type`.
- *
- * `type` is owned by the caller.
- */
-static
-int resolve_type(struct bt_ctf_field_type_common *type, struct resolve_context *ctx)
-{
-       int ret = 0;
-       enum bt_ctf_field_type_id type_id;
-
-       if (!type) {
-               /* Type is not available; still valid */
-               goto end;
-       }
-
-       type_id = bt_ctf_field_type_common_get_type_id(type);
-       ctx->cur_field_type = type;
-
-       /* Resolve sequence/variant field type */
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               ret = resolve_sequence_or_variant_type(type, ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve sequence field type's length or variant field type's tag: "
-                               "ret=%d, ft-addr=%p", ret, type);
-                       goto end;
-               }
-               break;
-       default:
-               break;
-       }
-
-       /* Recurse into compound types */
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       {
-               int64_t field_count, f_index;
-
-               ret = type_stack_push(ctx->type_stack, type);
-               if (ret) {
-                       BT_LOGW("Cannot push field type on context's stack: "
-                               "ft-addr=%p", type);
-                       goto end;
-               }
-
-               field_count = bt_ctf_field_type_common_get_field_count(type);
-               if (field_count < 0) {
-                       BT_LOGW("Cannot get field type's field count: "
-                               "ret=%" PRId64 ", ft-addr=%p",
-                               field_count, type);
-                       ret = field_count;
-                       goto end;
-               }
-
-               for (f_index = 0; f_index < field_count; f_index++) {
-                       struct bt_ctf_field_type_common *child_type =
-                               bt_ctf_field_type_common_borrow_field_at_index(type,
-                                       f_index);
-
-                       if (!child_type) {
-                               BT_LOGW("Cannot get field type's child field: "
-                                       "ft-addr=%p, index=%" PRId64 ", "
-                                       "count=%" PRId64, type, f_index,
-                                       field_count);
-                               ret = -1;
-                               goto end;
-                       }
-
-                       if (type_id == BT_CTF_FIELD_TYPE_ID_ARRAY||
-                                       type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
-                               type_stack_peek(ctx->type_stack)->index = -1;
-                       } else {
-                               type_stack_peek(ctx->type_stack)->index =
-                                       f_index;
-                       }
-
-                       BT_LOGV("Resolving field type's child field type: "
-                               "parent-ft-addr=%p, child-ft-addr=%p, "
-                               "index=%" PRId64 ", count=%" PRId64,
-                               type, child_type, f_index, field_count);
-                       ret = resolve_type(child_type, ctx);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               type_stack_pop(ctx->type_stack);
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Resolves the root field type corresponding to the scope `root_scope`.
- */
-static
-int resolve_root_type(enum bt_ctf_scope root_scope, struct resolve_context *ctx)
-{
-       int ret;
-
-       BT_ASSERT(type_stack_size(ctx->type_stack) == 0);
-       ctx->root_scope = root_scope;
-       ret = resolve_type(get_type_from_ctx(ctx, root_scope), ctx);
-       ctx->root_scope = BT_CTF_SCOPE_UNKNOWN;
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_resolve_types(
-               struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type,
-               struct bt_ctf_field_type_common *event_context_type,
-               struct bt_ctf_field_type_common *event_payload_type,
-               enum bt_ctf_resolve_flag flags)
-{
-       int ret = 0;
-       struct resolve_context ctx = {
-               .environment = environment,
-               .scopes = {
-                       packet_header_type,
-                       packet_context_type,
-                       event_header_type,
-                       stream_event_ctx_type,
-                       event_context_type,
-                       event_payload_type,
-               },
-               .root_scope = BT_CTF_SCOPE_UNKNOWN,
-       };
-
-       BT_LOGV("Resolving field types: "
-               "packet-header-ft-addr=%p, "
-               "packet-context-ft-addr=%p, "
-               "event-header-ft-addr=%p, "
-               "stream-event-context-ft-addr=%p, "
-               "event-context-ft-addr=%p, "
-               "event-payload-ft-addr=%p",
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type, event_context_type, event_payload_type);
-
-       /* Initialize type stack */
-       ctx.type_stack = type_stack_create();
-       if (!ctx.type_stack) {
-               BT_LOGE_STR("Cannot create field type stack.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Resolve packet header type */
-       if (flags & BT_CTF_RESOLVE_FLAG_PACKET_HEADER) {
-               ret = resolve_root_type(BT_CTF_SCOPE_TRACE_PACKET_HEADER, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve trace packet header field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve packet context type */
-       if (flags & BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT) {
-               ret = resolve_root_type(BT_CTF_SCOPE_STREAM_PACKET_CONTEXT, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve stream packet context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve event header type */
-       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_HEADER) {
-               ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_HEADER, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve stream event header field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve stream event context type */
-       if (flags & BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) {
-               ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_CONTEXT, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve stream event context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve event context type */
-       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT) {
-               ret = resolve_root_type(BT_CTF_SCOPE_EVENT_CONTEXT, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve event context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       /* Resolve event payload type */
-       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) {
-               ret = resolve_root_type(BT_CTF_SCOPE_EVENT_FIELDS, &ctx);
-               if (ret) {
-                       BT_LOGW("Cannot resolve event payload field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       BT_LOGV_STR("Resolved field types.");
-
-end:
-       type_stack_destroy(ctx.type_stack);
-
-       return ret;
-}
diff --git a/ctf-writer/stream-class.c b/ctf-writer/stream-class.c
deleted file mode 100644 (file)
index 4b61a7e..0000000
+++ /dev/null
@@ -1,1145 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-STREAM-CLASS"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/visitor-internal.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class,
-               const char *name, bt_ctf_object_release_func release_func)
-{
-       BT_LOGD("Initializing common stream class object: name=\"%s\"", name);
-
-       bt_ctf_object_init_shared_with_parent(&stream_class->base, release_func);
-       stream_class->name = g_string_new(name);
-       stream_class->event_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_ctf_object_try_spec_release);
-       if (!stream_class->event_classes) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       stream_class->event_classes_ht = g_hash_table_new_full(g_int64_hash,
-                       g_int64_equal, g_free, NULL);
-       if (!stream_class->event_classes_ht) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               goto error;
-       }
-
-       BT_LOGD("Initialized common stream class object: addr=%p, name=\"%s\"",
-               stream_class, name);
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class)
-{
-       BT_LOGD("Finalizing common stream class: addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-       bt_ctf_object_put_ref(stream_class->clock_class);
-
-       if (stream_class->event_classes_ht) {
-               g_hash_table_destroy(stream_class->event_classes_ht);
-       }
-       if (stream_class->event_classes) {
-               BT_LOGD_STR("Destroying event classes.");
-               g_ptr_array_free(stream_class->event_classes, TRUE);
-       }
-
-       if (stream_class->name) {
-               g_string_free(stream_class->name, TRUE);
-       }
-
-       BT_LOGD_STR("Putting event header field type.");
-       bt_ctf_object_put_ref(stream_class->event_header_field_type);
-       BT_LOGD_STR("Putting packet context field type.");
-       bt_ctf_object_put_ref(stream_class->packet_context_field_type);
-       BT_LOGD_STR("Putting event context field type.");
-       bt_ctf_object_put_ref(stream_class->event_context_field_type);
-}
-
-static
-void event_class_exists(gpointer element, gpointer query)
-{
-       struct bt_ctf_event_class_common *event_class_a = element;
-       struct bt_ctf_search_query *search_query = query;
-       struct bt_ctf_event_class_common *event_class_b = search_query->value;
-       int64_t id_a, id_b;
-
-       if (search_query->value == element) {
-               search_query->found = 1;
-               goto end;
-       }
-
-       /*
-        * Two event classes cannot share the same ID in a given
-        * stream class.
-        */
-       id_a = bt_ctf_event_class_common_get_id(event_class_a);
-       id_b = bt_ctf_event_class_common_get_id(event_class_b);
-
-       if (id_a < 0 || id_b < 0) {
-               /* at least one ID is not set: will be automatically set later */
-               goto end;
-       }
-
-       if (id_a == id_b) {
-               BT_LOGW("Event class with this ID already exists in the stream class: "
-                       "id=%" PRId64 ", name=\"%s\"",
-                       id_a, bt_ctf_event_class_common_get_name(event_class_a));
-               search_query->found = 1;
-               goto end;
-       }
-
-end:
-       return;
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_add_event_class(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_event_class_common *event_class,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
-{
-       int ret = 0;
-       int64_t *event_id = NULL;
-       struct bt_ctf_trace_common *trace = NULL;
-       struct bt_ctf_stream_class_common *old_stream_class = NULL;
-       struct bt_ctf_validation_output validation_output = { 0 };
-       struct bt_ctf_field_type_common *packet_header_type = NULL;
-       struct bt_ctf_field_type_common *packet_context_type = NULL;
-       struct bt_ctf_field_type_common *event_header_type = NULL;
-       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
-       struct bt_ctf_field_type_common *event_context_type = NULL;
-       struct bt_ctf_field_type_common *event_payload_type = NULL;
-       const enum bt_ctf_validation_flag validation_flags =
-               BT_CTF_VALIDATION_FLAG_EVENT;
-       struct bt_ctf_clock_class *expected_clock_class = NULL;
-
-       BT_ASSERT(copy_field_type_func);
-
-       if (!stream_class || !event_class) {
-               BT_LOGW("Invalid parameter: stream class or event class is NULL: "
-                       "stream-class-addr=%p, event-class-addr=%p",
-                       stream_class, event_class);
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGD("Adding event class to stream class: "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64 ", event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class),
-               event_class,
-               bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
-
-       if (stream_class->frozen) {
-               /*
-                * We only check that the event class to be added has a
-                * single class which matches the stream class's
-                * expected clock class if the stream class is frozen.
-                * If it's not, then this event class is added "as is"
-                * and the validation will be performed when calling
-                * either bt_ctf_trace_add_stream_class() or
-                * bt_ctf_event_create(). This is because the stream class's
-                * field types (packet context, event header, event
-                * context) could change before the next call to one of
-                * those two functions.
-                */
-               expected_clock_class = bt_ctf_object_get_ref(stream_class->clock_class);
-
-               /*
-                * At this point, `expected_clock_class` can be NULL,
-                * and bt_ctf_event_class_validate_single_clock_class()
-                * below can set it.
-                */
-               ret = bt_ctf_event_class_common_validate_single_clock_class(
-                       event_class, &expected_clock_class);
-               if (ret) {
-                       BT_LOGW("Event class contains a field type which is not "
-                               "recursively mapped to its stream class's "
-                               "expected clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-id=%" PRId64 ", "
-                               "stream-class-name=\"%s\", "
-                               "expected-clock-class-addr=%p, "
-                               "expected-clock-class-name=\"%s\"",
-                               stream_class,
-                               bt_ctf_stream_class_common_get_id(stream_class),
-                               bt_ctf_stream_class_common_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_ctf_clock_class_get_name(expected_clock_class) :
-                                       NULL);
-                       goto end;
-               }
-       }
-
-       event_id = g_new(int64_t, 1);
-       if (!event_id) {
-               BT_LOGE_STR("Failed to allocate one int64_t.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Check for duplicate event classes */
-       struct bt_ctf_search_query query = { .value = event_class, .found = 0 };
-       g_ptr_array_foreach(stream_class->event_classes, event_class_exists,
-               &query);
-       if (query.found) {
-               BT_LOGW_STR("Another event class part of this stream class has the same ID.");
-               ret = -1;
-               goto end;
-       }
-
-       old_stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
-       if (old_stream_class) {
-               /* Event class is already associated to a stream class. */
-               BT_LOGW("Event class is already part of another stream class: "
-                       "event-class-stream-class-addr=%p, "
-                       "event-class-stream-class-name=\"%s\", "
-                       "event-class-stream-class-id=%" PRId64,
-                       old_stream_class,
-                       bt_ctf_stream_class_common_get_name(old_stream_class),
-                       bt_ctf_stream_class_common_get_id(old_stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (trace) {
-               /*
-                * If the stream class is associated with a trace, then
-                * both those objects are frozen. Also, this event class
-                * is about to be frozen.
-                *
-                * Therefore the event class must be validated here.
-                * The trace and stream class should be valid at this
-                * point.
-                */
-               BT_ASSERT(trace->valid);
-               BT_ASSERT(stream_class->valid);
-               packet_header_type =
-                       bt_ctf_trace_common_borrow_packet_header_field_type(trace);
-               packet_context_type =
-                       bt_ctf_stream_class_common_borrow_packet_context_field_type(
-                               stream_class);
-               event_header_type =
-                       bt_ctf_stream_class_common_borrow_event_header_field_type(
-                               stream_class);
-               stream_event_ctx_type =
-                       bt_ctf_stream_class_common_borrow_event_context_field_type(
-                               stream_class);
-               event_context_type =
-                       bt_ctf_event_class_common_borrow_context_field_type(
-                               event_class);
-               event_payload_type =
-                       bt_ctf_event_class_common_borrow_payload_field_type(
-                               event_class);
-               ret = bt_ctf_validate_class_types(
-                       trace->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,
-                       copy_field_type_func);
-
-               if (ret) {
-                       /*
-                        * This means something went wrong during the
-                        * validation process, not that the objects are
-                        * invalid.
-                        */
-                       BT_LOGE("Failed to validate event class: ret=%d", ret);
-                       goto end;
-               }
-
-               if ((validation_output.valid_flags & validation_flags) !=
-                               validation_flags) {
-                       /* Invalid event class */
-                       BT_LOGW("Invalid trace, stream class, or event class: "
-                               "valid-flags=0x%x",
-                               validation_output.valid_flags);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /* Only set an event ID if none was explicitly set before */
-       *event_id = bt_ctf_event_class_common_get_id(event_class);
-       if (*event_id < 0) {
-               BT_LOGV("Event class has no ID: automatically setting it: "
-                       "id=%" PRId64, stream_class->next_event_id);
-
-               if (bt_ctf_event_class_common_set_id(event_class,
-                               stream_class->next_event_id)) {
-                       BT_LOGE("Cannot set event class's ID: id=%" PRId64,
-                               stream_class->next_event_id);
-                       ret = -1;
-                       goto end;
-               }
-               stream_class->next_event_id++;
-               *event_id = stream_class->next_event_id;
-       }
-
-       bt_ctf_object_set_parent(&event_class->base, &stream_class->base);
-
-       if (trace) {
-               /*
-                * At this point we know that the function will be
-                * successful. Therefore we can replace the event
-                * class's field types with what's in the validation
-                * output structure and mark this event class as valid.
-                */
-               bt_ctf_validation_replace_types(NULL, NULL, event_class,
-                       &validation_output, validation_flags);
-               event_class->valid = 1;
-
-               /*
-                * Put what was not moved in
-                * bt_ctf_validation_replace_types().
-                */
-               bt_ctf_validation_output_put_types(&validation_output);
-       }
-
-       /* Add to the event classes of the stream class */
-       g_ptr_array_add(stream_class->event_classes, event_class);
-       g_hash_table_insert(stream_class->event_classes_ht, event_id,
-                       event_class);
-       event_id = NULL;
-
-       /* Freeze the event class */
-       bt_ctf_event_class_common_freeze(event_class);
-
-       /*
-        * It is safe to set the stream class's unique clock class
-        * now if the stream class is frozen.
-        */
-       if (stream_class->frozen && expected_clock_class) {
-               BT_ASSERT(!stream_class->clock_class ||
-                       stream_class->clock_class == expected_clock_class);
-               BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
-       }
-
-       BT_LOGD("Added event class to stream class: "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64 ", event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class),
-               event_class,
-               bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class));
-
-end:
-       bt_ctf_validation_output_put_types(&validation_output);
-       bt_ctf_object_put_ref(expected_clock_class);
-       g_free(event_id);
-       return ret;
-}
-
-static
-int64_t get_event_class_count(void *element)
-{
-       return bt_ctf_stream_class_get_event_class_count(
-                       (struct bt_ctf_stream_class *) element);
-}
-
-static
-void *get_event_class(void *element, int i)
-{
-       return bt_ctf_stream_class_get_event_class_by_index(
-                       (struct bt_ctf_stream_class *) element, i);
-}
-
-static
-int visit_event_class(void *object, bt_ctf_visitor visitor,void *data)
-{
-       struct bt_ctf_visitor_object obj = {
-               .object = object,
-               .type = BT_CTF_VISITOR_OBJECT_TYPE_EVENT_CLASS
-       };
-
-       return visitor(&obj, data);
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class,
-               bt_ctf_visitor visitor, void *data)
-{
-       int ret;
-       struct bt_ctf_visitor_object obj = {
-               .object = stream_class,
-               .type = BT_CTF_VISITOR_OBJECT_TYPE_STREAM_CLASS
-       };
-
-       if (!stream_class || !visitor) {
-               BT_LOGW("Invalid parameter: stream class or visitor is NULL: "
-                       "stream-class-addr=%p, visitor=%p",
-                       stream_class, visitor);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_visitor_helper(&obj, get_event_class_count,
-                       get_event_class,
-                       visit_event_class, visitor, data);
-       BT_LOGV("bt_ctf_visitor_helper() returned: ret=%d", ret);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
-               bt_ctf_visitor visitor, void *data)
-{
-       return bt_ctf_stream_class_common_visit(BT_CTF_FROM_COMMON(stream_class),
-               visitor, data);
-}
-
-BT_HIDDEN
-void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class)
-{
-       if (!stream_class || stream_class->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-       stream_class->frozen = 1;
-       bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
-       bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
-       bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
-       bt_ctf_clock_class_freeze(stream_class->clock_class);
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_validate_single_clock_class(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_clock_class **expected_clock_class)
-{
-       int ret;
-       uint64_t i;
-
-       BT_ASSERT(stream_class);
-       BT_ASSERT(expected_clock_class);
-       ret = bt_ctf_field_type_common_validate_single_clock_class(
-               stream_class->packet_context_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Stream class's packet context field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->packet_context_field_type);
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_validate_single_clock_class(
-               stream_class->event_header_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Stream class's event header field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->event_header_field_type);
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_common_validate_single_clock_class(
-               stream_class->event_context_field_type,
-               expected_clock_class);
-       if (ret) {
-               BT_LOGW("Stream class's event context field type "
-                       "is not recursively mapped to the "
-                       "expected clock class: "
-                       "stream-class-addr=%p, "
-                       "stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", "
-                       "ft-addr=%p",
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       stream_class->id,
-                       stream_class->event_context_field_type);
-               goto end;
-       }
-
-       for (i = 0; i < stream_class->event_classes->len; i++) {
-               struct bt_ctf_event_class_common *event_class =
-                       g_ptr_array_index(stream_class->event_classes, i);
-
-               BT_ASSERT(event_class);
-               ret = bt_ctf_event_class_common_validate_single_clock_class(
-                       event_class, expected_clock_class);
-               if (ret) {
-                       BT_LOGW("Stream class's event class contains a "
-                               "field type which is not recursively mapped to "
-                               "the expected clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-name=\"%s\", "
-                               "stream-class-id=%" PRId64,
-                               stream_class,
-                               bt_ctf_stream_class_common_get_name(stream_class),
-                               stream_class->id);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int init_event_header(struct bt_ctf_stream_class *stream_class)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *event_header_type =
-               bt_ctf_field_type_structure_create();
-       struct bt_ctf_field_type *_uint32_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
-       struct bt_ctf_field_type *_uint64_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
-
-       if (!event_header_type) {
-               BT_LOGE_STR("Cannot create empty structure field type.");
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(event_header_type,
-               _uint32_t, "id");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `id` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(event_header_type,
-               _uint64_t, "timestamp");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(stream_class->common.event_header_field_type);
-       stream_class->common.event_header_field_type =
-               (void *) event_header_type;
-       event_header_type = NULL;
-
-end:
-       if (ret) {
-               bt_ctf_object_put_ref(event_header_type);
-       }
-
-       bt_ctf_object_put_ref(_uint32_t);
-       bt_ctf_object_put_ref(_uint64_t);
-       return ret;
-}
-
-static
-int init_packet_context(struct bt_ctf_stream_class *stream_class)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *packet_context_type =
-               bt_ctf_field_type_structure_create();
-       struct bt_ctf_field_type *_uint64_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
-       struct bt_ctf_field_type *ts_begin_end_uint64_t;
-
-       if (!packet_context_type) {
-               BT_LOGE_STR("Cannot create empty structure field type.");
-               ret = -1;
-               goto end;
-       }
-
-       ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t);
-       if (!ts_begin_end_uint64_t) {
-               BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * We create a stream packet context as proposed in the CTF
-        * specification.
-        */
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               ts_begin_end_uint64_t, "timestamp_begin");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               ts_begin_end_uint64_t, "timestamp_end");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               _uint64_t, "content_size");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               _uint64_t, "packet_size");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
-               _uint64_t, "events_discarded");
-       if (ret) {
-               BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(stream_class->common.packet_context_field_type);
-       stream_class->common.packet_context_field_type =
-               (void *) packet_context_type;
-       packet_context_type = NULL;
-
-end:
-       if (ret) {
-               bt_ctf_object_put_ref(packet_context_type);
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(_uint64_t);
-       bt_ctf_object_put_ref(ts_begin_end_uint64_t);
-       return ret;
-}
-
-static
-void bt_ctf_stream_class_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_stream_class *stream_class;
-
-       stream_class = (void *) obj;
-       BT_LOGD("Destroying CTF writer stream class: addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_ctf_stream_class_get_name(stream_class),
-               bt_ctf_stream_class_get_id(stream_class));
-       bt_ctf_stream_class_common_finalize(BT_CTF_TO_COMMON(stream_class));
-       bt_ctf_object_put_ref(stream_class->clock);
-       g_free(stream_class);
-}
-
-struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name)
-{
-       struct bt_ctf_stream_class *stream_class;
-       int ret;
-
-       BT_LOGD("Creating CTF writer stream class object: name=\"%s\"", name);
-       stream_class = g_new0(struct bt_ctf_stream_class, 1);
-       if (!stream_class) {
-               BT_LOGE_STR("Failed to allocate one CTF writer stream class.");
-               goto error;
-       }
-
-       ret = bt_ctf_stream_class_common_initialize(BT_CTF_TO_COMMON(stream_class),
-               name, bt_ctf_stream_class_destroy);
-       if (ret) {
-               /* bt_ctf_stream_class_common_initialize() logs errors */
-               goto error;
-       }
-
-       ret = init_event_header(stream_class);
-       if (ret) {
-               BT_LOGE_STR("Cannot initialize stream class's event header field type.");
-               goto error;
-       }
-
-       ret = init_packet_context(stream_class);
-       if (ret) {
-               BT_LOGE_STR("Cannot initialize stream class's packet context field type.");
-               goto error;
-       }
-
-       BT_LOGD("Created CTF writer stream class object: addr=%p, name=\"%s\"",
-               stream_class, name);
-       return stream_class;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_class);
-       return stream_class;
-}
-
-static
-int try_map_clock_class(struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *parent_ft, const char *field_name)
-{
-       struct bt_ctf_clock_class *mapped_clock_class = NULL;
-       int ret = 0;
-       struct bt_ctf_field_type *ft =
-               bt_ctf_field_type_structure_get_field_type_by_name(parent_ft,
-                       field_name);
-
-       BT_ASSERT(stream_class->clock);
-
-       if (!ft) {
-               /* Field does not exist: not an error */
-               goto end;
-       }
-
-       BT_ASSERT(((struct bt_ctf_field_type_common *) ft)->id ==
-               BT_CTF_FIELD_TYPE_ID_INTEGER);
-       mapped_clock_class =
-               bt_ctf_field_type_integer_get_mapped_clock_class(ft);
-       if (!mapped_clock_class) {
-               struct bt_ctf_field_type *ft_copy;
-
-               if (!stream_class->clock) {
-                       BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
-                               "stream-class-addr=%p, stream-class-name=\"%s\", "
-                               "stream-class-id=%" PRId64 ", ft-addr=%p",
-                               stream_class,
-                               bt_ctf_stream_class_get_name(stream_class),
-                               bt_ctf_stream_class_get_id(stream_class), ft);
-                       ret = -1;
-                       goto end;
-               }
-
-               ft_copy = bt_ctf_field_type_copy(ft);
-               if (!ft_copy) {
-                       BT_LOGE("Failed to copy integer field type: ft-addr=%p",
-                               ft);
-               }
-
-               ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
-                       (void *) ft_copy, stream_class->clock->clock_class);
-               BT_ASSERT(ret == 0);
-
-               ret = bt_ctf_field_type_common_structure_replace_field(
-                       (void *) parent_ft, field_name, (void *) ft_copy);
-               bt_ctf_object_put_ref(ft_copy);
-               BT_LOGV("Automatically mapped field type to stream class's clock class: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", ft-addr=%p, "
-                       "ft-copy-addr=%p",
-                       stream_class,
-                       bt_ctf_stream_class_get_name(stream_class),
-                       bt_ctf_stream_class_get_id(stream_class), ft, ft_copy);
-       }
-
-end:
-       bt_ctf_object_put_ref(ft);
-       bt_ctf_object_put_ref(mapped_clock_class);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_map_clock_class(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *packet_context_type,
-               struct bt_ctf_field_type *event_header_type)
-{
-       int ret = 0;
-
-       BT_ASSERT(stream_class);
-
-       if (!stream_class->clock) {
-               /* No clock class to map to */
-               goto end;
-       }
-
-       if (packet_context_type) {
-               if (try_map_clock_class(stream_class, packet_context_type,
-                               "timestamp_begin")) {
-                       BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
-                       ret = -1;
-                       goto end;
-               }
-
-               if (try_map_clock_class(stream_class, packet_context_type,
-                               "timestamp_end")) {
-                       BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       if (event_header_type) {
-               if (try_map_clock_class(stream_class, event_header_type,
-                               "timestamp")) {
-                       BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-struct bt_ctf_clock *bt_ctf_stream_class_get_clock(
-               struct bt_ctf_stream_class *stream_class)
-{
-       struct bt_ctf_clock *clock = NULL;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               goto end;
-       }
-
-       if (!stream_class->clock) {
-               BT_LOGV("Stream class has no clock: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_get_name(stream_class),
-                       bt_ctf_stream_class_get_id(stream_class));
-               goto end;
-       }
-
-       clock = bt_ctf_object_get_ref(stream_class->clock);
-
-end:
-       return clock;
-}
-
-int bt_ctf_stream_class_set_clock(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_clock *clock)
-{
-       int ret = 0;
-
-       if (!stream_class || !clock) {
-               BT_LOGW("Invalid parameter: stream class or clock is NULL: "
-                       "stream-class-addr=%p, clock-addr=%p",
-                       stream_class, clock);
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->common.frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_get_name(stream_class),
-                       bt_ctf_stream_class_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       /* Replace the current clock of this stream class. */
-       bt_ctf_object_put_ref(stream_class->clock);
-       stream_class->clock = bt_ctf_object_get_ref(clock);
-       BT_LOGV("Set stream class's clock: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", "
-               "clock-addr=%p, clock-name=\"%s\"",
-               stream_class,
-               bt_ctf_stream_class_get_name(stream_class),
-               bt_ctf_stream_class_get_id(stream_class),
-               stream_class->clock,
-               bt_ctf_clock_get_name(stream_class->clock));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
-               struct metadata_context *context)
-{
-       int ret = 0;
-       size_t i;
-       struct bt_ctf_trace *trace;
-       struct bt_ctf_field_type *packet_header_type = NULL;
-
-       BT_LOGD("Serializing stream class's metadata: "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64 ", metadata-context-addr=%p",
-               stream_class,
-               bt_ctf_stream_class_get_name(stream_class),
-               bt_ctf_stream_class_get_id(stream_class), context);
-       g_string_assign(context->field_name, "");
-       context->current_indentation_level = 1;
-       if (!stream_class->common.id_set) {
-               BT_LOGW_STR("Stream class's ID is not set.");
-               ret = -1;
-               goto end;
-       }
-
-       g_string_append(context->string, "stream {\n");
-
-       /*
-        * The reference to the trace is only borrowed since the
-        * serialization of the stream class might have been triggered
-        * by the trace's destruction. In such a case, the trace's
-        * reference count would, unexepectedly, go through the sequence
-        * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction
-        * and serialization.
-        */
-       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
-               BT_CTF_TO_COMMON(stream_class)));
-       BT_ASSERT(trace);
-       packet_header_type = bt_ctf_trace_get_packet_header_field_type(trace);
-       trace = NULL;
-       if (packet_header_type) {
-               struct bt_ctf_field_type *stream_id_type;
-
-               stream_id_type =
-                       bt_ctf_field_type_structure_get_field_type_by_name(
-                               packet_header_type, "stream_id");
-               if (stream_id_type) {
-                       /*
-                        * Only set the stream's id if the trace's packet header
-                        * contains a stream_id field. This field is only
-                        * needed if the trace contains only one stream
-                        * class.
-                        */
-                       g_string_append_printf(context->string,
-                               "\tid = %" PRId64 ";\n",
-                               stream_class->common.id);
-               }
-               bt_ctf_object_put_ref(stream_id_type);
-       }
-       if (stream_class->common.event_header_field_type) {
-               BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
-               g_string_append(context->string, "\tevent.header := ");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) stream_class->common.event_header_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";");
-       }
-
-
-       if (stream_class->common.packet_context_field_type) {
-               BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
-               g_string_append(context->string, "\n\n\tpacket.context := ");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) stream_class->common.packet_context_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";");
-       }
-
-       if (stream_class->common.event_context_field_type) {
-               BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
-               g_string_append(context->string, "\n\n\tevent.context := ");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) stream_class->common.event_context_field_type,
-                       context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-               g_string_append(context->string, ";");
-       }
-
-       g_string_append(context->string, "\n};\n\n");
-
-       for (i = 0; i < stream_class->common.event_classes->len; i++) {
-               struct bt_ctf_event_class *event_class =
-                       stream_class->common.event_classes->pdata[i];
-
-               ret = bt_ctf_event_class_serialize(event_class, context);
-               if (ret) {
-                       BT_LOGW("Cannot serialize event class's metadata: "
-                               "event-class-addr=%p, event-class-name=\"%s\", "
-                               "event-class-id=%" PRId64,
-                               event_class,
-                               bt_ctf_event_class_get_name(event_class),
-                               bt_ctf_event_class_get_id(event_class));
-                       goto end;
-               }
-       }
-
-end:
-       bt_ctf_object_put_ref(packet_header_type);
-       context->current_indentation_level = 0;
-       return ret;
-}
-
-struct bt_ctf_trace *bt_ctf_stream_class_get_trace(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_object_get_ref(bt_ctf_stream_class_common_borrow_trace(
-               BT_CTF_TO_COMMON(stream_class)));
-}
-
-const char *bt_ctf_stream_class_get_name(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_stream_class_common_get_name(BT_CTF_TO_COMMON(stream_class));
-}
-
-int bt_ctf_stream_class_set_name(
-               struct bt_ctf_stream_class *stream_class, const char *name)
-{
-       return bt_ctf_stream_class_common_set_name(BT_CTF_TO_COMMON(stream_class),
-               name);
-}
-
-int64_t bt_ctf_stream_class_get_id(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_stream_class_common_get_id(BT_CTF_TO_COMMON(stream_class));
-}
-
-int bt_ctf_stream_class_set_id(
-               struct bt_ctf_stream_class *stream_class, uint64_t id)
-{
-       return bt_ctf_stream_class_common_set_id(BT_CTF_TO_COMMON(stream_class), id);
-}
-
-struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_packet_context_field_type(
-                       BT_CTF_TO_COMMON(stream_class)));
-}
-
-int bt_ctf_stream_class_set_packet_context_type(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *packet_context_type)
-{
-       return bt_ctf_stream_class_common_set_packet_context_field_type(
-               BT_CTF_TO_COMMON(stream_class), (void *) packet_context_type);
-}
-
-struct bt_ctf_field_type *
-bt_ctf_stream_class_get_event_header_type(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_event_header_field_type(
-                       BT_CTF_TO_COMMON(stream_class)));
-}
-
-int bt_ctf_stream_class_set_event_header_type(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *event_header_type)
-{
-       return bt_ctf_stream_class_common_set_event_header_field_type(
-               BT_CTF_TO_COMMON(stream_class), (void *) event_header_type);
-}
-
-struct bt_ctf_field_type *
-bt_ctf_stream_class_get_event_context_type(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_event_context_field_type(
-                       BT_CTF_TO_COMMON(stream_class)));
-}
-
-int bt_ctf_stream_class_set_event_context_type(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *event_context_type)
-{
-       return bt_ctf_stream_class_common_set_event_context_field_type(
-               BT_CTF_TO_COMMON(stream_class), (void *) event_context_type);
-}
-
-int64_t bt_ctf_stream_class_get_event_class_count(
-               struct bt_ctf_stream_class *stream_class)
-{
-       return bt_ctf_stream_class_common_get_event_class_count(
-               BT_CTF_TO_COMMON(stream_class));
-}
-
-struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
-               struct bt_ctf_stream_class *stream_class, uint64_t index)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_event_class_by_index(
-                       BT_CTF_TO_COMMON(stream_class), index));
-}
-
-struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
-               struct bt_ctf_stream_class *stream_class, uint64_t id)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_stream_class_common_borrow_event_class_by_id(
-                       BT_CTF_TO_COMMON(stream_class), id));
-}
-
-int bt_ctf_stream_class_add_event_class(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_event_class *event_class)
-{
-       return bt_ctf_stream_class_common_add_event_class(
-               BT_CTF_TO_COMMON(stream_class), BT_CTF_TO_COMMON(event_class),
-               (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy);
-}
diff --git a/ctf-writer/stream.c b/ctf-writer/stream.c
deleted file mode 100644 (file)
index fc7557e..0000000
+++ /dev/null
@@ -1,1953 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-STREAM"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/stream.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <unistd.h>
-
-BT_HIDDEN
-void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream)
-{
-       BT_LOGD("Finalizing common stream object: addr=%p, name=\"%s\"",
-               stream, bt_ctf_stream_common_get_name(stream));
-
-       if (stream->name) {
-               g_string_free(stream->name, TRUE);
-       }
-}
-
-BT_HIDDEN
-int bt_ctf_stream_common_initialize(
-               struct bt_ctf_stream_common *stream,
-               struct bt_ctf_stream_class_common *stream_class, const char *name,
-               uint64_t id, bt_ctf_object_release_func release_func)
-{
-       int ret = 0;
-       struct bt_ctf_trace_common *trace = NULL;
-
-       bt_ctf_object_init_shared_with_parent(&stream->base, release_func);
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               goto error;
-       }
-
-       BT_LOGD("Initializing common stream object: stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-name=\"%s\", "
-               "stream-id=%" PRIu64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               name, id);
-       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
-       if (!trace) {
-               BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-name=\"%s\"",
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class), name);
-               goto error;
-       }
-
-       if (id != -1ULL) {
-               /*
-                * Validate that the given ID is unique amongst all the
-                * existing trace's streams created from the same stream
-                * class.
-                */
-               size_t i;
-
-               for (i = 0; i < trace->streams->len; i++) {
-                       struct bt_ctf_stream_common *trace_stream =
-                               g_ptr_array_index(trace->streams, i);
-
-                       if (trace_stream->stream_class != (void *) stream_class) {
-                               continue;
-                       }
-
-                       if (trace_stream->id == id) {
-                               BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID.");
-                               goto error;
-                       }
-               }
-       }
-
-       /*
-        * Acquire reference to parent since stream will become publicly
-        * reachable; it needs its parent to remain valid.
-        */
-       bt_ctf_object_set_parent(&stream->base, &trace->base);
-       stream->stream_class = stream_class;
-       stream->id = (int64_t) id;
-
-       if (name) {
-               stream->name = g_string_new(name);
-               if (!stream->name) {
-                       BT_LOGE_STR("Failed to allocate a GString.");
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Set common stream's trace parent: trace-addr=%p", trace);
-
-       /* Add this stream to the trace's streams */
-       BT_LOGD("Created common stream object: addr=%p", stream);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-void bt_ctf_stream_destroy(struct bt_ctf_object *obj);
-
-static
-int try_set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
-
-static
-int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *field_type = NULL;
-
-       if (!field) {
-               BT_LOGW_STR("Invalid parameter: field is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       field_type = bt_ctf_field_get_type(field);
-       BT_ASSERT(field_type);
-
-       if (bt_ctf_field_type_get_type_id(field_type) !=
-                       BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               /* Not an integer and the value is unset, error. */
-               BT_LOGW("Invalid parameter: field's type is not an integer field type: "
-                       "field-addr=%p, ft-addr=%p, ft-id=%s",
-                       field, field_type,
-                       bt_ctf_field_type_id_string((int)
-                               bt_ctf_field_type_get_type_id(field_type)));
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_ctf_field_type_integer_is_signed(field_type)) {
-               ret = bt_ctf_field_integer_signed_set_value(field, (int64_t) value);
-               if (ret) {
-                       /* Value is out of range, error. */
-                       BT_LOGW("Cannot set signed integer field's value: "
-                               "addr=%p, value=%" PRId64,
-                               field, (int64_t) value);
-                       goto end;
-               }
-       } else {
-               ret = bt_ctf_field_integer_unsigned_set_value(field, value);
-               if (ret) {
-                       /* Value is out of range, error. */
-                       BT_LOGW("Cannot set unsigned integer field's value: "
-                               "addr=%p, value=%" PRIu64,
-                               field, value);
-                       goto end;
-               }
-       }
-end:
-       bt_ctf_object_put_ref(field_type);
-       return ret;
-}
-
-static
-int set_packet_header_magic(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_header, "magic");
-       const uint32_t magic_value = 0xc1fc1fc1;
-
-       BT_ASSERT(stream);
-
-       if (!magic_field) {
-               /* No magic field found. Not an error, skip. */
-               BT_LOGV("No field named `magic` in packet header: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = bt_ctf_field_integer_unsigned_set_value(magic_field,
-               (uint64_t) magic_value);
-
-       if (ret) {
-               BT_LOGW("Cannot set packet header field's `magic` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       magic_field, (uint64_t) magic_value);
-       } else {
-               BT_LOGV("Set packet header field's `magic` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       magic_field, (uint64_t) magic_value);
-       }
-end:
-       bt_ctf_object_put_ref(magic_field);
-       return ret;
-}
-
-static
-int set_packet_header_uuid(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       int64_t i;
-       struct bt_ctf_trace *trace = NULL;
-       struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_header, "uuid");
-
-       BT_ASSERT(stream);
-
-       if (!uuid_field) {
-               /* No uuid field found. Not an error, skip. */
-               BT_LOGV("No field named `uuid` in packet header: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       trace = (struct bt_ctf_trace *)
-               bt_ctf_object_get_parent(&stream->common.base);
-
-       for (i = 0; i < 16; i++) {
-               struct bt_ctf_field *uuid_element =
-                       bt_ctf_field_array_get_field(uuid_field, i);
-
-               ret = bt_ctf_field_integer_unsigned_set_value(
-                       uuid_element, (uint64_t) trace->common.uuid[i]);
-               bt_ctf_object_put_ref(uuid_element);
-               if (ret) {
-                       BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
-                               "value=%" PRIu64 ", index=%" PRId64,
-                               stream, bt_ctf_stream_get_name(stream),
-                               uuid_element, (uint64_t) trace->common.uuid[i], i);
-                       goto end;
-               }
-       }
-
-       BT_LOGV("Set packet header field's `uuid` field's value: "
-               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), uuid_field);
-
-end:
-       bt_ctf_object_put_ref(uuid_field);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
-       return ret;
-}
-static
-int set_packet_header_stream_id(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       uint32_t stream_id;
-       struct bt_ctf_field *stream_id_field =
-               bt_ctf_field_structure_get_field_by_name(
-                       stream->packet_header, "stream_id");
-
-       if (!stream_id_field) {
-               /* No stream_id field found. Not an error, skip. */
-               BT_LOGV("No field named `stream_id` in packet header: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       stream_id = stream->common.stream_class->id;
-       ret = bt_ctf_field_integer_unsigned_set_value(stream_id_field,
-               (uint64_t) stream_id);
-       if (ret) {
-               BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       stream_id_field, (uint64_t) stream_id);
-       } else {
-               BT_LOGV("Set packet header field's `stream_id` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       stream_id_field, (uint64_t) stream_id);
-       }
-
-end:
-       bt_ctf_object_put_ref(stream_id_field);
-       return ret;
-}
-
-static
-int auto_populate_packet_header(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-
-       if (!stream->packet_header) {
-               goto end;
-       }
-
-       ret = set_packet_header_magic(stream);
-       if (ret) {
-               BT_LOGW("Cannot set packet header's magic number field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = set_packet_header_uuid(stream);
-       if (ret) {
-               BT_LOGW("Cannot set packet header's UUID field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = set_packet_header_stream_id(stream);
-       if (ret) {
-               BT_LOGW("Cannot set packet header's stream class ID field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       BT_LOGV("Automatically populated stream's packet header's known fields: "
-               "stream-addr=%p, stream-name=\"%s\"",
-               stream, bt_ctf_stream_get_name(stream));
-
-end:
-       return ret;
-}
-
-static
-int set_packet_context_packet_size(struct bt_ctf_stream *stream,
-               uint64_t packet_size_bits)
-{
-       int ret = 0;
-       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "packet_size");
-
-       ret = bt_ctf_field_integer_unsigned_set_value(field, packet_size_bits);
-       if (ret) {
-               BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, packet_size_bits);
-       } else {
-               BT_LOGV("Set packet context field's `packet_size` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, packet_size_bits);
-       }
-
-       bt_ctf_object_put_ref(field);
-       return ret;
-}
-
-static
-int set_packet_context_content_size(struct bt_ctf_stream *stream,
-               uint64_t content_size_bits)
-{
-       int ret = 0;
-       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "content_size");
-
-       BT_ASSERT(stream);
-
-       if (!field) {
-               /* No content size field found. Not an error, skip. */
-               BT_LOGV("No field named `content_size` in packet context: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = bt_ctf_field_integer_unsigned_set_value(field, content_size_bits);
-       if (ret) {
-               BT_LOGW("Cannot set packet context field's `content_size` integer field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, content_size_bits);
-       } else {
-               BT_LOGV("Set packet context field's `content_size` field's value: "
-                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, content_size_bits);
-       }
-
-end:
-       bt_ctf_object_put_ref(field);
-       return ret;
-}
-
-static
-int set_packet_context_events_discarded(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "events_discarded");
-
-       BT_ASSERT(stream);
-
-       if (!field) {
-               /* No discarded events count field found. Not an error, skip. */
-               BT_LOGV("No field named `events_discarded` in packet context: skipping: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       /*
-        * If the field is set by the user, make sure that the value is
-        * greater than or equal to the stream's current count of
-        * discarded events. We do not allow wrapping here. If it's
-        * valid, update the stream's current count.
-        */
-       if (bt_ctf_field_is_set_recursive(field)) {
-               uint64_t user_val;
-
-               ret = bt_ctf_field_integer_unsigned_get_value(field,
-                       &user_val);
-               if (ret) {
-                       BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
-                               stream, bt_ctf_stream_get_name(stream), field);
-                       goto end;
-               }
-
-               if (user_val < stream->discarded_events) {
-                       BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: "
-                               "value is lesser than the stream's current discarded events count: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
-                               "value=%" PRIu64 ", "
-                               "stream-discarded-events-count=%" PRIu64,
-                               stream, bt_ctf_stream_get_name(stream), field,
-                               user_val, stream->discarded_events);
-                       goto end;
-               }
-
-               stream->discarded_events = user_val;
-       } else {
-               ret = bt_ctf_field_integer_unsigned_set_value(field,
-                       stream->discarded_events);
-               if (ret) {
-                       BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                               stream, bt_ctf_stream_get_name(stream),
-                               field, stream->discarded_events);
-               } else {
-                       BT_LOGV("Set packet context field's `events_discarded` field's value: "
-                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
-                               stream, bt_ctf_stream_get_name(stream),
-                               field, stream->discarded_events);
-               }
-       }
-
-end:
-       bt_ctf_object_put_ref(field);
-       return ret;
-}
-
-static
-void update_clock_value(uint64_t *val, uint64_t new_val,
-               unsigned int new_val_size)
-{
-       const uint64_t pow2 = 1ULL << new_val_size;
-       const uint64_t mask = pow2 - 1;
-       uint64_t val_masked;
-
-#ifdef BT_LOG_ENABLED_VERBOSE
-       uint64_t old_val = *val;
-#endif
-
-       if (new_val_size == 64) {
-               *val = new_val;
-               goto end;
-       }
-
-       val_masked = *val & mask;
-
-       if (new_val < val_masked) {
-               /* Wrapped once */
-               new_val |= pow2;
-       }
-
-       *val &= ~mask;
-       *val |= new_val;
-
-end:
-       BT_LOGV("Updated clock value: old-val=%" PRIu64 ", new-val=%" PRIu64,
-               old_val, *val);
-       return;
-}
-
-static
-int visit_field_update_clock_value(struct bt_ctf_field *field, uint64_t *val)
-{
-       int ret = 0;
-       struct bt_ctf_field_common *field_common = (void *) field;
-
-       if (!field) {
-               goto end;
-       }
-
-       switch (bt_ctf_field_get_type_id(field)) {
-       case BT_CTF_FIELD_TYPE_ID_INTEGER:
-       {
-               struct bt_ctf_clock_class *cc =
-                       bt_ctf_field_type_integer_get_mapped_clock_class(
-                               (void *) field_common->type);
-               int val_size;
-               uint64_t uval;
-
-               if (!cc) {
-                       goto end;
-               }
-
-               bt_ctf_object_put_ref(cc);
-               val_size = bt_ctf_field_type_integer_get_size(
-                       (void *) field_common->type);
-               BT_ASSERT(val_size >= 1);
-
-               if (bt_ctf_field_type_integer_is_signed(
-                               (void *) field_common->type)) {
-                       int64_t ival;
-
-                       ret = bt_ctf_field_integer_signed_get_value(field, &ival);
-                       uval = (uint64_t) ival;
-               } else {
-                       ret = bt_ctf_field_integer_unsigned_get_value(field, &uval);
-               }
-
-               if (ret) {
-                       /* Not set */
-                       goto end;
-               }
-
-               update_clock_value(val, uval, val_size);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ENUM:
-       {
-               struct bt_ctf_field *int_field =
-                       bt_ctf_field_enumeration_get_container(field);
-
-               BT_ASSERT(int_field);
-               ret = visit_field_update_clock_value(int_field, val);
-               bt_ctf_object_put_ref(int_field);
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       {
-               uint64_t i;
-               int64_t len = bt_ctf_field_type_array_get_length(
-                       (void *) field_common->type);
-
-               BT_ASSERT(len >= 0);
-
-               for (i = 0; i < len; i++) {
-                       struct bt_ctf_field *elem_field =
-                               bt_ctf_field_array_get_field(field, i);
-
-                       BT_ASSERT(elem_field);
-                       ret = visit_field_update_clock_value(elem_field, val);
-                       bt_ctf_object_put_ref(elem_field);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       {
-               uint64_t i;
-               int64_t len = bt_ctf_field_common_sequence_get_length(
-                       (void *) field);
-
-               if (len < 0) {
-                       ret = -1;
-                       goto end;
-               }
-
-               for (i = 0; i < len; i++) {
-                       struct bt_ctf_field *elem_field =
-                               bt_ctf_field_sequence_get_field(field, i);
-
-                       BT_ASSERT(elem_field);
-                       ret = visit_field_update_clock_value(elem_field, val);
-                       bt_ctf_object_put_ref(elem_field);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               uint64_t i;
-               int64_t len = bt_ctf_field_type_structure_get_field_count(
-                       (void *) field_common->type);
-
-               BT_ASSERT(len >= 0);
-
-               for (i = 0; i < len; i++) {
-                       struct bt_ctf_field *member_field =
-                               bt_ctf_field_structure_get_field_by_index(field, i);
-
-                       BT_ASSERT(member_field);
-                       ret = visit_field_update_clock_value(member_field, val);
-                       bt_ctf_object_put_ref(member_field);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               break;
-       }
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-       {
-               struct bt_ctf_field *cur_field =
-                       bt_ctf_field_variant_get_current_field(field);
-
-               if (!cur_field) {
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = visit_field_update_clock_value(cur_field, val);
-               bt_ctf_object_put_ref(cur_field);
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-int visit_event_update_clock_value(struct bt_ctf_event *event, uint64_t *val)
-{
-       int ret = 0;
-       struct bt_ctf_field *field;
-
-       field = bt_ctf_event_get_header(event);
-       ret = visit_field_update_clock_value(field, val);
-       bt_ctf_object_put_ref(field);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically update clock value in "
-                       "event's header.");
-               goto end;
-       }
-
-       field = bt_ctf_event_get_stream_event_context(event);
-       ret = visit_field_update_clock_value(field, val);
-       bt_ctf_object_put_ref(field);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically update clock value in "
-                       "event's stream event context.");
-               goto end;
-       }
-
-       field = bt_ctf_event_get_context(event);
-       ret = visit_field_update_clock_value(field, val);
-       bt_ctf_object_put_ref(field);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically update clock value in "
-                       "event's context.");
-               goto end;
-       }
-
-       field = bt_ctf_event_get_payload_field(event);
-       ret = visit_field_update_clock_value(field, val);
-       bt_ctf_object_put_ref(field);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically update clock value in "
-                       "event's payload.");
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int set_packet_context_timestamps(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       uint64_t val;
-       uint64_t cur_clock_value;
-       uint64_t init_clock_value = 0;
-       struct bt_ctf_field *ts_begin_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "timestamp_begin");
-       struct bt_ctf_field *ts_end_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "timestamp_end");
-       struct bt_ctf_field_common *packet_context =
-               (void *) stream->packet_context;
-       uint64_t i;
-       int64_t len;
-
-       if (ts_begin_field && bt_ctf_field_is_set_recursive(ts_begin_field)) {
-               /* Use provided `timestamp_begin` value as starting value */
-               ret = bt_ctf_field_integer_unsigned_get_value(ts_begin_field, &val);
-               BT_ASSERT(ret == 0);
-               init_clock_value = val;
-       } else if (stream->last_ts_end != -1ULL) {
-               /* Use last packet's ending timestamp as starting value */
-               init_clock_value = stream->last_ts_end;
-       }
-
-       cur_clock_value = init_clock_value;
-
-       if (stream->last_ts_end != -1ULL &&
-                       cur_clock_value < stream->last_ts_end) {
-               BT_LOGW("Packet's initial timestamp is less than previous "
-                       "packet's final timestamp: "
-                       "stream-addr=%p, stream-name=\"%s\", "
-                       "cur-packet-ts-begin=%" PRIu64 ", "
-                       "prev-packet-ts-end=%" PRIu64,
-                       stream, bt_ctf_stream_get_name(stream),
-                       cur_clock_value, stream->last_ts_end);
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Visit all the packet context fields, followed by all the
-        * fields of all the events, in order, updating our current
-        * clock value as we visit.
-        *
-        * While visiting the packet context fields, do not consider
-        * `timestamp_begin` and `timestamp_end` because this function's
-        * purpose is to set them anyway. Also do not consider
-        * `packet_size`, `content_size`, `events_discarded`, and
-        * `packet_seq_num` if they are not set because those are
-        * autopopulating fields.
-        */
-       len = bt_ctf_field_type_structure_get_field_count(
-               (void *) packet_context->type);
-       BT_ASSERT(len >= 0);
-
-       for (i = 0; i < len; i++) {
-               const char *member_name;
-               struct bt_ctf_field *member_field;
-
-               ret = bt_ctf_field_type_structure_get_field_by_index(
-                       (void *) packet_context->type, &member_name, NULL, i);
-               BT_ASSERT(ret == 0);
-
-               if (strcmp(member_name, "timestamp_begin") == 0 ||
-                               strcmp(member_name, "timestamp_end") == 0) {
-                       continue;
-               }
-
-               member_field = bt_ctf_field_structure_get_field_by_index(
-                       stream->packet_context, i);
-               BT_ASSERT(member_field);
-
-               if (strcmp(member_name, "packet_size") == 0 &&
-                               !bt_ctf_field_is_set_recursive(member_field)) {
-                       bt_ctf_object_put_ref(member_field);
-                       continue;
-               }
-
-               if (strcmp(member_name, "content_size") == 0 &&
-                               !bt_ctf_field_is_set_recursive(member_field)) {
-                       bt_ctf_object_put_ref(member_field);
-                       continue;
-               }
-
-               if (strcmp(member_name, "events_discarded") == 0 &&
-                               !bt_ctf_field_is_set_recursive(member_field)) {
-                       bt_ctf_object_put_ref(member_field);
-                       continue;
-               }
-
-               if (strcmp(member_name, "packet_seq_num") == 0 &&
-                               !bt_ctf_field_is_set_recursive(member_field)) {
-                       bt_ctf_object_put_ref(member_field);
-                       continue;
-               }
-
-               ret = visit_field_update_clock_value(member_field,
-                       &cur_clock_value);
-               bt_ctf_object_put_ref(member_field);
-               if (ret) {
-                       BT_LOGW("Cannot automatically update clock value "
-                               "in stream's packet context: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "field-name=\"%s\"",
-                               stream, bt_ctf_stream_get_name(stream),
-                               member_name);
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < stream->events->len; i++) {
-               struct bt_ctf_event *event = g_ptr_array_index(stream->events, i);
-
-               BT_ASSERT(event);
-               ret = visit_event_update_clock_value(event, &cur_clock_value);
-               if (ret) {
-                       BT_LOGW("Cannot automatically update clock value "
-                               "in stream's packet context: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "index=%" PRIu64 ", event-addr=%p, "
-                               "event-class-id=%" PRId64 ", "
-                               "event-class-name=\"%s\"",
-                               stream, bt_ctf_stream_get_name(stream),
-                               i, event,
-                               bt_ctf_event_class_common_get_id(event->common.class),
-                               bt_ctf_event_class_common_get_name(event->common.class));
-                       goto end;
-               }
-       }
-
-       /*
-        * Everything is visited, thus the current clock value
-        * corresponds to the ending timestamp. Validate this value
-        * against the provided value of `timestamp_end`, if any,
-        * otherwise set it.
-        */
-       if (ts_end_field && bt_ctf_field_is_set_recursive(ts_end_field)) {
-               ret = bt_ctf_field_integer_unsigned_get_value(ts_end_field, &val);
-               BT_ASSERT(ret == 0);
-
-               if (val < cur_clock_value) {
-                       BT_LOGW("Packet's final timestamp is less than "
-                               "computed packet's final timestamp: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "cur-packet-ts-end=%" PRIu64 ", "
-                               "computed-packet-ts-end=%" PRIu64,
-                               stream, bt_ctf_stream_get_name(stream),
-                               val, cur_clock_value);
-                       ret = -1;
-                       goto end;
-               }
-
-               stream->last_ts_end = val;
-       }
-
-       if (ts_end_field && !bt_ctf_field_is_set_recursive(ts_end_field)) {
-               ret = set_integer_field_value(ts_end_field, cur_clock_value);
-               BT_ASSERT(ret == 0);
-               stream->last_ts_end = cur_clock_value;
-       }
-
-       if (!ts_end_field) {
-               stream->last_ts_end = cur_clock_value;
-       }
-
-       /* Set `timestamp_begin` field to initial clock value */
-       if (ts_begin_field && !bt_ctf_field_is_set_recursive(ts_begin_field)) {
-               ret = set_integer_field_value(ts_begin_field, init_clock_value);
-               BT_ASSERT(ret == 0);
-       }
-
-end:
-       bt_ctf_object_put_ref(ts_begin_field);
-       bt_ctf_object_put_ref(ts_end_field);
-       return ret;
-}
-
-static
-int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts,
-               uint64_t packet_size_bits, uint64_t content_size_bits)
-{
-       int ret = 0;
-
-       if (!stream->packet_context) {
-               goto end;
-       }
-
-       ret = set_packet_context_packet_size(stream, packet_size_bits);
-       if (ret) {
-               BT_LOGW("Cannot set packet context's packet size field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       ret = set_packet_context_content_size(stream, content_size_bits);
-       if (ret) {
-               BT_LOGW("Cannot set packet context's content size field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       if (set_ts) {
-               ret = set_packet_context_timestamps(stream);
-               if (ret) {
-                       BT_LOGW("Cannot set packet context's timestamp fields: "
-                               "stream-addr=%p, stream-name=\"%s\"",
-                               stream, bt_ctf_stream_get_name(stream));
-                       goto end;
-               }
-       }
-
-       ret = set_packet_context_events_discarded(stream);
-       if (ret) {
-               BT_LOGW("Cannot set packet context's discarded events count field: "
-                       "stream-addr=%p, stream-name=\"%s\"",
-                       stream, bt_ctf_stream_get_name(stream));
-               goto end;
-       }
-
-       BT_LOGV("Automatically populated stream's packet context's known fields: "
-               "stream-addr=%p, stream-name=\"%s\"",
-               stream, bt_ctf_stream_get_name(stream));
-
-end:
-       return ret;
-}
-
-static
-void release_event(struct bt_ctf_event *event)
-{
-       if (bt_ctf_object_get_ref_count(&event->common.base)) {
-               /*
-                * The event is being orphaned, but it must guarantee the
-                * existence of its event class for the duration of its
-                * lifetime.
-                */
-               bt_ctf_object_get_ref(event->common.class);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(event->common.base.parent);
-       } else {
-               bt_ctf_object_try_spec_release(&event->common.base);
-       }
-}
-
-static
-int create_stream_file(struct bt_ctf_writer *writer,
-               struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       GString *filename = g_string_new(NULL);
-       int64_t stream_class_id;
-       char *file_path = NULL;
-
-       BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, "
-               "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"",
-               writer, stream, bt_ctf_stream_get_name(stream),
-               stream->common.stream_class,
-               stream->common.stream_class->name->str);
-
-       if (stream->common.name && stream->common.name->len > 0) {
-               /* Use stream name's base name as prefix */
-               gchar *basename = g_path_get_basename(stream->common.name->str);
-
-               BT_ASSERT(basename);
-
-               if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
-                       g_string_assign(filename, "stream");
-               } else {
-                       g_string_assign(filename, basename);
-               }
-
-               g_free(basename);
-               goto append_ids;
-       }
-
-       if (stream->common.stream_class->name &&
-                       stream->common.stream_class->name->len > 0) {
-               /* Use stream class name's base name as prefix */
-               gchar *basename =
-                       g_path_get_basename(
-                               stream->common.stream_class->name->str);
-
-               BT_ASSERT(basename);
-
-               if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
-                       g_string_assign(filename, "stream");
-               } else {
-                       g_string_assign(filename, basename);
-               }
-
-               g_free(basename);
-               goto append_ids;
-       }
-
-       /* Default to using `stream-` as prefix */
-       g_string_assign(filename, "stream");
-
-append_ids:
-       stream_class_id = bt_ctf_stream_class_common_get_id(stream->common.stream_class);
-       BT_ASSERT(stream_class_id >= 0);
-       BT_ASSERT(stream->common.id >= 0);
-       g_string_append_printf(filename, "-%" PRId64 "-%" PRId64,
-               stream_class_id, stream->common.id);
-
-       file_path = g_build_filename(writer->path->str, filename->str, NULL);
-       if (file_path == NULL) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctfser_init(&stream->ctfser, file_path);
-       g_free(file_path);
-       if (ret) {
-               /* bt_ctfser_init() logs errors */
-               goto end;
-       }
-
-       BT_LOGD("Created stream file for writing: "
-               "stream-addr=%p, stream-name=\"%s\", "
-               "filename=\"%s\"", stream, bt_ctf_stream_get_name(stream),
-               filename->str);
-
-end:
-       g_string_free(filename, TRUE);
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_ctf_stream *bt_ctf_stream_create_with_id(
-               struct bt_ctf_stream_class *stream_class,
-               const char *name, uint64_t id)
-{
-       int ret;
-       int fd;
-       struct bt_ctf_stream *stream = NULL;
-       struct bt_ctf_trace *trace = NULL;
-       struct bt_ctf_writer *writer = NULL;
-
-       BT_LOGD("Creating CTF writer stream object: stream-class-addr=%p, "
-               "stream-class-name=\"%s\", stream-name=\"%s\", "
-               "stream-id=%" PRIu64,
-               stream_class, bt_ctf_stream_class_get_name(stream_class),
-               name, id);
-       stream = g_new0(struct bt_ctf_stream, 1);
-       if (!stream) {
-               BT_LOGE_STR("Failed to allocate one stream.");
-               goto error;
-       }
-
-       if (id == -1ULL) {
-               id = stream_class->next_stream_id;
-       }
-
-       ret = bt_ctf_stream_common_initialize(BT_CTF_TO_COMMON(stream),
-               BT_CTF_TO_COMMON(stream_class), name, id, bt_ctf_stream_destroy);
-       if (ret) {
-               /* bt_ctf_stream_common_initialize() logs errors */
-               goto error;
-       }
-
-       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
-               BT_CTF_TO_COMMON(stream_class)));
-       if (!trace) {
-               BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-name=\"%s\"",
-                       stream_class, bt_ctf_stream_class_get_name(stream_class),
-                       name);
-               goto error;
-       }
-
-       writer = (struct bt_ctf_writer *)
-               bt_ctf_object_get_parent(&trace->common.base);
-       stream->last_ts_end = -1ULL;
-       BT_LOGD("CTF writer stream object belongs writer's trace: "
-               "writer-addr=%p", writer);
-       BT_ASSERT(writer);
-
-       if (stream_class->common.packet_context_field_type) {
-               BT_LOGD("Creating stream's packet context field: "
-                       "ft-addr=%p",
-                       stream_class->common.packet_context_field_type);
-               stream->packet_context = bt_ctf_field_create(
-                       (void *) stream_class->common.packet_context_field_type);
-               if (!stream->packet_context) {
-                       BT_LOGW_STR("Cannot create stream's packet context field.");
-                       goto error;
-               }
-
-               /* Initialize events_discarded */
-               ret = try_set_structure_field_integer(
-                       stream->packet_context, "events_discarded", 0);
-               if (ret < 0) {
-                       BT_LOGW("Cannot set `events_discarded` field in packet context: "
-                               "ret=%d, packet-context-field-addr=%p",
-                               ret, stream->packet_context);
-                       goto error;
-               }
-       }
-
-       stream->events = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) release_event);
-       if (!stream->events) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       if (trace->common.packet_header_field_type) {
-               BT_LOGD("Creating stream's packet header field: "
-                       "ft-addr=%p", trace->common.packet_header_field_type);
-               stream->packet_header =
-                       bt_ctf_field_create(
-                               (void *) trace->common.packet_header_field_type);
-               if (!stream->packet_header) {
-                       BT_LOGW_STR("Cannot create stream's packet header field.");
-                       goto error;
-               }
-       }
-
-       /*
-        * Attempt to populate the default trace packet header fields
-        * (magic, uuid and stream_id). This will _not_ fail shall the
-        * fields not be found or be of an incompatible type; they will
-        * simply not be populated automatically. The user will have to
-        * make sure to set the trace packet header fields himself
-        * before flushing.
-        */
-       ret = auto_populate_packet_header(stream);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically populate the stream's packet header.");
-               goto error;
-       }
-
-       /* Create file associated with this stream */
-       fd = create_stream_file(writer, stream);
-       if (fd < 0) {
-               BT_LOGW_STR("Cannot create stream file.");
-               goto error;
-       }
-
-       /* Freeze the writer */
-       BT_LOGD_STR("Freezing stream's CTF writer.");
-       bt_ctf_writer_freeze(writer);
-
-       /* Add this stream to the trace's streams */
-       g_ptr_array_add(trace->common.streams, stream);
-       stream_class->next_stream_id++;
-       BT_LOGD("Created stream object: addr=%p", stream);
-       goto end;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
-
-end:
-       bt_ctf_object_put_ref(writer);
-       return stream;
-}
-
-struct bt_ctf_stream *bt_ctf_stream_create(
-               struct bt_ctf_stream_class *stream_class,
-               const char *name, uint64_t id_param)
-{
-       return bt_ctf_stream_create_with_id(stream_class,
-               name, id_param);
-}
-
-int bt_ctf_stream_get_discarded_events_count(
-               struct bt_ctf_stream *stream, uint64_t *count)
-{
-       int ret = 0;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!count) {
-               BT_LOGW_STR("Invalid parameter: count is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       *count = (uint64_t) stream->discarded_events;
-
-end:
-       return ret;
-}
-
-static
-int set_packet_context_events_discarded_field(struct bt_ctf_stream *stream,
-       uint64_t count)
-{
-       int ret = 0;
-       struct bt_ctf_field *events_discarded_field = NULL;
-
-       if (!stream->packet_context) {
-               goto end;
-       }
-
-       events_discarded_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "events_discarded");
-       if (!events_discarded_field) {
-               goto end;
-       }
-
-       ret = bt_ctf_field_integer_unsigned_set_value(
-               events_discarded_field, count);
-       if (ret) {
-               BT_LOGW("Cannot set packet context's `events_discarded` field: "
-                       "field-addr=%p, value=%" PRIu64,
-                       events_discarded_field, count);
-               goto end;
-       }
-
-end:
-       bt_ctf_object_put_ref(events_discarded_field);
-       return ret;
-}
-
-void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
-               uint64_t event_count)
-{
-       int ret;
-       uint64_t new_count;
-       struct bt_ctf_field *events_discarded_field = NULL;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               goto end;
-       }
-
-       BT_LOGV("Appending discarded events to stream: "
-               "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
-               stream, bt_ctf_stream_get_name(stream), event_count);
-
-       if (!stream->packet_context) {
-               BT_LOGW_STR("Invalid parameter: stream has no packet context field.");
-               goto end;
-       }
-
-       events_discarded_field = bt_ctf_field_structure_get_field_by_name(
-               stream->packet_context, "events_discarded");
-       if (!events_discarded_field) {
-               BT_LOGW_STR("No field named `events_discarded` in stream's packet context.");
-               goto end;
-       }
-
-       new_count = stream->discarded_events + event_count;
-       if (new_count < stream->discarded_events) {
-               BT_LOGW("New discarded events count is less than the stream's current discarded events count: "
-                       "cur-count=%" PRIu64 ", new-count=%" PRIu64,
-                       stream->discarded_events, new_count);
-               goto end;
-       }
-
-       ret = set_packet_context_events_discarded_field(stream, new_count);
-       if (ret) {
-               /* set_packet_context_events_discarded_field() logs errors */
-               goto end;
-       }
-
-       stream->discarded_events = new_count;
-       BT_LOGV("Appended discarded events to stream: "
-               "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
-               stream, bt_ctf_stream_get_name(stream), event_count);
-
-end:
-       bt_ctf_object_put_ref(events_discarded_field);
-}
-
-static int auto_populate_event_header(struct bt_ctf_stream *stream,
-               struct bt_ctf_event *event)
-{
-       int ret = 0;
-       struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
-       struct bt_ctf_clock_class *mapped_clock_class = NULL;
-       struct bt_ctf_stream_class *stream_class =
-               BT_CTF_FROM_COMMON(bt_ctf_stream_common_borrow_class(
-                       BT_CTF_TO_COMMON(stream)));
-       int64_t event_class_id;
-
-       BT_ASSERT(event);
-
-       if (!event->common.header_field) {
-               goto end;
-       }
-
-       if (event->common.frozen) {
-               BT_LOGW_STR("Cannot populate event header field: event is frozen.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Automatically populating event's header field: "
-               "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), event);
-
-       id_field = bt_ctf_field_structure_get_field_by_name(
-               (void *) event->common.header_field->field, "id");
-       event_class_id = bt_ctf_event_class_common_get_id(event->common.class);
-       BT_ASSERT(event_class_id >= 0);
-
-       if (id_field && bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               ret = set_integer_field_value(id_field, event_class_id);
-               if (ret) {
-                       BT_LOGW("Cannot set event header's `id` field's value: "
-                               "addr=%p, value=%" PRIu64, id_field,
-                               event_class_id);
-                       goto end;
-               }
-       }
-
-       /*
-        * The conditions to automatically set the timestamp are:
-        *
-        * 1. The event header field "timestamp" exists and is an
-        *    integer field.
-        * 2. This stream's class has a registered clock (set with
-        *    bt_ctf_stream_class_set_clock()).
-        * 3. The "timestamp" field is not set.
-        */
-       timestamp_field = bt_ctf_field_structure_get_field_by_name(
-                       (void *) event->common.header_field->field, "timestamp");
-       if (timestamp_field && stream_class->clock &&
-                       bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER &&
-                       !bt_ctf_field_is_set_recursive(timestamp_field)) {
-               mapped_clock_class =
-                       bt_ctf_field_type_integer_get_mapped_clock_class(
-                               (void *) ((struct bt_ctf_field_common *) timestamp_field)->type);
-               if (mapped_clock_class) {
-                       uint64_t timestamp;
-
-                       BT_ASSERT(mapped_clock_class ==
-                               stream_class->clock->clock_class);
-                       ret = bt_ctf_clock_get_value(
-                               stream_class->clock,
-                               &timestamp);
-                       BT_ASSERT(ret == 0);
-                       ret = set_integer_field_value(timestamp_field,
-                                       timestamp);
-                       if (ret) {
-                               BT_LOGW("Cannot set event header's `timestamp` field's value: "
-                                       "addr=%p, value=%" PRIu64,
-                                       timestamp_field, timestamp);
-                               goto end;
-                       }
-               }
-       }
-
-       BT_LOGV("Automatically populated event's header field: "
-               "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), event);
-
-end:
-       bt_ctf_object_put_ref(id_field);
-       bt_ctf_object_put_ref(timestamp_field);
-       bt_ctf_object_put_ref(mapped_clock_class);
-       return ret;
-}
-
-int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
-               struct bt_ctf_event *event)
-{
-       int ret = 0;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!event) {
-               BT_LOGW_STR("Invalid parameter: event is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Appending event to stream: "
-               "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               stream, bt_ctf_stream_get_name(stream), event,
-               bt_ctf_event_class_common_get_name(
-                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
-               bt_ctf_event_class_common_get_id(
-                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
-
-       /*
-        * The event is not supposed to have a parent stream at this
-        * point. The only other way an event can have a parent stream
-        * is if it was assigned when setting a packet to the event,
-        * in which case the packet's stream is not a writer stream,
-        * and thus the user is trying to append an event which belongs
-        * to another stream.
-        */
-       if (event->common.base.parent) {
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_set_parent(&event->common.base, &stream->common.base);
-       BT_LOGV_STR("Automatically populating the header of the event to append.");
-       ret = auto_populate_event_header(stream, event);
-       if (ret) {
-               /* auto_populate_event_header() reports errors */
-               goto error;
-       }
-
-       /* Make sure the various scopes of the event are set */
-       BT_LOGV_STR("Validating event to append.");
-       BT_CTF_ASSERT_PRE(bt_ctf_event_common_validate(BT_CTF_TO_COMMON(event)) == 0,
-               "Invalid event: event-addr=%p", event);
-
-       /* Save the new event and freeze it */
-       BT_LOGV_STR("Freezing the event to append.");
-       bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
-       g_ptr_array_add(stream->events, event);
-
-       /*
-        * Event had to hold a reference to its event class as long as it wasn't
-        * part of the same trace hierarchy. From now on, the event and its
-        * class share the same lifetime guarantees and the reference is no
-        * longer needed.
-        */
-       BT_LOGV_STR("Putting the event's class.");
-       bt_ctf_object_put_ref(event->common.class);
-       BT_LOGV("Appended event to stream: "
-               "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               stream, bt_ctf_stream_get_name(stream), event,
-               bt_ctf_event_class_common_get_name(
-                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
-               bt_ctf_event_class_common_get_id(
-                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
-
-end:
-       return ret;
-
-error:
-       /*
-        * Orphan the event; we were not successful in associating it to
-        * a stream.
-        */
-       bt_ctf_object_set_parent(&event->common.base, NULL);
-       return ret;
-}
-
-struct bt_ctf_field *bt_ctf_stream_get_packet_context(struct bt_ctf_stream *stream)
-{
-       struct bt_ctf_field *packet_context = NULL;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               goto end;
-       }
-
-       packet_context = stream->packet_context;
-       if (packet_context) {
-               bt_ctf_object_get_ref(packet_context);
-       }
-end:
-       return packet_context;
-}
-
-int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
-               struct bt_ctf_field *field)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *field_type;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       field_type = bt_ctf_field_get_type(field);
-       if (bt_ctf_field_type_common_compare((void *) field_type,
-                       stream->common.stream_class->packet_context_field_type)) {
-               BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: "
-                       "stream-addr=%p, stream-name=\"%s\", "
-                       "packet-context-field-addr=%p, "
-                       "packet-context-ft-addr=%p",
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, field_type);
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(field_type);
-       bt_ctf_object_put_ref(stream->packet_context);
-       stream->packet_context = bt_ctf_object_get_ref(field);
-       BT_LOGV("Set stream's packet context field: "
-               "stream-addr=%p, stream-name=\"%s\", "
-               "packet-context-field-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), field);
-end:
-       return ret;
-}
-
-struct bt_ctf_field *bt_ctf_stream_get_packet_header(struct bt_ctf_stream *stream)
-{
-       struct bt_ctf_field *packet_header = NULL;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               goto end;
-       }
-
-       packet_header = stream->packet_header;
-       if (packet_header) {
-               bt_ctf_object_get_ref(packet_header);
-       }
-end:
-       return packet_header;
-}
-
-int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
-               struct bt_ctf_field *field)
-{
-       int ret = 0;
-       struct bt_ctf_trace *trace = NULL;
-       struct bt_ctf_field_type *field_type = NULL;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       trace = (struct bt_ctf_trace *)
-               bt_ctf_object_get_parent(&stream->common.base);
-
-       if (!field) {
-               if (trace->common.packet_header_field_type) {
-                       BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: "
-                               "stream-addr=%p, stream-name=\"%s\", "
-                               "packet-header-field-addr=%p, "
-                               "expected-ft-addr=%p",
-                               stream, bt_ctf_stream_get_name(stream),
-                               field, trace->common.packet_header_field_type);
-                       ret = -1;
-                       goto end;
-               }
-
-               goto skip_validation;
-       }
-
-       field_type = bt_ctf_field_get_type(field);
-       BT_ASSERT(field_type);
-
-       if (bt_ctf_field_type_common_compare((void *) field_type,
-                       trace->common.packet_header_field_type)) {
-               BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: "
-                       "stream-addr=%p, stream-name=\"%s\", "
-                       "packet-header-field-addr=%p, "
-                       "packet-header-ft-addr=%p",
-                       stream, bt_ctf_stream_get_name(stream),
-                       field, field_type);
-               ret = -1;
-               goto end;
-       }
-
-skip_validation:
-       bt_ctf_object_put_ref(stream->packet_header);
-       stream->packet_header = bt_ctf_object_get_ref(field);
-       BT_LOGV("Set stream's packet header field: "
-               "stream-addr=%p, stream-name=\"%s\", "
-               "packet-header-field-addr=%p",
-               stream, bt_ctf_stream_get_name(stream), field);
-end:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
-       bt_ctf_object_put_ref(field_type);
-       return ret;
-}
-
-static
-void reset_structure_field(struct bt_ctf_field *structure, const char *name)
-{
-       struct bt_ctf_field *member;
-
-       member = bt_ctf_field_structure_get_field_by_name(structure, name);
-       if (member) {
-               bt_ctf_field_common_reset_recursive((void *) member);
-               bt_ctf_object_put_ref(member);
-       }
-}
-
-int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
-{
-       int ret = 0;
-       size_t i;
-       uint64_t packet_context_offset_bits = 0;
-       struct bt_ctf_trace *trace;
-       enum bt_ctf_byte_order native_byte_order;
-       bool has_packet_size = false;
-       uint64_t packet_size_bits = 0;
-       uint64_t content_size_bits = 0;
-
-       if (!stream) {
-               BT_LOGW_STR("Invalid parameter: stream is NULL.");
-               ret = -1;
-               goto end_no_stream;
-       }
-
-       if (stream->packet_context) {
-               struct bt_ctf_field *packet_size_field;
-
-               packet_size_field = bt_ctf_field_structure_get_field_by_name(
-                               stream->packet_context, "packet_size");
-               has_packet_size = (packet_size_field != NULL);
-               bt_ctf_object_put_ref(packet_size_field);
-       }
-
-       if (stream->flushed_packet_count == 1) {
-               if (!stream->packet_context) {
-                       BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
-                       ret = -1;
-                       goto end;
-               }
-
-               if (!has_packet_size) {
-                       BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       BT_LOGV("Flushing stream's current packet: stream-addr=%p, "
-               "stream-name=\"%s\", packet-index=%u", stream,
-               bt_ctf_stream_get_name(stream), stream->flushed_packet_count);
-       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
-               stream->common.stream_class));
-       BT_ASSERT(trace);
-       native_byte_order = bt_ctf_trace_get_native_byte_order(trace);
-
-       ret = auto_populate_packet_header(stream);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically populate the stream's packet header field.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Initialize packet/content sizes to `0`; we will overwrite later */
-       ret = auto_populate_packet_context(stream, true, 0, 0);
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctfser_open_packet(&stream->ctfser);
-       if (ret) {
-               /* bt_ctfser_open_packet() logs errors */
-               ret = -1;
-               goto end;
-       }
-
-       if (stream->packet_header) {
-               BT_LOGV_STR("Serializing packet header field (initial).");
-               ret = bt_ctf_field_serialize_recursive(stream->packet_header,
-                       &stream->ctfser, native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream's packet header field: "
-                               "field-addr=%p", stream->packet_header);
-                       goto end;
-               }
-       }
-
-       if (stream->packet_context) {
-               /* Save packet context's position to overwrite it later */
-               packet_context_offset_bits =
-                       bt_ctfser_get_offset_in_current_packet_bits(
-                               &stream->ctfser);
-
-               /* Write packet context */
-               BT_LOGV_STR("Serializing packet context field (initial).");
-               ret = bt_ctf_field_serialize_recursive(stream->packet_context,
-                       &stream->ctfser, native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream's packet context field: "
-                               "field-addr=%p", stream->packet_context);
-                       goto end;
-               }
-       }
-
-       BT_LOGV("Serializing events: count=%u", stream->events->len);
-
-       for (i = 0; i < stream->events->len; i++) {
-               struct bt_ctf_event *event = g_ptr_array_index(
-                       stream->events, i);
-               struct bt_ctf_event_class *event_class =
-                       BT_CTF_FROM_COMMON(bt_ctf_event_common_borrow_class(
-                               BT_CTF_TO_COMMON(event)));
-
-               BT_LOGV("Serializing event: index=%zu, event-addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-                       "ser-offset=%" PRIu64,
-                       i, event, bt_ctf_event_class_get_name(event_class),
-                       bt_ctf_event_class_get_id(event_class),
-                       bt_ctfser_get_offset_in_current_packet_bits(
-                               &stream->ctfser));
-
-               /* Write event header */
-               if (event->common.header_field) {
-                       BT_LOGV_STR("Serializing event's header field.");
-                       ret = bt_ctf_field_serialize_recursive(
-                               (void *) event->common.header_field->field,
-                               &stream->ctfser, native_byte_order);
-                       if (ret) {
-                               BT_LOGW("Cannot serialize event's header field: "
-                                       "field-addr=%p",
-                                       event->common.header_field->field);
-                               goto end;
-                       }
-               }
-
-               /* Write stream event context */
-               if (event->common.stream_event_context_field) {
-                       BT_LOGV_STR("Serializing event's stream event context field.");
-                       ret = bt_ctf_field_serialize_recursive(
-                               (void *) event->common.stream_event_context_field,
-                               &stream->ctfser, native_byte_order);
-                       if (ret) {
-                               BT_LOGW("Cannot serialize event's stream event context field: "
-                                       "field-addr=%p",
-                                       event->common.stream_event_context_field);
-                               goto end;
-                       }
-               }
-
-               /* Write event content */
-               ret = bt_ctf_event_serialize(event, &stream->ctfser,
-                       native_byte_order);
-               if (ret) {
-                       /* bt_ctf_event_serialize() logs errors */
-                       goto end;
-               }
-       }
-
-       content_size_bits = bt_ctfser_get_offset_in_current_packet_bits(
-               &stream->ctfser);
-
-       if (!has_packet_size && content_size_bits % 8 != 0) {
-               BT_LOGW("Stream's packet context field type has no `packet_size` field, "
-                       "but current content size is not a multiple of 8 bits: "
-                       "content-size=%" PRIu64 ", "
-                       "packet-size=%" PRIu64,
-                       content_size_bits,
-                       packet_size_bits);
-               ret = -1;
-               goto end;
-       }
-
-       /* Set packet size; make it a multiple of 8 */
-       packet_size_bits = (content_size_bits + 7) & ~UINT64_C(7);
-
-       if (stream->packet_context) {
-               /*
-                * The whole packet is serialized at this point. Make
-                * sure that, if `packet_size` is missing, the current
-                * content size is equal to the current packet size.
-                */
-               struct bt_ctf_field *field =
-                       bt_ctf_field_structure_get_field_by_name(
-                               stream->packet_context, "content_size");
-
-               bt_ctf_object_put_ref(field);
-               if (!field) {
-                       if (content_size_bits != packet_size_bits) {
-                               BT_LOGW("Stream's packet context's `content_size` field is missing, "
-                                       "but current packet's content size is not equal to its packet size: "
-                                       "content-size=%" PRIu64 ", "
-                                       "packet-size=%" PRIu64,
-                                       bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser),
-                                       packet_size_bits);
-                               ret = -1;
-                               goto end;
-                       }
-               }
-
-               /*
-                * Overwrite the packet context now that the stream
-                * position's packet and content sizes have the correct
-                * values.
-                */
-               bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser,
-                       packet_context_offset_bits);
-               ret = auto_populate_packet_context(stream, false,
-                       packet_size_bits, content_size_bits);
-               if (ret) {
-                       BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
-                       ret = -1;
-                       goto end;
-               }
-
-               BT_LOGV("Rewriting (serializing) packet context field.");
-               ret = bt_ctf_field_serialize_recursive(stream->packet_context,
-                       &stream->ctfser, native_byte_order);
-               if (ret) {
-                       BT_LOGW("Cannot serialize stream's packet context field: "
-                               "field-addr=%p", stream->packet_context);
-                       goto end;
-               }
-       }
-
-       g_ptr_array_set_size(stream->events, 0);
-       stream->flushed_packet_count++;
-       bt_ctfser_close_current_packet(&stream->ctfser, packet_size_bits / 8);
-
-end:
-       /* Reset automatically-set fields. */
-       if (stream->packet_context) {
-               reset_structure_field(stream->packet_context, "timestamp_begin");
-               reset_structure_field(stream->packet_context, "timestamp_end");
-               reset_structure_field(stream->packet_context, "packet_size");
-               reset_structure_field(stream->packet_context, "content_size");
-               reset_structure_field(stream->packet_context, "events_discarded");
-       }
-
-       if (ret == 0) {
-               BT_LOGV("Flushed stream's current packet: "
-                       "content-size=%" PRIu64 ", packet-size=%" PRIu64,
-                       content_size_bits, packet_size_bits);
-       }
-
-end_no_stream:
-       return ret;
-}
-
-static
-void bt_ctf_stream_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_stream *stream = (void *) obj;
-
-       BT_LOGD("Destroying CTF writer stream object: addr=%p, name=\"%s\"",
-               stream, bt_ctf_stream_get_name(stream));
-
-       bt_ctf_stream_common_finalize(BT_CTF_TO_COMMON(stream));
-       bt_ctfser_fini(&stream->ctfser);
-
-       if (stream->events) {
-               BT_LOGD_STR("Putting events.");
-               g_ptr_array_free(stream->events, TRUE);
-       }
-
-       BT_LOGD_STR("Putting packet header field.");
-       bt_ctf_object_put_ref(stream->packet_header);
-       BT_LOGD_STR("Putting packet context field.");
-       bt_ctf_object_put_ref(stream->packet_context);
-       g_free(stream);
-}
-
-static
-int _set_structure_field_integer(struct bt_ctf_field *structure, char *name,
-               uint64_t value, bt_bool force)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *field_type = NULL;
-       struct bt_ctf_field *integer;
-
-       BT_ASSERT(structure);
-       BT_ASSERT(name);
-
-       integer = bt_ctf_field_structure_get_field_by_name(structure, name);
-       if (!integer) {
-               /* Field not found, not an error. */
-               BT_LOGV("Field not found: struct-field-addr=%p, "
-                       "name=\"%s\", force=%d", structure, name, force);
-               goto end;
-       }
-
-       /* Make sure the payload has not already been set. */
-       if (!force && bt_ctf_field_is_set_recursive(integer)) {
-               /* Payload already set, not an error */
-               BT_LOGV("Field's payload is already set: struct-field-addr=%p, "
-                       "name=\"%s\", force=%d", structure, name, force);
-               goto end;
-       }
-
-       field_type = bt_ctf_field_get_type(integer);
-       BT_ASSERT(field_type);
-       if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-               /*
-                * The user most likely meant for us to populate this field
-                * automatically. However, we can only do this if the field
-                * is an integer. Return an error.
-                */
-               BT_LOGW("Invalid parameter: field's type is not an integer field type: "
-                       "field-addr=%p, ft-addr=%p, ft-id=%s",
-                       integer, field_type,
-                       bt_ctf_field_type_id_string((int)
-                               bt_ctf_field_type_get_type_id(field_type)));
-               ret = -1;
-               goto end;
-       }
-
-       if (bt_ctf_field_type_integer_is_signed(field_type)) {
-               ret = bt_ctf_field_integer_signed_set_value(integer,
-                       (int64_t) value);
-       } else {
-               ret = bt_ctf_field_integer_unsigned_set_value(integer, value);
-       }
-       ret = !ret ? 1 : ret;
-end:
-       bt_ctf_object_put_ref(integer);
-       bt_ctf_object_put_ref(field_type);
-       return ret;
-}
-
-/*
- * Returns the following codes:
- * 1 if the field was found and set,
- * 0 if nothing was done (field not found, or was already set),
- * <0 if an error was encoutered
- */
-static
-int try_set_structure_field_integer(struct bt_ctf_field *structure, char *name,
-               uint64_t value)
-{
-       return _set_structure_field_integer(structure, name, value, BT_FALSE);
-}
-
-struct bt_ctf_stream_class *bt_ctf_stream_get_class(
-               struct bt_ctf_stream *stream)
-{
-       return bt_ctf_object_get_ref(bt_ctf_stream_common_borrow_class(BT_CTF_TO_COMMON(stream)));
-}
-
-const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
-{
-       return bt_ctf_stream_common_get_name(BT_CTF_TO_COMMON(stream));
-}
-
-int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream)
-{
-       return bt_ctf_stream_common_get_id(BT_CTF_TO_COMMON(stream));
-}
diff --git a/ctf-writer/trace.c b/ctf-writer/trace.c
deleted file mode 100644 (file)
index 8737470..0000000
+++ /dev/null
@@ -1,1883 +0,0 @@
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-TRACE"
-#include "logging.h"
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/attributes-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
-#include <babeltrace2/ctf-writer/functor-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/visitor-internal.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define DEFAULT_IDENTIFIER_SIZE                128
-#define DEFAULT_METADATA_STRING_SIZE   4096
-
-BT_HIDDEN
-int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace,
-               bt_ctf_object_release_func release_func)
-{
-       int ret = 0;
-
-       BT_LOGD_STR("Initializing common trace object.");
-       trace->native_byte_order = BT_CTF_BYTE_ORDER_UNSPECIFIED;
-       bt_ctf_object_init_shared_with_parent(&trace->base, release_func);
-       trace->clock_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       if (!trace->clock_classes) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-
-       trace->streams = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_ctf_object_try_spec_release);
-       if (!trace->streams) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-
-       trace->stream_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_ctf_object_try_spec_release);
-       if (!trace->stream_classes) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-
-       /* Create the environment array object */
-       trace->environment = bt_ctf_attributes_create();
-       if (!trace->environment) {
-               BT_LOGE_STR("Cannot create empty attributes object.");
-               goto error;
-       }
-
-       BT_LOGD("Initialized common trace object: addr=%p", trace);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace)
-{
-       BT_LOGD("Finalizing common trace object: addr=%p, name=\"%s\"",
-               trace, bt_ctf_trace_common_get_name(trace));
-
-       if (trace->environment) {
-               BT_LOGD_STR("Destroying environment attributes.");
-               bt_ctf_attributes_destroy(trace->environment);
-       }
-
-       if (trace->name) {
-               g_string_free(trace->name, TRUE);
-       }
-
-       if (trace->clock_classes) {
-               BT_LOGD_STR("Putting clock classes.");
-               g_ptr_array_free(trace->clock_classes, TRUE);
-       }
-
-       if (trace->streams) {
-               BT_LOGD_STR("Destroying streams.");
-               g_ptr_array_free(trace->streams, TRUE);
-       }
-
-       if (trace->stream_classes) {
-               BT_LOGD_STR("Destroying stream classes.");
-               g_ptr_array_free(trace->stream_classes, TRUE);
-       }
-
-       BT_LOGD_STR("Putting packet header field type.");
-       bt_ctf_object_put_ref(trace->packet_header_field_type);
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char *name)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!name) {
-               BT_LOGW_STR("Invalid parameter: name is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               BT_LOGW("Invalid parameter: trace is frozen: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       trace->name = trace->name ? g_string_assign(trace->name, name) :
-                       g_string_new(name);
-       if (!trace->name) {
-               BT_LOGE_STR("Failed to allocate one GString.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace,
-               const unsigned char *uuid)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!uuid) {
-               BT_LOGW_STR("Invalid parameter: UUID is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               BT_LOGW("Invalid parameter: trace is frozen: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       memcpy(trace->uuid, uuid, BABELTRACE_UUID_LEN);
-       trace->uuid_set = BT_TRUE;
-       BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
-               "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-               trace, bt_ctf_trace_common_get_name(trace),
-               (unsigned int) uuid[0],
-               (unsigned int) uuid[1],
-               (unsigned int) uuid[2],
-               (unsigned int) uuid[3],
-               (unsigned int) uuid[4],
-               (unsigned int) uuid[5],
-               (unsigned int) uuid[6],
-               (unsigned int) uuid[7],
-               (unsigned int) uuid[8],
-               (unsigned int) uuid[9],
-               (unsigned int) uuid[10],
-               (unsigned int) uuid[11],
-               (unsigned int) uuid[12],
-               (unsigned int) uuid[13],
-               (unsigned int) uuid[14],
-               (unsigned int) uuid[15]);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace,
-               const char *name, struct bt_ctf_private_value *value)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!name) {
-               BT_LOGW_STR("Invalid parameter: name is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!value) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_identifier_is_valid(name)) {
-               BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace), name);
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_value_is_integer(bt_ctf_private_value_as_value(value)) &&
-                       !bt_ctf_value_is_string(bt_ctf_private_value_as_value(value))) {
-               BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\", env-value-type=%s",
-                       trace, bt_ctf_trace_common_get_name(trace), name,
-                       bt_ctf_value_type_string(
-                               bt_ctf_value_get_type(
-                                       bt_ctf_private_value_as_value(value))));
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               /*
-                * New environment fields may be added to a frozen trace,
-                * but existing fields may not be changed.
-                *
-                * The object passed is frozen like all other attributes.
-                */
-               struct bt_ctf_private_value *attribute =
-                       bt_ctf_attributes_borrow_field_value_by_name(
-                               trace->environment, name);
-
-               if (attribute) {
-                       BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
-                               "trace-addr=%p, trace-name=\"%s\", "
-                               "env-name=\"%s\"",
-                               trace, bt_ctf_trace_common_get_name(trace), name);
-                       ret = -1;
-                       goto end;
-               }
-
-               bt_ctf_value_freeze(bt_ctf_private_value_as_value(value));
-       }
-
-       ret = bt_ctf_attributes_set_field_value(trace->environment, name,
-               value);
-       if (ret) {
-               BT_LOGE("Cannot set environment field's value: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace), name);
-       } else {
-               BT_LOGV("Set environment field's value: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "env-name=\"%s\", value-addr=%p",
-                       trace, bt_ctf_trace_common_get_name(trace), name, value);
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace,
-               const char *name, const char *value)
-{
-       int ret = 0;
-       struct bt_ctf_private_value *env_value_string_obj = NULL;
-
-       if (!value) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       env_value_string_obj = bt_ctf_private_value_string_create_init(value);
-       if (!env_value_string_obj) {
-               BT_LOGE_STR("Cannot create string value object.");
-               ret = -1;
-               goto end;
-       }
-
-       /* bt_ctf_trace_common_set_environment_field() logs errors */
-       ret = bt_ctf_trace_common_set_environment_field(trace, name,
-               env_value_string_obj);
-
-end:
-       bt_ctf_object_put_ref(env_value_string_obj);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_environment_field_integer(
-               struct bt_ctf_trace_common *trace, const char *name, int64_t value)
-{
-       int ret = 0;
-       struct bt_ctf_private_value *env_value_integer_obj = NULL;
-
-       env_value_integer_obj = bt_ctf_private_value_integer_create_init(value);
-       if (!env_value_integer_obj) {
-               BT_LOGE_STR("Cannot create integer value object.");
-               ret = -1;
-               goto end;
-       }
-
-       /* bt_ctf_trace_common_set_environment_field() logs errors */
-       ret = bt_ctf_trace_common_set_environment_field(trace, name,
-               env_value_integer_obj);
-
-end:
-       bt_ctf_object_put_ref(env_value_integer_obj);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_clock_class *clock_class)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_ctf_clock_class_is_valid(clock_class)) {
-               BT_LOGW("Invalid parameter: clock class is invalid: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace),
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       /* Check for duplicate clock classes */
-       if (bt_ctf_trace_common_has_clock_class(trace, clock_class)) {
-               BT_LOGW("Invalid parameter: clock class already exists in trace: "
-                       "trace-addr=%p, trace-name=\"%s\", "
-                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace),
-                       clock_class, bt_ctf_clock_class_get_name(clock_class));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_get_ref(clock_class);
-       g_ptr_array_add(trace->clock_classes, clock_class);
-
-       if (trace->frozen) {
-               BT_LOGV_STR("Freezing added clock class because trace is frozen.");
-               bt_ctf_clock_class_freeze(clock_class);
-       }
-
-       BT_LOGV("Added clock class to trace: "
-               "trace-addr=%p, trace-name=\"%s\", "
-               "clock-class-addr=%p, clock-class-name=\"%s\"",
-               trace, bt_ctf_trace_common_get_name(trace),
-               clock_class, bt_ctf_clock_class_get_name(clock_class));
-
-end:
-       return ret;
-}
-
-static
-bool packet_header_field_type_is_valid(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_field_type_common *packet_header_type)
-{
-       int ret;
-       bool is_valid = true;
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       if (!packet_header_type) {
-               /*
-                * No packet header field type: trace must have only
-                * one stream. At this point the stream class being
-                * added is not part of the trace yet, so we validate
-                * that the trace contains no stream classes yet.
-                */
-               if (trace->stream_classes->len >= 1) {
-                       BT_LOGW_STR("Invalid packet header field type: "
-                               "packet header field type does not exist but there's more than one stream class in the trace.");
-                       goto invalid;
-               }
-
-               /* No packet header field type: valid at this point */
-               goto end;
-       }
-
-       /* Packet header field type, if it exists, must be a structure */
-       if (packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
-                       "ft-addr=%p, ft-id=%s",
-                       packet_header_type,
-                       bt_ctf_field_type_id_string(packet_header_type->id));
-               goto invalid;
-       }
-
-       /*
-        * If there's a `magic` field, it must be a 32-bit unsigned
-        * integer field type. Also it must be the first field of the
-        * packet header field type.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_header_type, "magic");
-       if (field_type) {
-               const char *field_name;
-
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
-                               "magic-ft-addr=%p, magic-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
-                               "magic-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_get_size(field_type) != 32) {
-                       BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
-                               "magic-ft-addr=%p, magic-ft-size=%u",
-                               field_type,
-                               bt_ctf_field_type_common_integer_get_size(field_type));
-                       goto invalid;
-               }
-
-               ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
-                       packet_header_type, &field_name, NULL, 0);
-               BT_ASSERT(ret == 0);
-
-               if (strcmp(field_name, "magic") != 0) {
-                       BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
-                               "magic-ft-addr=%p, first-field-name=\"%s\"",
-                               field_type, field_name);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `uuid` field, it must be an array field type of
-        * length 16 with an 8-bit unsigned integer element field type.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_header_type, "uuid");
-       if (field_type) {
-               struct bt_ctf_field_type_common *elem_ft;
-
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_ARRAY) {
-                       BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
-                               "uuid-ft-addr=%p, uuid-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_array_get_length(field_type) != 16) {
-                       BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
-                               "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
-                               field_type,
-                               bt_ctf_field_type_common_array_get_length(field_type));
-                       goto invalid;
-               }
-
-               elem_ft = bt_ctf_field_type_common_array_borrow_element_field_type(field_type);
-               BT_ASSERT(elem_ft);
-
-               if (elem_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
-                               "elem-ft-addr=%p, elem-ft-id=%s",
-                               elem_ft,
-                               bt_ctf_field_type_id_string(elem_ft->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(elem_ft)) {
-                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
-                               "elem-ft-addr=%p", elem_ft);
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_get_size(elem_ft) != 8) {
-                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
-                               "elem-ft-addr=%p, elem-ft-size=%u",
-                               elem_ft,
-                               bt_ctf_field_type_common_integer_get_size(elem_ft));
-                       goto invalid;
-               }
-       }
-
-       /*
-        * The `stream_id` field must exist if there's more than one
-        * stream classes in the trace.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_header_type, "stream_id");
-
-       if (!field_type && trace->stream_classes->len >= 1) {
-               BT_LOGW_STR("Invalid packet header field type: "
-                       "`stream_id` field does not exist but there's more than one stream class in the trace.");
-               goto invalid;
-       }
-
-       /*
-        * If there's a `stream_id` field, it must be an unsigned
-        * integer field type.
-        */
-       if (field_type) {
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
-                               "stream-id-ft-addr=%p, stream-id-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
-                               "stream-id-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `packet_seq_num` field, it must be an unsigned
-        * integer field type.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_header_type, "packet_seq_num");
-       if (field_type) {
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: "
-                               "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: "
-                               "packet-seq-num-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       goto end;
-
-invalid:
-       is_valid = false;
-
-end:
-       return is_valid;
-}
-
-static
-bool packet_context_field_type_is_valid(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *packet_context_type,
-               bool check_ts_begin_end_mapped)
-{
-       bool is_valid = true;
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       if (!packet_context_type) {
-               /* No packet context field type: valid at this point */
-               goto end;
-       }
-
-       /* Packet context field type, if it exists, must be a structure */
-       if (packet_context_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
-                       "ft-addr=%p, ft-id=%s",
-                       packet_context_type,
-                       bt_ctf_field_type_id_string(packet_context_type->id));
-               goto invalid;
-       }
-
-       /*
-        * If there's a `packet_size` field, it must be an unsigned
-        * integer field type.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "packet_size");
-       if (field_type) {
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
-                               "packet-size-ft-addr=%p, packet-size-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
-                               "packet-size-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `content_size` field, it must be an unsigned
-        * integer field type.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "content_size");
-       if (field_type) {
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
-                               "content-size-ft-addr=%p, content-size-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
-                               "content-size-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `events_discarded` field, it must be an unsigned
-        * integer field type.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "events_discarded");
-       if (field_type) {
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
-                               "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
-                               "events-discarded-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-       }
-
-       /*
-        * If there's a `timestamp_begin` field, it must be an unsigned
-        * integer field type. Also, if the trace is not a CTF writer's
-        * trace, then we cannot automatically set the mapped clock
-        * class of this field, so it must have a mapped clock class.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "timestamp_begin");
-       if (field_type) {
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
-                               "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
-                               "timestamp-begin-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-
-               if (check_ts_begin_end_mapped) {
-                       struct bt_ctf_clock_class *clock_class =
-                               bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
-                                       field_type);
-
-                       if (!clock_class) {
-                               BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
-                                       "timestamp-begin-ft-addr=%p", field_type);
-                               goto invalid;
-                       }
-               }
-       }
-
-       /*
-        * If there's a `timestamp_end` field, it must be an unsigned
-        * integer field type. Also, if the trace is not a CTF writer's
-        * trace, then we cannot automatically set the mapped clock
-        * class of this field, so it must have a mapped clock class.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               packet_context_type, "timestamp_end");
-       if (field_type) {
-               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
-                               "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
-                       BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
-                               "timestamp-end-ft-addr=%p", field_type);
-                       goto invalid;
-               }
-
-               if (check_ts_begin_end_mapped) {
-                       struct bt_ctf_clock_class *clock_class =
-                               bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
-                                       field_type);
-
-                       if (!clock_class) {
-                               BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
-                                       "timestamp-end-ft-addr=%p", field_type);
-                               goto invalid;
-                       }
-               }
-       }
-
-       goto end;
-
-invalid:
-       is_valid = false;
-
-end:
-       return is_valid;
-}
-
-static
-bool event_header_field_type_is_valid(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *event_header_type)
-{
-       bool is_valid = true;
-       struct bt_ctf_field_type_common *field_type = NULL;
-
-       /*
-        * We do not validate that the `timestamp` field exists here
-        * because CTF does not require this exact name to be mapped to
-        * a clock class.
-        */
-
-       if (!event_header_type) {
-               /*
-                * No event header field type: stream class must have
-                * only one event class.
-                */
-               if (bt_ctf_stream_class_common_get_event_class_count(stream_class) > 1) {
-                       BT_LOGW_STR("Invalid event header field type: "
-                               "event header field type does not exist but there's more than one event class in the stream class.");
-                       goto invalid;
-               }
-
-               /* No event header field type: valid at this point */
-               goto end;
-       }
-
-       /* Event header field type, if it exists, must be a structure */
-       if (event_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
-                       "ft-addr=%p, ft-id=%s",
-                       event_header_type,
-                       bt_ctf_field_type_id_string(event_header_type->id));
-               goto invalid;
-       }
-
-       /*
-        * If there's an `id` field, it must be an unsigned integer
-        * field type or an enumeration field type with an unsigned
-        * integer container field type.
-        */
-       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               event_header_type, "id");
-       if (field_type) {
-               struct bt_ctf_field_type_common *int_ft;
-
-               if (field_type->id == BT_CTF_FIELD_TYPE_ID_INTEGER) {
-                       int_ft = field_type;
-               } else if (field_type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
-                       int_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type(
-                               field_type);
-               } else {
-                       BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
-                               "id-ft-addr=%p, id-ft-id=%s",
-                               field_type,
-                               bt_ctf_field_type_id_string(field_type->id));
-                       goto invalid;
-               }
-
-               BT_ASSERT(int_ft);
-               if (bt_ctf_field_type_common_integer_is_signed(int_ft)) {
-                       BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
-                               "id-ft-addr=%p", int_ft);
-                       goto invalid;
-               }
-       }
-
-       goto end;
-
-invalid:
-       is_valid = false;
-
-end:
-       return is_valid;
-}
-
-static
-int check_packet_header_type_has_no_clock_class(struct bt_ctf_trace_common *trace)
-{
-       int ret = 0;
-
-       if (trace->packet_header_field_type) {
-               struct bt_ctf_clock_class *clock_class = NULL;
-
-               ret = bt_ctf_field_type_common_validate_single_clock_class(
-                       trace->packet_header_field_type,
-                       &clock_class);
-               bt_ctf_object_put_ref(clock_class);
-               if (ret || clock_class) {
-                       BT_LOGW("Trace's packet header field type cannot "
-                               "contain a field type which is mapped to "
-                               "a clock class: "
-                               "trace-addr=%p, trace-name=\"%s\", "
-                               "clock-class-name=\"%s\"",
-                               trace, bt_ctf_trace_common_get_name(trace),
-                               clock_class ?
-                                       bt_ctf_clock_class_get_name(clock_class) :
-                                       NULL);
-                       ret = -1;
-               }
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func,
-               struct bt_ctf_clock_class *init_expected_clock_class,
-               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
-                       struct bt_ctf_field_type_common *packet_context_field_type,
-                       struct bt_ctf_field_type_common *event_header_field_type),
-               bool check_ts_begin_end_mapped)
-{
-       int ret;
-       int64_t i;
-       int64_t stream_id;
-       struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
-       struct bt_ctf_validation_output *ec_validation_outputs = NULL;
-       const enum bt_ctf_validation_flag trace_sc_validation_flags =
-               BT_CTF_VALIDATION_FLAG_TRACE |
-               BT_CTF_VALIDATION_FLAG_STREAM;
-       const enum bt_ctf_validation_flag ec_validation_flags =
-               BT_CTF_VALIDATION_FLAG_EVENT;
-       struct bt_ctf_field_type_common *packet_header_type = NULL;
-       struct bt_ctf_field_type_common *packet_context_type = NULL;
-       struct bt_ctf_field_type_common *event_header_type = NULL;
-       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
-       int64_t event_class_count;
-       struct bt_ctf_trace_common *current_parent_trace = NULL;
-       struct bt_ctf_clock_class *expected_clock_class =
-               bt_ctf_object_get_ref(init_expected_clock_class);
-
-       BT_ASSERT(copy_field_type_func);
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGD("Adding stream class to trace: "
-               "trace-addr=%p, trace-name=\"%s\", "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64,
-               trace, bt_ctf_trace_common_get_name(trace),
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-
-       current_parent_trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
-       if (current_parent_trace) {
-               /* Stream class is already associated to a trace, abort. */
-               BT_LOGW("Invalid parameter: stream class is already part of a trace: "
-                       "stream-class-trace-addr=%p, "
-                       "stream-class-trace-name=\"%s\"",
-                       current_parent_trace,
-                       bt_ctf_trace_common_get_name(current_parent_trace));
-               ret = -1;
-               goto end;
-       }
-
-       event_class_count =
-               bt_ctf_stream_class_common_get_event_class_count(stream_class);
-       BT_ASSERT(event_class_count >= 0);
-
-       if (!stream_class->frozen) {
-               /*
-                * Stream class is not frozen yet. Validate that the
-                * stream class contains at most a single clock class
-                * because the previous
-                * bt_ctf_stream_class_common_add_event_class() calls did
-                * not make this validation since the stream class's
-                * direct field types (packet context, event header,
-                * event context) could change afterwards. This stream
-                * class is about to be frozen and those field types
-                * won't be changed if this function succeeds.
-                *
-                * At this point we're also sure that the stream class's
-                * clock, if any, has the same class as the stream
-                * class's expected clock class, if any. This is why, if
-                * bt_ctf_stream_class_common_validate_single_clock_class()
-                * succeeds below, the call to
-                * bt_ctf_stream_class_map_clock_class() at the end of this
-                * function is safe because it maps to the same, single
-                * clock class.
-                */
-               ret = bt_ctf_stream_class_common_validate_single_clock_class(
-                       stream_class, &expected_clock_class);
-               if (ret) {
-                       BT_LOGW("Invalid parameter: stream class or one of its "
-                               "event classes contains a field type which is "
-                               "not recursively mapped to the expected "
-                               "clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-id=%" PRId64 ", "
-                               "stream-class-name=\"%s\", "
-                               "expected-clock-class-addr=%p, "
-                               "expected-clock-class-name=\"%s\"",
-                               stream_class, bt_ctf_stream_class_common_get_id(stream_class),
-                               bt_ctf_stream_class_common_get_name(stream_class),
-                               expected_clock_class,
-                               expected_clock_class ?
-                                       bt_ctf_clock_class_get_name(expected_clock_class) :
-                                       NULL);
-                       goto end;
-               }
-       }
-
-       ret = check_packet_header_type_has_no_clock_class(trace);
-       if (ret) {
-               /* check_packet_header_type_has_no_clock_class() logs errors */
-               goto end;
-       }
-
-       /*
-        * We're about to freeze both the trace and the stream class.
-        * Also, each event class contained in this stream class are
-        * already frozen.
-        *
-        * This trace, this stream class, and all its event classes
-        * should be valid at this point.
-        *
-        * Validate trace and stream class first, then each event
-        * class of this stream class can be validated individually.
-        */
-       packet_header_type =
-               bt_ctf_trace_common_borrow_packet_header_field_type(trace);
-       packet_context_type =
-               bt_ctf_stream_class_common_borrow_packet_context_field_type(stream_class);
-       event_header_type =
-               bt_ctf_stream_class_common_borrow_event_header_field_type(stream_class);
-       stream_event_ctx_type =
-               bt_ctf_stream_class_common_borrow_event_context_field_type(stream_class);
-
-       BT_LOGD("Validating trace and stream class field types.");
-       ret = bt_ctf_validate_class_types(trace->environment,
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type, NULL, NULL, trace->valid,
-               stream_class->valid, 1, &trace_sc_validation_output,
-               trace_sc_validation_flags, copy_field_type_func);
-
-       if (ret) {
-               /*
-                * This means something went wrong during the validation
-                * process, not that the objects are invalid.
-                */
-               BT_LOGE("Failed to validate trace and stream class field types: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       if ((trace_sc_validation_output.valid_flags &
-                       trace_sc_validation_flags) !=
-                       trace_sc_validation_flags) {
-               /* Invalid trace/stream class */
-               BT_LOGW("Invalid trace or stream class field types: "
-                       "valid-flags=0x%x",
-                       trace_sc_validation_output.valid_flags);
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class_count > 0) {
-               ec_validation_outputs = g_new0(struct bt_ctf_validation_output,
-                       event_class_count);
-               if (!ec_validation_outputs) {
-                       BT_LOGE_STR("Failed to allocate one validation output structure.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /* Validate each event class individually */
-       for (i = 0; i < event_class_count; i++) {
-               struct bt_ctf_event_class_common *event_class =
-                       bt_ctf_stream_class_common_borrow_event_class_by_index(
-                               stream_class, i);
-               struct bt_ctf_field_type_common *event_context_type = NULL;
-               struct bt_ctf_field_type_common *event_payload_type = NULL;
-
-               event_context_type =
-                       bt_ctf_event_class_common_borrow_context_field_type(
-                               event_class);
-               event_payload_type =
-                       bt_ctf_event_class_common_borrow_payload_field_type(
-                               event_class);
-
-               /*
-                * It is important to use the field types returned by
-                * the previous trace and stream class validation here
-                * because copies could have been made.
-                */
-               BT_LOGD("Validating event class's field types: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class));
-               ret = bt_ctf_validate_class_types(trace->environment,
-                       trace_sc_validation_output.packet_header_type,
-                       trace_sc_validation_output.packet_context_type,
-                       trace_sc_validation_output.event_header_type,
-                       trace_sc_validation_output.stream_event_ctx_type,
-                       event_context_type, event_payload_type,
-                       1, 1, event_class->valid, &ec_validation_outputs[i],
-                       ec_validation_flags, copy_field_type_func);
-
-               if (ret) {
-                       BT_LOGE("Failed to validate event class field types: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-
-               if ((ec_validation_outputs[i].valid_flags &
-                               ec_validation_flags) != ec_validation_flags) {
-                       /* Invalid event class */
-                       BT_LOGW("Invalid event class field types: "
-                               "valid-flags=0x%x",
-                               ec_validation_outputs[i].valid_flags);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       stream_id = bt_ctf_stream_class_common_get_id(stream_class);
-       if (stream_id < 0) {
-               stream_id = trace->next_stream_id++;
-               if (stream_id < 0) {
-                       BT_LOGE_STR("No more stream class IDs available.");
-                       ret = -1;
-                       goto end;
-               }
-
-               /* Try to assign a new stream id */
-               for (i = 0; i < trace->stream_classes->len; i++) {
-                       if (stream_id == bt_ctf_stream_class_common_get_id(
-                               trace->stream_classes->pdata[i])) {
-                               /* Duplicate stream id found */
-                               BT_LOGW("Duplicate stream class ID: "
-                                       "id=%" PRId64, (int64_t) stream_id);
-                               ret = -1;
-                               goto end;
-                       }
-               }
-
-               if (bt_ctf_stream_class_common_set_id_no_check(stream_class,
-                               stream_id)) {
-                       /* TODO Should retry with a different stream id */
-                       BT_LOGE("Cannot set stream class's ID: "
-                               "id=%" PRId64, (int64_t) stream_id);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /*
-        * At this point all the field types in the validation output
-        * are valid. Validate the semantics of some scopes according to
-        * the CTF specification.
-        */
-       if (!packet_header_field_type_is_valid(trace,
-                       trace_sc_validation_output.packet_header_type)) {
-               BT_LOGW_STR("Invalid trace's packet header field type.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!packet_context_field_type_is_valid(trace,
-                       stream_class,
-                       trace_sc_validation_output.packet_context_type,
-                       check_ts_begin_end_mapped)) {
-               BT_LOGW_STR("Invalid stream class's packet context field type.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!event_header_field_type_is_valid(trace,
-                       stream_class,
-                       trace_sc_validation_output.event_header_type)) {
-               BT_LOGW_STR("Invalid steam class's event header field type.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Now is the time to automatically map specific field types of
-        * the stream class's packet context and event header field
-        * types to the stream class's clock's class if they are not
-        * mapped to a clock class yet. We do it here because we know
-        * that after this point, everything is frozen so it won't be
-        * possible for the user to modify the stream class's clock, or
-        * to map those field types to other clock classes.
-        */
-       if (map_clock_classes_func) {
-               if (map_clock_classes_func(stream_class,
-                               trace_sc_validation_output.packet_context_type,
-                               trace_sc_validation_output.event_header_type)) {
-                       /* map_clock_classes_func() logs errors */
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       bt_ctf_object_set_parent(&stream_class->base, &trace->base);
-       g_ptr_array_add(trace->stream_classes, stream_class);
-
-       /*
-        * At this point we know that the function will be successful.
-        * Therefore we can replace the trace and stream class field
-        * types with what's in their validation output structure and
-        * mark them as valid. We can also replace the field types of
-        * all the event classes of the stream class and mark them as
-        * valid.
-        */
-       bt_ctf_validation_replace_types(trace, stream_class, NULL,
-               &trace_sc_validation_output, trace_sc_validation_flags);
-       trace->valid = 1;
-       stream_class->valid = 1;
-
-       /*
-        * Put what was not moved in bt_ctf_validation_replace_types().
-        */
-       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
-
-       for (i = 0; i < event_class_count; i++) {
-               struct bt_ctf_event_class_common *event_class =
-                       bt_ctf_stream_class_common_borrow_event_class_by_index(
-                               stream_class, i);
-
-               bt_ctf_validation_replace_types(NULL, NULL, event_class,
-                       &ec_validation_outputs[i], ec_validation_flags);
-               event_class->valid = 1;
-
-               /*
-                * Put what was not moved in
-                * bt_ctf_validation_replace_types().
-                */
-               bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
-       }
-
-       /*
-        * Freeze the trace and the stream class.
-        */
-       bt_ctf_stream_class_common_freeze(stream_class);
-       bt_ctf_trace_common_freeze(trace);
-
-       /*
-        * It is safe to set the stream class's unique clock class
-        * now because the stream class is frozen.
-        */
-       if (expected_clock_class) {
-               BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
-       }
-
-       BT_LOGD("Added stream class to trace: "
-               "trace-addr=%p, trace-name=\"%s\", "
-               "stream-class-addr=%p, stream-class-name=\"%s\", "
-               "stream-class-id=%" PRId64,
-               trace, bt_ctf_trace_common_get_name(trace),
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-
-end:
-       if (ret) {
-               bt_ctf_object_set_parent(&stream_class->base, NULL);
-
-               if (ec_validation_outputs) {
-                       for (i = 0; i < event_class_count; i++) {
-                               bt_ctf_validation_output_put_types(
-                                       &ec_validation_outputs[i]);
-                       }
-               }
-       }
-
-       g_free(ec_validation_outputs);
-       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
-       bt_ctf_object_put_ref(expected_clock_class);
-       return ret;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_clock_class *clock_class)
-{
-       struct bt_ctf_search_query query = { .value = clock_class, .found = 0 };
-
-       BT_ASSERT(trace);
-       BT_ASSERT(clock_class);
-
-       g_ptr_array_foreach(trace->clock_classes, value_exists, &query);
-       return query.found;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace,
-               enum bt_ctf_byte_order byte_order, bool allow_unspecified)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               BT_LOGW("Invalid parameter: trace is frozen: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED && !allow_unspecified) {
-               BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_UNSPECIFIED byte order is not allowed: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
-                       byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
-                       byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
-               BT_LOGW("Invalid parameter: invalid byte order: "
-                       "addr=%p, name=\"%s\", bo=%s",
-                       trace, bt_ctf_trace_common_get_name(trace),
-                       bt_ctf_byte_order_string(byte_order));
-               ret = -1;
-               goto end;
-       }
-
-       trace->native_byte_order = byte_order;
-       BT_LOGV("Set trace's native byte order: "
-               "addr=%p, name=\"%s\", bo=%s",
-               trace, bt_ctf_trace_common_get_name(trace),
-               bt_ctf_byte_order_string(byte_order));
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_field_type_common *packet_header_type)
-{
-       int ret = 0;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (trace->frozen) {
-               BT_LOGW("Invalid parameter: trace is frozen: "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_ctf_trace_common_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       /* packet_header_type must be a structure. */
-       if (packet_header_type &&
-                       packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
-                       "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
-                       trace, bt_ctf_trace_common_get_name(trace),
-                       packet_header_type,
-                       bt_ctf_field_type_id_string(packet_header_type->id));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(trace->packet_header_field_type);
-       trace->packet_header_field_type = bt_ctf_object_get_ref(packet_header_type);
-       BT_LOGV("Set trace's packet header field type: "
-               "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
-               trace, bt_ctf_trace_common_get_name(trace), packet_header_type);
-end:
-       return ret;
-}
-
-static
-int64_t get_stream_class_count(void *element)
-{
-       return bt_ctf_trace_get_stream_class_count(
-                       (struct bt_ctf_trace *) element);
-}
-
-static
-void *get_stream_class(void *element, int i)
-{
-       return bt_ctf_trace_get_stream_class_by_index(
-                       (struct bt_ctf_trace *) element, i);
-}
-
-static
-int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
-{
-       return bt_ctf_stream_class_visit(object, visitor, data);
-}
-
-int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
-               bt_ctf_visitor visitor, void *data)
-{
-       int ret;
-       struct bt_ctf_visitor_object obj = {
-               .object = trace,
-               .type = BT_CTF_VISITOR_OBJECT_TYPE_TRACE
-       };
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!visitor) {
-               BT_LOGW_STR("Invalid parameter: visitor is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
-               trace, bt_ctf_trace_get_name(trace));
-       ret = bt_ctf_visitor_helper(&obj, get_stream_class_count,
-                       get_stream_class, visit_stream_class, visitor, data);
-end:
-       return ret;
-}
-
-static
-void bt_ctf_trace_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_trace *trace = (void *) obj;
-
-       BT_LOGD("Destroying CTF writer trace object: addr=%p, name=\"%s\"",
-               trace, bt_ctf_trace_get_name(trace));
-       bt_ctf_trace_common_finalize(BT_CTF_TO_COMMON(trace));
-       g_free(trace);
-}
-
-BT_HIDDEN
-struct bt_ctf_trace *bt_ctf_trace_create(void)
-{
-       struct bt_ctf_trace *trace = NULL;
-       int ret;
-
-       BT_LOGD_STR("Creating CTF writer trace object.");
-       trace = g_new0(struct bt_ctf_trace, 1);
-       if (!trace) {
-               BT_LOGE_STR("Failed to allocate one CTF writer trace.");
-               goto error;
-       }
-
-       ret = bt_ctf_trace_common_initialize(BT_CTF_TO_COMMON(trace),
-               bt_ctf_trace_destroy);
-       if (ret) {
-               /* bt_ctf_trace_common_initialize() logs errors */
-               goto error;
-       }
-
-       BT_LOGD("Created CTF writer trace object: addr=%p", trace);
-       return trace;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
-       return trace;
-}
-
-const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_uuid(BT_CTF_TO_COMMON(trace));
-}
-
-int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace,
-               const unsigned char *uuid)
-{
-       return bt_ctf_trace_common_set_uuid(BT_CTF_TO_COMMON(trace), uuid);
-}
-
-int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
-               const char *name, const char *value)
-{
-       return bt_ctf_trace_common_set_environment_field_string(BT_CTF_TO_COMMON(trace),
-               name, value);
-}
-
-int bt_ctf_trace_set_environment_field_integer(
-               struct bt_ctf_trace *trace, const char *name, int64_t value)
-{
-       return bt_ctf_trace_common_set_environment_field_integer(
-               BT_CTF_TO_COMMON(trace), name, value);
-}
-
-int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_environment_field_count(BT_CTF_TO_COMMON(trace));
-}
-
-const char *
-bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
-               uint64_t index)
-{
-       return bt_ctf_trace_common_get_environment_field_name_by_index(
-               BT_CTF_TO_COMMON(trace), index);
-}
-
-struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_index(
-               struct bt_ctf_trace *trace, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_index(
-               BT_CTF_TO_COMMON(trace), index));
-}
-
-struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_name(
-               struct bt_ctf_trace *trace, const char *name)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_name(
-               BT_CTF_TO_COMMON(trace), name));
-}
-
-BT_HIDDEN
-int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
-               struct bt_ctf_clock_class *clock_class)
-{
-       return bt_ctf_trace_common_add_clock_class(BT_CTF_TO_COMMON(trace),
-               (void *) clock_class);
-}
-
-BT_HIDDEN
-int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_clock_class_count(BT_CTF_TO_COMMON(trace));
-}
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
-               struct bt_ctf_trace *trace, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_clock_class_by_index(
-               BT_CTF_TO_COMMON(trace), index));
-}
-
-static
-int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type)
-{
-       int ret = bt_ctf_stream_class_map_clock_class(
-               BT_CTF_FROM_COMMON(stream_class),
-               BT_CTF_FROM_COMMON(packet_context_type),
-               BT_CTF_FROM_COMMON(event_header_type));
-
-       if (ret) {
-               BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
-       }
-
-       return ret;
-}
-
-int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
-               struct bt_ctf_stream_class *stream_class)
-{
-       int ret = 0;
-       struct bt_ctf_clock_class *expected_clock_class = NULL;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->clock) {
-               struct bt_ctf_clock_class *stream_clock_class =
-                       stream_class->clock->clock_class;
-
-               /*
-                * Make sure this clock was also added to the
-                * trace (potentially through its CTF writer
-                * owner).
-                */
-               size_t i;
-
-               for (i = 0; i < trace->common.clock_classes->len; i++) {
-                       if (trace->common.clock_classes->pdata[i] ==
-                                       stream_clock_class) {
-                               /* Found! */
-                               break;
-                       }
-               }
-
-               if (i == trace->common.clock_classes->len) {
-                       /* Not found */
-                       BT_LOGW("Stream class's clock's class is not part of the trace: "
-                               "clock-class-addr=%p, clock-class-name=\"%s\"",
-                               stream_clock_class,
-                               bt_ctf_clock_class_get_name(stream_clock_class));
-                       ret = -1;
-                       goto end;
-               }
-
-               if (stream_class->common.clock_class &&
-                               stream_class->common.clock_class !=
-                               stream_class->clock->clock_class) {
-                       /*
-                        * Stream class already has an expected clock
-                        * class, but it does not match its clock's
-                        * class.
-                        */
-                       BT_LOGW("Invalid parameter: stream class's clock's "
-                               "class does not match stream class's "
-                               "expected clock class: "
-                               "stream-class-addr=%p, "
-                               "stream-class-id=%" PRId64 ", "
-                               "stream-class-name=\"%s\", "
-                               "expected-clock-class-addr=%p, "
-                               "expected-clock-class-name=\"%s\"",
-                               stream_class,
-                               bt_ctf_stream_class_get_id(stream_class),
-                               bt_ctf_stream_class_get_name(stream_class),
-                               stream_class->common.clock_class,
-                               bt_ctf_clock_class_get_name(stream_class->common.clock_class));
-               } else if (!stream_class->common.clock_class) {
-                       /*
-                        * Set expected clock class to stream class's
-                        * clock's class.
-                        */
-                       expected_clock_class = stream_class->clock->clock_class;
-               }
-       }
-
-
-       ret = bt_ctf_trace_common_add_stream_class(BT_CTF_TO_COMMON(trace),
-               BT_CTF_TO_COMMON(stream_class),
-               (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy,
-               expected_clock_class, map_clock_classes_func,
-               false);
-
-end:
-       return ret;
-}
-
-int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_stream_count(BT_CTF_TO_COMMON(trace));
-}
-
-struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
-               struct bt_ctf_trace *trace, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_by_index(
-               BT_CTF_TO_COMMON(trace), index));
-}
-
-int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_stream_class_count(BT_CTF_TO_COMMON(trace));
-}
-
-struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
-               struct bt_ctf_trace *trace, uint64_t index)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_index(
-               BT_CTF_TO_COMMON(trace), index));
-}
-
-struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
-               struct bt_ctf_trace *trace, uint64_t id)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_id(
-               BT_CTF_TO_COMMON(trace), id));
-}
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
-               struct bt_ctf_trace *trace, const char *name)
-{
-       return bt_ctf_object_get_ref(
-               bt_ctf_trace_common_borrow_clock_class_by_name(BT_CTF_TO_COMMON(trace),
-                       name));
-}
-
-static
-int append_trace_metadata(struct bt_ctf_trace *trace,
-               struct metadata_context *context)
-{
-       unsigned char *uuid = trace->common.uuid;
-       int ret = 0;
-
-       if (trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NATIVE ||
-                       trace->common.native_byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED) {
-               BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_UNSPECIFIED at this point; "
-                       "set it with bt_ctf_trace_set_native_byte_order(): "
-                       "addr=%p, name=\"%s\"",
-                       trace, bt_ctf_trace_get_name(trace));
-               ret = -1;
-               goto end;
-       }
-
-       g_string_append(context->string, "trace {\n");
-       g_string_append(context->string, "\tmajor = 1;\n");
-       g_string_append(context->string, "\tminor = 8;\n");
-       BT_ASSERT(trace->common.native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
-               trace->common.native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
-               trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
-
-       if (trace->common.uuid_set) {
-               g_string_append_printf(context->string,
-                       "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
-                       uuid[0], uuid[1], uuid[2], uuid[3],
-                       uuid[4], uuid[5], uuid[6], uuid[7],
-                       uuid[8], uuid[9], uuid[10], uuid[11],
-                       uuid[12], uuid[13], uuid[14], uuid[15]);
-       }
-
-       g_string_append_printf(context->string, "\tbyte_order = %s;\n",
-               bt_ctf_get_byte_order_string(trace->common.native_byte_order));
-
-       if (trace->common.packet_header_field_type) {
-               g_string_append(context->string, "\tpacket.header := ");
-               context->current_indentation_level++;
-               g_string_assign(context->field_name, "");
-               BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
-               ret = bt_ctf_field_type_serialize_recursive(
-                       (void *) trace->common.packet_header_field_type,
-                       context);
-               if (ret) {
-                       goto end;
-               }
-               context->current_indentation_level--;
-       }
-
-       g_string_append(context->string, ";\n};\n\n");
-end:
-       return ret;
-}
-
-static
-void append_env_metadata(struct bt_ctf_trace *trace,
-               struct metadata_context *context)
-{
-       int64_t i;
-       int64_t env_size;
-
-       env_size = bt_ctf_attributes_get_count(trace->common.environment);
-       if (env_size <= 0) {
-               return;
-       }
-
-       g_string_append(context->string, "env {\n");
-
-       for (i = 0; i < env_size; i++) {
-               struct bt_ctf_private_value *env_field_value_obj = NULL;
-               const char *entry_name;
-
-               entry_name = bt_ctf_attributes_get_field_name(
-                       trace->common.environment, i);
-               env_field_value_obj = bt_ctf_attributes_borrow_field_value(
-                       trace->common.environment, i);
-
-               BT_ASSERT(entry_name);
-               BT_ASSERT(env_field_value_obj);
-
-               switch (bt_ctf_value_get_type(
-                       bt_ctf_private_value_as_value(env_field_value_obj))) {
-               case BT_CTF_VALUE_TYPE_INTEGER:
-               {
-                       int64_t int_value;
-
-                       int_value = bt_ctf_value_integer_get(
-                               bt_ctf_private_value_as_value(
-                                       env_field_value_obj));
-                       g_string_append_printf(context->string,
-                               "\t%s = %" PRId64 ";\n", entry_name,
-                               int_value);
-                       break;
-               }
-               case BT_CTF_VALUE_TYPE_STRING:
-               {
-                       const char *str_value;
-                       char *escaped_str = NULL;
-
-                       str_value = bt_ctf_value_string_get(
-                               bt_ctf_private_value_as_value(
-                                       env_field_value_obj));
-                       escaped_str = g_strescape(str_value, NULL);
-                       if (!escaped_str) {
-                               BT_LOGE("Cannot escape string: string=\"%s\"",
-                                       str_value);
-                               continue;
-                       }
-
-                       g_string_append_printf(context->string,
-                               "\t%s = \"%s\";\n", entry_name, escaped_str);
-                       free(escaped_str);
-                       break;
-               }
-               default:
-                       continue;
-               }
-       }
-
-       g_string_append(context->string, "};\n\n");
-}
-
-char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
-{
-       char *metadata = NULL;
-       struct metadata_context *context = NULL;
-       int err = 0;
-       size_t i;
-
-       if (!trace) {
-               BT_LOGW_STR("Invalid parameter: trace is NULL.");
-               goto end;
-       }
-
-       context = g_new0(struct metadata_context, 1);
-       if (!context) {
-               BT_LOGE_STR("Failed to allocate one metadata context.");
-               goto end;
-       }
-
-       context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
-       context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
-       g_string_append(context->string, "/* CTF 1.8 */\n\n");
-       if (append_trace_metadata(trace, context)) {
-               /* append_trace_metadata() logs errors */
-               goto error;
-       }
-       append_env_metadata(trace, context);
-       g_ptr_array_foreach(trace->common.clock_classes,
-               (GFunc) bt_ctf_clock_class_serialize, context);
-
-       for (i = 0; i < trace->common.stream_classes->len; i++) {
-               /* bt_ctf_stream_class_serialize() logs details */
-               err = bt_ctf_stream_class_serialize(
-                       trace->common.stream_classes->pdata[i], context);
-               if (err) {
-                       /* bt_ctf_stream_class_serialize() logs errors */
-                       goto error;
-               }
-       }
-
-       metadata = context->string->str;
-
-error:
-       g_string_free(context->string, err ? TRUE : FALSE);
-       g_string_free(context->field_name, TRUE);
-       g_free(context);
-
-end:
-       return metadata;
-}
-
-enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
-               struct bt_ctf_trace *trace)
-{
-       return (int) bt_ctf_trace_common_get_native_byte_order(BT_CTF_TO_COMMON(trace));
-}
-
-int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
-               enum bt_ctf_byte_order byte_order)
-{
-       return bt_ctf_trace_common_set_native_byte_order(BT_CTF_TO_COMMON(trace),
-               (int) byte_order, false);
-}
-
-struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_field_type(
-               struct bt_ctf_trace *trace)
-{
-       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_packet_header_field_type(
-               BT_CTF_TO_COMMON(trace)));
-}
-
-int bt_ctf_trace_set_packet_header_field_type(struct bt_ctf_trace *trace,
-               struct bt_ctf_field_type *packet_header_type)
-{
-       return bt_ctf_trace_common_set_packet_header_field_type(BT_CTF_TO_COMMON(trace),
-               (void *) packet_header_type);
-}
-
-const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
-{
-       return bt_ctf_trace_common_get_name(BT_CTF_TO_COMMON(trace));
-}
diff --git a/ctf-writer/utils.c b/ctf-writer/utils.c
deleted file mode 100644 (file)
index fdf0a93..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * utils.c
- *
- * Babeltrace CTF writer - Utilities
- *
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-UTILS"
-#include "logging.h"
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/utils.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <glib.h>
-#include <stdlib.h>
-
-static
-const char * const reserved_keywords_str[] = {"align", "callsite",
-       "const", "char", "clock", "double", "enum", "env", "event",
-       "floating_point", "float", "integer", "int", "long", "short", "signed",
-       "stream", "string", "struct", "trace", "typealias", "typedef",
-       "unsigned", "variant", "void" "_Bool", "_Complex", "_Imaginary"};
-
-static GHashTable *reserved_keywords_set;
-static int init_done;
-
-static
-void try_init_reserved_keywords(void)
-{
-       size_t i;
-       const size_t reserved_keywords_count =
-               sizeof(reserved_keywords_str) / sizeof(char *);
-
-       if (reserved_keywords_set) {
-               return;
-       }
-
-       reserved_keywords_set = g_hash_table_new(g_direct_hash, g_direct_equal);
-       BT_ASSERT(reserved_keywords_set);
-
-       for (i = 0; i < reserved_keywords_count; i++) {
-               gpointer quark = GINT_TO_POINTER(g_quark_from_string(
-                       reserved_keywords_str[i]));
-
-               g_hash_table_insert(reserved_keywords_set, quark, quark);
-       }
-
-       init_done = 1;
-}
-
-static __attribute__((destructor))
-void trace_finalize(void)
-{
-       if (reserved_keywords_set) {
-               g_hash_table_destroy(reserved_keywords_set);
-       }
-}
-
-bt_bool bt_ctf_identifier_is_valid(const char *identifier)
-{
-       bt_bool is_valid = BT_TRUE;
-       char *string = NULL;
-       char *save_ptr, *token;
-
-       if (!identifier) {
-               BT_LOGV_STR("Invalid parameter: input string is NULL.");
-               is_valid = BT_FALSE;
-               goto end;
-       }
-
-       try_init_reserved_keywords();
-
-       if (identifier[0] == '\0') {
-               is_valid = BT_FALSE;
-               goto end;
-       }
-
-       string = strdup(identifier);
-       if (!string) {
-               BT_LOGE("strdup() failed.");
-               is_valid = BT_FALSE;
-               goto end;
-       }
-
-       token = strtok_r(string, " ", &save_ptr);
-       while (token) {
-               if (g_hash_table_lookup_extended(reserved_keywords_set,
-                       GINT_TO_POINTER(g_quark_from_string(token)),
-                       NULL, NULL)) {
-                       is_valid = BT_FALSE;
-                       goto end;
-               }
-
-               token = strtok_r(NULL, " ", &save_ptr);
-       }
-end:
-       free(string);
-       return is_valid;
-}
diff --git a/ctf-writer/validation.c b/ctf-writer/validation.c
deleted file mode 100644 (file)
index 9c4276e..0000000
+++ /dev/null
@@ -1,652 +0,0 @@
-/*
- * validation.c
- *
- * Babeltrace - CTF writer: Validation of trace, stream class, and event class
- *
- * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-VALIDATION"
-#include "logging.h"
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/resolve-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-
-/*
- * This function resolves and validates the field types of an event
- * class. Only `event_context_type` and `event_payload_type` are
- * resolved and validated; the other field types are used as eventual
- * resolving targets.
- *
- * All parameters are owned by the caller.
- */
-static
-int validate_event_class_types(struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type,
-               struct bt_ctf_field_type_common *event_context_type,
-               struct bt_ctf_field_type_common *event_payload_type)
-{
-       int ret = 0;
-
-       BT_LOGV("Validating event class field types: "
-               "packet-header-ft-addr=%p, "
-               "packet-context-ft-addr=%p, "
-               "event-header-ft-addr=%p, "
-               "stream-event-context-ft-addr=%p, "
-               "event-context-ft-addr=%p, "
-               "event-payload-ft-addr=%p",
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type, event_context_type, event_payload_type);
-
-       /* Resolve sequence type lengths and variant type tags first */
-       ret = bt_ctf_resolve_types(environment, packet_header_type,
-               packet_context_type, event_header_type, stream_event_ctx_type,
-               event_context_type, event_payload_type,
-               BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT |
-               BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD);
-       if (ret) {
-               BT_LOGW("Cannot resolve event class field types: ret=%d",
-                       ret);
-               goto end;
-       }
-
-       /* Validate field types individually */
-       if (event_context_type) {
-               ret = bt_ctf_field_type_common_validate(event_context_type);
-               if (ret) {
-                       BT_LOGW("Invalid event class's context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       if (event_payload_type) {
-               ret = bt_ctf_field_type_common_validate(event_payload_type);
-               if (ret) {
-                       BT_LOGW("Invalid event class's payload field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * This function resolves and validates the field types of a stream
- * class. Only `packet_context_type`, `event_header_type`, and
- * `stream_event_ctx_type` are resolved and validated; the other field
- * type is used as an eventual resolving target.
- *
- * All parameters are owned by the caller.
- */
-static
-int validate_stream_class_types(struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type)
-{
-       int ret = 0;
-
-       BT_LOGV("Validating stream class field types: "
-               "packet-header-ft-addr=%p, "
-               "packet-context-ft-addr=%p, "
-               "event-header-ft-addr=%p, "
-               "stream-event-context-ft-addr=%p",
-               packet_header_type, packet_context_type, event_header_type,
-               stream_event_ctx_type);
-
-       /* Resolve sequence type lengths and variant type tags first */
-       ret = bt_ctf_resolve_types(environment, packet_header_type,
-               packet_context_type, event_header_type, stream_event_ctx_type,
-               NULL, NULL,
-               BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT |
-               BT_CTF_RESOLVE_FLAG_EVENT_HEADER |
-               BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX);
-       if (ret) {
-               BT_LOGW("Cannot resolve stream class field types: ret=%d",
-                       ret);
-               goto end;
-       }
-
-       /* Validate field types individually */
-       if (packet_context_type) {
-               ret = bt_ctf_field_type_common_validate(packet_context_type);
-               if (ret) {
-                       BT_LOGW("Invalid stream class's packet context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       if (event_header_type) {
-               ret = bt_ctf_field_type_common_validate(event_header_type);
-               if (ret) {
-                       BT_LOGW("Invalid stream class's event header field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       if (stream_event_ctx_type) {
-               ret = bt_ctf_field_type_common_validate(
-                       stream_event_ctx_type);
-               if (ret) {
-                       BT_LOGW("Invalid stream class's event context field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * This function resolves and validates the field types of a trace.
- *
- * All parameters are owned by the caller.
- */
-static
-int validate_trace_types(struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type)
-{
-       int ret = 0;
-
-       BT_LOGV("Validating event class field types: "
-               "packet-header-ft-addr=%p", packet_header_type);
-
-       /* Resolve sequence type lengths and variant type tags first */
-       ret = bt_ctf_resolve_types(environment, packet_header_type,
-               NULL, NULL, NULL, NULL, NULL,
-               BT_CTF_RESOLVE_FLAG_PACKET_HEADER);
-       if (ret) {
-               BT_LOGW("Cannot resolve trace field types: ret=%d",
-                       ret);
-               goto end;
-       }
-
-       /* Validate field types individually */
-       if (packet_header_type) {
-               ret = bt_ctf_field_type_common_validate(packet_header_type);
-               if (ret) {
-                       BT_LOGW("Invalid trace's packet header field type: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Checks whether or not `field_type` contains a variant or a sequence
- * field type, recursively. Returns 1 if it's the case.
- *
- * `field_type` is owned by the caller.
- */
-static
-int field_type_contains_sequence_or_variant_ft(struct bt_ctf_field_type_common *type)
-{
-       int ret = 0;
-       enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type);
-
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               ret = 1;
-               goto end;
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-       {
-               int i;
-               int field_count = bt_ctf_field_type_common_get_field_count(type);
-
-               if (field_count < 0) {
-                       ret = -1;
-                       goto end;
-               }
-
-               for (i = 0; i < field_count; ++i) {
-                       struct bt_ctf_field_type_common *child_type =
-                               bt_ctf_field_type_common_borrow_field_at_index(
-                                       type, i);
-
-                       ret = field_type_contains_sequence_or_variant_ft(
-                               child_type);
-                       if (ret != 0) {
-                               goto end;
-                       }
-               }
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctf_validate_class_types(struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type,
-               struct bt_ctf_field_type_common *event_context_type,
-               struct bt_ctf_field_type_common *event_payload_type,
-               int trace_valid, int stream_class_valid, int event_class_valid,
-               struct bt_ctf_validation_output *output,
-               enum bt_ctf_validation_flag validate_flags,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
-{
-       int ret = 0;
-       int contains_seq_var;
-       int valid_ret;
-
-       BT_LOGV("Validating field types: "
-               "packet-header-ft-addr=%p, "
-               "packet-context-ft-addr=%p, "
-               "event-header-ft-addr=%p, "
-               "stream-event-context-ft-addr=%p, "
-               "event-context-ft-addr=%p, "
-               "event-payload-ft-addr=%p, "
-               "trace-is-valid=%d, stream-class-is-valid=%d, "
-               "event-class-is-valid=%d, validation-flags=%x",
-               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,
-               (unsigned int) validate_flags);
-
-       /* Clean output values */
-       memset(output, 0, sizeof(*output));
-
-       /* Set initial valid flags according to valid parameters */
-       if (trace_valid) {
-               output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE;
-       }
-
-       if (stream_class_valid) {
-               output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM;
-       }
-
-       if (event_class_valid) {
-               output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT;
-       }
-
-       /* Own the type parameters */
-       bt_ctf_object_get_ref(packet_header_type);
-       bt_ctf_object_get_ref(packet_context_type);
-       bt_ctf_object_get_ref(event_header_type);
-       bt_ctf_object_get_ref(stream_event_ctx_type);
-       bt_ctf_object_get_ref(event_context_type);
-       bt_ctf_object_get_ref(event_payload_type);
-
-       /* Validate trace */
-       if ((validate_flags & BT_CTF_VALIDATION_FLAG_TRACE) && !trace_valid) {
-               struct bt_ctf_field_type_common *packet_header_type_copy = NULL;
-
-               /* Create field type copies */
-               if (packet_header_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       packet_header_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               packet_header_type_copy = packet_header_type;
-                               bt_ctf_object_get_ref(packet_header_type_copy);
-                               goto skip_packet_header_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying packet header field type because it contains at least one sequence or variant field type.");
-                       packet_header_type_copy =
-                               copy_field_type_func(packet_header_type);
-                       if (!packet_header_type_copy) {
-                               ret = -1;
-                               BT_LOGE_STR("Cannot copy packet header field type.");
-                               goto error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_ctf_field_type_common_freeze(packet_header_type_copy);
-               }
-
-skip_packet_header_type_copy:
-               /* Put original reference and move copy */
-               BT_CTF_OBJECT_MOVE_REF(packet_header_type, packet_header_type_copy);
-
-               /* Validate trace field types */
-               valid_ret = validate_trace_types(environment,
-                       packet_header_type);
-               if (valid_ret == 0) {
-                       /* Trace is valid */
-                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE;
-               }
-       }
-
-       /* Validate stream class */
-       if ((validate_flags & BT_CTF_VALIDATION_FLAG_STREAM) &&
-                       !stream_class_valid) {
-               struct bt_ctf_field_type_common *packet_context_type_copy = NULL;
-               struct bt_ctf_field_type_common *event_header_type_copy = NULL;
-               struct bt_ctf_field_type_common *stream_event_ctx_type_copy = NULL;
-
-               if (packet_context_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       packet_context_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               packet_context_type_copy = packet_context_type;
-                               bt_ctf_object_get_ref(packet_context_type_copy);
-                               goto skip_packet_context_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying packet context field type because it contains at least one sequence or variant field type.");
-                       packet_context_type_copy =
-                               copy_field_type_func(packet_context_type);
-                       if (!packet_context_type_copy) {
-                               BT_LOGE_STR("Cannot copy packet context field type.");
-                               goto sc_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_ctf_field_type_common_freeze(packet_context_type_copy);
-               }
-
-skip_packet_context_type_copy:
-               if (event_header_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       event_header_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               event_header_type_copy = event_header_type;
-                               bt_ctf_object_get_ref(event_header_type_copy);
-                               goto skip_event_header_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying event header field type because it contains at least one sequence or variant field type.");
-                       event_header_type_copy =
-                               copy_field_type_func(event_header_type);
-                       if (!event_header_type_copy) {
-                               BT_LOGE_STR("Cannot copy event header field type.");
-                               goto sc_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_ctf_field_type_common_freeze(event_header_type_copy);
-               }
-
-skip_event_header_type_copy:
-               if (stream_event_ctx_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       stream_event_ctx_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               stream_event_ctx_type_copy =
-                                       stream_event_ctx_type;
-                               bt_ctf_object_get_ref(stream_event_ctx_type_copy);
-                               goto skip_stream_event_ctx_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying stream event context field type because it contains at least one sequence or variant field type.");
-                       stream_event_ctx_type_copy =
-                               copy_field_type_func(stream_event_ctx_type);
-                       if (!stream_event_ctx_type_copy) {
-                               BT_LOGE_STR("Cannot copy stream event context field type.");
-                               goto sc_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_ctf_field_type_common_freeze(stream_event_ctx_type_copy);
-               }
-
-skip_stream_event_ctx_type_copy:
-               /* Put original references and move copies */
-               BT_CTF_OBJECT_MOVE_REF(packet_context_type, packet_context_type_copy);
-               BT_CTF_OBJECT_MOVE_REF(event_header_type, event_header_type_copy);
-               BT_CTF_OBJECT_MOVE_REF(stream_event_ctx_type, stream_event_ctx_type_copy);
-
-               /* Validate stream class field types */
-               valid_ret = validate_stream_class_types(environment,
-                       packet_header_type, packet_context_type,
-                       event_header_type, stream_event_ctx_type);
-               if (valid_ret == 0) {
-                       /* Stream class is valid */
-                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM;
-               }
-
-               goto sc_validation_done;
-
-sc_validation_error:
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type_copy);
-               ret = -1;
-               goto error;
-       }
-
-sc_validation_done:
-       /* Validate event class */
-       if ((validate_flags & BT_CTF_VALIDATION_FLAG_EVENT) &&
-                       !event_class_valid) {
-               struct bt_ctf_field_type_common *event_context_type_copy = NULL;
-               struct bt_ctf_field_type_common *event_payload_type_copy = NULL;
-
-               if (event_context_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       event_context_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               event_context_type_copy = event_context_type;
-                               bt_ctf_object_get_ref(event_context_type_copy);
-                               goto skip_event_context_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying event context field type because it contains at least one sequence or variant field type.");
-                       event_context_type_copy =
-                               copy_field_type_func(event_context_type);
-                       if (!event_context_type_copy) {
-                               BT_LOGE_STR("Cannot copy event context field type.");
-                               goto ec_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_ctf_field_type_common_freeze(event_context_type_copy);
-               }
-
-skip_event_context_type_copy:
-               if (event_payload_type) {
-                       contains_seq_var =
-                               field_type_contains_sequence_or_variant_ft(
-                                       event_payload_type);
-                       if (contains_seq_var < 0) {
-                               ret = contains_seq_var;
-                               goto error;
-                       } else if (!contains_seq_var) {
-                               /* No copy is needed */
-                               event_payload_type_copy = event_payload_type;
-                               bt_ctf_object_get_ref(event_payload_type_copy);
-                               goto skip_event_payload_type_copy;
-                       }
-
-                       BT_LOGV_STR("Copying event payload field type because it contains at least one sequence or variant field type.");
-                       event_payload_type_copy =
-                               copy_field_type_func(event_payload_type);
-                       if (!event_payload_type_copy) {
-                               BT_LOGE_STR("Cannot copy event payload field type.");
-                               goto ec_validation_error;
-                       }
-
-                       /*
-                        * Freeze this copy: if it's returned to the
-                        * caller, it cannot be modified any way since
-                        * it will be resolved.
-                        */
-                       bt_ctf_field_type_common_freeze(event_payload_type_copy);
-               }
-
-skip_event_payload_type_copy:
-               /* Put original references and move copies */
-               BT_CTF_OBJECT_MOVE_REF(event_context_type, event_context_type_copy);
-               BT_CTF_OBJECT_MOVE_REF(event_payload_type, event_payload_type_copy);
-
-               /* Validate event class field types */
-               valid_ret = validate_event_class_types(environment,
-                       packet_header_type, packet_context_type,
-                       event_header_type, stream_event_ctx_type,
-                       event_context_type, event_payload_type);
-               if (valid_ret == 0) {
-                       /* Event class is valid */
-                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT;
-               }
-
-               goto ec_validation_done;
-
-ec_validation_error:
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type_copy);
-               ret = -1;
-               goto error;
-       }
-
-ec_validation_done:
-       /*
-        * Validation is complete. Move the field types that were used
-        * to validate (and that were possibly altered by the validation
-        * process) to the output values.
-        */
-       BT_CTF_OBJECT_MOVE_REF(output->packet_header_type, packet_header_type);
-       BT_CTF_OBJECT_MOVE_REF(output->packet_context_type, packet_context_type);
-       BT_CTF_OBJECT_MOVE_REF(output->event_header_type, event_header_type);
-       BT_CTF_OBJECT_MOVE_REF(output->stream_event_ctx_type, stream_event_ctx_type);
-       BT_CTF_OBJECT_MOVE_REF(output->event_context_type, event_context_type);
-       BT_CTF_OBJECT_MOVE_REF(output->event_payload_type, event_payload_type);
-       return ret;
-
-error:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_header_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type);
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_validation_replace_types(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_validation_output *output,
-               enum bt_ctf_validation_flag replace_flags)
-{
-       if ((replace_flags & BT_CTF_VALIDATION_FLAG_TRACE) && trace) {
-               bt_ctf_field_type_common_freeze(trace->packet_header_field_type);
-               BT_CTF_OBJECT_MOVE_REF(trace->packet_header_field_type,
-                       output->packet_header_type);
-       }
-
-       if ((replace_flags & BT_CTF_VALIDATION_FLAG_STREAM) && stream_class) {
-               bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
-               bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
-               bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
-               BT_CTF_OBJECT_MOVE_REF(stream_class->packet_context_field_type,
-                       output->packet_context_type);
-               BT_CTF_OBJECT_MOVE_REF(stream_class->event_header_field_type,
-                       output->event_header_type);
-               BT_CTF_OBJECT_MOVE_REF(stream_class->event_context_field_type,
-                       output->stream_event_ctx_type);
-       }
-
-       if ((replace_flags & BT_CTF_VALIDATION_FLAG_EVENT) && event_class) {
-               bt_ctf_field_type_common_freeze(event_class->context_field_type);
-               bt_ctf_field_type_common_freeze(event_class->payload_field_type);
-               BT_CTF_OBJECT_MOVE_REF(event_class->context_field_type, output->event_context_type);
-               BT_CTF_OBJECT_MOVE_REF(event_class->payload_field_type, output->event_payload_type);
-       }
-}
-
-BT_HIDDEN
-void bt_ctf_validation_output_put_types(
-               struct bt_ctf_validation_output *output)
-{
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_header_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_context_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_header_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->stream_event_ctx_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_context_type);
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_payload_type);
-}
diff --git a/ctf-writer/values.c b/ctf-writer/values.c
deleted file mode 100644 (file)
index dd8ae94..0000000
+++ /dev/null
@@ -1,1344 +0,0 @@
-/*
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER-VALUES"
-#include "logging.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <string.h>
-#include <inttypes.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/compat/glib-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-
-#define BT_CTF_VALUE_FROM_CONCRETE(_concrete) ((struct bt_ctf_value *) (_concrete))
-#define BT_CTF_VALUE_TO_BOOL(_base) ((struct bt_ctf_value_bool *) (_base))
-#define BT_CTF_VALUE_TO_INTEGER(_base) ((struct bt_ctf_value_integer *) (_base))
-#define BT_CTF_VALUE_TO_REAL(_base) ((struct bt_ctf_value_real *) (_base))
-#define BT_CTF_VALUE_TO_STRING(_base) ((struct bt_ctf_value_string *) (_base))
-#define BT_CTF_VALUE_TO_ARRAY(_base) ((struct bt_ctf_value_array *) (_base))
-#define BT_CTF_VALUE_TO_MAP(_base) ((struct bt_ctf_value_map *) (_base))
-
-#define BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(_value, _type)                 \
-       BT_CTF_ASSERT_PRE(((struct bt_ctf_value *) (_value))->type == (_type),  \
-               "Value has the wrong type ID: expected-type=%d", (_type))
-
-#define BT_CTF_ASSERT_PRE_VALUE_HOT(_value, _name)                             \
-       BT_CTF_ASSERT_PRE_HOT(((struct bt_ctf_value *) (_value)), (_name), "")
-
-#define BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count)                \
-       BT_CTF_ASSERT_PRE((_index) < (_count),                          \
-               "Index is out of bound: "                               \
-               "index=%" PRIu64 ", count=%u", (_index), (_count));
-
-struct bt_ctf_value {
-       struct bt_ctf_object base;
-       enum bt_ctf_value_type type;
-       bt_bool frozen;
-};
-
-static
-void bt_ctf_value_null_instance_release_func(struct bt_ctf_object *obj)
-{
-       BT_LOGW("Releasing the null value singleton: addr=%p", obj);
-}
-
-static
-struct bt_ctf_value bt_ctf_value_null_instance = {
-       .base = {
-               .is_shared = true,
-               .ref_count = 1,
-               .release_func = bt_ctf_value_null_instance_release_func,
-               .spec_release_func = NULL,
-               .parent_is_owner_listener_func = NULL,
-               .parent = NULL,
-       },
-       .type = BT_CTF_VALUE_TYPE_NULL,
-       .frozen = BT_TRUE,
-};
-
-struct bt_ctf_value *const bt_ctf_value_null = &bt_ctf_value_null_instance;
-struct bt_ctf_private_value *const bt_ctf_private_value_null =
-       (void *) &bt_ctf_value_null_instance;
-
-struct bt_ctf_value_bool {
-       struct bt_ctf_value base;
-       bt_bool value;
-};
-
-struct bt_ctf_value_integer {
-       struct bt_ctf_value base;
-       int64_t value;
-};
-
-struct bt_ctf_value_real {
-       struct bt_ctf_value base;
-       double value;
-};
-
-struct bt_ctf_value_string {
-       struct bt_ctf_value base;
-       GString *gstr;
-};
-
-struct bt_ctf_value_array {
-       struct bt_ctf_value base;
-       GPtrArray *garray;
-};
-
-struct bt_ctf_value_map {
-       struct bt_ctf_value base;
-       GHashTable *ght;
-};
-
-static
-void bt_ctf_value_destroy(struct bt_ctf_object *obj);
-
-static
-void bt_ctf_value_string_destroy(struct bt_ctf_value *object)
-{
-       g_string_free(BT_CTF_VALUE_TO_STRING(object)->gstr, TRUE);
-       BT_CTF_VALUE_TO_STRING(object)->gstr = NULL;
-}
-
-static
-void bt_ctf_value_array_destroy(struct bt_ctf_value *object)
-{
-       /*
-        * Pointer array's registered value destructor will take care
-        * of putting each contained object.
-        */
-       g_ptr_array_free(BT_CTF_VALUE_TO_ARRAY(object)->garray, TRUE);
-       BT_CTF_VALUE_TO_ARRAY(object)->garray = NULL;
-}
-
-static
-void bt_ctf_value_map_destroy(struct bt_ctf_value *object)
-{
-       /*
-        * Hash table's registered value destructor will take care of
-        * putting each contained object. Keys are GQuarks and cannot
-        * be destroyed anyway.
-        */
-       g_hash_table_destroy(BT_CTF_VALUE_TO_MAP(object)->ght);
-       BT_CTF_VALUE_TO_MAP(object)->ght = NULL;
-}
-
-static
-void (* const destroy_funcs[])(struct bt_ctf_value *) = {
-       [BT_CTF_VALUE_TYPE_NULL] =              NULL,
-       [BT_CTF_VALUE_TYPE_BOOL] =              NULL,
-       [BT_CTF_VALUE_TYPE_INTEGER] =   NULL,
-       [BT_CTF_VALUE_TYPE_REAL] =              NULL,
-       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_destroy,
-       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_destroy,
-       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_destroy,
-};
-
-static
-struct bt_ctf_private_value *bt_ctf_value_null_copy(const struct bt_ctf_value *null_obj)
-{
-       return (void *) bt_ctf_value_null;
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_bool_copy(const struct bt_ctf_value *bool_obj)
-{
-       return bt_ctf_private_value_bool_create_init(
-               BT_CTF_VALUE_TO_BOOL(bool_obj)->value);
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_integer_copy(
-               const struct bt_ctf_value *integer_obj)
-{
-       return bt_ctf_private_value_integer_create_init(
-               BT_CTF_VALUE_TO_INTEGER(integer_obj)->value);
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_real_copy(const struct bt_ctf_value *real_obj)
-{
-       return bt_ctf_private_value_real_create_init(
-               BT_CTF_VALUE_TO_REAL(real_obj)->value);
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_string_copy(const struct bt_ctf_value *string_obj)
-{
-       return bt_ctf_private_value_string_create_init(
-               BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str);
-}
-
-static
-struct bt_ctf_private_value *bt_ctf_value_array_copy(const struct bt_ctf_value *array_obj)
-{
-       int i;
-       int ret;
-       struct bt_ctf_private_value *copy_obj;
-       struct bt_ctf_value_array *typed_array_obj;
-
-       BT_LOGD("Copying array value: addr=%p", array_obj);
-       typed_array_obj = BT_CTF_VALUE_TO_ARRAY(array_obj);
-       copy_obj = bt_ctf_private_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_ctf_private_value *element_obj_copy = NULL;
-               struct bt_ctf_value *element_obj =
-                       bt_ctf_value_array_borrow_element_by_index(
-                               array_obj, i);
-
-               BT_ASSERT(element_obj);
-               BT_LOGD("Copying array value's element: element-addr=%p, "
-                       "index=%d", element_obj, i);
-               ret = bt_ctf_value_copy(&element_obj_copy, element_obj);
-               if (ret) {
-                       BT_LOGE("Cannot copy array value's element: "
-                               "array-addr=%p, index=%d",
-                               array_obj, i);
-                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
-                       goto end;
-               }
-
-               BT_ASSERT(element_obj_copy);
-               ret = bt_ctf_private_value_array_append_element(copy_obj,
-                       (void *) element_obj_copy);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy);
-               if (ret) {
-                       BT_LOGE("Cannot append to array value: addr=%p",
-                               array_obj);
-                       BT_CTF_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_ctf_private_value *bt_ctf_value_map_copy(const struct bt_ctf_value *map_obj)
-{
-       int ret;
-       GHashTableIter iter;
-       gpointer key, element_obj;
-       struct bt_ctf_private_value *copy_obj;
-       struct bt_ctf_private_value *element_obj_copy = NULL;
-       struct bt_ctf_value_map *typed_map_obj;
-
-       BT_LOGD("Copying map value: addr=%p", map_obj);
-       typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj);
-       copy_obj = bt_ctf_private_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_ctf_value_copy(&element_obj_copy, element_obj);
-               if (ret) {
-                       BT_LOGE("Cannot copy map value's element: "
-                               "map-addr=%p, key=\"%s\"",
-                               map_obj, key_str);
-                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
-                       goto end;
-               }
-
-               BT_ASSERT(element_obj_copy);
-               ret = bt_ctf_private_value_map_insert_entry(copy_obj, key_str,
-                       (void *) element_obj_copy);
-               BT_CTF_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_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
-                       goto end;
-               }
-       }
-
-       BT_LOGD("Copied map value: addr=%p", map_obj);
-
-end:
-       return copy_obj;
-}
-
-static
-struct bt_ctf_private_value *(* const copy_funcs[])(const struct bt_ctf_value *) = {
-       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_copy,
-       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_bool_copy,
-       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_integer_copy,
-       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_real_copy,
-       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_copy,
-       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_copy,
-       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_copy,
-};
-
-static
-bt_bool bt_ctf_value_null_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       /*
-        * Always BT_TRUE since bt_ctf_value_compare() already checks if both
-        * object_a and object_b have the same type, and in the case of
-        * null value objects, they're always the same if it is so.
-        */
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_bool_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       if (BT_CTF_VALUE_TO_BOOL(object_a)->value !=
-                       BT_CTF_VALUE_TO_BOOL(object_b)->value) {
-               BT_LOGV("Boolean value objects are different: "
-                       "bool-a-val=%d, bool-b-val=%d",
-                       BT_CTF_VALUE_TO_BOOL(object_a)->value,
-                       BT_CTF_VALUE_TO_BOOL(object_b)->value);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_integer_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       if (BT_CTF_VALUE_TO_INTEGER(object_a)->value !=
-                       BT_CTF_VALUE_TO_INTEGER(object_b)->value) {
-               BT_LOGV("Integer value objects are different: "
-                       "int-a-val=%" PRId64 ", int-b-val=%" PRId64,
-                       BT_CTF_VALUE_TO_INTEGER(object_a)->value,
-                       BT_CTF_VALUE_TO_INTEGER(object_b)->value);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_real_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       if (BT_CTF_VALUE_TO_REAL(object_a)->value !=
-                       BT_CTF_VALUE_TO_REAL(object_b)->value) {
-               BT_LOGV("Real number value objects are different: "
-                       "real-a-val=%f, real-b-val=%f",
-                       BT_CTF_VALUE_TO_REAL(object_a)->value,
-                       BT_CTF_VALUE_TO_REAL(object_b)->value);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_string_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       if (strcmp(BT_CTF_VALUE_TO_STRING(object_a)->gstr->str,
-                       BT_CTF_VALUE_TO_STRING(object_b)->gstr->str) != 0) {
-               BT_LOGV("String value objects are different: "
-                       "string-a-val=\"%s\", string-b-val=\"%s\"",
-                       BT_CTF_VALUE_TO_STRING(object_a)->gstr->str,
-                       BT_CTF_VALUE_TO_STRING(object_b)->gstr->str);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_ctf_value_array_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       int i;
-       bt_bool ret = BT_TRUE;
-       const struct bt_ctf_value_array *array_obj_a =
-               BT_CTF_VALUE_TO_ARRAY(object_a);
-
-       if (bt_ctf_value_array_get_size(object_a) !=
-                       bt_ctf_value_array_get_size(object_b)) {
-               BT_LOGV("Array values are different: size mismatch "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
-                       object_a, object_b,
-                       bt_ctf_value_array_get_size(object_a),
-                       bt_ctf_value_array_get_size(object_b));
-               ret = BT_FALSE;
-               goto end;
-       }
-
-       for (i = 0; i < array_obj_a->garray->len; ++i) {
-               struct bt_ctf_value *element_obj_a;
-               struct bt_ctf_value *element_obj_b;
-
-               element_obj_a = bt_ctf_value_array_borrow_element_by_index(
-                       object_a, i);
-               element_obj_b = bt_ctf_value_array_borrow_element_by_index(
-                       object_b, i);
-
-               if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) {
-                       BT_LOGV("Array values's elements are different: "
-                               "value-a-addr=%p, value-b-addr=%p, index=%d",
-                               element_obj_a, element_obj_b, i);
-                       ret = BT_FALSE;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_bool bt_ctf_value_map_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b)
-{
-       bt_bool ret = BT_TRUE;
-       GHashTableIter iter;
-       gpointer key, element_obj_a;
-       const struct bt_ctf_value_map *map_obj_a = BT_CTF_VALUE_TO_MAP(object_a);
-
-       if (bt_ctf_value_map_get_size(object_a) !=
-                       bt_ctf_value_map_get_size(object_b)) {
-               BT_LOGV("Map values are different: size mismatch "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
-                       object_a, object_b,
-                       bt_ctf_value_map_get_size(object_a),
-                       bt_ctf_value_map_get_size(object_b));
-               ret = BT_FALSE;
-               goto end;
-       }
-
-       g_hash_table_iter_init(&iter, map_obj_a->ght);
-
-       while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) {
-               struct bt_ctf_value *element_obj_b;
-               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
-
-               element_obj_b = bt_ctf_value_map_borrow_entry_value(object_b,
-                       key_str);
-
-               if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) {
-                       BT_LOGV("Map values's elements are different: "
-                               "value-a-addr=%p, value-b-addr=%p, key=\"%s\"",
-                               element_obj_a, element_obj_b, key_str);
-                       ret = BT_FALSE;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_bool (* const compare_funcs[])(const struct bt_ctf_value *,
-               const struct bt_ctf_value *) = {
-       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_compare,
-       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_bool_compare,
-       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_integer_compare,
-       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_real_compare,
-       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_compare,
-       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_compare,
-       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_compare,
-};
-
-static
-void bt_ctf_value_null_freeze(struct bt_ctf_value *object)
-{
-}
-
-static
-void bt_ctf_value_generic_freeze(struct bt_ctf_value *object)
-{
-       object->frozen = BT_TRUE;
-}
-
-static
-void bt_ctf_value_array_freeze(struct bt_ctf_value *object)
-{
-       int i;
-       struct bt_ctf_value_array *typed_array_obj =
-               BT_CTF_VALUE_TO_ARRAY(object);
-
-       for (i = 0; i < typed_array_obj->garray->len; ++i) {
-               bt_ctf_value_freeze(g_ptr_array_index(typed_array_obj->garray, i));
-       }
-
-       bt_ctf_value_generic_freeze(object);
-}
-
-static
-void bt_ctf_value_map_freeze(struct bt_ctf_value *object)
-{
-       GHashTableIter iter;
-       gpointer key, element_obj;
-       const struct bt_ctf_value_map *map_obj = BT_CTF_VALUE_TO_MAP(object);
-
-       g_hash_table_iter_init(&iter, map_obj->ght);
-
-       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
-               bt_ctf_value_freeze(element_obj);
-       }
-
-       bt_ctf_value_generic_freeze(object);
-}
-
-static
-void (* const freeze_funcs[])(struct bt_ctf_value *) = {
-       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_freeze,
-       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_generic_freeze,
-       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_generic_freeze,
-       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_generic_freeze,
-       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_generic_freeze,
-       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_freeze,
-       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_freeze,
-};
-
-static
-void bt_ctf_value_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_value *value;
-
-       value = container_of(obj, struct bt_ctf_value, base);
-       BT_LOGD("Destroying value: addr=%p", value);
-
-       if (bt_ctf_value_is_null(value)) {
-               BT_LOGD_STR("Not destroying the null value singleton.");
-               return;
-       }
-
-       if (destroy_funcs[value->type]) {
-               destroy_funcs[value->type](value);
-       }
-
-       g_free(value);
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status _bt_ctf_value_freeze(struct bt_ctf_value *object)
-{
-       enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK;
-
-       BT_ASSERT(object);
-
-       if (object->frozen) {
-               goto end;
-       }
-
-       BT_LOGD("Freezing value: addr=%p", object);
-       freeze_funcs[object->type](object);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_type bt_ctf_value_get_type(const struct bt_ctf_value *object)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(object, "Value object");
-       return object->type;
-}
-
-static
-struct bt_ctf_value bt_ctf_value_create_base(enum bt_ctf_value_type type)
-{
-       struct bt_ctf_value value;
-
-       value.type = type;
-       value.frozen = BT_FALSE;
-       bt_ctf_object_init_shared(&value.base, bt_ctf_value_destroy);
-       return value;
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_bool_create_init(bt_bool val)
-{
-       struct bt_ctf_value_bool *bool_obj;
-
-       BT_LOGD("Creating boolean value object: val=%d", val);
-       bool_obj = g_new0(struct bt_ctf_value_bool, 1);
-       if (!bool_obj) {
-               BT_LOGE_STR("Failed to allocate one boolean value object.");
-               goto end;
-       }
-
-       bool_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_BOOL);
-       bool_obj->value = val;
-       BT_LOGD("Created boolean value object: addr=%p", bool_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(bool_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_bool_create(void)
-{
-       return bt_ctf_private_value_bool_create_init(BT_FALSE);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_integer_create_init(int64_t val)
-{
-       struct bt_ctf_value_integer *integer_obj;
-
-       BT_LOGD("Creating integer value object: val=%" PRId64, val);
-       integer_obj = g_new0(struct bt_ctf_value_integer, 1);
-       if (!integer_obj) {
-               BT_LOGE_STR("Failed to allocate one integer value object.");
-               goto end;
-       }
-
-       integer_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_INTEGER);
-       integer_obj->value = val;
-       BT_LOGD("Created integer value object: addr=%p",
-               integer_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(integer_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_integer_create(void)
-{
-       return bt_ctf_private_value_integer_create_init(0);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_real_create_init(double val)
-{
-       struct bt_ctf_value_real *real_obj;
-
-       BT_LOGD("Creating real number value object: val=%f", val);
-       real_obj = g_new0(struct bt_ctf_value_real, 1);
-       if (!real_obj) {
-               BT_LOGE_STR("Failed to allocate one real number value object.");
-               goto end;
-       }
-
-       real_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_REAL);
-       real_obj->value = val;
-       BT_LOGD("Created real number value object: addr=%p",
-               real_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(real_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_real_create(void)
-{
-       return bt_ctf_private_value_real_create_init(0.);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_string_create_init(const char *val)
-{
-       struct bt_ctf_value_string *string_obj = NULL;
-
-       if (!val) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               goto end;
-       }
-
-       BT_LOGD("Creating string value object: val-len=%zu", strlen(val));
-       string_obj = g_new0(struct bt_ctf_value_string, 1);
-       if (!string_obj) {
-               BT_LOGE_STR("Failed to allocate one string object.");
-               goto end;
-       }
-
-       string_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_STRING);
-       string_obj->gstr = g_string_new(val);
-       if (!string_obj->gstr) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               g_free(string_obj);
-               string_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created string value object: addr=%p",
-               string_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(string_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_string_create(void)
-{
-       return bt_ctf_private_value_string_create_init("");
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_array_create(void)
-{
-       struct bt_ctf_value_array *array_obj;
-
-       BT_LOGD_STR("Creating empty array value object.");
-       array_obj = g_new0(struct bt_ctf_value_array, 1);
-       if (!array_obj) {
-               BT_LOGE_STR("Failed to allocate one array object.");
-               goto end;
-       }
-
-       array_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_ARRAY);
-       array_obj->garray = bt_g_ptr_array_new_full(0,
-               (GDestroyNotify) bt_ctf_object_put_ref);
-       if (!array_obj->garray) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               g_free(array_obj);
-               array_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created array value object: addr=%p",
-               array_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(array_obj);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_map_create(void)
-{
-       struct bt_ctf_value_map *map_obj;
-
-       BT_LOGD_STR("Creating empty map value object.");
-       map_obj = g_new0(struct bt_ctf_value_map, 1);
-       if (!map_obj) {
-               BT_LOGE_STR("Failed to allocate one map object.");
-               goto end;
-       }
-
-       map_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_MAP);
-       map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-               NULL, (GDestroyNotify) bt_ctf_object_put_ref);
-       if (!map_obj->ght) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               g_free(map_obj);
-               map_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created map value object: addr=%p",
-               map_obj);
-
-end:
-       return (void *) BT_CTF_VALUE_FROM_CONCRETE(map_obj);
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_value_bool_get(const struct bt_ctf_value *bool_obj)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL);
-       return BT_CTF_VALUE_TO_BOOL(bool_obj)->value;
-}
-
-BT_HIDDEN
-void bt_ctf_private_value_bool_set(struct bt_ctf_private_value *bool_obj, bt_bool val)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL);
-       BT_CTF_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object");
-       BT_CTF_VALUE_TO_BOOL(bool_obj)->value = val;
-       BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d",
-               bool_obj, val);
-}
-
-BT_HIDDEN
-int64_t bt_ctf_value_integer_get(const struct bt_ctf_value *integer_obj)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER);
-       return BT_CTF_VALUE_TO_INTEGER(integer_obj)->value;
-}
-
-BT_HIDDEN
-void bt_ctf_private_value_integer_set(struct bt_ctf_private_value *integer_obj,
-               int64_t val)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER);
-       BT_CTF_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object");
-       BT_CTF_VALUE_TO_INTEGER(integer_obj)->value = val;
-       BT_LOGV("Set integer value's raw value: value-addr=%p, value=%" PRId64,
-               integer_obj, val);
-}
-
-BT_HIDDEN
-double bt_ctf_value_real_get(const struct bt_ctf_value *real_obj)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(real_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL);
-       return BT_CTF_VALUE_TO_REAL(real_obj)->value;
-}
-
-BT_HIDDEN
-void bt_ctf_private_value_real_set(struct bt_ctf_private_value *real_obj, double val)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(real_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL);
-       BT_CTF_ASSERT_PRE_VALUE_HOT(real_obj, "Value object");
-       BT_CTF_VALUE_TO_REAL(real_obj)->value = val;
-       BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f",
-               real_obj, val);
-}
-
-BT_HIDDEN
-const char *bt_ctf_value_string_get(const struct bt_ctf_value *string_obj)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(string_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING);
-       return BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_string_set(
-               struct bt_ctf_private_value *string_obj, const char *val)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(string_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING);
-       BT_CTF_ASSERT_PRE_VALUE_HOT(string_obj, "Value object");
-       g_string_assign(BT_CTF_VALUE_TO_STRING(string_obj)->gstr, val);
-       BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p",
-               string_obj, val);
-       return BT_CTF_VALUE_STATUS_OK;
-}
-
-BT_HIDDEN
-uint64_t bt_ctf_value_array_get_size(const struct bt_ctf_value *array_obj)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
-       return (uint64_t) BT_CTF_VALUE_TO_ARRAY(array_obj)->garray->len;
-}
-
-BT_HIDDEN
-struct bt_ctf_value *bt_ctf_value_array_borrow_element_by_index(
-               const struct bt_ctf_value *array_obj,
-               uint64_t index)
-{
-       struct bt_ctf_value_array *typed_array_obj =
-               BT_CTF_VALUE_TO_ARRAY(array_obj);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
-       BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
-               typed_array_obj->garray->len);
-       return g_ptr_array_index(typed_array_obj->garray, index);
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_array_borrow_element_by_index(
-               const struct bt_ctf_private_value *array_obj,
-               uint64_t index)
-{
-       return (void *) bt_ctf_value_array_borrow_element_by_index(
-               (void *) array_obj, index);
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_element(
-               struct bt_ctf_private_value *array_obj,
-               struct bt_ctf_value *element_obj)
-{
-       struct bt_ctf_value_array *typed_array_obj =
-               BT_CTF_VALUE_TO_ARRAY(array_obj);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
-       BT_CTF_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
-       g_ptr_array_add(typed_array_obj->garray, element_obj);
-       bt_ctf_object_get_ref(element_obj);
-       BT_LOGV("Appended element to array value: array-value-addr=%p, "
-               "element-value-addr=%p, new-size=%u",
-               array_obj, element_obj, typed_array_obj->garray->len);
-       return BT_CTF_VALUE_STATUS_OK;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_bool_element(
-               struct bt_ctf_private_value *array_obj, bt_bool val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *bool_obj = NULL;
-
-       bool_obj = bt_ctf_private_value_bool_create_init(val);
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) bool_obj);
-       bt_ctf_object_put_ref(bool_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_integer_element(
-               struct bt_ctf_private_value *array_obj, int64_t val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *integer_obj = NULL;
-
-       integer_obj = bt_ctf_private_value_integer_create_init(val);
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) integer_obj);
-       bt_ctf_object_put_ref(integer_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_real_element(
-               struct bt_ctf_private_value *array_obj, double val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *real_obj = NULL;
-
-       real_obj = bt_ctf_private_value_real_create_init(val);
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) real_obj);
-       bt_ctf_object_put_ref(real_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_string_element(
-               struct bt_ctf_private_value *array_obj, const char *val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *string_obj = NULL;
-
-       string_obj = bt_ctf_private_value_string_create_init(val);
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) string_obj);
-       bt_ctf_object_put_ref(string_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_array_element(
-               struct bt_ctf_private_value *array_obj)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *empty_array_obj = NULL;
-
-       empty_array_obj = bt_ctf_private_value_array_create();
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) empty_array_obj);
-       bt_ctf_object_put_ref(empty_array_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_map_element(
-               struct bt_ctf_private_value *array_obj)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *map_obj = NULL;
-
-       map_obj = bt_ctf_private_value_map_create();
-       ret = bt_ctf_private_value_array_append_element(array_obj,
-               (void *) map_obj);
-       bt_ctf_object_put_ref(map_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_set_element_by_index(
-               struct bt_ctf_private_value *array_obj, uint64_t index,
-               struct bt_ctf_value *element_obj)
-{
-       struct bt_ctf_value_array *typed_array_obj =
-               BT_CTF_VALUE_TO_ARRAY(array_obj);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
-       BT_CTF_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
-       BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
-               typed_array_obj->garray->len);
-       bt_ctf_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index));
-       g_ptr_array_index(typed_array_obj->garray, index) = element_obj;
-       bt_ctf_object_get_ref(element_obj);
-       BT_LOGV("Set array value's element: array-value-addr=%p, "
-               "index=%" PRIu64 ", element-value-addr=%p",
-               array_obj, index, element_obj);
-       return BT_CTF_VALUE_STATUS_OK;
-}
-
-BT_HIDDEN
-uint64_t bt_ctf_value_map_get_size(const struct bt_ctf_value *map_obj)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       return (uint64_t) g_hash_table_size(BT_CTF_VALUE_TO_MAP(map_obj)->ght);
-}
-
-BT_HIDDEN
-struct bt_ctf_value *bt_ctf_value_map_borrow_entry_value(const struct bt_ctf_value *map_obj,
-               const char *key)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       return g_hash_table_lookup(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)));
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_map_borrow_entry_value(
-               const struct bt_ctf_private_value *map_obj, const char *key)
-{
-       return (void *) bt_ctf_value_map_borrow_entry_value((void *) map_obj, key);
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_value_map_has_entry(const struct bt_ctf_value *map_obj, const char *key)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       return bt_g_hash_table_contains(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)));
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_entry(
-               struct bt_ctf_private_value *map_obj,
-               const char *key, struct bt_ctf_value *element_obj)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Map value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       BT_CTF_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object");
-       g_hash_table_insert(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)), element_obj);
-       bt_ctf_object_get_ref(element_obj);
-       BT_LOGV("Inserted value into map value: map-value-addr=%p, "
-               "key=\"%s\", element-value-addr=%p",
-               map_obj, key, element_obj);
-       return BT_CTF_VALUE_STATUS_OK;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_bool_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, bt_bool val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *bool_obj = NULL;
-
-       bool_obj = bt_ctf_private_value_bool_create_init(val);
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) bool_obj);
-       bt_ctf_object_put_ref(bool_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_integer_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, int64_t val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *integer_obj = NULL;
-
-       integer_obj = bt_ctf_private_value_integer_create_init(val);
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) integer_obj);
-       bt_ctf_object_put_ref(integer_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_real_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, double val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *real_obj = NULL;
-
-       real_obj = bt_ctf_private_value_real_create_init(val);
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) real_obj);
-       bt_ctf_object_put_ref(real_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_string_entry(
-               struct bt_ctf_private_value *map_obj, const char *key,
-               const char *val)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *string_obj = NULL;
-
-       string_obj = bt_ctf_private_value_string_create_init(val);
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) string_obj);
-       bt_ctf_object_put_ref(string_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_array_entry(
-               struct bt_ctf_private_value *map_obj, const char *key)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *array_obj = NULL;
-
-       array_obj = bt_ctf_private_value_array_create();
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) array_obj);
-       bt_ctf_object_put_ref(array_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_map_entry(
-               struct bt_ctf_private_value *map_obj, const char *key)
-{
-       enum bt_ctf_value_status ret;
-       struct bt_ctf_private_value *empty_map_obj = NULL;
-
-       empty_map_obj = bt_ctf_private_value_map_create();
-       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
-               (void *) empty_map_obj);
-       bt_ctf_object_put_ref(empty_map_obj);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_map_foreach_entry(const struct bt_ctf_value *map_obj,
-               bt_ctf_value_map_foreach_entry_cb cb, void *data)
-{
-       enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK;
-       gpointer key, element_obj;
-       GHashTableIter iter;
-       struct bt_ctf_value_map *typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(cb, "Callback");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
-       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));
-
-               if (!cb(key_str, element_obj, data)) {
-                       BT_LOGV("User canceled the loop: key=\"%s\", "
-                               "value-addr=%p, data=%p",
-                               key_str, element_obj, data);
-                       ret = BT_CTF_VALUE_STATUS_CANCELED;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_foreach_entry(
-               const struct bt_ctf_private_value *map_obj,
-               bt_ctf_private_value_map_foreach_entry_cb cb, void *data)
-{
-       return bt_ctf_value_map_foreach_entry((void *) map_obj,
-               (bt_ctf_value_map_foreach_entry_cb) cb, data);
-}
-
-struct extend_map_element_data {
-       struct bt_ctf_private_value *extended_obj;
-       enum bt_ctf_value_status status;
-};
-
-static
-bt_bool extend_map_element(const char *key,
-               struct bt_ctf_value *extension_obj_elem, void *data)
-{
-       bt_bool ret = BT_TRUE;
-       struct extend_map_element_data *extend_data = data;
-       struct bt_ctf_private_value *extension_obj_elem_copy = NULL;
-
-       /* Copy object which is to replace the current one */
-       extend_data->status = bt_ctf_value_copy(&extension_obj_elem_copy,
-               extension_obj_elem);
-       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_ctf_private_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_CTF_VALUE_STATUS_OK);
-       ret = BT_FALSE;
-
-end:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy);
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_map_extend(
-               struct bt_ctf_private_value **extended_map_obj,
-               const struct bt_ctf_value *base_map_obj,
-               const struct bt_ctf_value *extension_obj)
-{
-       struct extend_map_element_data extend_data = {
-               .extended_obj = NULL,
-               .status = BT_CTF_VALUE_STATUS_OK,
-       };
-
-       BT_CTF_ASSERT_PRE_NON_NULL(base_map_obj, "Base value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(extension_obj, "Extension value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(extended_map_obj,
-               "Extended value object (output)");
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(base_map_obj, BT_CTF_VALUE_TYPE_MAP);
-       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(extension_obj, BT_CTF_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_ctf_value_copy(extended_map_obj, base_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_ctf_value_map_foreach_entry(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_CTF_OBJECT_PUT_REF_AND_RESET(*extended_map_obj);
-       *extended_map_obj = NULL;
-
-end:
-       return extend_data.status;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_copy(struct bt_ctf_private_value **copy_obj,
-               const struct bt_ctf_value *object)
-{
-       enum bt_ctf_value_status status = BT_CTF_VALUE_STATUS_OK;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(object, "Value object");
-       BT_CTF_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)");
-       BT_LOGD("Copying value object: addr=%p", object);
-       *copy_obj = copy_funcs[object->type](object);
-       if (*copy_obj) {
-               BT_LOGD("Copied value object: copy-value-addr=%p",
-                       copy_obj);
-       } else {
-               status = BT_CTF_VALUE_STATUS_NOMEM;
-               *copy_obj = NULL;
-               BT_LOGE_STR("Failed to copy value object.");
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-bt_bool bt_ctf_value_compare(const struct bt_ctf_value *object_a,
-       const struct bt_ctf_value *object_b)
-{
-       bt_bool ret = BT_FALSE;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(object_a, "Value object A");
-       BT_CTF_ASSERT_PRE_NON_NULL(object_b, "Value object B");
-
-       if (object_a->type != object_b->type) {
-               BT_LOGV("Values are different: type mismatch: "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-type=%d, value-b-type=%d",
-                       object_a, object_b, object_a->type, object_b->type);
-               goto end;
-       }
-
-       ret = compare_funcs[object_a->type](object_a, object_b);
-
-end:
-       return ret;
-}
diff --git a/ctf-writer/visitor.c b/ctf-writer/visitor.c
deleted file mode 100644 (file)
index 707cc7a..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * visitor.c
- *
- * Babeltrace CTF writer - Visitor
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/ctf-writer/visitor-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-
-BT_HIDDEN
-int bt_ctf_visitor_helper(struct bt_ctf_visitor_object *root,
-               bt_ctf_child_count_accessor child_counter,
-               bt_ctf_child_accessor child_accessor,
-               bt_ctf_child_visitor child_visitor,
-               bt_ctf_visitor visitor,
-               void *data)
-{
-       int ret, child_count, i;
-
-       ret = visitor(root, data);
-       if (ret) {
-               goto end;
-       }
-
-       child_count = child_counter(root->object);
-       if (child_count < 0) {
-               ret = child_count;
-               goto end;
-       }
-
-       for (i = 0; i < child_count; i++) {
-               void *child;
-
-               child = child_accessor(root->object, i);
-               if (!child) {
-                       ret = -1;
-                       goto end;
-               }
-               ret = child_visitor(child, visitor, data);
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(child);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       return ret;
-}
-
-enum bt_ctf_visitor_object_type bt_ctf_visitor_object_get_type(
-               struct bt_ctf_visitor_object *object)
-{
-       enum bt_ctf_visitor_object_type ret = BT_CTF_VISITOR_OBJECT_TYPE_UNKNOWN;
-
-       if (!object) {
-               goto end;
-       }
-
-       ret = object->type;
-end:
-       return ret;
-}
-
-void *bt_ctf_visitor_object_get_object(struct bt_ctf_visitor_object *object)
-{
-       void *ret = NULL;
-
-       if (!object) {
-               goto end;
-       }
-
-       ret = object->object;
-end:
-       return ret;
-}
diff --git a/ctf-writer/writer.c b/ctf-writer/writer.c
deleted file mode 100644 (file)
index 949bbea..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * writer.c
- *
- * Babeltrace CTF Writer
- *
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTF-WRITER"
-#include "logging.h"
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/functor-internal.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/ctf-writer/object.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-static
-void bt_ctf_writer_destroy(struct bt_ctf_object *obj);
-
-static
-int init_trace_packet_header(struct bt_ctf_trace *trace)
-{
-       int ret = 0;
-       struct bt_ctf_field_type *_uint32_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
-       struct bt_ctf_field_type *_uint8_t =
-               get_field_type(FIELD_TYPE_ALIAS_UINT8_T);
-       struct bt_ctf_field_type *trace_packet_header_type =
-               bt_ctf_field_type_structure_create();
-       struct bt_ctf_field_type *uuid_array_type =
-               bt_ctf_field_type_array_create(_uint8_t, 16);
-
-       if (!trace_packet_header_type || !uuid_array_type) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
-               _uint32_t, "magic");
-       if (ret) {
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
-               uuid_array_type, "uuid");
-       if (ret) {
-               goto end;
-       }
-
-       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
-               _uint32_t, "stream_id");
-       if (ret) {
-               goto end;
-       }
-
-       ret = bt_ctf_trace_set_packet_header_field_type(trace,
-               trace_packet_header_type);
-       if (ret) {
-               goto end;
-       }
-end:
-       bt_ctf_object_put_ref(uuid_array_type);
-       bt_ctf_object_put_ref(_uint32_t);
-       bt_ctf_object_put_ref(_uint8_t);
-       bt_ctf_object_put_ref(trace_packet_header_type);
-       return ret;
-}
-
-struct bt_ctf_writer *bt_ctf_writer_create(const char *path)
-{
-       int ret;
-       struct bt_ctf_writer *writer = NULL;
-       unsigned char uuid[16];
-       char *metadata_path = NULL;
-
-       if (!path) {
-               goto error;
-       }
-
-       writer = g_new0(struct bt_ctf_writer, 1);
-       if (!writer) {
-               goto error;
-       }
-
-       metadata_path = g_build_filename(path, "metadata", NULL);
-
-       bt_ctf_object_init_shared(&writer->base, bt_ctf_writer_destroy);
-       writer->path = g_string_new(path);
-       if (!writer->path) {
-               goto error_destroy;
-       }
-
-       writer->trace = bt_ctf_trace_create();
-       if (!writer->trace) {
-               goto error_destroy;
-       }
-
-       ret = init_trace_packet_header(writer->trace);
-       if (ret) {
-               goto error_destroy;
-       }
-
-       /* Generate a UUID for this writer's trace */
-       ret = bt_uuid_generate(uuid);
-       if (ret) {
-               BT_LOGE_STR("Cannot generate UUID for CTF writer's trace.");
-               goto error_destroy;
-       }
-
-       ret = bt_ctf_trace_set_uuid(writer->trace, uuid);
-       if (ret) {
-               goto error_destroy;
-       }
-
-       bt_ctf_object_set_parent(&writer->trace->common.base, &writer->base);
-       bt_ctf_object_put_ref(writer->trace);
-
-       /* Default to little-endian */
-       ret = bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE);
-       BT_ASSERT(ret == 0);
-
-       /* Create trace directory if necessary and open a metadata file */
-       if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) {
-               perror("g_mkdir_with_parents");
-               goto error_destroy;
-       }
-
-       writer->metadata_fd = open(metadata_path,
-               O_WRONLY | O_CREAT | O_TRUNC,
-               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
-       if (writer->metadata_fd < 0) {
-               perror("open");
-               goto error_destroy;
-       }
-
-       g_free(metadata_path);
-       return writer;
-
-error_destroy:
-       BT_CTF_OBJECT_PUT_REF_AND_RESET(writer);
-error:
-       g_free(metadata_path);
-       return writer;
-}
-
-void bt_ctf_writer_destroy(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_writer *writer;
-
-       writer = container_of(obj, struct bt_ctf_writer, base);
-       bt_ctf_writer_flush_metadata(writer);
-       if (writer->path) {
-               g_string_free(writer->path, TRUE);
-       }
-
-       if (writer->metadata_fd > 0) {
-               if (close(writer->metadata_fd)) {
-                       perror("close");
-               }
-       }
-
-       bt_ctf_object_try_spec_release(&writer->trace->common.base);
-       g_free(writer);
-}
-
-struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer)
-{
-       struct bt_ctf_trace *trace = NULL;
-
-       if (!writer) {
-               goto end;
-       }
-
-       trace = writer->trace;
-       bt_ctf_object_get_ref(trace);
-end:
-       return trace;
-}
-
-struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer,
-               struct bt_ctf_stream_class *stream_class)
-{
-       struct bt_ctf_stream *stream = NULL;
-       int stream_class_count;
-       bt_bool stream_class_found = BT_FALSE;
-       int i;
-
-       if (!writer || !stream_class) {
-               goto error;
-       }
-
-       /* Make sure the stream class is part of the writer's trace */
-       stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace);
-       if (stream_class_count < 0) {
-               goto error;
-       }
-
-       for (i = 0; i < stream_class_count; i++) {
-               struct bt_ctf_stream_class *existing_stream_class =
-                       bt_ctf_trace_get_stream_class_by_index(
-                               writer->trace, i);
-
-               if (existing_stream_class == stream_class) {
-                       stream_class_found = BT_TRUE;
-               }
-
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(existing_stream_class);
-
-               if (stream_class_found) {
-                       break;
-               }
-       }
-
-       if (!stream_class_found) {
-               int ret = bt_ctf_trace_add_stream_class(writer->trace,
-                       stream_class);
-
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       stream = bt_ctf_stream_create_with_id(stream_class, NULL, -1ULL);
-       if (!stream) {
-               goto error;
-       }
-
-       return stream;
-
-error:
-        BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
-       return stream;
-}
-
-int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer,
-               const char *name,
-               const char *value)
-{
-       int ret = -1;
-
-       if (!writer || !name || !value) {
-               goto end;
-       }
-
-       ret = bt_ctf_trace_set_environment_field_string(writer->trace,
-               name, value);
-end:
-       return ret;
-}
-
-int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer,
-               const char *name, int64_t value)
-{
-       int ret = -1;
-
-       if (!writer || !name) {
-               goto end;
-       }
-
-       ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name,
-               value);
-end:
-       return ret;
-}
-
-int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer,
-               struct bt_ctf_clock *clock)
-{
-       int ret = -1;
-
-       if (!writer || !clock) {
-               goto end;
-       }
-
-       ret = bt_ctf_trace_add_clock_class(writer->trace, clock->clock_class);
-end:
-       return ret;
-}
-
-char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer)
-{
-       char *metadata_string = NULL;
-
-       if (!writer) {
-               goto end;
-       }
-
-       metadata_string = bt_ctf_trace_get_metadata_string(
-               writer->trace);
-end:
-       return metadata_string;
-}
-
-void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer)
-{
-       int ret;
-       char *metadata_string = NULL;
-
-       if (!writer) {
-               goto end;
-       }
-
-       metadata_string = bt_ctf_trace_get_metadata_string(
-               writer->trace);
-       if (!metadata_string) {
-               goto end;
-       }
-
-       if (lseek(writer->metadata_fd, 0, SEEK_SET) == (off_t)-1) {
-               perror("lseek");
-               goto end;
-       }
-
-       if (ftruncate(writer->metadata_fd, 0)) {
-               perror("ftruncate");
-               goto end;
-       }
-
-       ret = write(writer->metadata_fd, metadata_string,
-               strlen(metadata_string));
-       if (ret < 0) {
-               perror("write");
-               goto end;
-       }
-end:
-       g_free(metadata_string);
-}
-
-int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer,
-               enum bt_ctf_byte_order byte_order)
-{
-       int ret = 0;
-
-       if (!writer || writer->frozen) {
-               ret = -1;
-               goto end;
-       }
-
-       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
-               if (BYTE_ORDER == LITTLE_ENDIAN) {
-                       byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
-               } else {
-                       byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
-               }
-       }
-
-       ret = bt_ctf_trace_set_native_byte_order(writer->trace,
-               byte_order);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_writer_freeze(struct bt_ctf_writer *writer)
-{
-       writer->frozen = 1;
-}
-
-static
-const unsigned int field_type_aliases_alignments[] = {
-       [FIELD_TYPE_ALIAS_UINT5_T] = 1,
-       [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
-       [FIELD_TYPE_ALIAS_UINT27_T] = 1,
-       [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
-};
-
-static
-const unsigned int field_type_aliases_sizes[] = {
-       [FIELD_TYPE_ALIAS_UINT5_T] = 5,
-       [FIELD_TYPE_ALIAS_UINT8_T] = 8,
-       [FIELD_TYPE_ALIAS_UINT16_T] = 16,
-       [FIELD_TYPE_ALIAS_UINT27_T] = 27,
-       [FIELD_TYPE_ALIAS_UINT32_T] = 32,
-       [FIELD_TYPE_ALIAS_UINT64_T] = 64,
-};
-
-BT_HIDDEN
-struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
-{
-       int ret;
-       unsigned int alignment, size;
-       struct bt_ctf_field_type *field_type = NULL;
-
-       if (alias >= NR_FIELD_TYPE_ALIAS) {
-               goto end;
-       }
-
-       alignment = field_type_aliases_alignments[alias];
-       size = field_type_aliases_sizes[alias];
-       field_type = bt_ctf_field_type_integer_create(size);
-       ret = bt_ctf_field_type_set_alignment(field_type, alignment);
-       if (ret) {
-               BT_CTF_OBJECT_PUT_REF_AND_RESET(field_type);
-       }
-end:
-       return field_type;
-}
-
-BT_HIDDEN
-const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order)
-{
-       const char *string;
-
-       switch (byte_order) {
-       case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
-               string = "le";
-               break;
-       case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
-               string = "be";
-               break;
-       case BT_CTF_BYTE_ORDER_NATIVE:
-               string = "native";
-               break;
-       default:
-               abort();
-       }
-
-       return string;
-}
diff --git a/ctfser/Makefile.am b/ctfser/Makefile.am
deleted file mode 100644 (file)
index 717621a..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-AM_CPPFLAGS += -DINSTALL_LIBDIR=\"$(libdir)\"
-
-noinst_LTLIBRARIES = libbabeltrace2-ctfser.la
-
-libbabeltrace2_ctfser_la_SOURCES = ctfser.c logging.c logging.h
diff --git a/ctfser/ctfser.c b/ctfser/ctfser.c
deleted file mode 100644 (file)
index 32cc9d0..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CTFSER"
-#include "logging.h"
-
-#include <unistd.h>
-#include <string.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <glib.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <wchar.h>
-#include <stdbool.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <babeltrace2/compat/unistd-internal.h>
-#include <babeltrace2/compat/fcntl-internal.h>
-
-static inline
-uint64_t get_packet_size_increment_bytes(void)
-{
-       return bt_common_get_page_size() * 8;
-}
-
-static inline
-void mmap_align_ctfser(struct bt_ctfser *ctfser)
-{
-       ctfser->base_mma = mmap_align(ctfser->cur_packet_size_bytes,
-               PROT_READ | PROT_WRITE,
-               MAP_SHARED, ctfser->fd, ctfser->mmap_offset);
-}
-
-BT_HIDDEN
-int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser)
-{
-       int ret;
-
-       BT_ASSERT(ctfser);
-       BT_LOGV("Increasing stream file's current packet size: "
-               "path=\"%s\", fd=%d, "
-               "offset-in-cur-packet-bits=%" PRIu64 ", "
-               "cur-packet-size-bytes=%" PRIu64,
-               ctfser->path->str, ctfser->fd,
-               ctfser->offset_in_cur_packet_bits,
-               ctfser->cur_packet_size_bytes);
-       ret = munmap_align(ctfser->base_mma);
-       if (ret) {
-               BT_LOGE_ERRNO("Failed to perform an aligned memory unmapping",
-                       ": ret=%d", ret);
-               goto end;
-       }
-
-       ctfser->cur_packet_size_bytes += get_packet_size_increment_bytes();
-
-       do {
-               ret = bt_posix_fallocate(ctfser->fd, ctfser->mmap_offset,
-                       ctfser->cur_packet_size_bytes);
-       } while (ret == EINTR);
-
-       if (ret) {
-               BT_LOGE("Failed to preallocate memory space: ret=%d", ret);
-               goto end;
-       }
-
-       mmap_align_ctfser(ctfser);
-       if (ctfser->base_mma == MAP_FAILED) {
-               BT_LOGE_ERRNO("Failed to perform an aligned memory mapping",
-                       ": ret=%d", ret);
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Increased packet size: "
-               "path=\"%s\", fd=%d, "
-               "offset-in-cur-packet-bits=%" PRIu64 ", "
-               "new-packet-size-bytes=%" PRIu64,
-               ctfser->path->str, ctfser->fd,
-               ctfser->offset_in_cur_packet_bits,
-               ctfser->cur_packet_size_bytes);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path)
-{
-       int ret = 0;
-
-       BT_ASSERT(ctfser);
-       memset(ctfser, 0, sizeof(*ctfser));
-       ctfser->fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
-               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
-       if (ctfser->fd < 0) {
-               BT_LOGW_ERRNO("Failed to open stream file for writing",
-                       ": path=\"%s\", ret=%d",
-                       path, ctfser->fd);
-               ret = -1;
-               goto end;
-       }
-
-       ctfser->path = g_string_new(path);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctfser_fini(struct bt_ctfser *ctfser)
-{
-       int ret = 0;
-
-       if (ctfser->fd == -1) {
-               goto free_path;
-       }
-
-       /*
-        * Truncate the stream file's size to the minimum required to
-        * fit the last packet as we might have grown it too much during
-        * the last memory map.
-        */
-       do {
-               ret = ftruncate(ctfser->fd, ctfser->stream_size_bytes);
-       } while (ret == -1 && errno == EINTR);
-
-       if (ret) {
-               BT_LOGE_ERRNO("Failed to truncate stream file",
-                       ": ret=%d, size-bytes=%" PRIu64,
-                       ret, ctfser->stream_size_bytes);
-               goto end;
-       }
-
-       if (ctfser->base_mma) {
-               /* Unmap old base */
-               ret = munmap_align(ctfser->base_mma);
-               if (ret) {
-                       BT_LOGE_ERRNO("Failed to unmap stream file",
-                               ": ret=%d, size-bytes=%" PRIu64,
-                               ret, ctfser->stream_size_bytes);
-                       goto end;
-               }
-
-               ctfser->base_mma = NULL;
-       }
-
-       ret = close(ctfser->fd);
-       if (ret) {
-               BT_LOGE_ERRNO("Failed to close stream file",
-                       ": ret=%d", ret);
-               goto end;
-       }
-
-       ctfser->fd = -1;
-
-free_path:
-       if (ctfser->path) {
-               g_string_free(ctfser->path, TRUE);
-               ctfser->path = NULL;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int bt_ctfser_open_packet(struct bt_ctfser *ctfser)
-{
-       int ret = 0;
-
-       BT_LOGV("Opening packet: path=\"%s\", fd=%d, "
-               "prev-packet-size-bytes=%" PRIu64,
-               ctfser->path->str, ctfser->fd,
-               ctfser->prev_packet_size_bytes);
-
-       if (ctfser->base_mma) {
-               /* Unmap old base (previous packet) */
-               ret = munmap_align(ctfser->base_mma);
-               if (ret) {
-                       BT_LOGE_ERRNO("Failed to unmap stream file",
-                               ": ret=%d, size-bytes=%" PRIu64,
-                               ret, ctfser->stream_size_bytes);
-                       goto end;
-               }
-
-               ctfser->base_mma = NULL;
-       }
-
-       /*
-        * Add the previous packet's size to the memory map address
-        * offset to start writing immediately after it.
-        */
-       ctfser->mmap_offset += ctfser->prev_packet_size_bytes;
-       ctfser->prev_packet_size_bytes = 0;
-
-       /* Make initial space for the current packet */
-       ctfser->cur_packet_size_bytes = get_packet_size_increment_bytes();
-
-       do {
-               ret = bt_posix_fallocate(ctfser->fd, ctfser->mmap_offset,
-                       ctfser->cur_packet_size_bytes);
-       } while (ret == EINTR);
-
-       if (ret) {
-               BT_LOGE("Failed to preallocate memory space: ret=%d", ret);
-               goto end;
-       }
-
-       /* Start writing at the beginning of the current packet */
-       ctfser->offset_in_cur_packet_bits = 0;
-
-       /* Get new base address */
-       mmap_align_ctfser(ctfser);
-       if (ctfser->base_mma == MAP_FAILED) {
-               BT_LOGE_ERRNO("Failed to perform an aligned memory mapping",
-                       ": ret=%d", ret);
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Opened packet: path=\"%s\", fd=%d, "
-               "cur-packet-size-bytes=%" PRIu64,
-               ctfser->path->str, ctfser->fd,
-               ctfser->cur_packet_size_bytes);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
-               uint64_t packet_size_bytes)
-{
-       BT_LOGV("Closing packet: path=\"%s\", fd=%d, "
-               "offset-in-cur-packet-bits=%" PRIu64
-               "cur-packet-size-bytes=%" PRIu64,
-               ctfser->path->str, ctfser->fd,
-               ctfser->offset_in_cur_packet_bits,
-               ctfser->cur_packet_size_bytes);
-
-       /*
-        * This will be used during the next call to
-        * bt_ctfser_open_packet(): we add
-        * `ctfser->prev_packet_size_bytes` to the current memory map
-        * address offset (first byte of _this_ packet), effectively
-        * making _this_ packet the required size.
-        */
-       ctfser->prev_packet_size_bytes = packet_size_bytes;
-       ctfser->stream_size_bytes += packet_size_bytes;
-       BT_LOGV("Closed packet: path=\"%s\", fd=%d, "
-               "stream-file-size-bytes=%" PRIu64,
-               ctfser->path->str, ctfser->fd,
-               ctfser->stream_size_bytes);
-}
diff --git a/ctfser/logging.c b/ctfser/logging.c
deleted file mode 100644 (file)
index 249c3ca..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_ctfser_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_ctfser_log_level, "BABELTRACE_CTFSER_LOG_LEVEL");
diff --git a/ctfser/logging.h b/ctfser/logging.h
deleted file mode 100644 (file)
index f18e726..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef COMMON_LOGGING_H
-#define COMMON_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_ctfser_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_ctfser_log_level);
-
-#endif /* COMMON_LOGGING_H */
index 9715ca6b335bb76d95b1b8cae4596c6e88304037..376888cebf0b9ef263648612cf5b18eaa7a8cc3a 100644 (file)
@@ -164,7 +164,7 @@ FILE_PATTERNS          = *.h \
 RECURSIVE              = NO
 EXCLUDE                =
 EXCLUDE_SYMLINKS       = NO
 RECURSIVE              = NO
 EXCLUDE                =
 EXCLUDE_SYMLINKS       = NO
-EXCLUDE_PATTERNS       = *-internal.h
+EXCLUDE_PATTERNS       =
 EXCLUDE_SYMBOLS        =
 EXAMPLE_PATH           =
 EXAMPLE_PATTERNS       = *
 EXCLUDE_SYMBOLS        =
 EXAMPLE_PATH           =
 EXAMPLE_PATTERNS       = *
index aa94c271112c4c118b186102dfaf77b70f098bd0..71252a0296634563d246772d8c8c2db387a61d11 100644 (file)
@@ -9,9 +9,9 @@ EXTRA_DIST = $(srcdir)/source
 
 all-local: $(SPHINX_HTML_TARGET) $(SPHINX_DIRHTML_TARGET)
 
 
 all-local: $(SPHINX_HTML_TARGET) $(SPHINX_DIRHTML_TARGET)
 
-PYTHON_BT2_BUILD_LIB_DIR = $(abs_top_builddir)/bindings/python/bt2/build/build_lib
+PYTHON_BT2_BUILD_LIB_DIR = $(abs_top_builddir)/src/bindings/python/bt2/build/build_lib
 PP = $(PYTHON_BT2_BUILD_LIB_DIR)
 PP = $(PYTHON_BT2_BUILD_LIB_DIR)
-LLP = $(abs_top_builddir)/lib/.libs
+LLP = $(abs_top_builddir)/src/lib/.libs
 SPHINXBUILD = PYTHONPATH="$(PP)" LD_LIBRARY_PATH="$(LLP)" $(PYTHON) -m sphinx
 SPHINX_SRC = $(wildcard $(SPHINX_SOURCE_DIR)/*.rst)
 
 SPHINXBUILD = PYTHONPATH="$(PP)" LD_LIBRARY_PATH="$(LLP)" $(PYTHON) -m sphinx
 SPHINX_SRC = $(wildcard $(SPHINX_SOURCE_DIR)/*.rst)
 
diff --git a/fd-cache/Makefile.am b/fd-cache/Makefile.am
deleted file mode 100644 (file)
index 9bc55df..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-AM_CPPFLAGS += -DINSTALL_LIBDIR=\"$(libdir)\"
-
-noinst_LTLIBRARIES = libbabeltrace2-fd-cache.la
-
-libbabeltrace2_fd_cache_la_SOURCES = \
-       fd-cache.c \
-       logging.c \
-       logging.h
diff --git a/fd-cache/fd-cache.c b/fd-cache/fd-cache.c
deleted file mode 100644 (file)
index fcd4f4c..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * fd-cache.c
- *
- * Babeltrace - File descriptor cache
- *
- * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Author: Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "FD-CACHE"
-#include "logging.h"
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <glib.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/fd-cache-internal.h>
-
-struct file_key {
-       uint64_t dev;
-       uint64_t ino;
-};
-
-struct fd_handle_internal {
-       struct bt_fd_cache_handle fd_handle;
-       uint64_t ref_count;
-       struct file_key *key;
-};
-
-static
-void fd_cache_handle_internal_destroy(
-               struct fd_handle_internal *internal_fd)
-{
-       if (!internal_fd) {
-               goto end;
-       }
-
-       if (internal_fd->fd_handle.fd >= 0) {
-               close(internal_fd->fd_handle.fd);
-               internal_fd->fd_handle.fd = -1;
-       }
-
-end:
-       g_free(internal_fd);
-}
-
-/*
- * Using simple hash algorithm found on stackoverflow:
- * https://stackoverflow.com/questions/664014/
- */
-static inline
-uint64_t hash_uint64_t(uint64_t x) {
-       x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
-       x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
-       x = x ^ (x >> 31);
-       return x;
-}
-
-static
-guint file_key_hash(gconstpointer v)
-{
-       const struct file_key *fk = v;
-       return hash_uint64_t(fk->dev) ^ hash_uint64_t(fk->ino);
-}
-
-static
-gboolean file_key_equal(gconstpointer v1, gconstpointer v2)
-{
-       const struct file_key *fk1 = v1;
-       const struct file_key *fk2 = v2;
-
-       return (fk1->dev == fk2->dev) && (fk1->ino == fk2->ino);
-}
-
-static
-void file_key_destroy(gpointer data)
-{
-       struct file_key *fk = data;
-       g_free(fk);
-}
-
-BT_HIDDEN
-int bt_fd_cache_init(struct bt_fd_cache *fdc)
-{
-       int ret = 0;
-
-       fdc->cache = g_hash_table_new_full(file_key_hash, file_key_equal,
-               file_key_destroy, (GDestroyNotify) fd_cache_handle_internal_destroy);
-       if (!fdc->cache) {
-               ret = -1;
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-void bt_fd_cache_fini(struct bt_fd_cache *fdc)
-{
-       BT_ASSERT(fdc->cache);
-       /*
-        * All handle should have been removed for the hashtable at this point.
-        */
-       BT_ASSERT(g_hash_table_size(fdc->cache) == 0);
-       g_hash_table_destroy(fdc->cache);
-
-       return;
-}
-
-BT_HIDDEN
-struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc,
-               const char *path)
-{
-       struct fd_handle_internal *fd_internal = NULL;
-       struct stat statbuf;
-       struct file_key fk;
-       int ret, fd = -1;
-
-       ret = stat(path, &statbuf);
-       if (ret < 0) {
-               /*
-                * This is not necessarily an error as we sometimes try to open
-                * files to see if they exist. Log the error as DEBUG severity
-                * level.
-                */
-               BT_LOGD_ERRNO("Failed to stat file", ": path=%s", path);
-               goto end;
-       }
-
-       /*
-        * Use the device number and inode number to uniquely identify a file.
-        * Even if the file has the same path, it may have been replaced so we
-        * must open a new FD for it. This replacement of file is more likely
-        * to happen with a lttng-live source component.
-        */
-       fk.dev = statbuf.st_dev;
-       fk.ino = statbuf.st_ino;
-
-       fd_internal = g_hash_table_lookup(fdc->cache, &fk);
-       if (!fd_internal) {
-               struct file_key *file_key;
-
-               fd = open(path, O_RDONLY);
-               if (fd < 0) {
-                       BT_LOGE_ERRNO("Failed to open file", "path=%s", path);
-                       goto error;
-               }
-
-               fd_internal = g_new0(struct fd_handle_internal, 1);
-               if (!fd_internal) {
-                       BT_LOGE("Failed to allocate fd internal handle");
-                       goto error;
-               }
-
-               file_key = g_new0(struct file_key, 1);
-               if (!fd_internal) {
-                       BT_LOGE("Failed to allocate file key");
-                       goto error;
-               }
-
-               *file_key = fk;
-
-               fd_internal->fd_handle.fd = fd;
-               fd_internal->ref_count = 0;
-               fd_internal->key = file_key;
-
-               /* Insert the newly created fd handle. */
-               g_hash_table_insert(fdc->cache, fd_internal->key, fd_internal);
-       }
-
-       fd_internal->ref_count++;
-       goto end;
-
-error:
-       /*
-        * Close file descriptor if it was open() and we are currently on error
-        * path.
-        */
-       if (fd != -1) {
-               ret = close(fd);
-               if (ret) {
-                       BT_LOGE_ERRNO("Failed to close file descriptor",
-                               ": fd=%i, path=%s", fd, path);
-               }
-       }
-
-       fd_cache_handle_internal_destroy(fd_internal);
-       fd_internal = NULL;
-end:
-       return (struct bt_fd_cache_handle *) fd_internal;
-}
-
-BT_HIDDEN
-void bt_fd_cache_put_handle(struct bt_fd_cache *fdc,
-               struct bt_fd_cache_handle *handle)
-{
-       struct fd_handle_internal *fd_internal;
-
-       if (!handle) {
-               goto end;
-       }
-
-       fd_internal = (struct fd_handle_internal *) handle;
-
-       BT_ASSERT(fd_internal->ref_count > 0);
-
-       if (fd_internal->ref_count > 1) {
-               fd_internal->ref_count--;
-       } else {
-               gboolean ret;
-               int close_ret;
-
-               close_ret = close(fd_internal->fd_handle.fd);
-               if (close_ret == -1) {
-                       BT_LOGW_ERRNO("Failed to close file descriptor",
-                               ": fd=%d", fd_internal->fd_handle.fd);
-               }
-               ret = g_hash_table_remove(fdc->cache, fd_internal->key);
-               BT_ASSERT(ret);
-       }
-
-end:
-       return;
-}
diff --git a/fd-cache/logging.c b/fd-cache/logging.c
deleted file mode 100644 (file)
index e203ee7..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_fd_cache_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_fd_cache_log_level, "BABELTRACE_FD_CACHE_LOG_LEVEL");
diff --git a/fd-cache/logging.h b/fd-cache/logging.h
deleted file mode 100644 (file)
index ae851e7..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef FD_CACHE_LOGGING_H
-#define FD_CACHE_LOGGING_H
-
-/*
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_fd_cache_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_fd_cache_log_level);
-
-#endif /* FD_CACHE_LOGGING_H */
index a340b8052d835123f915ae1157071e4759806b0c..9b4f0530d6c4a77f6850b6c1c623d99da331df54 100644 (file)
@@ -1,73 +1,3 @@
-##
-## This target generates an include file that contains the git version
-## string of the current branch, it must be continuously updated when
-## we build in the git repo and shipped in dist tarballs to reflect the
-## status of the tree when it was generated. If the tree is clean and
-## the current commit is tag a starting with "v", consider this a
-## release version and set an empty git version.
-##
-## Here is what the inline script does:
-##
-## First, delete any stale "version.i.tmp" file.
-##
-## If "bootstrap" and ".git" exists in the top source directory and the git
-## executable is available, get the current git version string in the form:
-##
-##  "latest_tag"(-"number_of_commits_on_top")(-g"latest_commit_hash")(-dirty)
-##
-## And store it in "version.i.tmp", if the current commit is tagged, the tag
-## starts with "v" and the tree is clean, consider this a release version and
-## overwrite the git version with an empty string in "version.i.tmp".
-##
-## If we don't have a "version.i.tmp" nor a "version.i", generate an empty
-## string as a failover.
-##
-## If we don't have a "version.i" or we have both files and they are different,
-## copy "version.i.tmp" over "version.i". This way the dependent targets are
-## only rebuilt when the version string changes.
-##
-
-version_verbose = $(version_verbose_@AM_V@)
-version_verbose_ = $(version_verbose_@AM_DEFAULT_V@)
-version_verbose_0 = @echo "  GEN       " $@;
-
-version.i:
-       $(version_verbose)rm -f version.i.tmp; \
-       if (test -r "$(top_srcdir)/bootstrap" && test -r "$(top_srcdir)/.git") && \
-                       test -x "`which git 2>&1;true`"; then \
-               GIT_VERSION_STR="`cd "$(top_srcdir)" && git describe --tags --dirty`"; \
-               GIT_CURRENT_TAG="`cd "$(top_srcdir)" && git describe --tags --exact-match --match="v[0-9]*" HEAD 2> /dev/null`"; \
-               echo "#define GIT_VERSION \"$$GIT_VERSION_STR\"" > version.i.tmp; \
-               if ! $(GREP) -- "-dirty" version.i.tmp > /dev/null && \
-                               test "x$$GIT_CURRENT_TAG" != "x"; then \
-                       echo "#define GIT_VERSION \"\"" > version.i.tmp; \
-               fi; \
-       fi; \
-       if test ! -f version.i.tmp; then \
-               if test ! -f version.i; then \
-                       echo '#define GIT_VERSION ""' > version.i; \
-               fi; \
-       elif test ! -f version.i || \
-                       test x"`cat version.i.tmp`" != x"`cat version.i`"; then \
-               mv version.i.tmp version.i; \
-       fi; \
-       rm -f version.i.tmp; \
-       true
-
-##
-## version.i is defined as a .PHONY target even if it's a real file,
-## we want the target to be re-run on every make.
-##
-.PHONY: version.i
-
-CLEANFILES = version.i.tmp
-
-##
-## Only clean "version.i" on dist-clean, we need to keep it on regular
-## clean when it's part of a dist tarball.
-##
-DISTCLEANFILES = version.i
-
 # Core API
 babeltrace2includedir = "$(includedir)/babeltrace2"
 babeltrace2include_HEADERS = \
 # Core API
 babeltrace2includedir = "$(includedir)/babeltrace2"
 babeltrace2include_HEADERS = \
@@ -210,99 +140,3 @@ babeltrace2graphinclude_HEADERS = \
        babeltrace2/graph/self-component-source.h \
        babeltrace2/graph/self-component.h \
        babeltrace2/graph/self-message-iterator.h
        babeltrace2/graph/self-component-source.h \
        babeltrace2/graph/self-component.h \
        babeltrace2/graph/self-message-iterator.h
-
-noinst_HEADERS = \
-       babeltrace2/compat/stdlib-internal.h \
-       babeltrace2/compat/fcntl-internal.h \
-       babeltrace2/compat/glib-internal.h \
-       babeltrace2/compat/uuid-internal.h \
-       babeltrace2/compat/unistd-internal.h \
-       babeltrace2/compat/stdio-internal.h \
-       babeltrace2/compat/time-internal.h \
-       babeltrace2/compat/utc-internal.h \
-       babeltrace2/compat/memstream-internal.h \
-       babeltrace2/compat/string-internal.h \
-       babeltrace2/compat/limits-internal.h \
-       babeltrace2/compat/mman-internal.h \
-       babeltrace2/compat/socket-internal.h \
-       babeltrace2/common-internal.h \
-       babeltrace2/ctfser-internal.h \
-       babeltrace2/bitfield-internal.h \
-       babeltrace2/object-internal.h \
-       babeltrace2/object-pool-internal.h \
-       babeltrace2/plugin/plugin-internal.h \
-       babeltrace2/plugin/plugin-so-internal.h \
-       babeltrace2/plugin/python-plugin-provider-internal.h \
-       babeltrace2/assert-internal.h \
-       babeltrace2/value-internal.h \
-       babeltrace2/ctf-writer/assert-pre-internal.h \
-       babeltrace2/ctf-writer/attributes-internal.h \
-       babeltrace2/ctf-writer/clock-class-internal.h \
-       babeltrace2/ctf-writer/clock-internal.h \
-       babeltrace2/ctf-writer/event-class-internal.h \
-       babeltrace2/ctf-writer/event-internal.h \
-       babeltrace2/ctf-writer/field-path-internal.h \
-       babeltrace2/ctf-writer/fields-internal.h \
-       babeltrace2/ctf-writer/field-types-internal.h \
-       babeltrace2/ctf-writer/field-wrapper-internal.h \
-       babeltrace2/ctf-writer/functor-internal.h \
-       babeltrace2/ctf-writer/object-internal.h \
-       babeltrace2/ctf-writer/object-pool-internal.h \
-       babeltrace2/ctf-writer/resolve-internal.h \
-       babeltrace2/ctf-writer/stream-class-internal.h \
-       babeltrace2/ctf-writer/stream-internal.h \
-       babeltrace2/ctf-writer/trace-internal.h \
-       babeltrace2/ctf-writer/utils-internal.h \
-       babeltrace2/ctf-writer/validation-internal.h \
-       babeltrace2/ctf-writer/values-internal.h \
-       babeltrace2/ctf-writer/visitor-internal.h \
-       babeltrace2/ctf-writer/writer-internal.h \
-       babeltrace2/mmap-align-internal.h \
-       babeltrace2/align-internal.h \
-       babeltrace2/logging-internal.h \
-       babeltrace2/endian-internal.h \
-       babeltrace2/trace-ir/attributes-internal.h \
-       babeltrace2/trace-ir/clock-class-internal.h \
-       babeltrace2/trace-ir/clock-snapshot-internal.h \
-       babeltrace2/trace-ir/clock-snapshot-set-internal.h \
-       babeltrace2/trace-ir/event-class-internal.h \
-       babeltrace2/trace-ir/event-internal.h \
-       babeltrace2/trace-ir/field-class-internal.h \
-       babeltrace2/trace-ir/field-path-internal.h \
-       babeltrace2/trace-ir/field-internal.h \
-       babeltrace2/trace-ir/field-wrapper-internal.h \
-       babeltrace2/trace-ir/packet-internal.h \
-       babeltrace2/trace-ir/resolve-field-path-internal.h \
-       babeltrace2/trace-ir/stream-class-internal.h \
-       babeltrace2/trace-ir/stream-internal.h \
-       babeltrace2/trace-ir/trace-class-internal.h \
-       babeltrace2/trace-ir/trace-internal.h \
-       babeltrace2/trace-ir/utils-internal.h \
-       babeltrace2/prio-heap-internal.h \
-       babeltrace2/lib-logging-internal.h \
-       babeltrace2/compiler-internal.h \
-       babeltrace2/babeltrace-internal.h \
-       babeltrace2/assert-pre-internal.h \
-       babeltrace2/graph/component-class-internal.h \
-       babeltrace2/graph/component-class-sink-colander-internal.h \
-       babeltrace2/graph/component-filter-internal.h \
-       babeltrace2/graph/component-internal.h \
-       babeltrace2/graph/component-sink-internal.h \
-       babeltrace2/graph/component-source-internal.h \
-       babeltrace2/graph/connection-internal.h \
-       babeltrace2/graph/graph-internal.h \
-       babeltrace2/graph/message-discarded-items-internal.h \
-       babeltrace2/graph/message-event-internal.h \
-       babeltrace2/graph/message-message-iterator-inactivity-internal.h \
-       babeltrace2/graph/message-internal.h \
-       babeltrace2/graph/message-iterator-internal.h \
-       babeltrace2/graph/message-packet-internal.h \
-       babeltrace2/graph/message-stream-activity-internal.h \
-       babeltrace2/graph/message-stream-internal.h \
-       babeltrace2/graph/port-internal.h \
-       babeltrace2/graph/query-executor-internal.h \
-       babeltrace2/list-internal.h \
-       babeltrace2/fd-cache-internal.h \
-       babeltrace2/property-internal.h \
-       version.h \
-       version.i
diff --git a/include/babeltrace2/align-internal.h b/include/babeltrace2/align-internal.h
deleted file mode 100644 (file)
index 4e76cd0..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef _BABELTRACE_ALIGN_H
-#define _BABELTRACE_ALIGN_H
-
-/*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/compat/limits-internal.h>
-
-#define ALIGN(x, a)            __ALIGN_MASK(x, (typeof(x))(a) - 1)
-#define __ALIGN_MASK(x, mask)  (((x) + (mask)) & ~(mask))
-#define PTR_ALIGN(p, a)                ((typeof(p)) ALIGN((unsigned long) (p), a))
-#define ALIGN_FLOOR(x, a)      __ALIGN_FLOOR_MASK(x, (typeof(x)) (a) - 1)
-#define __ALIGN_FLOOR_MASK(x, mask)    ((x) & ~(mask))
-#define PTR_ALIGN_FLOOR(p, a) \
-                       ((typeof(p)) ALIGN_FLOOR((unsigned long) (p), a))
-#define IS_ALIGNED(x, a)       (((x) & ((typeof(x)) (a) - 1)) == 0)
-
-/*
- * Align pointer on natural object alignment.
- */
-#define object_align(obj)      PTR_ALIGN(obj, __alignof__(*(obj)))
-#define object_align_floor(obj)        PTR_ALIGN_FLOOR(obj, __alignof__(*(obj)))
-
-/**
- * offset_align - Calculate the offset needed to align an object on its natural
- *                alignment towards higher addresses.
- * @align_drift:  object offset from an "alignment"-aligned address.
- * @alignment:    natural object alignment. Must be non-zero, power of 2.
- *
- * Returns the offset that must be added to align towards higher
- * addresses.
- */
-#define offset_align(align_drift, alignment)                                  \
-       ({                                                                     \
-               MAYBE_BUILD_BUG_ON((alignment) == 0                            \
-                                  || ((alignment) & ((alignment) - 1)));      \
-               (((alignment) - (align_drift)) & ((alignment) - 1));           \
-       })
-
-/**
- * offset_align_floor - Calculate the offset needed to align an object
- *                      on its natural alignment towards lower addresses.
- * @align_drift:  object offset from an "alignment"-aligned address.
- * @alignment:    natural object alignment. Must be non-zero, power of 2.
- *
- * Returns the offset that must be substracted to align towards lower addresses.
- */
-#define offset_align_floor(align_drift, alignment)                            \
-       ({                                                                     \
-               MAYBE_BUILD_BUG_ON((alignment) == 0                            \
-                                  || ((alignment) & ((alignment) - 1)));      \
-               (((align_drift) - (alignment)) & ((alignment) - 1));           \
-       })
-
-#endif /* _BABELTRACE_ALIGN_H */
diff --git a/include/babeltrace2/assert-internal.h b/include/babeltrace2/assert-internal.h
deleted file mode 100644 (file)
index 2df876d..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef BABELTRACE_ASSERT_INTERNAL_H
-#define BABELTRACE_ASSERT_INTERNAL_H
-
-/*
- * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <assert.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#ifdef BT_DEBUG_MODE
-
-extern void bt_common_assert_failed(const char *file, int line,
-       const char *func, const char *assertion) __attribute__((noreturn));
-
-/*
- * Internal assertion (to detect logic errors on which the library user
- * has no influence). Use BT_ASSERT_PRE() to check a precondition which
- * must be directly or indirectly satisfied by the library user.
- */
-#define BT_ASSERT(_cond)                                                       \
-       do {                                                                   \
-               if (!(_cond)) {                                                \
-                       bt_common_assert_failed(__FILE__, __LINE__, __func__,  \
-                               TOSTRING(_cond));                              \
-               }                                                              \
-       } while (0)
-
-/*
- * Marks a function as being only used within a BT_ASSERT() context.
- */
-# define BT_ASSERT_FUNC
-#else
-/*
- * When BT_DEBUG_MODE is not defined, define BT_ASSERT() macro to the following
- * to trick the compiler into thinking that the variable passed as condition to
- * the assertion is used. This is to prevent set-but-not-used warnings from the
- * compiler when assertions are disabled. The `sizeof` operator also makes sure
- * that the `_cond` expression is not evaluated, thus preventing unwanted side
- * effects.
- *
- * In-depth explanation: https://stackoverflow.com/questions/37411809/how-to-elegantly-fix-this-unused-variable-warning/37412551#37412551
- */
-# define BT_ASSERT(_cond)      ((void) sizeof((void) (_cond), 0))
-# define BT_ASSERT_FUNC                BT_UNUSED
-#endif /* BT_DEBUG_MODE */
-
-#endif /* BABELTRACE_ASSERT_INTERNAL_H */
diff --git a/include/babeltrace2/assert-pre-internal.h b/include/babeltrace2/assert-pre-internal.h
deleted file mode 100644 (file)
index cb50366..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef BABELTRACE_ASSERT_PRE_INTERNAL_H
-#define BABELTRACE_ASSERT_PRE_INTERNAL_H
-
-/*
- * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * The macros in this header use macros defined in
- * <babeltrace2/lib-logging-internal.h>. We don't want this header to
- * automatically include <babeltrace2/lib-logging-internal.h> because you
- * need to manually define BT_LOG_TAG before including
- * <babeltrace2/lib-logging-internal.h> and it is unexpected that you
- * also need to define it before including this header.
- *
- * This is a reminder that in order to use
- * <babeltrace2/assert-pre-internal.h>, you also need to use logging
- * explicitly.
- */
-
-#ifndef BABELTRACE_LIB_LOGGING_INTERNAL_H
-# error Include <babeltrace2/lib-logging-internal.h> before this header.
-#endif
-
-#include <stdlib.h>
-#include <inttypes.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#ifdef BT_DEV_MODE
-/*
- * Asserts that the library precondition _cond is satisfied.
- *
- * If _cond is false, log a fatal statement using _fmt and the optional
- * arguments using BT_LIB_LOGF(), and abort.
- *
- * To assert that a postcondition is satisfied or that some internal
- * object/context/value is in the expected state, use BT_ASSERT().
- */
-# define BT_ASSERT_PRE(_cond, _fmt, ...)                               \
-       do {                                                            \
-               if (!(_cond)) {                                         \
-                       BT_LOGF_STR("Library precondition not satisfied; error is:"); \
-                       BT_LIB_LOGF((_fmt), ##__VA_ARGS__);             \
-                       BT_LOGF_STR("Aborting...");                     \
-                       abort();                                        \
-               }                                                       \
-       } while (0)
-
-/*
- * Marks a function as being only used within a BT_ASSERT_PRE() context.
- */
-# define BT_ASSERT_PRE_FUNC
-
-/*
- * Prints the details of an unsatisfied precondition without immediately
- * aborting. You should use this within a function which checks
- * preconditions, but which is called from a BT_ASSERT_PRE() context, so
- * that the function can still return its result for BT_ASSERT_PRE() to
- * evaluate it.
- *
- * Example:
- *
- *     BT_ASSERT_PRE_FUNC
- *     static inline bool check_complex_precond(...)
- *     {
- *         ...
- *
- *         if (...) {
- *             BT_ASSERT_PRE_MSG("Invalid object: ...", ...);
- *             return false;
- *         }
- *
- *         ...
- *     }
- *
- *     ...
- *
- *     BT_ASSERT_PRE(check_complex_precond(...),
- *                   "Precondition is not satisfied: ...", ...);
- */
-# define BT_ASSERT_PRE_MSG     BT_LIB_LOGF
-#else
-# define BT_ASSERT_PRE(_cond, _fmt, ...)       ((void) sizeof((void) (_cond), 0))
-# define BT_ASSERT_PRE_FUNC    BT_UNUSED
-# define BT_ASSERT_PRE_MSG(_fmt, ...)
-#endif /* BT_DEV_MODE */
-
-/*
- * Developer mode: asserts that a given variable is not NULL.
- */
-#define BT_ASSERT_PRE_NON_NULL(_obj, _obj_name)                                \
-       BT_ASSERT_PRE((_obj) != NULL, "%s is NULL: ", _obj_name)
-
-/*
- * Developer mode: asserts that a given object is NOT frozen. This macro
- * checks the `frozen` field of _obj.
- */
-#define BT_ASSERT_PRE_HOT(_obj, _obj_name, _fmt, ...)                  \
-       BT_ASSERT_PRE(!(_obj)->frozen, "%s is frozen" _fmt, _obj_name,  \
-               ##__VA_ARGS__)
-
-/*
- * Developer mode: asserts that a given index is less than a given size.
- */
-#define BT_ASSERT_PRE_VALID_INDEX(_index, _length)                     \
-       BT_ASSERT_PRE((_index) < (_length),                             \
-               "Index is out of bounds: index=%" PRIu64 ", "           \
-               "count=%" PRIu64, (uint64_t) (_index), (uint64_t) (_length))
-
-#endif /* BABELTRACE_ASSERT_PRE_INTERNAL_H */
diff --git a/include/babeltrace2/babeltrace-internal.h b/include/babeltrace2/babeltrace-internal.h
deleted file mode 100644 (file)
index c30725d..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-#ifndef _BABELTRACE_INTERNAL_H
-#define _BABELTRACE_INTERNAL_H
-
-/*
- * Copyright 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <stdio.h>
-#include <glib.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <babeltrace2/compat/string-internal.h>
-#include <babeltrace2/types.h>
-
-#define PERROR_BUFLEN  200
-
-#ifndef likely
-# ifdef __GNUC__
-#  define likely(x)      __builtin_expect(!!(x), 1)
-# else
-#  define likely(x)      (!!(x))
-# endif
-#endif
-
-#ifndef unlikely
-# ifdef __GNUC__
-#  define unlikely(x)    __builtin_expect(!!(x), 0)
-# else
-#  define unlikely(x)    (!!(x))
-# endif
-#endif
-
-#ifndef min
-#define min(a, b)      (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef max
-#define max(a, b)      (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifndef max_t
-#define max_t(type, a, b)      \
-       ((type) (a) > (type) (b) ? (type) (a) : (type) (b))
-#endif
-
-static inline
-bool bt_safe_to_mul_int64(int64_t a, int64_t b)
-{
-       if (a == 0 || b == 0) {
-               return true;
-       }
-
-       return a < INT64_MAX / b;
-}
-
-static inline
-bool bt_safe_to_mul_uint64(uint64_t a, uint64_t b)
-{
-       if (a == 0 || b == 0) {
-               return true;
-       }
-
-       return a < UINT64_MAX / b;
-}
-
-static inline
-bool bt_safe_to_add_int64(int64_t a, int64_t b)
-{
-       return a <= INT64_MAX - b;
-}
-
-static inline
-bool bt_safe_to_add_uint64(uint64_t a, uint64_t b)
-{
-       return a <= UINT64_MAX - b;
-}
-
-/*
- * Memory allocation zeroed
- */
-#define zmalloc(x) calloc(1, x)
-
-/*
- * BT_HIDDEN: set the hidden attribute for internal functions
- * On Windows, symbols are local unless explicitly exported,
- * see https://gcc.gnu.org/wiki/Visibility
- */
-#if defined(_WIN32) || defined(__CYGWIN__)
-#define BT_HIDDEN
-#else
-#define BT_HIDDEN __attribute__((visibility("hidden")))
-#endif
-
-#ifndef __STRINGIFY
-#define __STRINGIFY(x) #x
-#endif
-
-#define TOSTRING(x)    __STRINGIFY(x)
-
-#define BT_UNUSED      __attribute__((unused))
-
-#endif
diff --git a/include/babeltrace2/bitfield-internal.h b/include/babeltrace2/bitfield-internal.h
deleted file mode 100644 (file)
index 1835b9d..0000000
+++ /dev/null
@@ -1,551 +0,0 @@
-#ifndef _BABELTRACE_BITFIELD_H
-#define _BABELTRACE_BITFIELD_H
-
-/*
- * Copyright 2010-2019 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>    /* C99 5.2.4.2 Numerical limits */
-#include <stdbool.h>   /* C99 7.16 bool type */
-#include <babeltrace2/compat/limits-internal.h>        /* C99 5.2.4.2 Numerical limits */
-#include <babeltrace2/endian-internal.h>       /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */
-
-/*
- * This header strictly follows the C99 standard, except for use of the
- * compiler-specific __typeof__.
- */
-
-/*
- * This bitfield header requires the compiler representation of signed
- * integers to be two's complement.
- */
-#if (-1 != ~0)
-#error "bitfield.h requires the compiler representation of signed integers to be two's complement."
-#endif
-
-/*
- * _bt_is_signed_type() willingly generates comparison of unsigned
- * expression < 0, which is always false. Silence compiler warnings.
- */
-#ifdef __GNUC__
-# define _BT_DIAG_PUSH                 _Pragma("GCC diagnostic push")
-# define _BT_DIAG_POP                  _Pragma("GCC diagnostic pop")
-
-# define _BT_DIAG_STRINGIFY_1(x)       #x
-# define _BT_DIAG_STRINGIFY(x)         _BT_DIAG_STRINGIFY_1(x)
-
-# define _BT_DIAG_IGNORE(option)       \
-       _Pragma(_BT_DIAG_STRINGIFY(GCC diagnostic ignored option))
-# define _BT_DIAG_IGNORE_TYPE_LIMITS   _BT_DIAG_IGNORE("-Wtype-limits")
-#else
-# define _BT_DIAG_PUSH
-# define _BT_DIAG_POP
-# define _BT_DIAG_IGNORE
-#endif
-
-#define _bt_is_signed_type(type)       ((type) -1 < (type) 0)
-
-/*
- * Produce a build-time error if the condition `cond` is non-zero.
- * Evaluates as a size_t expression.
- */
-#define _BT_BUILD_ASSERT(cond)                                 \
-       sizeof(struct { int f:(2 * !!(cond) - 1); })
-
-/*
- * Cast value `v` to an unsigned integer of the same size as `v`.
- */
-#define _bt_cast_value_to_unsigned(v)                                  \
-       (sizeof(v) == sizeof(uint8_t) ? (uint8_t) (v) :                 \
-       sizeof(v) == sizeof(uint16_t) ? (uint16_t) (v) :                \
-       sizeof(v) == sizeof(uint32_t) ? (uint32_t) (v) :                \
-       sizeof(v) == sizeof(uint64_t) ? (uint64_t) (v) :                \
-       _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t)))
-
-/*
- * Cast value `v` to an unsigned integer type of the size of type `type`
- * *without* sign-extension.
- *
- * The unsigned cast ensures that we're not shifting a negative value,
- * which is undefined in C. However, this limits the maximum type size
- * of `type` to 64-bit. Generate a compile-time error if the size of
- * `type` is larger than 64-bit.
- */
-#define _bt_cast_value_to_unsigned_type(type, v)                       \
-       (sizeof(type) == sizeof(uint8_t) ?                              \
-               (uint8_t) _bt_cast_value_to_unsigned(v) :               \
-       sizeof(type) == sizeof(uint16_t) ?                              \
-               (uint16_t) _bt_cast_value_to_unsigned(v) :              \
-       sizeof(type) == sizeof(uint32_t) ?                              \
-               (uint32_t) _bt_cast_value_to_unsigned(v) :              \
-       sizeof(type) == sizeof(uint64_t) ?                              \
-               (uint64_t) _bt_cast_value_to_unsigned(v) :              \
-       _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t)))
-
-/*
- * _bt_fill_mask evaluates to a "type" integer with all bits set.
- */
-#define _bt_fill_mask(type)    ((type) ~(type) 0)
-
-/*
- * Left shift a value `v` of `shift` bits.
- *
- * The type of `v` can be signed or unsigned integer.
- * The value of `shift` must be less than the size of `v` (in bits),
- * otherwise the behavior is undefined.
- * Evaluates to the result of the shift operation.
- *
- * According to the C99 standard, left shift of a left hand-side signed
- * type is undefined if it has a negative value or if the result cannot
- * be represented in the result type. This bitfield header discards the
- * bits that are left-shifted beyond the result type representation,
- * which is the behavior of an unsigned type left shift operation.
- * Therefore, always perform left shift on an unsigned type.
- *
- * This macro should not be used if `shift` can be greater or equal than
- * the bitwidth of `v`. See `_bt_safe_lshift`.
- */
-#define _bt_lshift(v, shift)                                           \
-       ((__typeof__(v)) (_bt_cast_value_to_unsigned(v) << (shift)))
-
-/*
- * Generate a mask of type `type` with the `length` least significant bits
- * cleared, and the most significant bits set.
- */
-#define _bt_make_mask_complement(type, length)                         \
-       _bt_lshift(_bt_fill_mask(type), length)
-
-/*
- * Generate a mask of type `type` with the `length` least significant bits
- * set, and the most significant bits cleared.
- */
-#define _bt_make_mask(type, length)                                    \
-       ((type) ~_bt_make_mask_complement(type, length))
-
-/*
- * Right shift a value `v` of `shift` bits.
- *
- * The type of `v` can be signed or unsigned integer.
- * The value of `shift` must be less than the size of `v` (in bits),
- * otherwise the behavior is undefined.
- * Evaluates to the result of the shift operation.
- *
- * According to the C99 standard, right shift of a left hand-side signed
- * type which has a negative value is implementation defined. This
- * bitfield header relies on the right shift implementation carrying the
- * sign bit. If the compiler implementation has a different behavior,
- * emulate carrying the sign bit.
- *
- * This macro should not be used if `shift` can be greater or equal than
- * the bitwidth of `v`. See `_bt_safe_rshift`.
- */
-#if ((-1 >> 1) == -1)
-#define _bt_rshift(v, shift)   ((v) >> (shift))
-#else
-#define _bt_rshift(v, shift)                                           \
-       ((__typeof__(v)) ((_bt_cast_value_to_unsigned(v) >> (shift)) |  \
-               ((v) < 0 ? _bt_make_mask_complement(__typeof__(v),      \
-                       sizeof(v) * CHAR_BIT - (shift)) : 0)))
-#endif
-
-/*
- * Right shift a signed or unsigned integer with `shift` value being an
- * arbitrary number of bits. `v` is modified by this macro. The shift
- * is transformed into a sequence of `_nr_partial_shifts` consecutive
- * shift operations, each of a number of bits smaller than the bitwidth
- * of `v`, ending with a shift of the number of left over bits.
- */
-#define _bt_safe_rshift(v, shift)                                      \
-do {                                                                   \
-       unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \
-       unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \
-                                                                       \
-       for (; _nr_partial_shifts; _nr_partial_shifts--)                \
-               (v) = _bt_rshift(v, sizeof(v) * CHAR_BIT - 1);          \
-       (v) = _bt_rshift(v, _leftover_bits);                            \
-} while (0)
-
-/*
- * Left shift a signed or unsigned integer with `shift` value being an
- * arbitrary number of bits. `v` is modified by this macro. The shift
- * is transformed into a sequence of `_nr_partial_shifts` consecutive
- * shift operations, each of a number of bits smaller than the bitwidth
- * of `v`, ending with a shift of the number of left over bits.
- */
-#define _bt_safe_lshift(v, shift)                                      \
-do {                                                                   \
-       unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \
-       unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \
-                                                                       \
-       for (; _nr_partial_shifts; _nr_partial_shifts--)                \
-               (v) = _bt_lshift(v, sizeof(v) * CHAR_BIT - 1);          \
-       (v) = _bt_lshift(v, _leftover_bits);                            \
-} while (0)
-
-/*
- * bt_bitfield_write - write integer to a bitfield in native endianness
- *
- * Save integer to the bitfield, which starts at the "start" bit, has "len"
- * bits.
- * The inside of a bitfield is from high bits to low bits.
- * Uses native endianness.
- * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
- * For signed "v", sign-extend v if bitfield is larger than v.
- *
- * On little endian, bytes are placed from the less significant to the most
- * significant. Also, consecutive bitfields are placed from lower bits to higher
- * bits.
- *
- * On big endian, bytes are places from most significant to less significant.
- * Also, consecutive bitfields are placed from higher to lower bits.
- */
-
-#define _bt_bitfield_write_le(ptr, type, start, length, v)             \
-do {                                                                   \
-       __typeof__(v) _v = (v);                                 \
-       type *_ptr = (void *) (ptr);                                    \
-       unsigned long _start = (start), _length = (length);             \
-       type _mask, _cmask;                                             \
-       unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */    \
-       unsigned long _start_unit, _end_unit, _this_unit;               \
-       unsigned long _end, _cshift; /* _cshift is "complement shift" */ \
-                                                                       \
-       if (!_length)                                                   \
-               break;                                                  \
-                                                                       \
-       _end = _start + _length;                                        \
-       _start_unit = _start / _ts;                                     \
-       _end_unit = (_end + (_ts - 1)) / _ts;                           \
-                                                                       \
-       /* Trim v high bits */                                          \
-       if (_length < sizeof(_v) * CHAR_BIT)                            \
-               _v &= _bt_make_mask(__typeof__(_v), _length);           \
-                                                                       \
-       /* We can now append v with a simple "or", shift it piece-wise */ \
-       _this_unit = _start_unit;                                       \
-       if (_start_unit == _end_unit - 1) {                             \
-               _mask = _bt_make_mask(type, _start % _ts);              \
-               if (_end % _ts)                                         \
-                       _mask |= _bt_make_mask_complement(type, _end % _ts); \
-               _cmask = _bt_lshift((type) (_v), _start % _ts);         \
-               _cmask &= ~_mask;                                       \
-               _ptr[_this_unit] &= _mask;                              \
-               _ptr[_this_unit] |= _cmask;                             \
-               break;                                                  \
-       }                                                               \
-       if (_start % _ts) {                                             \
-               _cshift = _start % _ts;                                 \
-               _mask = _bt_make_mask(type, _cshift);                   \
-               _cmask = _bt_lshift((type) (_v), _cshift);              \
-               _cmask &= ~_mask;                                       \
-               _ptr[_this_unit] &= _mask;                              \
-               _ptr[_this_unit] |= _cmask;                             \
-               _bt_safe_rshift(_v, _ts - _cshift);                     \
-               _start += _ts - _cshift;                                \
-               _this_unit++;                                           \
-       }                                                               \
-       for (; _this_unit < _end_unit - 1; _this_unit++) {              \
-               _ptr[_this_unit] = (type) _v;                           \
-               _bt_safe_rshift(_v, _ts);                               \
-               _start += _ts;                                          \
-       }                                                               \
-       if (_end % _ts) {                                               \
-               _mask = _bt_make_mask_complement(type, _end % _ts);     \
-               _cmask = (type) _v;                                     \
-               _cmask &= ~_mask;                                       \
-               _ptr[_this_unit] &= _mask;                              \
-               _ptr[_this_unit] |= _cmask;                             \
-       } else                                                          \
-               _ptr[_this_unit] = (type) _v;                           \
-} while (0)
-
-#define _bt_bitfield_write_be(ptr, type, start, length, v)             \
-do {                                                                   \
-       __typeof__(v) _v = (v);                                         \
-       type *_ptr = (void *) (ptr);                                    \
-       unsigned long _start = (start), _length = (length);             \
-       type _mask, _cmask;                                             \
-       unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */    \
-       unsigned long _start_unit, _end_unit, _this_unit;               \
-       unsigned long _end, _cshift; /* _cshift is "complement shift" */ \
-                                                                       \
-       if (!_length)                                                   \
-               break;                                                  \
-                                                                       \
-       _end = _start + _length;                                        \
-       _start_unit = _start / _ts;                                     \
-       _end_unit = (_end + (_ts - 1)) / _ts;                           \
-                                                                       \
-       /* Trim v high bits */                                          \
-       if (_length < sizeof(_v) * CHAR_BIT)                            \
-               _v &= _bt_make_mask(__typeof__(_v), _length);           \
-                                                                       \
-       /* We can now append v with a simple "or", shift it piece-wise */ \
-       _this_unit = _end_unit - 1;                                     \
-       if (_start_unit == _end_unit - 1) {                             \
-               _mask = _bt_make_mask(type, (_ts - (_end % _ts)) % _ts); \
-               if (_start % _ts)                                       \
-                       _mask |= _bt_make_mask_complement(type, _ts - (_start % _ts)); \
-               _cmask = _bt_lshift((type) (_v), (_ts - (_end % _ts)) % _ts); \
-               _cmask &= ~_mask;                                       \
-               _ptr[_this_unit] &= _mask;                              \
-               _ptr[_this_unit] |= _cmask;                             \
-               break;                                                  \
-       }                                                               \
-       if (_end % _ts) {                                               \
-               _cshift = _end % _ts;                                   \
-               _mask = _bt_make_mask(type, _ts - _cshift);             \
-               _cmask = _bt_lshift((type) (_v), _ts - _cshift);        \
-               _cmask &= ~_mask;                                       \
-               _ptr[_this_unit] &= _mask;                              \
-               _ptr[_this_unit] |= _cmask;                             \
-               _bt_safe_rshift(_v, _cshift);                           \
-               _end -= _cshift;                                        \
-               _this_unit--;                                           \
-       }                                                               \
-       for (; (long) _this_unit >= (long) _start_unit + 1; _this_unit--) { \
-               _ptr[_this_unit] = (type) _v;                           \
-               _bt_safe_rshift(_v, _ts);                               \
-               _end -= _ts;                                            \
-       }                                                               \
-       if (_start % _ts) {                                             \
-               _mask = _bt_make_mask_complement(type, _ts - (_start % _ts)); \
-               _cmask = (type) _v;                                     \
-               _cmask &= ~_mask;                                       \
-               _ptr[_this_unit] &= _mask;                              \
-               _ptr[_this_unit] |= _cmask;                             \
-       } else                                                          \
-               _ptr[_this_unit] = (type) _v;                           \
-} while (0)
-
-/*
- * bt_bitfield_write - write integer to a bitfield in native endianness
- * bt_bitfield_write_le - write integer to a bitfield in little endian
- * bt_bitfield_write_be - write integer to a bitfield in big endian
- */
-
-#if (BYTE_ORDER == LITTLE_ENDIAN)
-
-#define bt_bitfield_write(ptr, type, start, length, v)                 \
-       _bt_bitfield_write_le(ptr, type, start, length, v)
-
-#define bt_bitfield_write_le(ptr, type, start, length, v)              \
-       _bt_bitfield_write_le(ptr, type, start, length, v)
-
-#define bt_bitfield_write_be(ptr, type, start, length, v)              \
-       _bt_bitfield_write_be(ptr, unsigned char, start, length, v)
-
-#elif (BYTE_ORDER == BIG_ENDIAN)
-
-#define bt_bitfield_write(ptr, type, start, length, v)                 \
-       _bt_bitfield_write_be(ptr, type, start, length, v)
-
-#define bt_bitfield_write_le(ptr, type, start, length, v)              \
-       _bt_bitfield_write_le(ptr, unsigned char, start, length, v)
-
-#define bt_bitfield_write_be(ptr, type, start, length, v)              \
-       _bt_bitfield_write_be(ptr, type, start, length, v)
-
-#else /* (BYTE_ORDER == PDP_ENDIAN) */
-
-#error "Byte order not supported"
-
-#endif
-
-#define _bt_bitfield_read_le(ptr, type, start, length, vptr)           \
-do {                                                                   \
-       __typeof__(*(vptr)) *_vptr = (vptr);                            \
-       __typeof__(*_vptr) _v;                                          \
-       type *_ptr = (void *) (ptr);                                    \
-       unsigned long _start = (start), _length = (length);             \
-       type _mask, _cmask;                                             \
-       unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */    \
-       unsigned long _start_unit, _end_unit, _this_unit;               \
-       unsigned long _end, _cshift; /* _cshift is "complement shift" */ \
-       bool _is_signed_type;                                           \
-                                                                       \
-       if (!_length) {                                                 \
-               *_vptr = 0;                                             \
-               break;                                                  \
-       }                                                               \
-                                                                       \
-       _end = _start + _length;                                        \
-       _start_unit = _start / _ts;                                     \
-       _end_unit = (_end + (_ts - 1)) / _ts;                           \
-                                                                       \
-       _this_unit = _end_unit - 1;                                     \
-       _BT_DIAG_PUSH                                                   \
-       _BT_DIAG_IGNORE_TYPE_LIMITS                                     \
-       _is_signed_type = _bt_is_signed_type(__typeof__(_v));           \
-       _BT_DIAG_POP                                                    \
-       if (_is_signed_type                                             \
-           && (_ptr[_this_unit] & _bt_lshift((type) 1, (_end % _ts ? _end % _ts : _ts) - 1))) \
-               _v = ~(__typeof__(_v)) 0;                               \
-       else                                                            \
-               _v = 0;                                                 \
-       if (_start_unit == _end_unit - 1) {                             \
-               _cmask = _ptr[_this_unit];                              \
-               _cmask = _bt_rshift(_cmask, _start % _ts);              \
-               if ((_end - _start) % _ts) {                            \
-                       _mask = _bt_make_mask(type, _end - _start);     \
-                       _cmask &= _mask;                                \
-               }                                                       \
-               _bt_safe_lshift(_v, _end - _start);                     \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
-               *_vptr = _v;                                            \
-               break;                                                  \
-       }                                                               \
-       if (_end % _ts) {                                               \
-               _cshift = _end % _ts;                                   \
-               _mask = _bt_make_mask(type, _cshift);                   \
-               _cmask = _ptr[_this_unit];                              \
-               _cmask &= _mask;                                        \
-               _bt_safe_lshift(_v, _cshift);                           \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
-               _end -= _cshift;                                        \
-               _this_unit--;                                           \
-       }                                                               \
-       for (; (long) _this_unit >= (long) _start_unit + 1; _this_unit--) { \
-               _bt_safe_lshift(_v, _ts);                               \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \
-               _end -= _ts;                                            \
-       }                                                               \
-       if (_start % _ts) {                                             \
-               _mask = _bt_make_mask(type, _ts - (_start % _ts));      \
-               _cmask = _ptr[_this_unit];                              \
-               _cmask = _bt_rshift(_cmask, _start % _ts);              \
-               _cmask &= _mask;                                        \
-               _bt_safe_lshift(_v, _ts - (_start % _ts));              \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
-       } else {                                                        \
-               _bt_safe_lshift(_v, _ts);                               \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \
-       }                                                               \
-       *_vptr = _v;                                                    \
-} while (0)
-
-#define _bt_bitfield_read_be(ptr, type, start, length, vptr)           \
-do {                                                                   \
-       __typeof__(*(vptr)) *_vptr = (vptr);                            \
-       __typeof__(*_vptr) _v;                                          \
-       type *_ptr = (void *) (ptr);                                    \
-       unsigned long _start = (start), _length = (length);             \
-       type _mask, _cmask;                                             \
-       unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */    \
-       unsigned long _start_unit, _end_unit, _this_unit;               \
-       unsigned long _end, _cshift; /* _cshift is "complement shift" */ \
-       bool _is_signed_type;                                           \
-                                                                       \
-       if (!_length) {                                                 \
-               *_vptr = 0;                                             \
-               break;                                                  \
-       }                                                               \
-                                                                       \
-       _end = _start + _length;                                        \
-       _start_unit = _start / _ts;                                     \
-       _end_unit = (_end + (_ts - 1)) / _ts;                           \
-                                                                       \
-       _this_unit = _start_unit;                                       \
-       _BT_DIAG_PUSH                                                   \
-       _BT_DIAG_IGNORE_TYPE_LIMITS                                     \
-       _is_signed_type = _bt_is_signed_type(__typeof__(_v));           \
-       _BT_DIAG_POP                                                    \
-       if (_is_signed_type                                             \
-           && (_ptr[_this_unit] & _bt_lshift((type) 1, _ts - (_start % _ts) - 1))) \
-               _v = ~(__typeof__(_v)) 0;                               \
-       else                                                            \
-               _v = 0;                                                 \
-       if (_start_unit == _end_unit - 1) {                             \
-               _cmask = _ptr[_this_unit];                              \
-               _cmask = _bt_rshift(_cmask, (_ts - (_end % _ts)) % _ts); \
-               if ((_end - _start) % _ts) {                            \
-                       _mask = _bt_make_mask(type, _end - _start);     \
-                       _cmask &= _mask;                                \
-               }                                                       \
-               _bt_safe_lshift(_v, _end - _start);                     \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
-               *_vptr = _v;                                            \
-               break;                                                  \
-       }                                                               \
-       if (_start % _ts) {                                             \
-               _cshift = _start % _ts;                                 \
-               _mask = _bt_make_mask(type, _ts - _cshift);             \
-               _cmask = _ptr[_this_unit];                              \
-               _cmask &= _mask;                                        \
-               _bt_safe_lshift(_v, _ts - _cshift);                     \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
-               _start += _ts - _cshift;                                \
-               _this_unit++;                                           \
-       }                                                               \
-       for (; _this_unit < _end_unit - 1; _this_unit++) {              \
-               _bt_safe_lshift(_v, _ts);                               \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \
-               _start += _ts;                                          \
-       }                                                               \
-       if (_end % _ts) {                                               \
-               _mask = _bt_make_mask(type, _end % _ts);                \
-               _cmask = _ptr[_this_unit];                              \
-               _cmask = _bt_rshift(_cmask, _ts - (_end % _ts));        \
-               _cmask &= _mask;                                        \
-               _bt_safe_lshift(_v, _end % _ts);                        \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
-       } else {                                                        \
-               _bt_safe_lshift(_v, _ts);                               \
-               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \
-       }                                                               \
-       *_vptr = _v;                                                    \
-} while (0)
-
-/*
- * bt_bitfield_read - read integer from a bitfield in native endianness
- * bt_bitfield_read_le - read integer from a bitfield in little endian
- * bt_bitfield_read_be - read integer from a bitfield in big endian
- */
-
-#if (BYTE_ORDER == LITTLE_ENDIAN)
-
-#define bt_bitfield_read(ptr, type, start, length, vptr)               \
-       _bt_bitfield_read_le(ptr, type, start, length, vptr)
-
-#define bt_bitfield_read_le(ptr, type, start, length, vptr)            \
-       _bt_bitfield_read_le(ptr, type, start, length, vptr)
-
-#define bt_bitfield_read_be(ptr, type, start, length, vptr)            \
-       _bt_bitfield_read_be(ptr, unsigned char, start, length, vptr)
-
-#elif (BYTE_ORDER == BIG_ENDIAN)
-
-#define bt_bitfield_read(ptr, type, start, length, vptr)               \
-       _bt_bitfield_read_be(ptr, type, start, length, vptr)
-
-#define bt_bitfield_read_le(ptr, type, start, length, vptr)            \
-       _bt_bitfield_read_le(ptr, unsigned char, start, length, vptr)
-
-#define bt_bitfield_read_be(ptr, type, start, length, vptr)            \
-       _bt_bitfield_read_be(ptr, type, start, length, vptr)
-
-#else /* (BYTE_ORDER == PDP_ENDIAN) */
-
-#error "Byte order not supported"
-
-#endif
-
-#endif /* _BABELTRACE_BITFIELD_H */
diff --git a/include/babeltrace2/common-internal.h b/include/babeltrace2/common-internal.h
deleted file mode 100644 (file)
index d30da97..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-#ifndef BABELTRACE_COMMON_INTERNAL_H
-#define BABELTRACE_COMMON_INTERNAL_H
-
-/*
- * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdbool.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/trace-ir/field-class-const.h>
-#include <babeltrace2/trace-ir/field-path-const.h>
-#include <babeltrace2/trace-ir/event-class-const.h>
-#include <babeltrace2/graph/self-message-iterator.h>
-#include <babeltrace2/value.h>
-#include <inttypes.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <glib.h>
-
-#define BT_COMMON_COLOR_RESET              "\033[0m"
-#define BT_COMMON_COLOR_BOLD               "\033[1m"
-#define BT_COMMON_COLOR_FG_DEFAULT         "\033[39m"
-#define BT_COMMON_COLOR_FG_RED             "\033[31m"
-#define BT_COMMON_COLOR_FG_GREEN           "\033[32m"
-#define BT_COMMON_COLOR_FG_YELLOW          "\033[33m"
-#define BT_COMMON_COLOR_FG_BLUE            "\033[34m"
-#define BT_COMMON_COLOR_FG_MAGENTA         "\033[35m"
-#define BT_COMMON_COLOR_FG_CYAN            "\033[36m"
-#define BT_COMMON_COLOR_FG_LIGHT_GRAY      "\033[37m"
-#define BT_COMMON_COLOR_BG_DEFAULT         "\033[49m"
-#define BT_COMMON_COLOR_BG_RED             "\033[41m"
-#define BT_COMMON_COLOR_BG_GREEN           "\033[42m"
-#define BT_COMMON_COLOR_BG_YELLOW          "\033[43m"
-#define BT_COMMON_COLOR_BG_BLUE            "\033[44m"
-#define BT_COMMON_COLOR_BG_MAGENTA         "\033[45m"
-#define BT_COMMON_COLOR_BG_CYAN            "\033[46m"
-#define BT_COMMON_COLOR_BG_LIGHT_GRAY      "\033[47m"
-
-struct bt_common_lttng_live_url_parts {
-       GString *proto;
-       GString *hostname;
-       GString *target_hostname;
-       GString *session_name;
-
-       /* -1 means default port */
-       int port;
-};
-
-/*
- * Checks if the current process has setuid or setgid access rights.
- * Returns `true` if so.
- */
-BT_HIDDEN
-bool bt_common_is_setuid_setgid(void);
-
-/*
- * Returns the system-wide plugin path, e.g.
- * `/usr/lib/babeltrace2/plugins`. Do not free the return value.
- */
-BT_HIDDEN
-const char *bt_common_get_system_plugin_path(void);
-
-/*
- * Returns the user plugin path, e.g.
- * `/home/user/.local/lib/babeltrace2/plugins`. You need to free the
- * return value.
- */
-BT_HIDDEN
-char *bt_common_get_home_plugin_path(void);
-
-/*
- * Appends the list of directories in `paths` to the array `dirs`.
- * `paths` is a list of directories separated by `:`. Returns 0 on
- * success.
- */
-BT_HIDDEN
-int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs);
-
-/*
- * Returns `true` if terminal color codes are supported for this
- * process.
- */
-BT_HIDDEN
-bool bt_common_colors_supported(void);
-
-BT_HIDDEN
-const char *bt_common_color_reset(void);
-
-BT_HIDDEN
-const char *bt_common_color_bold(void);
-
-BT_HIDDEN
-const char *bt_common_color_fg_default(void);
-
-BT_HIDDEN
-const char *bt_common_color_fg_red(void);
-
-BT_HIDDEN
-const char *bt_common_color_fg_green(void);
-
-BT_HIDDEN
-const char *bt_common_color_fg_yellow(void);
-
-BT_HIDDEN
-const char *bt_common_color_fg_blue(void);
-
-BT_HIDDEN
-const char *bt_common_color_fg_magenta(void);
-
-BT_HIDDEN
-const char *bt_common_color_fg_cyan(void);
-
-BT_HIDDEN
-const char *bt_common_color_fg_light_gray(void);
-
-BT_HIDDEN
-const char *bt_common_color_bg_default(void);
-
-BT_HIDDEN
-const char *bt_common_color_bg_red(void);
-
-BT_HIDDEN
-const char *bt_common_color_bg_green(void);
-
-BT_HIDDEN
-const char *bt_common_color_bg_yellow(void);
-
-BT_HIDDEN
-const char *bt_common_color_bg_blue(void);
-
-BT_HIDDEN
-const char *bt_common_color_bg_magenta(void);
-
-BT_HIDDEN
-const char *bt_common_color_bg_cyan(void);
-
-BT_HIDDEN
-const char *bt_common_color_bg_light_gray(void);
-
-/*
- * Returns the substring from `input` to the first character found
- * in the list of characters `end_chars`, unescaping any character
- * found in `escapable_chars`, and sets `*end_pos` to the position of
- * the end (from `input`). The caller owns the returned GString.
- */
-BT_HIDDEN
-GString *bt_common_string_until(const char *input, const char *escapable_chars,
-                    const char *end_chars, size_t *end_pos);
-
-/*
- * Returns the quoted version of `input` for a shell. If
- * `with_single_quotes` is `true`, prepends and appends the `'` prefix
- * and suffix to the returned string; otherwise the caller should
- * prepend and append them manually, although they are not always
- * required. The caller owns the returned GString.
- */
-BT_HIDDEN
-GString *bt_common_shell_quote(const char *input, bool with_single_quotes);
-
-/*
- * Returns `true` if `input` is a string made only of printable
- * characters.
- */
-BT_HIDDEN
-bool bt_common_string_is_printable(const char *input);
-
-/*
- * Destroys the parts of an LTTng live URL as returned by
- * bt_common_parse_lttng_live_url().
- */
-BT_HIDDEN
-void bt_common_destroy_lttng_live_url_parts(
-               struct bt_common_lttng_live_url_parts *parts);
-
-/*
- * Parses the LTTng live URL `url` and returns its different parts.
- * If there's an error, writes the error message into `*error_buf`
- * up to `error_buf_size` bytes. You must destroy the returned value
- * with bt_common_destroy_lttng_live_url_parts().
- */
-BT_HIDDEN
-struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
-               const char *url, char *error_buf, size_t error_buf_size);
-
-/*
- * Normalizes (in place) a star globbing pattern to be used with
- * bt_common_star_glob_match(). This function always succeeds.
- */
-BT_HIDDEN
-void bt_common_normalize_star_glob_pattern(char *pattern);
-
-/*
- * Returns `true` if `candidate` (of size `candidate_len`) matches
- * the star globbing pattern `pattern` (of size `pattern_len`).
- */
-BT_HIDDEN
-bool bt_common_star_glob_match(const char *pattern, size_t pattern_len,
-                const char *candidate, size_t candidate_len);
-
-/*
- * Normalizes the path `path`:
- *
- * * If it's a relative path, converts it to an absolute path using
- *   `wd` as the working directory (or the current working directory
- *   if `wd` is NULL).
- * * Removes consecutive and trailing slashes.
- * * Resolves `..` and `.` in the path (both in `path` and in `wd`).
- * * Does NOT resolve symbolic links.
- *
- * The caller owns the returned GString.
- */
-BT_HIDDEN
-GString *bt_common_normalize_path(const char *path, const char *wd);
-
-typedef void (* bt_common_handle_custom_specifier_func)(void *priv_data,
-               char **buf, size_t avail_size, const char **fmt, va_list *args);
-
-/*
- * This is a custom vsnprintf() which handles the standard conversion
- * specifier as well as custom ones.
- *
- * `fmt` is a typical printf()-style format string, with the following
- * limitations:
- *
- * * The `*` width specifier is not accepted.
- * * The `*` precision specifier is not accepted.
- * * The `j` and `t` length modifiers are not accepted.
- * * The `n` format specifier is not accepted.
- * * The format specifiers defined in <inttypes.h> are not accepted
- *   except for `PRId64`, `PRIu64`, `PRIx64`, `PRIX64`, `PRIo64`, and
- *   `PRIi64`.
- *
- * `intro` specifies which special character immediately following an
- * introductory `%` character in `fmt` is used to indicate a custom
- * conversion specifier. For example, if `intro` is '@', then any `%@`
- * sequence in `fmt` is the beginning of a custom conversion specifier.
- *
- * When a custom conversion specifier is encountered in `fmt`,
- * the function calls `handle_specifier`. This callback receives:
- *
- * `priv_data`:
- *     Custom, private data.
- *
- * `buf`:
- *     Address of the current buffer pointer. `*buf` is the position to
- *     append new data. The callback must update `*buf` when appending
- *     new data. The callback must ensure not to write passed the whole
- *     buffer passed to bt_common_custom_vsnprintf().
- *
- * `avail_size`:
- *     Number of bytes left in whole buffer from the `*buf` point.
- *
- * `fmt`:
- *     Address of the current format string pointer. `*fmt` points to
- *     the introductory `%` character, which is followed by the
- *     character `intro`. The callback must update `*fmt` so that it
- *     points after the whole custom conversion specifier.
- *
- * `args`:
- *     Variable argument list. Use va_arg() to get new arguments from
- *     this list and update it at the same time.
- *
- * Because this is an internal utility, this function and its callback
- * do not return error codes: they abort when there's any error (bad
- * format string, for example).
- */
-BT_HIDDEN
-void bt_common_custom_vsnprintf(char *buf, size_t buf_size,
-               char intro,
-               bt_common_handle_custom_specifier_func handle_specifier,
-               void *priv_data, const char *fmt, va_list *args);
-
-/*
- * Variadic form of bt_common_custom_vsnprintf().
- */
-BT_HIDDEN
-void bt_common_custom_snprintf(char *buf, size_t buf_size,
-               char intro,
-               bt_common_handle_custom_specifier_func handle_specifier,
-               void *priv_data, const char *fmt, ...);
-
-/*
- * Returns the system page size.
- */
-BT_HIDDEN
-size_t bt_common_get_page_size(void);
-
-/*
- * Wraps read() function to handle EINTR and partial reads.
- * On success, it returns `count` received as parameter. On error, it returns a
- * value smaller than the requested `count`.
- */
-static inline
-ssize_t bt_common_read(int fd, void *buf, size_t count)
-{
-       size_t i = 0;
-       ssize_t ret;
-
-       BT_ASSERT(buf);
-
-       /* Never return an overflow value. */
-       BT_ASSERT(count <= SSIZE_MAX);
-
-       do {
-               ret = read(fd, buf + i, count - i);
-               if (ret < 0) {
-                       if (errno == EINTR) {
-#ifdef BT_LOGD_STR
-                               BT_LOGD_STR("read() call interrupted. Retrying...");
-#endif
-                               /* retry operation */
-                               continue;
-                       } else {
-#ifdef BT_LOGE_ERRNO
-                               BT_LOGE_ERRNO("Error while reading", ": fd=%d",
-                                       fd);
-#endif
-                               goto end;
-                       }
-               }
-               i += ret;
-               BT_ASSERT(i <= count);
-       } while (count - i > 0 && ret > 0);
-
-end:
-       if (ret >= 0) {
-               if (i == 0) {
-                       ret = -1;
-               } else {
-                       ret = i;
-               }
-       }
-
-       return ret;
-}
-
-static inline
-const char *bt_common_field_class_type_string(enum bt_field_class_type class_type)
-{
-       switch (class_type) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
-               return "BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER";
-       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
-               return "BT_FIELD_CLASS_TYPE_SIGNED_INTEGER";
-       case BT_FIELD_CLASS_TYPE_REAL:
-               return "BT_FIELD_CLASS_TYPE_REAL";
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-               return "BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION";
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-               return "BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION";
-       case BT_FIELD_CLASS_TYPE_STRING:
-               return "BT_FIELD_CLASS_TYPE_STRING";
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-               return "BT_FIELD_CLASS_TYPE_STRUCTURE";
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-               return "BT_FIELD_CLASS_TYPE_STATIC_ARRAY";
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-               return "BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY";
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-               return "BT_FIELD_CLASS_TYPE_VARIANT";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-const char *bt_common_field_class_integer_preferred_display_base_string(enum bt_field_class_integer_preferred_display_base base)
-{
-       switch (base) {
-       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
-               return "BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY";
-       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
-               return "BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL";
-       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
-               return "BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL";
-       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
-               return "BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-const char *bt_common_scope_string(enum bt_scope scope)
-{
-       switch (scope) {
-       case BT_SCOPE_PACKET_CONTEXT:
-               return "BT_SCOPE_PACKET_CONTEXT";
-       case BT_SCOPE_EVENT_COMMON_CONTEXT:
-               return "BT_SCOPE_EVENT_COMMON_CONTEXT";
-       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               return "BT_SCOPE_EVENT_SPECIFIC_CONTEXT";
-       case BT_SCOPE_EVENT_PAYLOAD:
-               return "BT_SCOPE_EVENT_PAYLOAD";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-const char *bt_common_event_class_log_level_string(
-               enum bt_event_class_log_level level)
-{
-       switch (level) {
-       case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
-               return "BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY";
-       case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
-               return "BT_EVENT_CLASS_LOG_LEVEL_ALERT";
-       case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
-               return "BT_EVENT_CLASS_LOG_LEVEL_CRITICAL";
-       case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
-               return "BT_EVENT_CLASS_LOG_LEVEL_ERROR";
-       case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
-               return "BT_EVENT_CLASS_LOG_LEVEL_WARNING";
-       case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
-               return "BT_EVENT_CLASS_LOG_LEVEL_NOTICE";
-       case BT_EVENT_CLASS_LOG_LEVEL_INFO:
-               return "BT_EVENT_CLASS_LOG_LEVEL_INFO";
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
-               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM";
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
-               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM";
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
-               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS";
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
-               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE";
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
-               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT";
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
-               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION";
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
-               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE";
-       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
-               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-const char *bt_common_value_type_string(enum bt_value_type type)
-{
-       switch (type) {
-       case BT_VALUE_TYPE_NULL:
-               return "BT_VALUE_TYPE_NULL";
-       case BT_VALUE_TYPE_BOOL:
-               return "BT_VALUE_TYPE_BOOL";
-       case BT_VALUE_TYPE_UNSIGNED_INTEGER:
-               return "BT_VALUE_TYPE_UNSIGNED_INTEGER";
-       case BT_VALUE_TYPE_SIGNED_INTEGER:
-               return "BT_VALUE_TYPE_SIGNED_INTEGER";
-       case BT_VALUE_TYPE_REAL:
-               return "BT_VALUE_TYPE_REAL";
-       case BT_VALUE_TYPE_STRING:
-               return "BT_VALUE_TYPE_STRING";
-       case BT_VALUE_TYPE_ARRAY:
-               return "BT_VALUE_TYPE_ARRAY";
-       case BT_VALUE_TYPE_MAP:
-               return "BT_VALUE_TYPE_MAP";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-GString *bt_common_field_path_string(struct bt_field_path *path)
-{
-       GString *str = g_string_new(NULL);
-       uint64_t i;
-
-       BT_ASSERT(path);
-
-       if (!str) {
-               goto end;
-       }
-
-       g_string_append_printf(str, "[%s", bt_common_scope_string(
-               bt_field_path_get_root_scope(path)));
-
-       for (i = 0; i < bt_field_path_get_item_count(path); i++) {
-               const struct bt_field_path_item *fp_item =
-                       bt_field_path_borrow_item_by_index_const(path, i);
-
-               switch (bt_field_path_item_get_type(fp_item)) {
-               case BT_FIELD_PATH_ITEM_TYPE_INDEX:
-                       g_string_append_printf(str, ", %" PRIu64,
-                               bt_field_path_item_index_get_index(fp_item));
-                       break;
-               case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
-                       g_string_append(str, ", <CUR>");
-                       break;
-               default:
-                       abort();
-               }
-       }
-
-       g_string_append(str, "]");
-
-end:
-       return str;
-}
-
-static inline
-const char *bt_common_self_message_iterator_status_string(
-               enum bt_self_message_iterator_status status)
-{
-       switch (status) {
-       case BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN:
-               return "BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN";
-       case BT_SELF_MESSAGE_ITERATOR_STATUS_END:
-               return "BT_SELF_MESSAGE_ITERATOR_STATUS_END";
-       case BT_SELF_MESSAGE_ITERATOR_STATUS_OK:
-               return "BT_SELF_MESSAGE_ITERATOR_STATUS_OK";
-       case BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR:
-               return "BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR";
-       case BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM:
-               return "BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-};
-
-#define NS_PER_S_I     INT64_C(1000000000)
-#define NS_PER_S_U     UINT64_C(1000000000)
-
-static inline
-int bt_common_clock_value_from_ns_from_origin(
-               int64_t cc_offset_seconds, uint64_t cc_offset_cycles,
-               uint64_t cc_freq, int64_t ns_from_origin,
-               uint64_t *raw_value)
-{
-       int ret = 0;
-       int64_t offset_in_ns;
-       uint64_t value_in_ns;
-       uint64_t rem_value_in_ns;
-       uint64_t value_periods;
-       uint64_t value_period_cycles;
-       int64_t ns_to_add;
-
-       BT_ASSERT(raw_value);
-
-       /* Compute offset part of requested value, in nanoseconds */
-       if (!bt_safe_to_mul_int64(cc_offset_seconds, NS_PER_S_I)) {
-               ret = -1;
-               goto end;
-       }
-
-       offset_in_ns = cc_offset_seconds * NS_PER_S_I;
-
-       if (cc_freq == NS_PER_S_U) {
-               ns_to_add = (int64_t) cc_offset_cycles;
-       } else {
-               if (!bt_safe_to_mul_int64((int64_t) cc_offset_cycles,
-                               NS_PER_S_I)) {
-                       ret = -1;
-                       goto end;
-               }
-
-               ns_to_add = ((int64_t) cc_offset_cycles * NS_PER_S_I) /
-                       (int64_t) cc_freq;
-       }
-
-       if (!bt_safe_to_add_int64(offset_in_ns, ns_to_add)) {
-               ret = -1;
-               goto end;
-       }
-
-       offset_in_ns += ns_to_add;
-
-       /* Value part in nanoseconds */
-       if (ns_from_origin < offset_in_ns) {
-               ret = -1;
-               goto end;
-       }
-
-       value_in_ns = (uint64_t) (ns_from_origin - offset_in_ns);
-
-       /* Number of whole clock periods in `value_in_ns` */
-       value_periods = value_in_ns / NS_PER_S_U;
-
-       /* Remaining nanoseconds in cycles + whole clock periods in cycles */
-       rem_value_in_ns = value_in_ns - value_periods * NS_PER_S_U;
-
-       if (value_periods > UINT64_MAX / cc_freq) {
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_safe_to_mul_uint64(value_periods, cc_freq)) {
-               ret = -1;
-               goto end;
-       }
-
-       value_period_cycles = value_periods * cc_freq;
-
-       if (!bt_safe_to_mul_uint64(cc_freq, rem_value_in_ns)) {
-               ret = -1;
-               goto end;
-       }
-
-       if (!bt_safe_to_add_uint64(cc_freq * rem_value_in_ns / NS_PER_S_U,
-                       value_period_cycles)) {
-               ret = -1;
-               goto end;
-       }
-
-       *raw_value = cc_freq * rem_value_in_ns / NS_PER_S_U +
-               value_period_cycles;
-
-end:
-       return ret;
-}
-
-static inline
-enum bt_self_message_iterator_status bt_common_message_iterator_status_to_self(
-               enum bt_message_iterator_status status)
-{
-       return (int) status;
-}
-#endif /* BABELTRACE_COMMON_INTERNAL_H */
diff --git a/include/babeltrace2/compat/fcntl-internal.h b/include/babeltrace2/compat/fcntl-internal.h
deleted file mode 100644 (file)
index c528943..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_FCNTL_H
-#define _BABELTRACE_COMPAT_FCNTL_H
-
-/*
- * Copyright 2015 (c) - Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * fcntl compatibility layer.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifdef BABELTRACE_HAVE_POSIX_FALLOCATE
-
-#include <fcntl.h>
-
-static inline
-int bt_posix_fallocate(int fd, off_t offset, off_t len)
-{
-       return posix_fallocate(fd, offset, len);
-}
-
-#elif defined(__MINGW32__) /* #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
-
-#include <stdlib.h>
-#include <windows.h>
-#include <fcntl.h>
-
-static inline
-int bt_posix_fallocate(int fd, off_t offset, off_t len)
-{
-       HANDLE handle;
-       LARGE_INTEGER pos, file_pos, orig_end_offset, range_end;
-       int ret = 0;
-       char zero = 0;
-       DWORD byteswritten;
-
-       if (offset < 0 || len <= 0) {
-               ret = EINVAL;
-               goto end;
-       }
-
-       range_end.QuadPart = (__int64) offset + (__int64) len;
-
-       /* Get a handle from the fd */
-       handle = (HANDLE) _get_osfhandle(fd);
-       if (handle == INVALID_HANDLE_VALUE) {
-               ret = EBADF;
-               goto end;
-       }
-
-       /* Get the file original end offset */
-       ret = GetFileSizeEx(handle, &orig_end_offset);
-       if (ret == 0) {
-               ret = EBADF;
-               goto end;
-       }
-
-       /* Make sure we don't truncate the file */
-       if (orig_end_offset.QuadPart >= range_end.QuadPart) {
-               ret = 0;
-               goto end;
-       }
-
-       /* Get the current file pointer position */
-       pos.QuadPart = 0;
-       ret = SetFilePointerEx(handle, pos, &file_pos, FILE_CURRENT);
-       if (ret == 0) {
-               ret = EBADF;
-               goto end;
-       }
-
-       /* Move the file pointer to the new end offset */
-       ret = SetFilePointerEx(handle, range_end, NULL, FILE_BEGIN);
-       if (ret == 0) {
-               ret = EBADF;
-               goto end;
-       }
-
-       /* Sets the physical file size to the current position */
-       ret = SetEndOfFile(handle);
-       if (ret == 0) {
-               ret = EINVAL;
-               goto restore;
-       }
-
-       /*
-        * Move the file pointer back 1 byte, and write a single 0 at the
-        * last byte of the new end offset, the operating system will zero
-        * fill the file.
-        */
-       pos.QuadPart = -1;
-       ret = SetFilePointerEx(handle, pos, NULL, FILE_END);
-       if (ret == 0) {
-               ret = EBADF;
-               goto end;
-       }
-
-       ret = WriteFile(handle, &zero, 1, &byteswritten, NULL);
-       if (ret == 0 || byteswritten != 1) {
-               ret = ENOSPC;
-       } else {
-               ret = 0;
-       }
-
-restore:
-       /* Restore the original file pointer position */
-       if (!SetFilePointerEx(handle, file_pos, NULL, FILE_BEGIN)) {
-               /* We moved the file pointer but failed to restore it. */
-               abort();
-       }
-
-end:
-       return ret;
-}
-
-#else
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <string.h>
-
-#define BABELTRACE_FALLOCATE_BUFLEN    256
-
-#ifndef min_t
-#define min_t(type, a, b)      \
-       ((type) (a) < (type) (b) ? (type) (a) : (type) (b))
-#endif
-
-static inline
-int bt_posix_fallocate(int fd, off_t offset, off_t len)
-{
-       int ret = 0;
-       ssize_t copy_len;
-       char buf[BABELTRACE_FALLOCATE_BUFLEN];
-       off_t i, file_pos, orig_end_offset, range_end;
-
-       if (offset < 0 || len < 0) {
-               ret = EINVAL;
-               goto end;
-       }
-
-       range_end = offset + len;
-       if (range_end < 0) {
-               ret = EFBIG;
-               goto end;
-       }
-
-       file_pos = lseek(fd, 0, SEEK_CUR);
-       if (file_pos < 0) {
-               ret = errno;
-               goto end;
-       }
-
-       orig_end_offset = lseek(fd, 0, SEEK_END);
-       if (orig_end_offset < 0) {
-               ret = errno;
-               goto end;
-       }
-
-       /* Seek back to original position. */
-       ret = lseek(fd, file_pos, SEEK_SET);
-       if (ret) {
-               ret = errno;
-               goto end;
-       }
-
-       /*
-        * The file may not need to grow, but we want to ensure the
-        * space has actually been reserved by the file system. First, copy
-        * the "existing" region of the file, then grow the file if needed.
-        */
-       for (i = file_pos; i < min_t(off_t, range_end, orig_end_offset);
-                       i += copy_len) {
-               ssize_t copy_ret;
-
-               copy_len = min_t(size_t, BABELTRACE_FALLOCATE_BUFLEN,
-                               min_t(off_t, range_end - i,
-                                       orig_end_offset - i));
-               copy_ret = pread(fd, &buf, copy_len, i);
-               if (copy_ret < copy_len) {
-                       /*
-                        * The caller must handle any EINTR.
-                        * POSIX_FALLOCATE(3) does not mention EINTR.
-                        * However, glibc does forward to fallocate()
-                        * directly on Linux, which may be interrupted.
-                        */
-                       ret = errno;
-                       goto end;
-               }
-
-               copy_ret = pwrite(fd, &buf, copy_len, i);
-               if (copy_ret < copy_len) {
-                       /* Same caveat as noted at pread() */
-                       ret = errno;
-                       goto end;
-               }
-       }
-
-       /* Grow file, as necessary. */
-       memset(&buf, 0, BABELTRACE_FALLOCATE_BUFLEN);
-       for (i = orig_end_offset; i < range_end; i += copy_len) {
-               ssize_t write_ret;
-
-               copy_len = min_t(size_t, BABELTRACE_FALLOCATE_BUFLEN,
-                               range_end - i);
-               write_ret = pwrite(fd, &buf, copy_len, i);
-               if (write_ret < copy_len) {
-                       ret = errno;
-                       goto end;
-               }
-       }
-end:
-       return ret;
-}
-#endif /* #else #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
-
-#endif /* _BABELTRACE_COMPAT_FCNTL_H */
diff --git a/include/babeltrace2/compat/glib-internal.h b/include/babeltrace2/compat/glib-internal.h
deleted file mode 100644 (file)
index e956280..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_GLIB_H
-#define _BABELTRACE_COMPAT_GLIB_H
-
-/*
- * Copyright (C) 2015 Michael Jeanson <mjeanson@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-
-#if GLIB_CHECK_VERSION(2,31,8)
-
-static inline gboolean
-bt_g_hash_table_contains(GHashTable *hash_table, gconstpointer key)
-{
-       return g_hash_table_contains(hash_table, key);
-}
-
-#else
-
-static inline gboolean
-bt_g_hash_table_contains(GHashTable *hash_table, gconstpointer key)
-{
-       gpointer orig_key;
-       gpointer value;
-
-       return g_hash_table_lookup_extended(hash_table, key, &orig_key,
-               &value);
-}
-
-#endif
-
-
-#if GLIB_CHECK_VERSION(2,29,16)
-
-static inline GPtrArray *
-bt_g_ptr_array_new_full(guint reserved_size,
-               GDestroyNotify element_free_func)
-{
-       return g_ptr_array_new_full(reserved_size, element_free_func);
-}
-
-#else
-
-static inline GPtrArray *
-bt_g_ptr_array_new_full(guint reserved_size,
-               GDestroyNotify element_free_func)
-{
-       GPtrArray *array;
-
-       array = g_ptr_array_sized_new(reserved_size);
-       if (!array) {
-              goto end;
-       }
-       g_ptr_array_set_free_func(array, element_free_func);
-end:
-       return array;
-}
-#endif
-
-#endif /* _BABELTRACE_COMPAT_GLIB_H */
diff --git a/include/babeltrace2/compat/limits-internal.h b/include/babeltrace2/compat/limits-internal.h
deleted file mode 100644 (file)
index b276183..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _BABELTRACE_LIMITS_H
-#define _BABELTRACE_LIMITS_H
-
-/*
- * Copyright (C) 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <limits.h>
-
-#ifdef __linux__
-
-#define BABELTRACE_HOST_NAME_MAX HOST_NAME_MAX
-
-#elif defined(__FreeBSD__)
-
-#define BABELTRACE_HOST_NAME_MAX MAXHOSTNAMELEN
-
-#elif defined(_POSIX_HOST_NAME_MAX)
-
-#define BABELTRACE_HOST_NAME_MAX _POSIX_HOST_NAME_MAX
-
-#else
-
-#define BABELTRACE_HOST_NAME_MAX 256
-
-#endif /* __linux__, __FreeBSD__, _POSIX_HOST_NAME_MAX */
-
-#endif /* _BABELTRACE_LIMITS_H */
diff --git a/include/babeltrace2/compat/memstream-internal.h b/include/babeltrace2/compat/memstream-internal.h
deleted file mode 100644 (file)
index 60ff60b..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-#ifndef _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
-#define _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
-
-/*
- * Copyright 2012 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * memstream compatibility layer.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifdef BABELTRACE_HAVE_FMEMOPEN
-#include <stdio.h>
-
-static inline
-FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
-{
-       return fmemopen(buf, size, mode);
-}
-
-#else /* BABELTRACE_HAVE_FMEMOPEN */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <babeltrace2/endian-internal.h>
-
-#ifdef __MINGW32__
-
-#include <io.h>
-#include <glib.h>
-
-/*
- * Fallback for systems which don't have fmemopen. Copy buffer to a
- * temporary file, and use that file as FILE * input.
- */
-static inline
-FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
-{
-       char *tmpname;
-       size_t len;
-       FILE *fp;
-       int ret;
-
-       /*
-        * Support reading only.
-        */
-       if (strcmp(mode, "rb") != 0) {
-               return NULL;
-       }
-
-       /* Build a temporary filename */
-       tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
-       if (_mktemp(tmpname) == NULL) {
-               goto error_free;
-       }
-
-       /*
-        * Open as a read/write binary temporary deleted on close file.
-        * Will be deleted when the last file pointer is closed.
-        */
-       fp = fopen(tmpname, "w+bTD");
-       if (!fp) {
-               goto error_free;
-       }
-
-       /* Copy the entire buffer to the file */
-       len = fwrite(buf, sizeof(char), size, fp);
-       if (len != size) {
-               goto error_close;
-       }
-
-       /* Set the file pointer to the start of file */
-       ret = fseek(fp, 0L, SEEK_SET);
-       if (ret < 0) {
-               perror("fseek");
-               goto error_close;
-       }
-
-       g_free(tmpname);
-       return fp;
-
-error_close:
-       ret = fclose(fp);
-       if (ret < 0) {
-               perror("close");
-       }
-error_free:
-       g_free(tmpname);
-       return NULL;
-}
-
-#else /* __MINGW32__ */
-
-/*
- * Fallback for systems which don't have fmemopen. Copy buffer to a
- * temporary file, and use that file as FILE * input.
- */
-static inline
-FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
-{
-       char *tmpname;
-       size_t len;
-       FILE *fp;
-       int ret;
-
-       /*
-        * Support reading only.
-        */
-       if (strcmp(mode, "rb") != 0) {
-               return NULL;
-       }
-
-       tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
-       ret = mkstemp(tmpname);
-       if (ret < 0) {
-               g_free(tmpname);
-               return NULL;
-       }
-       /*
-        * We need to write to the file.
-        */
-       fp = fdopen(ret, "wb+");
-       if (!fp) {
-               goto error_unlink;
-       }
-       /* Copy the entire buffer to the file */
-       len = fwrite(buf, sizeof(char), size, fp);
-       if (len != size) {
-               goto error_close;
-       }
-       ret = fseek(fp, 0L, SEEK_SET);
-       if (ret < 0) {
-               perror("fseek");
-               goto error_close;
-       }
-       /* We keep the handle open, but can unlink the file on the VFS. */
-       ret = unlink(tmpname);
-       if (ret < 0) {
-               perror("unlink");
-       }
-       g_free(tmpname);
-       return fp;
-
-error_close:
-       ret = fclose(fp);
-       if (ret < 0) {
-               perror("close");
-       }
-error_unlink:
-       ret = unlink(tmpname);
-       if (ret < 0) {
-               perror("unlink");
-       }
-       g_free(tmpname);
-       return NULL;
-}
-
-#endif /* __MINGW32__ */
-
-#endif /* BABELTRACE_HAVE_FMEMOPEN */
-
-
-#ifdef BABELTRACE_HAVE_OPEN_MEMSTREAM
-
-#include <stdio.h>
-
-static inline
-FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
-{
-       return open_memstream(ptr, sizeloc);
-}
-
-static inline
-int bt_close_memstream(char **buf, size_t *size, FILE *fp)
-{
-       return fclose(fp);
-}
-
-#else /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <glib.h>
-
-#ifdef __MINGW32__
-
-/*
- * Fallback for systems which don't have open_memstream. Create FILE *
- * with bt_open_memstream, but require call to
- * bt_close_memstream to flush all data written to the FILE *
- * into the buffer (which we allocate).
- */
-static inline
-FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
-{
-       char *tmpname;
-       FILE *fp;
-
-       tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
-
-       if (_mktemp(tmpname) == NULL) {
-               goto error_free;
-       }
-
-       /*
-        * Open as a read/write binary temporary deleted on close file.
-        * Will be deleted when the last file pointer is closed.
-        */
-       fp = fopen(tmpname, "w+bTD");
-       if (!fp) {
-               goto error_free;
-       }
-
-       g_free(tmpname);
-       return fp;
-
-error_free:
-       g_free(tmpname);
-       return NULL;
-}
-
-#else /* __MINGW32__ */
-
-/*
- * Fallback for systems which don't have open_memstream. Create FILE *
- * with bt_open_memstream, but require call to
- * bt_close_memstream to flush all data written to the FILE *
- * into the buffer (which we allocate).
- */
-static inline
-FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
-{
-       char *tmpname;
-       int ret;
-       FILE *fp;
-
-       tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
-
-       ret = mkstemp(tmpname);
-       if (ret < 0) {
-               perror("mkstemp");
-               g_free(tmpname);
-               return NULL;
-       }
-       fp = fdopen(ret, "wb+");
-       if (!fp) {
-               goto error_unlink;
-       }
-       /*
-        * babeltrace_flush_memstream will update the buffer content
-        * with read from fp. No need to keep the file around, just the
-        * handle.
-        */
-       ret = unlink(tmpname);
-       if (ret < 0) {
-               perror("unlink");
-       }
-       g_free(tmpname);
-       return fp;
-
-error_unlink:
-       ret = unlink(tmpname);
-       if (ret < 0) {
-               perror("unlink");
-       }
-       g_free(tmpname);
-       return NULL;
-}
-
-#endif /* __MINGW32__ */
-
-/* Get file size, allocate buffer, copy. */
-static inline
-int bt_close_memstream(char **buf, size_t *size, FILE *fp)
-{
-       size_t len, n;
-       long pos;
-       int ret;
-
-       ret = fflush(fp);
-       if (ret < 0) {
-               perror("fflush");
-               return ret;
-       }
-       ret = fseek(fp, 0L, SEEK_END);
-       if (ret < 0) {
-               perror("fseek");
-               return ret;
-       }
-       pos = ftell(fp);
-       if (ret < 0) {
-               perror("ftell");
-               return ret;
-       }
-       *size = pos;
-       /* add final \0 */
-       *buf = calloc(pos + 1, sizeof(char));
-       if (!*buf) {
-               return -ENOMEM;
-       }
-       ret = fseek(fp, 0L, SEEK_SET);
-       if (ret < 0) {
-               perror("fseek");
-               goto error_free;
-       }
-       /* Copy the entire file into the buffer */
-       n = 0;
-       clearerr(fp);
-       while (!feof(fp) && !ferror(fp) && (*size - n > 0)) {
-               len = fread(*buf, sizeof(char), *size - n, fp);
-               n += len;
-       }
-       if (n != *size) {
-               ret = -1;
-               goto error_close;
-       }
-       ret = fclose(fp);
-       if (ret < 0) {
-               perror("fclose");
-               return ret;
-       }
-       return 0;
-
-error_close:
-       ret = fclose(fp);
-       if (ret < 0) {
-               perror("fclose");
-       }
-error_free:
-       free(*buf);
-       *buf = NULL;
-       return ret;
-}
-
-#endif /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
-
-#endif /* _BABELTRACE_FORMAT_CTF_MEMSTREAM_H */
diff --git a/include/babeltrace2/compat/mman-internal.h b/include/babeltrace2/compat/mman-internal.h
deleted file mode 100644 (file)
index 9f49452..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_MMAN_H
-#define _BABELTRACE_COMPAT_MMAN_H
-
-/*
- * Copyright (C) 2015-2016  Michael Jeanson <mjeanson@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifdef __MINGW32__
-
-#include <sys/types.h>
-
-#define PROT_NONE      0x0
-#define PROT_READ      0x1
-#define PROT_WRITE     0x2
-#define PROT_EXEC      0x4
-
-#define MAP_FILE       0
-#define MAP_SHARED     1
-#define MAP_PRIVATE    2
-#define MAP_TYPE       0xF
-#define MAP_FIXED      0x10
-#define MAP_ANONYMOUS  0x20
-#define MAP_ANON       MAP_ANONYMOUS
-#define MAP_FAILED     ((void *) -1)
-
-/*
- * Note that some platforms (e.g. Windows) do not allow read-only
- * mappings to exceed the file's size (even within a page).
- */
-void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
-       off_t offset);
-
-int bt_munmap(void *addr, size_t length);
-
-#else /* __MINGW32__ */
-
-#include <sys/mman.h>
-
-static inline
-void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
-       off_t offset)
-{
-       return (void *) mmap(addr, length, prot, flags, fd, offset);
-}
-
-static inline
-int bt_munmap(void *addr, size_t length)
-{
-       return munmap(addr, length);
-}
-#endif /* __MINGW32__ */
-
-#ifndef MAP_ANONYMOUS
-# ifdef MAP_ANON
-#   define MAP_ANONYMOUS MAP_ANON
-# endif
-#endif
-
-#endif /* _BABELTRACE_COMPAT_MMAN_H */
diff --git a/include/babeltrace2/compat/socket-internal.h b/include/babeltrace2/compat/socket-internal.h
deleted file mode 100644 (file)
index b1fe159..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_SOCKET_H
-#define _BABELTRACE_COMPAT_SOCKET_H
-
-/*
- * Copyright (C) 2015-2017  Michael Jeanson <mjeanson@efficios.com>
- *               2015  Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifdef __MINGW32__
-
-#include <winsock2.h>
-
-#define BT_INVALID_SOCKET INVALID_SOCKET
-#define BT_SOCKET_ERROR SOCKET_ERROR
-#define BT_SOCKET SOCKET
-
-static inline
-int bt_socket_init(void)
-{
-       WORD verreq;
-       WSADATA wsa;
-       int ret;
-
-       /* Request winsock 2.2 support */
-       verreq = MAKEWORD(2, 2);
-
-       ret = WSAStartup(verreq, &wsa);
-       if (ret != 0) {
-#ifdef BT_LOGE
-               BT_LOGE("Winsock init failed with error: %d", ret);
-#endif
-               goto end;
-       }
-
-       if (LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 2) {
-#ifdef BT_LOGE_STR
-               BT_LOGE_STR("Could not init winsock 2.2 support");
-#endif
-               WSACleanup();
-               ret = -1;
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int bt_socket_fini(void)
-{
-       return WSACleanup();
-}
-
-static inline
-int bt_socket_send(int sockfd, const void *buf, size_t len, int flags)
-{
-       return send(sockfd, buf, len, flags);
-}
-
-static inline
-int bt_socket_recv(int sockfd, void *buf, size_t len, int flags)
-{
-       return recv(sockfd, buf, len, flags);
-}
-
-static inline
-int bt_socket_close(int fd)
-{
-       return closesocket(fd);
-}
-
-static inline
-bool bt_socket_interrupted(void)
-{
-       /* There is no equivalent to EINTR in winsock 2.2 */
-       return false;
-}
-
-static inline
-const char *bt_socket_errormsg(void)
-{
-       const char *errstr;
-       int error = WSAGetLastError();
-
-       switch (error) {
-       case WSAEINTR:
-               errstr = "Call interrupted";
-               break;
-       case WSAEBADF:
-               errstr = "Bad file";
-               break;
-       case WSAEACCES:
-               errstr = "Bad access";
-               break;
-       case WSAEFAULT:
-               errstr = "Bad argument";
-               break;
-       case WSAEINVAL:
-               errstr = "Invalid arguments";
-               break;
-       case WSAEMFILE:
-               errstr = "Out of file descriptors";
-               break;
-       case WSAEWOULDBLOCK:
-               errstr = "Call would block";
-               break;
-       case WSAEINPROGRESS:
-       case WSAEALREADY:
-               errstr = "Blocking call in progress";
-               break;
-       case WSAENOTSOCK:
-               errstr = "Descriptor is not a socket";
-               break;
-       case WSAEDESTADDRREQ:
-               errstr = "Need destination address";
-               break;
-       case WSAEMSGSIZE:
-               errstr = "Bad message size";
-               break;
-       case WSAEPROTOTYPE:
-               errstr = "Bad protocol";
-               break;
-       case WSAENOPROTOOPT:
-               errstr = "Protocol option is unsupported";
-               break;
-       case WSAEPROTONOSUPPORT:
-               errstr = "Protocol is unsupported";
-               break;
-       case WSAESOCKTNOSUPPORT:
-               errstr = "Socket is unsupported";
-               break;
-       case WSAEOPNOTSUPP:
-               errstr = "Operation not supported";
-               break;
-       case WSAEAFNOSUPPORT:
-               errstr = "Address family not supported";
-               break;
-       case WSAEPFNOSUPPORT:
-               errstr = "Protocol family not supported";
-               break;
-       case WSAEADDRINUSE:
-               errstr = "Address already in use";
-               break;
-       case WSAEADDRNOTAVAIL:
-               errstr = "Address not available";
-               break;
-       case WSAENETDOWN:
-               errstr = "Network down";
-               break;
-       case WSAENETUNREACH:
-               errstr = "Network unreachable";
-               break;
-       case WSAENETRESET:
-               errstr = "Network has been reset";
-               break;
-       case WSAECONNABORTED:
-               errstr = "Connection was aborted";
-               break;
-       case WSAECONNRESET:
-               errstr = "Connection was reset";
-               break;
-       case WSAENOBUFS:
-               errstr = "No buffer space";
-               break;
-       case WSAEISCONN:
-               errstr = "Socket is already connected";
-               break;
-       case WSAENOTCONN:
-               errstr = "Socket is not connected";
-               break;
-       case WSAESHUTDOWN:
-               errstr = "Socket has been shut down";
-               break;
-       case WSAETOOMANYREFS:
-               errstr = "Too many references";
-               break;
-       case WSAETIMEDOUT:
-               errstr = "Timed out";
-               break;
-       case WSAECONNREFUSED:
-               errstr = "Connection refused";
-               break;
-       case WSAELOOP:
-               errstr = "Loop??";
-               break;
-       case WSAENAMETOOLONG:
-               errstr = "Name too long";
-               break;
-       case WSAEHOSTDOWN:
-               errstr = "Host down";
-               break;
-       case WSAEHOSTUNREACH:
-               errstr = "Host unreachable";
-               break;
-       case WSAENOTEMPTY:
-               errstr = "Not empty";
-               break;
-       case WSAEPROCLIM:
-               errstr = "Process limit reached";
-               break;
-       case WSAEUSERS:
-               errstr = "Too many users";
-               break;
-       case WSAEDQUOT:
-               errstr = "Bad quota";
-               break;
-       case WSAESTALE:
-               errstr = "Something is stale";
-               break;
-       case WSAEREMOTE:
-               errstr = "Remote error";
-               break;
-       case WSAEDISCON:
-               errstr = "Disconnected";
-               break;
-
-       /* Extended Winsock errors */
-       case WSASYSNOTREADY:
-               errstr = "Winsock library is not ready";
-               break;
-       case WSANOTINITIALISED:
-               errstr = "Winsock library not initialised";
-               break;
-       case WSAVERNOTSUPPORTED:
-               errstr = "Winsock version not supported";
-               break;
-
-       /* getXbyY() errors (already handled in herrmsg):
-        * Authoritative Answer: Host not found */
-       case WSAHOST_NOT_FOUND:
-               errstr = "Host not found";
-               break;
-
-       /* Non-Authoritative: Host not found, or SERVERFAIL */
-       case WSATRY_AGAIN:
-               errstr = "Host not found, try again";
-               break;
-
-       /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
-       case WSANO_RECOVERY:
-               errstr = "Unrecoverable error in call to nameserver";
-               break;
-
-       /* Valid name, no data record of requested type */
-       case WSANO_DATA:
-               errstr = "No data record of requested type";
-               break;
-
-       default:
-               errstr = "Unknown error";
-       }
-
-       return errstr;
-}
-
-#else /* __MINGW32__ */
-
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-
-#define BT_INVALID_SOCKET -1
-#define BT_SOCKET_ERROR -1
-#define BT_SOCKET int
-
-static inline
-int bt_socket_init(void)
-{
-       return 0;
-}
-
-static inline
-int bt_socket_fini(void)
-{
-       return 0;
-}
-
-static inline
-int bt_socket_send(int sockfd, const void *buf, size_t len, int flags)
-{
-       return send(sockfd, buf, len, flags);
-}
-
-static inline
-int bt_socket_recv(int sockfd, void *buf, size_t len, int flags)
-{
-       return recv(sockfd, buf, len, flags);
-}
-
-static inline
-int bt_socket_close(int fd)
-{
-       return close(fd);
-}
-
-static inline
-bool bt_socket_interrupted(void)
-{
-       return (errno == EINTR);
-}
-
-static inline
-const char *bt_socket_errormsg(void)
-{
-       return g_strerror(errno);
-}
-#endif
-
-
-/*
- * This wrapper is used on platforms that have no way of ignoring SIGPIPE
- * during a send().
- */
-
-#ifndef MSG_NOSIGNAL
-# ifdef SO_NOSIGPIPE
-#   define MSG_NOSIGNAL SO_NOSIGPIPE
-# elif defined(__MINGW32__)
-#   define MSG_NOSIGNAL 0
-# endif
-#endif
-
-#if defined(MSG_NOSIGNAL)
-static inline
-ssize_t bt_socket_send_nosigpipe(int fd, const void *buffer, size_t size)
-{
-       return bt_socket_send(fd, buffer, size, MSG_NOSIGNAL);
-}
-#else
-
-#include <signal.h>
-
-static inline
-ssize_t bt_socket_send_nosigpipe(int fd, const void *buffer, size_t size)
-{
-       ssize_t sent;
-       int saved_err;
-       sigset_t sigpipe_set, pending_set, old_set;
-       int sigpipe_was_pending;
-
-       /*
-        * Discard the SIGPIPE from send(), not disturbing any SIGPIPE
-        * that might be already pending. If a bogus SIGPIPE is sent to
-        * the entire process concurrently by a malicious user, it may
-        * be simply discarded.
-        */
-       if (sigemptyset(&pending_set)) {
-               return -1;
-       }
-       /*
-        * sigpending returns the mask of signals that are _both_
-        * blocked for the thread _and_ pending for either the thread or
-        * the entire process.
-        */
-       if (sigpending(&pending_set)) {
-               return -1;
-       }
-       sigpipe_was_pending = sigismember(&pending_set, SIGPIPE);
-       /*
-        * If sigpipe was pending, it means it was already blocked, so
-        * no need to block it.
-        */
-       if (!sigpipe_was_pending) {
-               if (sigemptyset(&sigpipe_set)) {
-                       return -1;
-               }
-               if (sigaddset(&sigpipe_set, SIGPIPE)) {
-                       return -1;
-               }
-               if (pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set)) {
-                       return -1;
-               }
-       }
-
-       /* Send and save errno. */
-       sent = bt_socket_send(fd, buffer, size, 0);
-       saved_err = errno;
-
-       if (sent == -1 && errno == EPIPE && !sigpipe_was_pending) {
-               struct timespec timeout = { 0, 0 };
-               int ret;
-
-               do {
-                       ret = sigtimedwait(&sigpipe_set, NULL,
-                               &timeout);
-               } while (ret == -1 && errno == EINTR);
-       }
-       if (!sigpipe_was_pending) {
-               if (pthread_sigmask(SIG_SETMASK, &old_set, NULL)) {
-                       return -1;
-               }
-       }
-       /* Restore send() errno */
-       errno = saved_err;
-
-       return sent;
-}
-#endif
-
-
-#endif /* _BABELTRACE_COMPAT_SOCKET_H */
diff --git a/include/babeltrace2/compat/stdio-internal.h b/include/babeltrace2/compat/stdio-internal.h
deleted file mode 100644 (file)
index 4c73763..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_STDIO_H
-#define _BABELTRACE_COMPAT_STDIO_H
-
-/*
- * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <babeltrace2/assert-internal.h>
-
-#define BT_GETLINE_MINBUFLEN   64
-
-static inline
-char * _bt_getline_bufalloc(char **lineptr, size_t *n, size_t linelen)
-{
-       size_t buflen = *n;
-       char *buf = *lineptr;
-
-       if (buflen >= linelen && buf != NULL) {
-               return buf;
-       }
-       if (buf == NULL) {
-               buflen = BT_GETLINE_MINBUFLEN;
-       } else {
-               buflen = buflen << 1;
-               if (buflen < BT_GETLINE_MINBUFLEN) {
-                       buflen = BT_GETLINE_MINBUFLEN;
-               }
-       }
-       /* Check below not strictly needed, extra safety. */
-       if (buflen < linelen) {
-               buflen = linelen;
-       }
-       buf = realloc(buf, buflen);
-       if (!buf) {
-               errno = ENOMEM;
-               return NULL;
-       }
-       *n = buflen;
-       *lineptr = buf;
-       return buf;
-}
-
-/*
- * Returns line length (including possible final \n, excluding final
- * \0). On end of file, returns -1 with nonzero feof(stream) and errno
- * set to 0. On error, returns -1 with errno set.
- *
- * This interface is similar to the getline(3) man page part of the
- * Linux man-pages project, release 3.74. One major difference from the
- * Open Group POSIX specification is that this implementation does not
- * necessarily set the ferror() flag on error (because it is internal to
- * libc).
- */
-static inline
-ssize_t bt_getline(char **lineptr, size_t *n, FILE *stream)
-{
-       size_t linelen = 0;
-       char *buf;
-       int found_eof = 0;
-
-       if (lineptr == NULL || n == NULL) {
-               errno = EINVAL;
-               return -1;
-       }
-       for (;;) {
-               char c;
-               int ret;
-
-               ret = fgetc(stream);
-               if (ret == EOF) {
-                       if (ferror(stream)) {
-                               /* ferror() is set, errno set by fgetc(). */
-                               return -1;
-                       }
-                       BT_ASSERT(feof(stream));
-                       found_eof = 1;
-                       break;
-               }
-               c = (char) ret;
-               if (linelen == SSIZE_MAX) {
-                       errno = EOVERFLOW;
-                       return -1;
-               }
-               buf = _bt_getline_bufalloc(lineptr, n, ++linelen);
-               if (!buf) {
-                       return -1;
-               }
-               buf[linelen - 1] = c;
-               if (c == '\n') {
-                       break;
-               }
-       }
-       if (!linelen && found_eof) {
-               /* feof() is set. */
-               errno = 0;
-               return -1;
-       }
-       buf = _bt_getline_bufalloc(lineptr, n, ++linelen);
-       if (!buf) {
-               return -1;
-       }
-       buf[linelen - 1] = '\0';
-       return linelen - 1;     /* Count don't include final \0. */
-}
-
-#endif /* _BABELTRACE_COMPAT_STDIO_H */
diff --git a/include/babeltrace2/compat/stdlib-internal.h b/include/babeltrace2/compat/stdlib-internal.h
deleted file mode 100644 (file)
index bd2a2c9..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_STDLIB_H
-#define _BABELTRACE_COMPAT_STDLIB_H
-
-/*
- * Copyright (C) 2015 Michael Jeanson <mjeanson@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This compat wrapper can be removed and replaced by g_mkdtemp() when we bump
- * the requirement on glib to version 2.30.
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <glib.h>
-
-#ifdef HAVE_MKDTEMP
-
-static inline
-char *bt_mkdtemp(char *template)
-{
-       return mkdtemp(template);
-}
-
-#elif GLIB_CHECK_VERSION(2,30,0)
-
-#include <glib/gstdio.h>
-static inline
-char *bt_mkdtemp(char *template)
-{
-       return g_mkdtemp(template);
-}
-
-#else
-
-static inline
-char *bt_mkdtemp(char *template)
-{
-       char *ret;
-
-       ret = mktemp(template);
-       if (!ret) {
-               goto end;
-       }
-
-       if(mkdir(template, 0700)) {
-               ret = NULL;
-               goto end;
-       }
-
-       ret = template;
-end:
-       return ret;
-}
-
-#endif
-
-#endif /* _BABELTRACE_COMPAT_STDLIB_H */
diff --git a/include/babeltrace2/compat/string-internal.h b/include/babeltrace2/compat/string-internal.h
deleted file mode 100644 (file)
index c3325a3..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_STRING_H
-#define _BABELTRACE_COMPAT_STRING_H
-
-/*
- * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <string.h>
-#include <stdlib.h>
-
-#ifdef HAVE_STRNLEN
-static inline
-size_t bt_strnlen(const char *str, size_t max)
-{
-       return strnlen(str, max);
-}
-#else
-static inline
-size_t bt_strnlen(const char *str, size_t max)
-{
-       size_t ret;
-       const char *end;
-
-       end = memchr(str, 0, max);
-
-       if (end) {
-               ret = (size_t) (end - str);
-       } else {
-               ret = max;
-       }
-
-       return ret;
-}
-#endif /* HAVE_STRNLEN */
-
-#ifdef HAVE_STRNDUP
-static inline
-char *bt_strndup(const char *s, size_t n)
-{
-       return strndup(s, n);
-}
-#else
-static inline
-char *bt_strndup(const char *s, size_t n)
-{
-       char *ret;
-       size_t navail;
-
-       if (!s) {
-               ret = NULL;
-               goto end;
-       }
-
-       /* min() */
-       navail = strlen(s) + 1;
-       if ((n + 1) < navail) {
-               navail = n + 1;
-       }
-
-       ret = malloc(navail);
-       if (!ret) {
-               goto end;
-       }
-
-       memcpy(ret, s, navail);
-       ret[navail - 1] = '\0';
-end:
-       return ret;
-}
-#endif /* HAVE_STRNDUP */
-
-#endif /* _BABELTRACE_COMPAT_STRING_H */
diff --git a/include/babeltrace2/compat/time-internal.h b/include/babeltrace2/compat/time-internal.h
deleted file mode 100644 (file)
index f5c09a9..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef _BABELTRACE_INCLUDE_COMPAT_TIME_H
-#define _BABELTRACE_INCLUDE_COMPAT_TIME_H
-
-/*
- * Copyright (C) 2013 JP Ikaheimonen <jp_ikaheimonen@mentor.com>
- *               2016 Michael Jeanson <mjeanson@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-
-#include <time.h>
-#include <stdlib.h>
-
-#ifdef __MINGW32__
-
-#include <string.h>
-
-/*
- * The Windows version of the time functions use one common tm structure per
- * thread which makes them thread-safe. Implement the POSIX _r variants by
- * copying this to a user supplied struct.
- */
-
-static inline
-struct tm *bt_gmtime_r(const time_t *timep, struct tm *result)
-{
-       struct tm *local_res;
-
-       if (!result) {
-               goto error;
-       }
-
-       local_res = gmtime(timep);
-       if (!local_res) {
-               result = NULL;
-               goto error;
-       }
-
-       memcpy(result, local_res, sizeof(struct tm));
-
-error:
-       return result;
-}
-
-static inline
-struct tm *bt_localtime_r(const time_t *timep, struct tm *result)
-{
-       struct tm *local_res;
-
-       if (!result) {
-               goto error;
-       }
-
-       local_res = localtime(timep);
-       if (!local_res) {
-               result = NULL;
-               goto error;
-       }
-
-       memcpy(result, local_res, sizeof(struct tm));
-
-error:
-       return result;
-}
-
-#else /* __MINGW32__ */
-
-static inline
-struct tm *bt_gmtime_r(const time_t *timep, struct tm *result)
-{
-       return gmtime_r(timep, result);
-}
-
-static inline
-struct tm *bt_localtime_r(const time_t *timep, struct tm *result)
-{
-       return localtime_r(timep, result);
-}
-
-#endif /* __MINGW32__ */
-#endif /* _BABELTRACE_INCLUDE_COMPAT_TIME_H */
diff --git a/include/babeltrace2/compat/unistd-internal.h b/include/babeltrace2/compat/unistd-internal.h
deleted file mode 100644 (file)
index 502e87a..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_UNISTD_H
-#define _BABELTRACE_COMPAT_UNISTD_H
-
-/*
- * (C) Copyright 2016 - Michael Jeanson <mjeanson@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-
-#include <unistd.h>
-
-#ifdef __MINGW32__
-#include <windows.h>
-#include <errno.h>
-
-#define _SC_PAGESIZE 30
-
-static inline
-long bt_sysconf(int name)
-{
-       SYSTEM_INFO si;
-
-       switch(name) {
-       case _SC_PAGESIZE:
-               GetNativeSystemInfo(&si);
-               return si.dwPageSize;
-       default:
-               errno = EINVAL;
-               return -1;
-       }
-}
-
-#else
-
-static inline
-long bt_sysconf(int name)
-{
-       return sysconf(name);
-}
-
-#endif
-#endif /* _BABELTRACE_COMPAT_UNISTD_H */
diff --git a/include/babeltrace2/compat/utc-internal.h b/include/babeltrace2/compat/utc-internal.h
deleted file mode 100644 (file)
index 3660e08..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef _BABELTRACE_UTC_H
-#define _BABELTRACE_UTC_H
-
-/*
- * Copyright (C) 2011-2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <time.h>
-
-/* If set, use GNU or BSD timegm(3) */
-#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
-
-static inline
-time_t bt_timegm(struct tm *tm)
-{
-       return timegm(tm);
-}
-
-#elif defined(__MINGW32__)
-
-static inline
-time_t bt_timegm(struct tm *tm)
-{
-       return _mkgmtime(tm);
-}
-
-#else
-
-#include <errno.h>
-
-/*
- * This is a simple implementation of timegm() it just turns the "struct tm" into
- * a GMT time_t. It does not normalize any of the fields of the "struct tm", nor
- * does it set tm_wday or tm_yday.
- */
-
-static inline
-int bt_leapyear(int year)
-{
-    return ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0));
-}
-
-static inline
-time_t bt_timegm(struct tm *tm)
-{
-       int year, month, total_days;
-
-       int monthlen[2][12] = {
-               /* Days per month for a regular year */
-               { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
-               /* Days per month for a leap year */
-               { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
-       };
-
-       if ((tm->tm_mon >= 12) ||
-                       (tm->tm_mday >= 32) ||
-                       (tm->tm_hour >= 24) ||
-                       (tm->tm_min >= 60) ||
-                       (tm->tm_sec >= 61)) {
-               errno = EOVERFLOW;
-               return (time_t) -1;
-       }
-
-       /* Add 365 days for each year since 1970 */
-       total_days = 365 * (tm->tm_year - 70);
-
-       /* Add one day for each leap year since 1970 */
-       for (year = 70; year < tm->tm_year; year++) {
-               if (bt_leapyear(1900 + year)) {
-                       total_days++;
-               }
-       }
-
-       /* Add days for each remaining month */
-       for (month = 0; month < tm->tm_mon; month++) {
-               total_days += monthlen[bt_leapyear(1900 + year)][month];
-       }
-
-       /* Add remaining days */
-       total_days += tm->tm_mday - 1;
-
-       return ((((total_days * 24) + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec);
-}
-
-#endif
-
-#endif /* _BABELTRACE_UTC_H */
diff --git a/include/babeltrace2/compat/uuid-internal.h b/include/babeltrace2/compat/uuid-internal.h
deleted file mode 100644 (file)
index 2c2e929..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-#ifndef _BABELTRACE_COMPAT_UUID_H
-#define _BABELTRACE_COMPAT_UUID_H
-
-/*
- * Copyright (C) 2011   Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/* Includes final \0. */
-#define BABELTRACE_UUID_STR_LEN                37
-#define BABELTRACE_UUID_LEN            16
-
-#ifdef BABELTRACE_HAVE_LIBUUID
-#include <uuid/uuid.h>
-
-static inline
-int bt_uuid_generate(unsigned char *uuid_out)
-{
-       uuid_generate(uuid_out);
-       return 0;
-}
-
-/* Sun's libuuid lacks const qualifiers */
-#if defined(__sun__)
-static inline
-int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out)
-{
-       uuid_unparse((unsigned char *) uuid_in, str_out);
-       return 0;
-}
-
-static inline
-int bt_uuid_parse(const char *str_in, unsigned char *uuid_out)
-{
-       return uuid_parse((char *) str_in, uuid_out);
-}
-
-static inline
-int bt_uuid_compare(const unsigned char *uuid_a,
-               const unsigned char *uuid_b)
-{
-       return uuid_compare((unsigned char *) uuid_a,
-               (unsigned char *) uuid_b);
-}
-#else
-static inline
-int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out)
-{
-       uuid_unparse(uuid_in, str_out);
-       return 0;
-}
-
-static inline
-int bt_uuid_parse(const char *str_in, unsigned char *uuid_out)
-{
-       return uuid_parse(str_in, uuid_out);
-}
-
-static inline
-int bt_uuid_compare(const unsigned char *uuid_a,
-               const unsigned char *uuid_b)
-{
-       return uuid_compare(uuid_a, uuid_b);
-}
-#endif
-
-#elif defined(BABELTRACE_HAVE_LIBC_UUID)
-#include <uuid.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-
-static inline
-int bt_uuid_generate(unsigned char *uuid_out)
-{
-       uint32_t status;
-
-       uuid_create((uuid_t *) uuid_out, &status);
-       if (status == uuid_s_ok)
-               return 0;
-       else
-               return -1;
-}
-
-static inline
-int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out)
-{
-       uint32_t status;
-       char *alloc_str;
-       int ret;
-
-       uuid_to_string((uuid_t *) uuid_in, &alloc_str, &status);
-       if (status == uuid_s_ok) {
-               strcpy(str_out, alloc_str);
-               ret = 0;
-       } else {
-               ret = -1;
-       }
-       free(alloc_str);
-       return ret;
-}
-
-static inline
-int bt_uuid_parse(const char *str_in, unsigned char *uuid_out)
-{
-       uint32_t status;
-
-       uuid_from_string(str_in, (uuid_t *) uuid_out, &status);
-       if (status == uuid_s_ok)
-               return 0;
-       else
-               return -1;
-}
-
-static inline
-int bt_uuid_compare(const unsigned char *uuid_a,
-               const unsigned char *uuid_b)
-{
-       uint32_t status;
-
-       uuid_compare((uuid_t *) uuid_a, (uuid_t *) uuid_b, &status);
-       if (status == uuid_s_ok)
-               return 0;
-       else
-               return -1;
-}
-
-#elif defined(__MINGW32__)
-
-int bt_uuid_generate(unsigned char *uuid_out);
-int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out);
-int bt_uuid_parse(const char *str_in, unsigned char *uuid_out);
-int bt_uuid_compare(const unsigned char *uuid_a,
-               const unsigned char *uuid_b);
-
-#else
-#error "Babeltrace needs to have a UUID generator configured."
-#endif
-
-#endif /* _BABELTRACE_COMPAT_UUID_H */
diff --git a/include/babeltrace2/compiler-internal.h b/include/babeltrace2/compiler-internal.h
deleted file mode 100644 (file)
index c4c72cc..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef _BABELTRACE_COMPILER_H
-#define _BABELTRACE_COMPILER_H
-
-/*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stddef.h>    /* for offsetof */
-
-#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
-
-#ifndef container_of
-#define container_of(ptr, type, member)                                        \
-       ({                                                              \
-               const typeof(((type *)NULL)->member) * __ptr = (ptr);   \
-               (type *)((char *)__ptr - offsetof(type, member));       \
-       })
-#endif
-
-#define BT_ARRAY_SIZE(arr)     (sizeof(arr) / sizeof((arr)[0]))
-
-#endif /* _BABELTRACE_COMPILER_H */
diff --git a/include/babeltrace2/ctf-writer/assert-pre-internal.h b/include/babeltrace2/ctf-writer/assert-pre-internal.h
deleted file mode 100644 (file)
index 3ac3af1..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H
-
-/*
- * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * The macros in this header use macros defined in
- * <babeltrace2/lib-logging-internal.h>. We don't want this header to
- * automatically include <babeltrace2/lib-logging-internal.h> because you
- * need to manually define BT_LOG_TAG before including
- * <babeltrace2/lib-logging-internal.h> and it is unexpected that you
- * also need to define it before including this header.
- *
- * This is a reminder that in order to use
- * <babeltrace2/assert-pre-internal.h>, you also need to use logging
- * explicitly.
- */
-
-#ifndef BABELTRACE_LOGGING_INTERNAL_H
-# error Include <babeltrace2/logging-internal.h> before this header.
-#endif
-
-#include <stdlib.h>
-#include <inttypes.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#ifdef BT_DEV_MODE
-/*
- * Asserts that the library precondition _cond is satisfied.
- *
- * If _cond is false, log a fatal statement using _fmt and the optional
- * arguments using BT_LOGF(), and abort.
- *
- * To assert that a postcondition is satisfied or that some internal
- * object/context/value is in the expected state, use BT_ASSERT().
- */
-# define BT_CTF_ASSERT_PRE(_cond, _fmt, ...)                           \
-       do {                                                            \
-               if (!(_cond)) {                                         \
-                       BT_LOGF_STR("Library precondition not satisfied; error is:"); \
-                       BT_LOGF((_fmt), ##__VA_ARGS__);         \
-                       BT_LOGF_STR("Aborting...");                     \
-                       abort();                                        \
-               }                                                       \
-       } while (0)
-
-/*
- * Marks a function as being only used within a BT_CTF_ASSERT_PRE() context.
- */
-# define BT_CTF_ASSERT_PRE_FUNC
-
-/*
- * Prints the details of an unsatisfied precondition without immediately
- * aborting. You should use this within a function which checks
- * preconditions, but which is called from a BT_CTF_ASSERT_PRE() context, so
- * that the function can still return its result for BT_CTF_ASSERT_PRE() to
- * evaluate it.
- *
- * Example:
- *
- *     BT_CTF_ASSERT_PRE_FUNC
- *     static inline bool check_complex_precond(...)
- *     {
- *         ...
- *
- *         if (...) {
- *             BT_CTF_ASSERT_PRE_MSG("Invalid object: ...", ...);
- *             return false;
- *         }
- *
- *         ...
- *     }
- *
- *     ...
- *
- *     BT_CTF_ASSERT_PRE(check_complex_precond(...),
- *                   "Precondition is not satisfied: ...", ...);
- */
-# define BT_CTF_ASSERT_PRE_MSG BT_LOGF
-#else
-# define BT_CTF_ASSERT_PRE(_cond, _fmt, ...)   ((void) sizeof((void) (_cond), 0))
-# define BT_CTF_ASSERT_PRE_FUNC        BT_UNUSED
-# define BT_CTF_ASSERT_PRE_MSG(_fmt, ...)
-#endif /* BT_DEV_MODE */
-
-/*
- * Developer mode: asserts that a given variable is not NULL.
- */
-#define BT_CTF_ASSERT_PRE_NON_NULL(_obj, _obj_name)                            \
-       BT_CTF_ASSERT_PRE((_obj) != NULL, "%s is NULL: ", _obj_name)
-
-/*
- * Developer mode: asserts that a given object is NOT frozen. This macro
- * checks the `frozen` field of _obj.
- */
-#define BT_CTF_ASSERT_PRE_HOT(_obj, _obj_name, _fmt, ...)                      \
-       BT_CTF_ASSERT_PRE(!(_obj)->frozen, "%s is frozen" _fmt, _obj_name,      \
-               ##__VA_ARGS__)
-
-/*
- * Developer mode: asserts that a given index is less than a given size.
- */
-#define BT_CTF_ASSERT_PRE_VALID_INDEX(_index, _length)                 \
-       BT_CTF_ASSERT_PRE((_index) < (_length),                         \
-               "Index is out of bounds: index=%" PRIu64 ", "           \
-               "count=%" PRIu64, (uint64_t) (_index), (uint64_t) (_length))
-
-#endif /* BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/attributes-internal.h b/include/babeltrace2/ctf-writer/attributes-internal.h
deleted file mode 100644 (file)
index cb36512..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_ATTRIBUTES_H
-#define BABELTRACE_CTF_WRITER_ATTRIBUTES_H
-
-/*
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_create(void);
-
-BT_HIDDEN
-void bt_ctf_attributes_destroy(struct bt_ctf_private_value *attr_obj);
-
-BT_HIDDEN
-int64_t bt_ctf_attributes_get_count(struct bt_ctf_private_value *attr_obj);
-
-BT_HIDDEN
-const char *bt_ctf_attributes_get_field_name(struct bt_ctf_private_value *attr_obj,
-               uint64_t index);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value(struct bt_ctf_private_value *attr_obj,
-               uint64_t index);
-
-BT_HIDDEN
-int bt_ctf_attributes_set_field_value(struct bt_ctf_private_value *attr_obj,
-               const char *name, struct bt_ctf_private_value *value_obj);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value_by_name(
-               struct bt_ctf_private_value *attr_obj, const char *name);
-
-BT_HIDDEN
-int bt_ctf_attributes_freeze(struct bt_ctf_private_value *attr_obj);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BABELTRACE_CTF_WRITER_ATTRIBUTES_H */
diff --git a/include/babeltrace2/ctf-writer/clock-class-internal.h b/include/babeltrace2/ctf-writer/clock-class-internal.h
deleted file mode 100644 (file)
index a9d9672..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_CLOCK_CLASS_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_CLOCK_CLASS_INTERNAL_H
-
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/types.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <glib.h>
-
-struct bt_ctf_clock_class {
-       struct bt_ctf_object base;
-       GString *name;
-       GString *description;
-       uint64_t frequency;
-       uint64_t precision;
-       int64_t offset_s;       /* Offset in seconds */
-       int64_t offset;         /* Offset in ticks */
-       unsigned char uuid[BABELTRACE_UUID_LEN];
-       int uuid_set;
-       int absolute;
-
-       /*
-        * A clock's properties can't be modified once it is added to a stream
-        * class.
-        */
-       int frozen;
-};
-
-BT_HIDDEN
-void bt_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class);
-
-BT_HIDDEN
-bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class);
-
-BT_HIDDEN
-int bt_ctf_clock_class_compare(struct bt_ctf_clock_class *clock_class_a,
-               struct bt_ctf_clock_class *clock_class_b);
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name,
-               uint64_t freq);
-BT_HIDDEN
-const char *bt_ctf_clock_class_get_name(
-               struct bt_ctf_clock_class *clock_class);
-BT_HIDDEN
-int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class,
-               const char *name);
-BT_HIDDEN
-const char *bt_ctf_clock_class_get_description(
-               struct bt_ctf_clock_class *clock_class);
-BT_HIDDEN
-int bt_ctf_clock_class_set_description(
-               struct bt_ctf_clock_class *clock_class,
-               const char *desc);
-BT_HIDDEN
-uint64_t bt_ctf_clock_class_get_frequency(
-               struct bt_ctf_clock_class *clock_class);
-BT_HIDDEN
-int bt_ctf_clock_class_set_frequency(
-               struct bt_ctf_clock_class *clock_class, uint64_t freq);
-BT_HIDDEN
-uint64_t bt_ctf_clock_class_get_precision(
-               struct bt_ctf_clock_class *clock_class);
-BT_HIDDEN
-int bt_ctf_clock_class_set_precision(
-               struct bt_ctf_clock_class *clock_class, uint64_t precision);
-BT_HIDDEN
-int bt_ctf_clock_class_get_offset_s(
-               struct bt_ctf_clock_class *clock_class, int64_t *seconds);
-BT_HIDDEN
-int bt_ctf_clock_class_set_offset_s(
-               struct bt_ctf_clock_class *clock_class, int64_t seconds);
-BT_HIDDEN
-int bt_ctf_clock_class_get_offset_cycles(
-               struct bt_ctf_clock_class *clock_class, int64_t *cycles);
-BT_HIDDEN
-int bt_ctf_clock_class_set_offset_cycles(
-               struct bt_ctf_clock_class *clock_class, int64_t cycles);
-BT_HIDDEN
-bt_bool bt_ctf_clock_class_is_absolute(
-               struct bt_ctf_clock_class *clock_class);
-BT_HIDDEN
-int bt_ctf_clock_class_set_is_absolute(
-               struct bt_ctf_clock_class *clock_class, bt_bool is_absolute);
-BT_HIDDEN
-const unsigned char *bt_ctf_clock_class_get_uuid(
-               struct bt_ctf_clock_class *clock_class);
-BT_HIDDEN
-int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class,
-               const unsigned char *uuid);
-
-#endif /* BABELTRACE_CTF_WRITER_CLOCK_CLASS_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/clock-internal.h b/include/babeltrace2/ctf-writer/clock-internal.h
deleted file mode 100644 (file)
index 8d3e141..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H
-
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/ctf-writer/clock.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <glib.h>
-#include <babeltrace2/compat/uuid-internal.h>
-
-struct bt_ctf_clock {
-       struct bt_ctf_object base;
-       struct bt_ctf_clock_class *clock_class;
-       uint64_t value;         /* Current clock value */
-};
-
-struct metadata_context;
-
-BT_HIDDEN
-int bt_ctf_clock_get_value(struct bt_ctf_clock *clock, uint64_t *value);
-
-BT_HIDDEN
-void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class,
-               struct metadata_context *context);
-
-#endif /* BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/event-class-internal.h b/include/babeltrace2/ctf-writer/event-class-internal.h
deleted file mode 100644 (file)
index c67184a..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_EVENT_CLASS_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_EVENT_CLASS_INTERNAL_H
-
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/stream.h>
-#include <babeltrace2/ctf-writer/trace-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <glib.h>
-
-struct bt_ctf_event_class_common {
-       struct bt_ctf_object base;
-       struct bt_ctf_field_type_common *context_field_type;
-       struct bt_ctf_field_type_common *payload_field_type;
-       int frozen;
-
-       /*
-        * This flag indicates if the event class is valid. A valid
-        * event class is _always_ frozen. However, an event class
-        * may be frozen, but not valid yet. This is okay, as long as
-        * no events are created out of this event class.
-        */
-       int valid;
-
-       /* Attributes */
-       GString *name;
-       int64_t id;
-       int log_level;
-       GString *emf_uri;
-};
-
-BT_HIDDEN
-void bt_ctf_event_class_common_freeze(struct bt_ctf_event_class_common *event_class);
-
-BT_HIDDEN
-void bt_ctf_event_class_common_set_native_byte_order(
-               struct bt_ctf_event_class_common *event_class, int byte_order);
-
-static inline
-struct bt_ctf_stream_class_common *bt_ctf_event_class_common_borrow_stream_class(
-               struct bt_ctf_event_class_common *event_class)
-{
-       BT_ASSERT(event_class);
-       return (void *) bt_ctf_object_borrow_parent(&event_class->base);
-}
-
-typedef struct bt_ctf_field_type_common *(*bt_ctf_field_type_structure_create_func)();
-
-BT_HIDDEN
-int bt_ctf_event_class_common_initialize(struct bt_ctf_event_class_common *event_class,
-               const char *name, bt_ctf_object_release_func release_func,
-               bt_ctf_field_type_structure_create_func ft_struct_create_func);
-
-BT_HIDDEN
-void bt_ctf_event_class_common_finalize(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-int bt_ctf_event_class_common_validate_single_clock_class(
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_clock_class **expected_clock_class);
-
-static inline
-const char *bt_ctf_event_class_common_get_name(
-               struct bt_ctf_event_class_common *event_class)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT(event_class->name);
-       return event_class->name->str;
-}
-
-static inline
-int64_t bt_ctf_event_class_common_get_id(
-               struct bt_ctf_event_class_common *event_class)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->id;
-}
-
-static inline
-int bt_ctf_event_class_common_set_id(
-               struct bt_ctf_event_class_common *event_class, uint64_t id_param)
-{
-       int ret = 0;
-       int64_t id = (int64_t) id_param;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class,
-                       bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (id < 0) {
-               BT_LOGW("Invalid parameter: invalid event class's ID: "
-                       "addr=%p, name=\"%s\", id=%" PRIu64,
-                       event_class,
-                       bt_ctf_event_class_common_get_name(event_class),
-                       id_param);
-               ret = -1;
-               goto end;
-       }
-
-       event_class->id = id;
-       BT_LOGV("Set event class's ID: "
-               "addr=%p, name=\"%s\", id=%" PRId64,
-               event_class, bt_ctf_event_class_common_get_name(event_class), id);
-
-end:
-       return ret;
-}
-
-static inline
-int bt_ctf_event_class_common_get_log_level(
-               struct bt_ctf_event_class_common *event_class)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->log_level;
-}
-
-static inline
-int bt_ctf_event_class_common_set_log_level(
-               struct bt_ctf_event_class_common *event_class, int log_level)
-{
-       int ret = 0;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class,
-                       bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       switch (log_level) {
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_ALERT:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_CRITICAL:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_ERROR:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_WARNING:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_NOTICE:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_INFO:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG:
-               break;
-       default:
-               BT_LOGW("Invalid parameter: unknown event class log level: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", log-level=%d",
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class), log_level);
-               ret = -1;
-               goto end;
-       }
-
-       event_class->log_level = log_level;
-       BT_LOGV("Set event class's log level: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", log-level=%s",
-               event_class, bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class),
-               bt_ctf_event_class_log_level_string(log_level));
-
-end:
-       return ret;
-}
-
-static inline
-const char *bt_ctf_event_class_common_get_emf_uri(
-               struct bt_ctf_event_class_common *event_class)
-{
-       const char *emf_uri = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
-
-       if (event_class->emf_uri->len > 0) {
-               emf_uri = event_class->emf_uri->str;
-       }
-
-       return emf_uri;
-}
-
-static inline
-int bt_ctf_event_class_common_set_emf_uri(
-               struct bt_ctf_event_class_common *event_class,
-               const char *emf_uri)
-{
-       int ret = 0;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (emf_uri && strlen(emf_uri) == 0) {
-               BT_LOGW_STR("Invalid parameter: EMF URI is empty.");
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (emf_uri) {
-               g_string_assign(event_class->emf_uri, emf_uri);
-               BT_LOGV("Set event class's EMF URI: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", emf-uri=\"%s\"",
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class), emf_uri);
-       } else {
-               g_string_assign(event_class->emf_uri, "");
-               BT_LOGV("Reset event class's EMF URI: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class));
-       }
-
-end:
-       return ret;
-}
-
-static inline
-struct bt_ctf_field_type_common *bt_ctf_event_class_common_borrow_context_field_type(
-               struct bt_ctf_event_class_common *event_class)
-{
-       struct bt_ctf_field_type_common *context_ft = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
-
-       if (!event_class->context_field_type) {
-               BT_LOGV("Event class has no context field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class));
-               goto end;
-       }
-
-       context_ft = event_class->context_field_type;
-
-end:
-       return context_ft;
-}
-
-static inline
-int bt_ctf_event_class_common_set_context_field_type(
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_field_type_common *context_ft)
-{
-       int ret = 0;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (event_class->frozen) {
-               BT_LOGW("Invalid parameter: event class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (context_ft && bt_ctf_field_type_common_get_type_id(context_ft) !=
-                       BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: event class's context field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "context-ft-id=%s",
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class),
-                       bt_ctf_field_type_id_string(
-                               bt_ctf_field_type_common_get_type_id(context_ft)));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(event_class->context_field_type);
-       event_class->context_field_type = context_ft;
-       bt_ctf_object_get_ref(event_class->context_field_type);
-       BT_LOGV("Set event class's context field type: "
-               "event-class-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", context-ft-addr=%p",
-               event_class, bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class), context_ft);
-
-end:
-       return ret;
-}
-
-static inline
-struct bt_ctf_field_type_common *bt_ctf_event_class_common_borrow_payload_field_type(
-               struct bt_ctf_event_class_common *event_class)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->payload_field_type;
-}
-
-static inline
-int bt_ctf_event_class_common_set_payload_field_type(
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_field_type_common *payload_ft)
-{
-       int ret = 0;
-
-       if (!event_class) {
-               BT_LOGW_STR("Invalid parameter: event class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (payload_ft && bt_ctf_field_type_common_get_type_id(payload_ft) !=
-                       BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               BT_LOGW("Invalid parameter: event class's payload field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "payload-ft-addr=%p, payload-ft-id=%s",
-                       event_class, bt_ctf_event_class_common_get_name(event_class),
-                       bt_ctf_event_class_common_get_id(event_class), payload_ft,
-                       bt_ctf_field_type_id_string(
-                               bt_ctf_field_type_common_get_type_id(payload_ft)));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(event_class->payload_field_type);
-       event_class->payload_field_type = payload_ft;
-       bt_ctf_object_get_ref(event_class->payload_field_type);
-       BT_LOGV("Set event class's payload field type: "
-               "event-class-addr=%p, event-class-name=\"%s\", "
-               "event-class-id=%" PRId64 ", payload-ft-addr=%p",
-               event_class, bt_ctf_event_class_common_get_name(event_class),
-               bt_ctf_event_class_common_get_id(event_class), payload_ft);
-end:
-       return ret;
-}
-
-#endif /* BABELTRACE_CTF_WRITER_EVENT_CLASS_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/event-internal.h b/include/babeltrace2/ctf-writer/event-internal.h
deleted file mode 100644 (file)
index 9703987..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H
-
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/event-class-internal.h>
-#include <babeltrace2/ctf-writer/event-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/field-wrapper-internal.h>
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/stream-class.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/stream.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/ctfser-internal.h>
-
-struct bt_ctf_stream_class;
-struct bt_ctf_stream_pos;
-struct metadata_context;
-
-struct bt_ctf_event_common {
-       struct bt_ctf_object base;
-       struct bt_ctf_event_class_common *class;
-       struct bt_ctf_field_wrapper *header_field;
-       struct bt_ctf_field_common *stream_event_context_field;
-       struct bt_ctf_field_common *context_field;
-       struct bt_ctf_field_common *payload_field;
-       int frozen;
-};
-
-BT_HIDDEN
-int _bt_ctf_event_common_validate(struct bt_ctf_event_common *event);
-
-BT_HIDDEN
-void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event,
-               bool is_frozen);
-
-#ifdef BT_DEV_MODE
-# define bt_ctf_event_common_validate  _bt_ctf_event_common_validate
-# define bt_ctf_event_common_set_is_frozen     _bt_ctf_event_common_set_is_frozen
-#else
-# define bt_ctf_event_common_validate(_event)                  0
-# define bt_ctf_event_common_set_is_frozen(_event, _is_frozen)
-#endif
-
-#define BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(_event, _name)                      \
-       BT_CTF_ASSERT_PRE_HOT((_event), (_name), ": event-addr=%p", (_event))
-
-static inline
-struct bt_ctf_event_class_common *bt_ctf_event_common_borrow_class(
-               struct bt_ctf_event_common *event)
-{
-       BT_ASSERT(event);
-       return event->class;
-}
-
-typedef void *(*create_field_func)(void *);
-typedef void (*release_field_func)(void *);
-typedef void *(*create_header_field_func)(void *, void *);
-typedef void (*release_header_field_func)(void *, void *);
-
-BT_HIDDEN
-int bt_ctf_event_common_initialize(struct bt_ctf_event_common *event,
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_clock_class *init_expected_clock_class,
-               bool is_shared_with_parent, bt_ctf_object_release_func release_func,
-               bt_ctf_validation_flag_copy_field_type_func field_type_copy_func,
-               bool must_be_in_trace,
-               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
-                       struct bt_ctf_field_type_common *packet_context_field_type,
-                       struct bt_ctf_field_type_common *event_header_field_type),
-               create_field_func create_field_func,
-               release_field_func release_field_func,
-               create_header_field_func create_header_field_func,
-               release_header_field_func release_header_field_func);
-
-static inline
-struct bt_ctf_field_common *bt_ctf_event_common_borrow_payload(
-               struct bt_ctf_event_common *event)
-{
-       struct bt_ctf_field_common *payload = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (!event->payload_field) {
-               BT_LOGV("Event has no current payload field: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_ctf_event_class_common_get_name(event->class),
-                       bt_ctf_event_class_common_get_id(event->class));
-               goto end;
-       }
-
-       payload = event->payload_field;
-
-end:
-       return payload;
-}
-
-static inline
-struct bt_ctf_field_common *bt_ctf_event_common_borrow_header(
-               struct bt_ctf_event_common *event)
-{
-       struct bt_ctf_field_common *header = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (!event->header_field) {
-               BT_LOGV("Event has no current header field: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_ctf_event_class_common_get_name(event->class),
-                       bt_ctf_event_class_common_get_id(event->class));
-               goto end;
-       }
-
-       header = event->header_field->field;
-
-end:
-       return header;
-}
-
-static inline
-struct bt_ctf_field_common *bt_ctf_event_common_borrow_context(
-               struct bt_ctf_event_common *event)
-{
-       struct bt_ctf_field_common *context = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (!event->context_field) {
-               BT_LOGV("Event has no current context field: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_ctf_event_class_common_get_name(event->class),
-                       bt_ctf_event_class_common_get_id(event->class));
-               goto end;
-       }
-
-       context = event->context_field;
-
-end:
-       return context;
-}
-
-static inline
-struct bt_ctf_field_common *bt_ctf_event_common_borrow_stream_event_context(
-               struct bt_ctf_event_common *event)
-{
-       struct bt_ctf_field_common *stream_event_context = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
-
-       if (!event->stream_event_context_field) {
-               BT_LOGV("Event has no current stream event context field: addr=%p, "
-                       "event-class-name=\"%s\", event-class-id=%" PRId64,
-                       event, bt_ctf_event_class_common_get_name(event->class),
-                       bt_ctf_event_class_common_get_id(event->class));
-               goto end;
-       }
-
-       stream_event_context = event->stream_event_context_field;
-
-end:
-       return stream_event_context;
-}
-
-static inline
-void bt_ctf_event_common_finalize(struct bt_ctf_object *obj,
-               void (*field_release_func)(void *),
-               void (*header_field_release_func)(void *, struct bt_ctf_event_common *))
-{
-       struct bt_ctf_event_common *event = (void *) obj;
-
-       BT_LOGD("Destroying event: addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64,
-               event,
-               event->class ? bt_ctf_event_class_common_get_name(event->class) : NULL,
-               event->class ? bt_ctf_event_class_common_get_id(event->class) : INT64_C(-1));
-
-       if (event->header_field) {
-               BT_LOGD_STR("Releasing event's header field.");
-               header_field_release_func(event->header_field, event);
-       }
-
-       if (event->stream_event_context_field) {
-               BT_LOGD_STR("Releasing event's stream event context field.");
-               field_release_func(event->stream_event_context_field);
-       }
-
-       if (event->context_field) {
-               BT_LOGD_STR("Releasing event's context field.");
-               field_release_func(event->context_field);
-       }
-
-       if (event->payload_field) {
-               BT_LOGD_STR("Releasing event's payload field.");
-               field_release_func(event->payload_field);
-       }
-
-       /*
-        * Leave this after calling header_field_release_func() because
-        * this function receives the event object and could need its
-        * class to perform some cleanup.
-        */
-       if (!event->base.parent) {
-               /*
-                * Event was keeping a reference to its class since it shared no
-                * common ancestor with it to guarantee they would both have the
-                * same lifetime.
-                */
-               bt_ctf_object_put_ref(event->class);
-       }
-}
-
-struct bt_ctf_event {
-       struct bt_ctf_event_common common;
-};
-
-struct bt_ctf_event_class {
-       struct bt_ctf_event_class_common common;
-};
-
-BT_HIDDEN
-int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class,
-               struct metadata_context *context);
-
-BT_HIDDEN
-int bt_ctf_event_serialize(struct bt_ctf_event *event,
-               struct bt_ctfser *pos,
-               enum bt_ctf_byte_order native_byte_order);
-
-static inline
-struct bt_ctf_stream_class *bt_ctf_event_class_borrow_stream_class(
-               struct bt_ctf_event_class *event_class)
-{
-       return BT_CTF_FROM_COMMON(bt_ctf_event_class_common_borrow_stream_class(
-               BT_CTF_TO_COMMON(event_class)));
-}
-
-#endif /* BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/field-path-internal.h b/include/babeltrace2/ctf-writer/field-path-internal.h
deleted file mode 100644 (file)
index d018e40..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_FIELD_PATH_INTERNAL
-#define BABELTRACE_CTF_WRITER_FIELD_PATH_INTERNAL
-
-/*
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <glib.h>
-
-struct bt_ctf_field_path {
-       struct bt_ctf_object base;
-       enum bt_ctf_scope root;
-
-       /*
-        * Array of integers (int) indicating the index in either
-        * structures, variants, arrays, or sequences that make up
-        * the path to a field type. -1 means the "current element
-        * of an array or sequence type".
-        */
-       GArray *indexes;
-};
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_path_create(void);
-
-BT_HIDDEN
-void bt_ctf_field_path_clear(struct bt_ctf_field_path *field_path);
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_path_copy(
-               struct bt_ctf_field_path *path);
-
-BT_HIDDEN enum bt_ctf_scope bt_ctf_field_path_get_root_scope(
-               const struct bt_ctf_field_path *field_path);
-
-BT_HIDDEN int64_t bt_ctf_field_path_get_index_count(
-               const struct bt_ctf_field_path *field_path);
-
-BT_HIDDEN int bt_ctf_field_path_get_index(
-               const struct bt_ctf_field_path *field_path, uint64_t index);
-
-#endif /* BABELTRACE_CTF_WRITER_FIELD_PATH_INTERNAL */
diff --git a/include/babeltrace2/ctf-writer/field-types-internal.h b/include/babeltrace2/ctf-writer/field-types-internal.h
deleted file mode 100644 (file)
index 757170f..0000000
+++ /dev/null
@@ -1,790 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_FIELD_TYPES_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_FIELD_TYPES_INTERNAL_H
-
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <stdint.h>
-#include <stddef.h>
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/writer-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/types.h>
-
-#define BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(_ft, _type_id, _name)   \
-       BT_CTF_ASSERT_PRE(((struct bt_ctf_field_type_common *) (_ft))->id == (_type_id), \
-               _name " has the wrong type ID: expected-type-id=%s, "   \
-               "ft-addr=%p", bt_ctf_field_type_id_string(_type_id), (_ft))
-
-#define BT_CTF_ASSERT_PRE_CTF_FT_HOT(_ft, _name)                               \
-       BT_CTF_ASSERT_PRE_HOT((_ft), (_name), ": ft-addr=%p", (_ft))
-
-#define BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(_ft, _index) \
-       (&g_array_index(((struct bt_ctf_field_type_common_structure *) (_ft))->fields, \
-               struct bt_ctf_field_type_common_structure_field, (_index)))
-
-#define BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(_ft, _index)  \
-       (&g_array_index(((struct bt_ctf_field_type_common_variant *) (_ft))->choices, \
-               struct bt_ctf_field_type_common_variant_choice, (_index)))
-
-struct bt_ctf_field_common;
-struct bt_ctf_field_type_common;
-
-typedef void (*bt_ctf_field_type_common_method_freeze)(
-               struct bt_ctf_field_type_common *);
-typedef int (*bt_ctf_field_type_common_method_validate)(
-               struct bt_ctf_field_type_common *);
-typedef void (*bt_ctf_field_type_common_method_set_byte_order)(
-               struct bt_ctf_field_type_common *, enum bt_ctf_byte_order);
-typedef struct bt_ctf_field_type_common *(*bt_ctf_field_type_common_method_copy)(
-               struct bt_ctf_field_type_common *);
-typedef int (*bt_ctf_field_type_common_method_compare)(
-               struct bt_ctf_field_type_common *,
-               struct bt_ctf_field_type_common *);
-
-struct bt_ctf_field_type_common_methods {
-       bt_ctf_field_type_common_method_freeze freeze;
-       bt_ctf_field_type_common_method_validate validate;
-       bt_ctf_field_type_common_method_set_byte_order set_byte_order;
-       bt_ctf_field_type_common_method_copy copy;
-       bt_ctf_field_type_common_method_compare compare;
-};
-
-struct bt_ctf_field_type_common {
-       struct bt_ctf_object base;
-       enum bt_ctf_field_type_id id;
-       unsigned int alignment;
-
-       /* Virtual table */
-       struct bt_ctf_field_type_common_methods *methods;
-
-       /*
-        * A type can't be modified once it is added to an event or after a
-        * a field has been instanciated from it.
-        */
-       int frozen;
-
-       /*
-        * This flag indicates if the field type is valid. A valid
-        * field type is _always_ frozen. All the nested field types of
-        * a valid field type are also valid (and thus frozen).
-        */
-       int valid;
-
-       /*
-        * Specialized data for either CTF IR or CTF writer APIs.
-        * Having this here ensures that:
-        *
-        * * The type-specific common data is always found at the same
-        *   offset when the common API has a `struct
-        *   bt_ctf_field_type_common *` so that you can cast it to `struct
-        *   bt_ctf_field_type_common_integer *` for example and access the
-        *   common integer field type fields.
-        *
-        * * The specific CTF IR and CTF writer APIs can access their
-        *   specific field type fields in this union at an offset known
-        *   at build time. This avoids a pointer to specific data so
-        *   that all the fields, common or specific, of a CTF IR
-        *   integer field type or of a CTF writer integer field type,
-        *   for example, are contained within the same contiguous block
-        *   of memory.
-        */
-       union {
-               struct {
-               } ir;
-               struct {
-                       void *serialize_func;
-               } writer;
-       } spec;
-};
-
-struct bt_ctf_field_type_common_integer {
-       struct bt_ctf_field_type_common common;
-
-       /* Owned by this */
-       struct bt_ctf_clock_class *mapped_clock_class;
-
-       enum bt_ctf_byte_order user_byte_order;
-       bt_bool is_signed;
-       unsigned int size;
-       enum bt_ctf_integer_base base;
-       enum bt_ctf_string_encoding encoding;
-};
-
-struct bt_ctf_enumeration_mapping {
-       union {
-               uint64_t _unsigned;
-               int64_t _signed;
-       } range_start;
-       union {
-               uint64_t _unsigned;
-               int64_t _signed;
-       } range_end;
-       GQuark string;
-};
-
-struct bt_ctf_field_type_common_enumeration {
-       struct bt_ctf_field_type_common common;
-
-       /* Owned by this */
-       struct bt_ctf_field_type_common_integer *container_ft;
-
-       /* Array of `struct bt_ctf_enumeration_mapping *`, owned by this */
-       GPtrArray *entries;
-
-       /* Only set during validation */
-       bt_bool has_overlapping_ranges;
-};
-
-enum bt_ctf_field_type_enumeration_mapping_iterator_type {
-       CTF_ITERATOR_BY_NAME,
-       CTF_ITERATOR_BY_SIGNED_VALUE,
-       CTF_ITERATOR_BY_UNSIGNED_VALUE,
-};
-
-struct bt_ctf_field_type_enumeration_mapping_iterator {
-       struct bt_ctf_object base;
-
-       /* Owned by this */
-       struct bt_ctf_field_type_common_enumeration *enumeration_ft;
-
-       enum bt_ctf_field_type_enumeration_mapping_iterator_type type;
-       int index;
-       union {
-               GQuark name_quark;
-               int64_t signed_value;
-               uint64_t unsigned_value;
-       } u;
-};
-
-struct bt_ctf_field_type_common_floating_point {
-       struct bt_ctf_field_type_common common;
-       enum bt_ctf_byte_order user_byte_order;
-       unsigned int exp_dig;
-       unsigned int mant_dig;
-};
-
-struct bt_ctf_field_type_common_structure_field {
-       GQuark name;
-
-       /* Owned by this */
-       struct bt_ctf_field_type_common *type;
-};
-
-struct bt_ctf_field_type_common_structure {
-       struct bt_ctf_field_type_common common;
-       GHashTable *field_name_to_index;
-
-       /*
-        * Array of `struct bt_ctf_field_type_common_structure_field`,
-        * owned by this
-        */
-       GArray *fields;
-};
-
-struct bt_ctf_field_type_common_variant_choice_range {
-       union {
-               int64_t i;
-               uint64_t u;
-       } lower;
-       union {
-               int64_t i;
-               uint64_t u;
-       } upper;
-};
-
-struct bt_ctf_field_type_common_variant_choice {
-       GQuark name;
-
-       /* Owned by this */
-       struct bt_ctf_field_type_common *type;
-
-       /* Array of `struct bt_ctf_field_type_common_variant_choice_range` */
-       GArray *ranges;
-};
-
-struct bt_ctf_field_type_common_variant {
-       struct bt_ctf_field_type_common common;
-       GString *tag_name;
-       bool choices_up_to_date;
-
-       /* Owned by this */
-       struct bt_ctf_field_type_common_enumeration *tag_ft;
-
-       /* Owned by this */
-       struct bt_ctf_field_path *tag_field_path;
-
-       GHashTable *choice_name_to_index;
-
-       /*
-        * Array of `struct bt_ctf_field_type_common_variant_choice`,
-        * owned by this */
-       GArray *choices;
-};
-
-struct bt_ctf_field_type_common_array {
-       struct bt_ctf_field_type_common common;
-
-       /* Owned by this */
-       struct bt_ctf_field_type_common *element_ft;
-
-       unsigned int length;
-};
-
-struct bt_ctf_field_type_common_sequence {
-       struct bt_ctf_field_type_common common;
-
-       /* Owned by this */
-       struct bt_ctf_field_type_common *element_ft;
-
-       GString *length_field_name;
-
-       /* Owned by this */
-       struct bt_ctf_field_path *length_field_path;
-};
-
-struct bt_ctf_field_type_common_string {
-       struct bt_ctf_field_type_common common;
-       enum bt_ctf_string_encoding encoding;
-};
-
-typedef struct bt_ctf_field_common *(* bt_ctf_field_common_create_func)(
-               struct bt_ctf_field_type_common *);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_initialize(struct bt_ctf_field_type_common *ft,
-               bool init_bo, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_initialize(
-               struct bt_ctf_field_type_common *ft,
-               unsigned int size, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *container_ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_string_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_initialize(
-               struct bt_ctf_field_type_common *ft,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft,
-               unsigned int length, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft,
-               const char *length_field_name,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_initialize(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *tag_ft,
-               const char *tag_name,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_type_common_methods *methods);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_destroy(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_destroy(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_destroy_recursive(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_string_destroy(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_destroy_recursive(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_destroy_recursive(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_destroy_recursive(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_destroy_recursive(struct bt_ctf_object *obj);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_validate(struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_validate_recursive(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_validate_recursive(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_validate_recursive(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_validate_recursive(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_validate_recursive(
-               struct bt_ctf_field_type_common *type);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_validate(struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_get_size(struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-bt_bool bt_ctf_field_type_common_integer_is_signed(struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_is_signed(struct bt_ctf_field_type_common *ft,
-               bt_bool is_signed);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_size(struct bt_ctf_field_type_common *ft,
-               unsigned int size);
-
-BT_HIDDEN
-enum bt_ctf_integer_base bt_ctf_field_type_common_integer_get_base(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_base(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_integer_base base);
-
-BT_HIDDEN
-enum bt_ctf_string_encoding bt_ctf_field_type_common_integer_get_encoding(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_encoding(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_string_encoding encoding);
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_clock_class *clock_class);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_set_mapped_clock_class(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_clock_class *clock_class);
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_find_mappings_by_name(
-               struct bt_ctf_field_type_common *ft, const char *name);
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_signed_find_mappings_by_value(
-               struct bt_ctf_field_type_common *ft, int64_t value);
-
-BT_HIDDEN
-struct bt_ctf_field_type_enumeration_mapping_iterator *
-bt_ctf_field_type_common_enumeration_unsigned_find_mappings_by_value(
-               struct bt_ctf_field_type_common *ft, uint64_t value);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
-               struct bt_ctf_field_type_common *ft, uint64_t index,
-               const char **mapping_name, int64_t *range_begin,
-               int64_t *range_end);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
-               struct bt_ctf_field_type_common *ft, uint64_t index,
-               const char **mapping_name, uint64_t *range_begin,
-               uint64_t *range_end);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_enumeration_borrow_container_field_type(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_signed_add_mapping(
-               struct bt_ctf_field_type_common *ft, const char *string,
-               int64_t range_start, int64_t range_end);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
-               struct bt_ctf_field_type_common *ft, const char *string,
-               uint64_t range_start, uint64_t range_end);
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_enumeration_get_mapping_count(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_get_exponent_digits(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_set_exponent_digits(
-               struct bt_ctf_field_type_common *ft,
-               unsigned int exponent_digits);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_get_mantissa_digits(
-               struct bt_ctf_field_type_common *type);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_set_mantissa_digits(
-               struct bt_ctf_field_type_common *ft, unsigned int mantissa_digits);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_replace_field(
-               struct bt_ctf_field_type_common *ft,
-               const char *field_name,
-               struct bt_ctf_field_type_common *field_type);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_add_field(struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *field_type,
-               const char *field_name);
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_structure_get_field_count(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_borrow_field_by_index(
-               struct bt_ctf_field_type_common *ft,
-               const char **field_name,
-               struct bt_ctf_field_type_common **field_type, uint64_t index);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_structure_borrow_field_type_by_name(
-               struct bt_ctf_field_type_common *ft, const char *name);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_tag_field_type(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-const char *bt_ctf_field_type_common_variant_get_tag_name(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_set_tag_name(
-               struct bt_ctf_field_type_common *ft, const char *name);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_add_field(struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *field_type,
-               const char *field_name);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_update_choices(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_by_name(
-               struct bt_ctf_field_type_common *ft,
-               const char *field_name);
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_variant_get_field_count(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_borrow_field_by_index(
-               struct bt_ctf_field_type_common *ft,
-               const char **field_name,
-               struct bt_ctf_field_type_common **field_type, uint64_t index);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_array_borrow_element_field_type(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_set_element_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft);
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_array_get_length(struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_sequence_borrow_element_field_type(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_set_element_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *element_ft);
-
-BT_HIDDEN
-const char *bt_ctf_field_type_common_sequence_get_length_field_name(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-enum bt_ctf_string_encoding bt_ctf_field_type_common_string_get_encoding(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_string_set_encoding(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_string_encoding encoding);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_get_alignment(struct bt_ctf_field_type_common *type);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_set_alignment(struct bt_ctf_field_type_common *ft,
-               unsigned int alignment);
-
-BT_HIDDEN
-enum bt_ctf_byte_order bt_ctf_field_type_common_get_byte_order(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_set_byte_order(struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-enum bt_ctf_field_type_id bt_ctf_field_type_common_get_type_id(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_freeze(struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_signed(
-               struct bt_ctf_field_type_common_variant *var_ft,
-               int64_t tag_value);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *
-bt_ctf_field_type_common_variant_borrow_field_type_unsigned(
-               struct bt_ctf_field_type_common_variant *var_ft,
-               uint64_t tag_value);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *bt_ctf_field_type_common_copy(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_get_field_name_index(
-               struct bt_ctf_field_type_common *ft, const char *name);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_get_field_name_index(
-               struct bt_ctf_field_type_common *ft, const char *name);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_set_length_field_path(
-               struct bt_ctf_field_type_common *ft, struct bt_ctf_field_path *path);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_set_tag_field_path(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_path *path);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_set_tag_field_type(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_field_type_common *tag_ft);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_generic_freeze(struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_freeze_recursive(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_freeze_recursive(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_freeze_recursive(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_freeze_recursive(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_freeze_recursive(
-               struct bt_ctf_field_type_common *type);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_integer_set_byte_order(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_enumeration_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_floating_point_set_byte_order(
-               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_structure_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_variant_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_array_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-void bt_ctf_field_type_common_sequence_set_byte_order_recursive(
-               struct bt_ctf_field_type_common *ft,
-               enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_integer_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_floating_point_compare(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_enumeration_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_string_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_structure_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_variant_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_array_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_sequence_compare_recursive(
-               struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_compare(struct bt_ctf_field_type_common *ft_a,
-               struct bt_ctf_field_type_common *ft_b);
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_get_field_count(struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-struct bt_ctf_field_type_common *bt_ctf_field_type_common_borrow_field_at_index(
-               struct bt_ctf_field_type_common *ft, int index);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_get_field_index(struct bt_ctf_field_type_common *ft,
-               const char *name);
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_type_common_variant_borrow_tag_field_path(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-struct bt_ctf_field_path *bt_ctf_field_type_common_sequence_borrow_length_field_path(
-               struct bt_ctf_field_type_common *ft);
-
-BT_HIDDEN
-int bt_ctf_field_type_common_validate_single_clock_class(
-               struct bt_ctf_field_type_common *ft,
-               struct bt_ctf_clock_class **expected_clock_class);
-
-BT_HIDDEN
-int64_t bt_ctf_field_type_common_variant_find_choice_index(
-               struct bt_ctf_field_type_common *ft, uint64_t uval,
-               bool is_signed);
-
-BT_HIDDEN
-int bt_ctf_field_type_serialize_recursive(struct bt_ctf_field_type *type,
-               struct metadata_context *context);
-
-BT_HIDDEN
-struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *ft);
-
-#endif /* BABELTRACE_CTF_WRITER_FIELD_TYPES_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/field-wrapper-internal.h b/include/babeltrace2/ctf-writer/field-wrapper-internal.h
deleted file mode 100644 (file)
index dcdf968..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_FIELD_WRAPPER_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_FIELD_WRAPPER_INTERNAL_H
-
-/*
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/ctf-writer/fields-internal.h>
-#include <babeltrace2/ctf-writer/object-pool-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-
-struct bt_ctf_field_wrapper {
-       struct bt_ctf_object base;
-
-       /* Owned by this */
-       struct bt_ctf_field_common *field;
-};
-
-BT_HIDDEN
-struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_new(void *data);
-
-BT_HIDDEN
-void bt_ctf_field_wrapper_destroy(struct bt_ctf_field_wrapper *field);
-
-BT_HIDDEN
-struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_create(
-               struct bt_ctf_object_pool *pool, struct bt_ctf_field_type *ft);
-
-#endif /* BABELTRACE_CTF_WRITER_FIELD_WRAPPER_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/fields-internal.h b/include/babeltrace2/ctf-writer/fields-internal.h
deleted file mode 100644 (file)
index e9bd396..0000000
+++ /dev/null
@@ -1,851 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_FIELDS_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_FIELDS_INTERNAL_H
-
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <stdint.h>
-#include <stddef.h>
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-
-#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(_field, _type_id, _name) \
-       BT_CTF_ASSERT_PRE((_field)->type->id == ((int) (_type_id)),             \
-               _name " has the wrong type ID: expected-type-id=%s, "   \
-               "field-addr=%p",                                        \
-               bt_ctf_field_type_id_string((int) (_type_id)), (_field))
-
-#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(_field, _name)               \
-       BT_CTF_ASSERT_PRE(bt_ctf_field_common_is_set_recursive(_field), \
-               _name " is not set: field-addr=%p", (_field))
-
-#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(_field, _name)          \
-       BT_CTF_ASSERT_PRE_HOT((_field), (_name), ": field-addr=%p", (_field))
-
-struct bt_ctf_field_common;
-
-typedef void (*bt_ctf_field_common_method_set_is_frozen)(struct bt_ctf_field_common *,
-               bool);
-typedef int (*bt_ctf_field_common_method_validate)(struct bt_ctf_field_common *);
-typedef struct bt_ctf_field_common *(*bt_ctf_field_common_method_copy)(
-               struct bt_ctf_field_common *);
-typedef bt_bool (*bt_ctf_field_common_method_is_set)(struct bt_ctf_field_common *);
-typedef void (*bt_ctf_field_common_method_reset)(struct bt_ctf_field_common *);
-
-struct bt_ctf_field_common_methods {
-       bt_ctf_field_common_method_set_is_frozen set_is_frozen;
-       bt_ctf_field_common_method_validate validate;
-       bt_ctf_field_common_method_copy copy;
-       bt_ctf_field_common_method_is_set is_set;
-       bt_ctf_field_common_method_reset reset;
-};
-
-struct bt_ctf_field_common {
-       struct bt_ctf_object base;
-       struct bt_ctf_field_type_common *type;
-       struct bt_ctf_field_common_methods *methods;
-       bool payload_set;
-       bool frozen;
-
-       /*
-        * Specialized data for either CTF IR or CTF writer APIs.
-        * See comment in `field-types-internal.h` for more details.
-        */
-       union {
-               struct {
-               } ir;
-               struct {
-                       void *serialize_func;
-               } writer;
-       } spec;
-};
-
-struct bt_ctf_field_common_integer {
-       struct bt_ctf_field_common common;
-       union {
-               int64_t signd;
-               uint64_t unsignd;
-       } payload;
-};
-
-struct bt_ctf_field_common_floating_point {
-       struct bt_ctf_field_common common;
-       double payload;
-};
-
-struct bt_ctf_field_common_structure {
-       struct bt_ctf_field_common common;
-
-       /* Array of `struct bt_ctf_field_common *`, owned by this */
-       GPtrArray *fields;
-};
-
-struct bt_ctf_field_common_variant {
-       struct bt_ctf_field_common common;
-
-       union {
-               uint64_t u;
-               int64_t i;
-       } tag_value;
-
-       /* Weak: belongs to `choices` below */
-       struct bt_ctf_field_common *current_field;
-
-       /* Array of `struct bt_ctf_field_common *`, owned by this */
-       GPtrArray *fields;
-};
-
-struct bt_ctf_field_common_array {
-       struct bt_ctf_field_common common;
-
-       /* Array of `struct bt_ctf_field_common *`, owned by this */
-       GPtrArray *elements;
-};
-
-struct bt_ctf_field_common_sequence {
-       struct bt_ctf_field_common common;
-
-       /*
-        * This is the true sequence field's length: its value can be
-        * less than `elements->len` below because we never shrink the
-        * array of elements to avoid reallocation.
-        */
-       uint64_t length;
-
-       /* Array of `struct bt_ctf_field_common *`, owned by this */
-       GPtrArray *elements;
-};
-
-struct bt_ctf_field_common_string {
-       struct bt_ctf_field_common common;
-       GArray *buf;
-       size_t size;
-};
-
-BT_HIDDEN
-struct bt_ctf_field_common *bt_ctf_field_common_copy(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-int bt_ctf_field_common_structure_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_release_func);
-
-BT_HIDDEN
-int bt_ctf_field_common_array_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_destroy_func);
-
-BT_HIDDEN
-int bt_ctf_field_common_sequence_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               GDestroyNotify field_destroy_func);
-
-BT_HIDDEN
-int bt_ctf_field_common_variant_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods,
-               bt_ctf_field_common_create_func field_create_func,
-               GDestroyNotify field_release_func);
-
-BT_HIDDEN
-int bt_ctf_field_common_string_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *type,
-               bool is_shared, bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods);
-
-BT_HIDDEN
-int bt_ctf_field_common_generic_validate(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-int bt_ctf_field_common_structure_validate_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-int bt_ctf_field_common_variant_validate_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-int bt_ctf_field_common_array_validate_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-int bt_ctf_field_common_sequence_validate_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-void bt_ctf_field_common_generic_reset(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-void bt_ctf_field_common_structure_reset_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-void bt_ctf_field_common_variant_reset_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-void bt_ctf_field_common_array_reset_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-void bt_ctf_field_common_sequence_reset_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-void bt_ctf_field_common_generic_set_is_frozen(struct bt_ctf_field_common *field,
-               bool is_frozen);
-
-BT_HIDDEN
-void bt_ctf_field_common_structure_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen);
-
-BT_HIDDEN
-void bt_ctf_field_common_variant_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen);
-
-BT_HIDDEN
-void bt_ctf_field_common_array_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen);
-
-BT_HIDDEN
-void bt_ctf_field_common_sequence_set_is_frozen_recursive(
-               struct bt_ctf_field_common *field, bool is_frozen);
-
-BT_HIDDEN
-void _bt_ctf_field_common_set_is_frozen_recursive(struct bt_ctf_field_common *field,
-               bool is_frozen);
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_generic_is_set(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_structure_is_set_recursive(
-               struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_variant_is_set_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_array_is_set_recursive(struct bt_ctf_field_common *field);
-
-BT_HIDDEN
-bt_bool bt_ctf_field_common_sequence_is_set_recursive(struct bt_ctf_field_common *field);
-
-#ifdef BT_DEV_MODE
-# define bt_ctf_field_common_validate_recursive                _bt_ctf_field_common_validate_recursive
-# define bt_ctf_field_common_set_is_frozen_recursive   _bt_ctf_field_common_set_is_frozen_recursive
-# define bt_ctf_field_common_is_set_recursive          _bt_ctf_field_common_is_set_recursive
-# define bt_ctf_field_common_reset_recursive           _bt_ctf_field_common_reset_recursive
-# define bt_ctf_field_common_set                               _bt_ctf_field_common_set
-#else
-# define bt_ctf_field_common_validate_recursive(_field)        (-1)
-# define bt_ctf_field_common_set_is_frozen_recursive(_field, _is_frozen)
-# define bt_ctf_field_common_is_set_recursive(_field)  (BT_FALSE)
-# define bt_ctf_field_common_reset_recursive(_field)
-# define bt_ctf_field_common_set(_field, _val)
-#endif
-
-BT_ASSERT_FUNC
-static inline bool field_type_common_has_known_id(
-               struct bt_ctf_field_type_common *ft)
-{
-       return (int) ft->id > BT_CTF_FIELD_TYPE_ID_UNKNOWN ||
-               (int) ft->id < BT_CTF_FIELD_TYPE_ID_NR;
-}
-
-static inline
-int _bt_ctf_field_common_validate_recursive(struct bt_ctf_field_common *field)
-{
-       int ret = 0;
-
-       if (!field) {
-               BT_CTF_ASSERT_PRE_MSG("%s", "Invalid field: field is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_ASSERT(field_type_common_has_known_id(field->type));
-
-       if (field->methods->validate) {
-               ret = field->methods->validate(field);
-       }
-
-end:
-       return ret;
-}
-
-static inline
-void _bt_ctf_field_common_reset_recursive(struct bt_ctf_field_common *field)
-{
-       BT_ASSERT(field);
-       BT_ASSERT(field->methods->reset);
-       field->methods->reset(field);
-}
-
-static inline
-void _bt_ctf_field_common_set(struct bt_ctf_field_common *field, bool value)
-{
-       BT_ASSERT(field);
-       field->payload_set = value;
-}
-
-static inline
-bt_bool _bt_ctf_field_common_is_set_recursive(struct bt_ctf_field_common *field)
-{
-       bt_bool is_set = BT_FALSE;
-
-       if (!field) {
-               goto end;
-       }
-
-       BT_ASSERT(field_type_common_has_known_id(field->type));
-       BT_ASSERT(field->methods->is_set);
-       is_set = field->methods->is_set(field);
-
-end:
-       return is_set;
-}
-
-static inline
-void bt_ctf_field_common_initialize(struct bt_ctf_field_common *field,
-               struct bt_ctf_field_type_common *ft, bool is_shared,
-               bt_ctf_object_release_func release_func,
-               struct bt_ctf_field_common_methods *methods)
-{
-       BT_ASSERT(field);
-       BT_ASSERT(ft);
-       bt_ctf_object_init(&field->base, is_shared, release_func);
-       field->methods = methods;
-       field->type = (void *) bt_ctf_object_get_ref(ft);
-}
-
-static inline
-struct bt_ctf_field_type_common *bt_ctf_field_common_borrow_type(
-               struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_type_common *ret = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
-       ret = field->type;
-       return ret;
-}
-
-static inline
-int64_t bt_ctf_field_common_sequence_get_length(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
-               "Field");
-       return (int64_t) sequence->length;
-}
-
-static inline
-int bt_ctf_field_common_sequence_set_length(struct bt_ctf_field_common *field,
-               uint64_t length, bt_ctf_field_common_create_func field_create_func)
-{
-       int ret = 0;
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_CTF_ASSERT_PRE(((int64_t) length) >= 0,
-               "Invalid sequence length (too large): length=%" PRId64,
-               length);
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Sequence field");
-
-       if (unlikely(length > sequence->elements->len)) {
-               /* Make more room */
-               struct bt_ctf_field_type_common_sequence *sequence_ft;
-               uint64_t cur_len = sequence->elements->len;
-               uint64_t i;
-
-               g_ptr_array_set_size(sequence->elements, length);
-               sequence_ft = BT_CTF_FROM_COMMON(sequence->common.type);
-
-               for (i = cur_len; i < sequence->elements->len; i++) {
-                       struct bt_ctf_field_common *elem_field =
-                               field_create_func(sequence_ft->element_ft);
-
-                       if (!elem_field) {
-                               ret = -1;
-                               goto end;
-                       }
-
-                       BT_ASSERT(!sequence->elements->pdata[i]);
-                       sequence->elements->pdata[i] = elem_field;
-               }
-       }
-
-       sequence->length = length;
-
-end:
-       return ret;
-}
-
-static inline
-struct bt_ctf_field_common *bt_ctf_field_common_structure_borrow_field_by_name(
-               struct bt_ctf_field_common *field, const char *name)
-{
-       struct bt_ctf_field_common *ret = NULL;
-       GQuark field_quark;
-       struct bt_ctf_field_type_common_structure *structure_ft;
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-       size_t index;
-       GHashTable *field_name_to_index;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Structure field");
-       BT_CTF_ASSERT_PRE_NON_NULL(name, "Field name");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_CTF_FIELD_TYPE_ID_STRUCT, "Field");
-       structure_ft = BT_CTF_FROM_COMMON(field->type);
-       field_name_to_index = structure_ft->field_name_to_index;
-       field_quark = g_quark_from_string(name);
-       if (!g_hash_table_lookup_extended(field_name_to_index,
-                       GUINT_TO_POINTER(field_quark),
-                       NULL, (gpointer *) &index)) {
-               BT_LOGV("Invalid parameter: no such field in structure field's type: "
-                       "struct-field-addr=%p, struct-ft-addr=%p, name=\"%s\"",
-                       field, field->type, name);
-               goto error;
-       }
-
-       ret = structure->fields->pdata[index];
-       BT_ASSERT(ret);
-
-error:
-       return ret;
-}
-
-static inline
-struct bt_ctf_field_common *bt_ctf_field_common_structure_borrow_field_by_index(
-               struct bt_ctf_field_common *field, uint64_t index)
-{
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Structure field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_CTF_FIELD_TYPE_ID_STRUCT, "Field");
-       BT_CTF_ASSERT_PRE(index < structure->fields->len,
-               "Index is out of bound: struct-field-addr=%p, "
-               "index=%" PRIu64 ", count=%u", field, index,
-               structure->fields->len);
-       return structure->fields->pdata[index];
-}
-
-static inline
-struct bt_ctf_field_common *bt_ctf_field_common_array_borrow_field(
-               struct bt_ctf_field_common *field, uint64_t index)
-{
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Array field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_ARRAY,
-               "Field");
-       BT_CTF_ASSERT_PRE(index < array->elements->len,
-               "Index is out of bound: array-field-addr=%p, "
-               "index=%" PRIu64 ", count=%u", field,
-               index, array->elements->len);
-       return array->elements->pdata[(size_t) index];
-}
-
-static inline
-struct bt_ctf_field_common *bt_ctf_field_common_sequence_borrow_field(
-               struct bt_ctf_field_common *field, uint64_t index)
-{
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
-               "Field");
-       BT_CTF_ASSERT_PRE(index < sequence->length,
-               "Index is out of bound: seq-field-addr=%p, "
-               "index=%" PRIu64 ", count=%u", field, index,
-               sequence->elements->len);
-       return sequence->elements->pdata[(size_t) index];
-}
-
-static inline
-int bt_ctf_field_common_variant_set_tag(struct bt_ctf_field_common *variant_field,
-               uint64_t tag_uval, bool is_signed)
-{
-       int ret = 0;
-       int64_t choice_index;
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
-               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-
-       /* Find matching index in variant field's type */
-       choice_index = bt_ctf_field_type_common_variant_find_choice_index(
-               variant_field->type, tag_uval, is_signed);
-       if (choice_index < 0) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Select corresponding field */
-       BT_ASSERT(choice_index < variant->fields->len);
-       variant->current_field = variant->fields->pdata[choice_index];
-       variant->tag_value.u = tag_uval;
-
-end:
-       return ret;
-}
-
-static inline
-struct bt_ctf_field_common *bt_ctf_field_common_variant_borrow_current_field(
-               struct bt_ctf_field_common *variant_field)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
-               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_CTF_ASSERT_PRE(variant->current_field,
-               "Variant field has no current field: field-addr=%p", variant_field);
-       return variant->current_field;
-}
-
-static inline
-int bt_ctf_field_common_variant_get_tag_signed(struct bt_ctf_field_common *variant_field,
-       int64_t *tag)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
-               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_CTF_ASSERT_PRE(variant->current_field,
-               "Variant field has no current field: field-addr=%p", variant_field);
-       *tag = variant->tag_value.i;
-       return 0;
-}
-
-static inline
-int bt_ctf_field_common_variant_get_tag_unsigned(struct bt_ctf_field_common *variant_field,
-       uint64_t *tag)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
-               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
-       BT_CTF_ASSERT_PRE(variant->current_field,
-               "Variant field has no current field: field-addr=%p", variant_field);
-       *tag = variant->tag_value.u;
-       return 0;
-}
-
-static inline
-int bt_ctf_field_common_floating_point_get_value(struct bt_ctf_field_common *field,
-               double *value)
-{
-       struct bt_ctf_field_common_floating_point *floating_point =
-               BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Floating point number field");
-       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_CTF_FIELD_TYPE_ID_FLOAT, "Field");
-       *value = floating_point->payload;
-       return 0;
-}
-
-static inline
-int bt_ctf_field_common_floating_point_set_value(struct bt_ctf_field_common *field,
-               double value)
-{
-       struct bt_ctf_field_common_floating_point *floating_point =
-               BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "Floating point number field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Floating point number field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_CTF_FIELD_TYPE_ID_FLOAT, "Field");
-       floating_point->payload = value;
-       bt_ctf_field_common_set(field, true);
-       return 0;
-}
-
-static inline
-const char *bt_ctf_field_common_string_get_value(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_CTF_FIELD_TYPE_ID_STRING, "Field");
-       return (const char *) string->buf->data;
-}
-
-static inline
-int bt_ctf_field_common_string_clear(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_string *string_field = BT_CTF_FROM_COMMON(field);
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_CTF_FIELD_TYPE_ID_STRING, "Field");
-       string_field->size = 0;
-       bt_ctf_field_common_set(field, true);
-       return 0;
-}
-
-static inline
-int bt_ctf_field_common_string_append_len(struct bt_ctf_field_common *field,
-               const char *value, unsigned int length)
-{
-       struct bt_ctf_field_common_string *string_field = BT_CTF_FROM_COMMON(field);
-       char *data;
-       size_t new_size;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_CTF_FIELD_TYPE_ID_STRING, "Field");
-
-       /* Make sure no null bytes are appended */
-       BT_CTF_ASSERT_PRE(memchr(value, '\0', length) == NULL,
-               "String value to append contains a null character: "
-               "partial-value=\"%.32s\", length=%u", value, length);
-
-       new_size = string_field->size + length;
-
-       if (unlikely(new_size + 1 > string_field->buf->len)) {
-               g_array_set_size(string_field->buf, new_size + 1);
-       }
-
-       data = string_field->buf->data;
-       memcpy(data + string_field->size, value, length);
-       ((char *) string_field->buf->data)[new_size] = '\0';
-       string_field->size = new_size;
-       bt_ctf_field_common_set(field, true);
-       return 0;
-}
-
-static inline
-int bt_ctf_field_common_string_append(struct bt_ctf_field_common *field,
-               const char *value)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
-       return bt_ctf_field_common_string_append_len(field, value,
-               strlen(value));
-}
-
-static inline
-int bt_ctf_field_common_string_set_value(struct bt_ctf_field_common *field,
-               const char *value)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
-       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
-       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
-               BT_CTF_FIELD_TYPE_ID_STRING, "Field");
-       bt_ctf_field_common_string_clear(field);
-       return bt_ctf_field_common_string_append_len(field,
-               value, strlen(value));
-}
-
-static inline
-void bt_ctf_field_common_finalize(struct bt_ctf_field_common *field)
-{
-       BT_ASSERT(field);
-       BT_LOGD_STR("Putting field's type.");
-       bt_ctf_object_put_ref(field->type);
-}
-
-static inline
-void bt_ctf_field_common_integer_finalize(struct bt_ctf_field_common *field)
-{
-       BT_ASSERT(field);
-       BT_LOGD("Finalizing common integer field object: addr=%p", field);
-       bt_ctf_field_common_finalize(field);
-}
-
-static inline
-void bt_ctf_field_common_floating_point_finalize(struct bt_ctf_field_common *field)
-{
-       BT_ASSERT(field);
-       BT_LOGD("Finalizing common floating point number field object: addr=%p", field);
-       bt_ctf_field_common_finalize(field);
-}
-
-static inline
-void bt_ctf_field_common_structure_finalize_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-       BT_LOGD("Finalizing common structure field object: addr=%p", field);
-       bt_ctf_field_common_finalize(field);
-
-       if (structure->fields) {
-               g_ptr_array_free(structure->fields, TRUE);
-       }
-}
-
-static inline
-void bt_ctf_field_common_variant_finalize_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-       BT_LOGD("Finalizing common variant field object: addr=%p", field);
-       bt_ctf_field_common_finalize(field);
-
-       if (variant->fields) {
-               g_ptr_array_free(variant->fields, TRUE);
-       }
-}
-
-static inline
-void bt_ctf_field_common_array_finalize_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-       BT_LOGD("Finalizing common array field object: addr=%p", field);
-       bt_ctf_field_common_finalize(field);
-
-       if (array->elements) {
-               g_ptr_array_free(array->elements, TRUE);
-       }
-}
-
-static inline
-void bt_ctf_field_common_sequence_finalize_recursive(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-       BT_LOGD("Finalizing common sequence field object: addr=%p", field);
-       bt_ctf_field_common_finalize(field);
-
-       if (sequence->elements) {
-               g_ptr_array_free(sequence->elements, TRUE);
-       }
-}
-
-static inline
-void bt_ctf_field_common_string_finalize(struct bt_ctf_field_common *field)
-{
-       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
-
-       BT_ASSERT(field);
-       BT_LOGD("Finalizing common string field object: addr=%p", field);
-       bt_ctf_field_common_finalize(field);
-
-       if (string->buf) {
-               g_array_free(string->buf, TRUE);
-       }
-}
-
-BT_CTF_ASSERT_PRE_FUNC
-static inline bool value_is_in_range_signed(unsigned int size, int64_t value)
-{
-       bool ret = true;
-       int64_t min_value, max_value;
-
-       min_value = -(1ULL << (size - 1));
-       max_value = (1ULL << (size - 1)) - 1;
-       if (value < min_value || value > max_value) {
-               BT_LOGF("Value is out of bounds: value=%" PRId64 ", "
-                       "min-value=%" PRId64 ", max-value=%" PRId64,
-                       value, min_value, max_value);
-               ret = false;
-       }
-
-       return ret;
-}
-
-BT_CTF_ASSERT_PRE_FUNC
-static inline bool value_is_in_range_unsigned(unsigned int size, uint64_t value)
-{
-       bool ret = true;
-       int64_t max_value;
-
-       max_value = (size == 64) ? UINT64_MAX : ((uint64_t) 1 << size) - 1;
-       if (value > max_value) {
-               BT_LOGF("Value is out of bounds: value=%" PRIu64 ", "
-                       "max-value=%" PRIu64,
-                       value, max_value);
-               ret = false;
-       }
-
-       return ret;
-}
-
-struct bt_ctf_field_enumeration {
-       struct bt_ctf_field_common common;
-       struct bt_ctf_field_common_integer *container;
-};
-
-struct bt_ctf_field_variant {
-       struct bt_ctf_field_common_variant common;
-       struct bt_ctf_field_enumeration *tag;
-};
-
-BT_HIDDEN
-int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
-               struct bt_ctfser *ctfser,
-               enum bt_ctf_byte_order native_byte_order);
-
-BT_HIDDEN
-int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
-               const char *name, struct bt_ctf_field *value);
-
-BT_HIDDEN
-struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container(
-               struct bt_ctf_field *field);
-
-static inline
-bt_bool bt_ctf_field_is_set_recursive(struct bt_ctf_field *field)
-{
-       return bt_ctf_field_common_is_set_recursive((void *) field);
-}
-
-#endif /* BABELTRACE_CTF_WRITER_FIELDS_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/functor-internal.h b/include/babeltrace2/ctf-writer/functor-internal.h
deleted file mode 100644 (file)
index 0d6cda1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H
-
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-BT_HIDDEN
-void value_exists(gpointer element, gpointer search_query);
-
-#endif /* BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/object-internal.h b/include/babeltrace2/ctf-writer/object-internal.h
deleted file mode 100644 (file)
index 365b112..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H
-
-/*
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdbool.h>
-
-struct bt_ctf_object;
-
-typedef void (*bt_ctf_object_release_func)(struct bt_ctf_object *);
-typedef void (*bt_ctf_object_parent_is_owner_listener_func)(
-               struct bt_ctf_object *);
-
-static inline
-void *bt_ctf_object_get_no_null_check(struct bt_ctf_object *obj);
-
-static inline
-void bt_ctf_object_put_no_null_check(struct bt_ctf_object *obj);
-
-/*
- * Babeltrace object base.
- *
- * All objects publicly exposed by Babeltrace APIs must contain this
- * object as their first member.
- */
-struct bt_ctf_object {
-       /*
-        * True if this object is shared, that is, it has a reference
-        * count.
-        */
-       bool is_shared;
-
-       /*
-        * Current reference count.
-        */
-       unsigned long long ref_count;
-
-       /*
-        * Release function called when the object's reference count
-        * falls to zero. For an object with a parent, this function is
-        * bt_ctf_object_with_parent_release_func(), which calls
-        * `spec_release_func` below if there's no current parent.
-        */
-       bt_ctf_object_release_func release_func;
-
-       /*
-        * Specific release function called by
-        * bt_ctf_object_with_parent_release_func() or directly by a
-        * parent object.
-        */
-       bt_ctf_object_release_func spec_release_func;
-
-       /*
-        * Optional callback for an object with a parent, called by
-        * bt_ctf_object_with_parent_release_func() to indicate to the
-        * object that its parent is its owner.
-        */
-       bt_ctf_object_parent_is_owner_listener_func
-               parent_is_owner_listener_func;
-
-       /*
-        * Optional parent object.
-        */
-       struct bt_ctf_object *parent;
-};
-
-static inline
-unsigned long long bt_ctf_object_get_ref_count(struct bt_ctf_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       return obj->ref_count;
-}
-
-static inline
-struct bt_ctf_object *bt_ctf_object_borrow_parent(struct bt_ctf_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       return obj->parent;
-}
-
-static inline
-struct bt_ctf_object *bt_ctf_object_get_parent(struct bt_ctf_object *obj)
-{
-       struct bt_ctf_object *parent = bt_ctf_object_borrow_parent(obj);
-
-       if (parent) {
-               bt_ctf_object_get_no_null_check(parent);
-       }
-
-       return parent;
-}
-
-static inline
-void bt_ctf_object_set_parent(struct bt_ctf_object *child, struct bt_ctf_object *parent)
-{
-       BT_ASSERT(child);
-       BT_ASSERT(child->is_shared);
-
-#ifdef BT_LOGV
-       BT_LOGV("Setting object's parent: addr=%p, parent-addr=%p",
-               child, parent);
-#endif
-
-       /*
-        * It is assumed that a "child" having a parent is publicly
-        * reachable. Therefore, a reference to its parent must be
-        * taken. The reference to the parent will be released once the
-        * object's reference count falls to zero.
-        */
-       if (parent) {
-               BT_ASSERT(!child->parent);
-               child->parent = parent;
-               bt_ctf_object_get_no_null_check(parent);
-       } else {
-               if (child->parent) {
-                       bt_ctf_object_put_no_null_check(child->parent);
-               }
-
-               child->parent = NULL;
-       }
-}
-
-static inline
-void bt_ctf_object_try_spec_release(struct bt_ctf_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       BT_ASSERT(obj->spec_release_func);
-
-       if (bt_ctf_object_get_ref_count(obj) == 0) {
-               obj->spec_release_func(obj);
-       }
-}
-
-static inline
-void bt_ctf_object_with_parent_release_func(struct bt_ctf_object *obj)
-{
-       if (obj->parent) {
-               /*
-                * Keep our own copy of the parent address because `obj`
-                * could be destroyed in
-                * obj->parent_is_owner_listener_func().
-                */
-               struct bt_ctf_object *parent = obj->parent;
-
-#ifdef BT_LOGV
-               BT_LOGV("Releasing parented object: addr=%p, ref-count=%llu, "
-                       "parent-addr=%p, parent-ref-count=%llu",
-                       obj, obj->ref_count,
-                       parent, parent->ref_count);
-#endif
-
-               if (obj->parent_is_owner_listener_func) {
-                       /*
-                        * Object has a chance to destroy itself here
-                        * under certain conditions and notify its
-                        * parent. At this point the parent is
-                        * guaranteed to exist because it's not put yet.
-                        */
-                       obj->parent_is_owner_listener_func(obj);
-               }
-
-               /* The release function will be invoked by the parent. */
-               bt_ctf_object_put_no_null_check(parent);
-       } else {
-               bt_ctf_object_try_spec_release(obj);
-       }
-}
-
-static inline
-void bt_ctf_object_init(struct bt_ctf_object *obj, bool is_shared,
-               bt_ctf_object_release_func release_func)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(!is_shared || release_func);
-       obj->is_shared = is_shared;
-       obj->release_func = release_func;
-       obj->parent_is_owner_listener_func = NULL;
-       obj->spec_release_func = NULL;
-       obj->parent = NULL;
-       obj->ref_count = 1;
-}
-
-static inline
-void bt_ctf_object_init_shared(struct bt_ctf_object *obj,
-               bt_ctf_object_release_func release_func)
-{
-       bt_ctf_object_init(obj, true, release_func);
-}
-
-static inline
-void bt_ctf_object_init_unique(struct bt_ctf_object *obj)
-{
-       bt_ctf_object_init(obj, false, NULL);
-}
-
-static inline
-void bt_ctf_object_init_shared_with_parent(struct bt_ctf_object *obj,
-               bt_ctf_object_release_func spec_release_func)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(spec_release_func);
-       bt_ctf_object_init_shared(obj, bt_ctf_object_with_parent_release_func);
-       obj->spec_release_func = spec_release_func;
-}
-
-static inline
-void bt_ctf_object_set_parent_is_owner_listener_func(struct bt_ctf_object *obj,
-               bt_ctf_object_parent_is_owner_listener_func func)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       BT_ASSERT(obj->spec_release_func);
-       ((struct bt_ctf_object *) obj)->parent_is_owner_listener_func = func;
-}
-
-static inline
-void bt_ctf_object_inc_ref_count(struct bt_ctf_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       obj->ref_count++;
-       BT_ASSERT(obj->ref_count != 0);
-}
-
-static inline
-void *bt_ctf_object_get_no_null_check_no_parent_check(struct bt_ctf_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-
-#ifdef BT_LOGV
-       BT_LOGV("Incrementing object's reference count: %llu -> %llu: "
-               "addr=%p, cur-count=%llu, new-count=%llu",
-               obj->ref_count, obj->ref_count + 1,
-               obj, obj->ref_count, obj->ref_count + 1);
-#endif
-
-       bt_ctf_object_inc_ref_count(obj);
-       return obj;
-}
-
-static inline
-void *bt_ctf_object_get_no_null_check(struct bt_ctf_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-
-       if (unlikely(obj->parent && bt_ctf_object_get_ref_count(obj) == 0)) {
-#ifdef BT_LOGV
-               BT_LOGV("Incrementing object's parent's reference count: "
-                       "addr=%p, parent-addr=%p", obj, obj->parent);
-#endif
-
-               bt_ctf_object_get_no_null_check(obj->parent);
-       }
-
-#ifdef BT_LOGV
-       BT_LOGV("Incrementing object's reference count: %llu -> %llu: "
-               "addr=%p, cur-count=%llu, new-count=%llu",
-               obj->ref_count, obj->ref_count + 1,
-               obj, obj->ref_count, obj->ref_count + 1);
-#endif
-
-       bt_ctf_object_inc_ref_count(obj);
-       return obj;
-}
-
-static inline
-void bt_ctf_object_put_no_null_check(struct bt_ctf_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       BT_ASSERT(obj->ref_count > 0);
-
-#ifdef BT_LOGV
-       BT_LOGV("Decrementing object's reference count: %llu -> %llu: "
-               "addr=%p, cur-count=%llu, new-count=%llu",
-               obj->ref_count, obj->ref_count - 1,
-               obj, obj->ref_count, obj->ref_count - 1);
-#endif
-
-       obj->ref_count--;
-
-       if (obj->ref_count == 0) {
-               BT_ASSERT(obj->release_func);
-               obj->release_func(obj);
-       }
-}
-
-#endif /* BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/object-pool-internal.h b/include/babeltrace2/ctf-writer/object-pool-internal.h
deleted file mode 100644 (file)
index 1217ef1..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_OBJECT_POOL_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_OBJECT_POOL_INTERNAL_H
-
-/*
- * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This is a generic object pool to avoid memory allocation/deallocation
- * for objects of which the lifespan is typically short, but which are
- * created a lot.
- *
- * The object pool, thanks to two user functions, knows how to allocate
- * a brand new object in memory when the pool is empty and how to
- * destroy an object when we destroy the pool.
- *
- * The object pool's user is responsible for:
- *
- * * Setting whatever references the object needs to keep and reset some
- *   properties _after_ calling bt_ctf_object_pool_create_object(). This is
- *   typically done in the bt_*_create() function which calls
- *   bt_ctf_object_pool_create_object() (which could call the user-provided
- *   allocation function if the pool is empty) and then sets the
- *   appropriate properties on the possibly recycled object.
- *
- * * Releasing whatever references the object keeps _before_ calling
- *   bt_ctf_object_pool_recycle_object(). This is typically done in a custom
- *   bt_*_recycle() function which does the necessary before calling
- *   bt_ctf_object_pool_recycle_object() with an object ready to be reused
- *   at any time.
- */
-
-#include <glib.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-
-typedef void *(*bt_ctf_object_pool_new_object_func)(void *data);
-typedef void *(*bt_ctf_object_pool_destroy_object_func)(void *obj, void *data);
-
-struct bt_ctf_object_pool {
-       /*
-        * Container of recycled objects, owned by this. The array's size
-        * is the pool's capacity.
-        */
-       GPtrArray *objects;
-
-       /*
-        * Pool's size, that is, number of elements in the array above,
-        * starting at index 0, which exist as recycled objects.
-        */
-       size_t size;
-
-       /* User functions */
-       struct {
-               /* Allocate a new object in memory */
-               bt_ctf_object_pool_new_object_func new_object;
-
-               /* Free direct and indirect memory occupied by object */
-               bt_ctf_object_pool_destroy_object_func destroy_object;
-       } funcs;
-
-       /* User data passed to user functions */
-       void *data;
-};
-
-/*
- * Initializes an object pool which is already allocated.
- */
-int bt_ctf_object_pool_initialize(struct bt_ctf_object_pool *pool,
-               bt_ctf_object_pool_new_object_func new_object_func,
-               bt_ctf_object_pool_destroy_object_func destroy_object_func,
-               void *data);
-
-/*
- * Finalizes an object pool without deallocating it.
- */
-void bt_ctf_object_pool_finalize(struct bt_ctf_object_pool *pool);
-
-/*
- * Creates an object from an object pool. If the pool is empty, this
- * function calls the "new" user function to allocate a new object
- * before returning it. Otherwise this function returns a recycled
- * object, removing it from the pool.
- *
- * The returned object is owned by the caller.
- */
-static inline
-void *bt_ctf_object_pool_create_object(struct bt_ctf_object_pool *pool)
-{
-       struct bt_ctf_object *obj;
-
-       BT_ASSERT(pool);
-
-#ifdef BT_LOGV
-       BT_LOGV("Creating object from pool: pool-addr=%p, pool-size=%zu, pool-cap=%u",
-               pool, pool->size, pool->objects->len);
-#endif
-
-       if (pool->size > 0) {
-               /* Pick one from the pool */
-               pool->size--;
-               obj = pool->objects->pdata[pool->size];
-               pool->objects->pdata[pool->size] = NULL;
-               goto end;
-       }
-
-       /* Pool is empty: create a brand new object */
-#ifdef BT_LOGV
-       BT_LOGV("Pool is empty: allocating new object: pool-addr=%p",
-               pool);
-#endif
-
-       obj = pool->funcs.new_object(pool->data);
-
-end:
-#ifdef BT_LOGV
-       BT_LOGV("Created one object from pool: pool-addr=%p, obj-addr=%p",
-               pool, obj);
-#endif
-
-       return obj;
-}
-
-/*
- * Recycles an object, that is, puts it back into the pool.
- *
- * The pool becomes the sole owner of the object to recycle.
- */
-static inline
-void bt_ctf_object_pool_recycle_object(struct bt_ctf_object_pool *pool, void *obj)
-{
-       struct bt_ctf_object *bt_obj = obj;
-
-       BT_ASSERT(pool);
-       BT_ASSERT(obj);
-
-#ifdef BT_LOGV
-       BT_LOGV("Recycling object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
-               pool, pool->size, pool->objects->len, obj);
-#endif
-
-       if (pool->size == pool->objects->len) {
-               /* Backing array is full: make place for recycled object */
-#ifdef BT_LOGV
-               BT_LOGV("Object pool is full: increasing object pool capacity: "
-                       "pool-addr=%p, old-pool-cap=%u, new-pool-cap=%u",
-                       pool, pool->objects->len, pool->objects->len + 1);
-#endif
-               g_ptr_array_set_size(pool->objects, pool->size + 1);
-       }
-
-       /* Reset reference count to 1 since it could be 0 now */
-       bt_obj->ref_count = 1;
-
-       /* Back to the pool */
-       pool->objects->pdata[pool->size] = obj;
-       pool->size++;
-
-#ifdef BT_LOGV
-       BT_LOGV("Recycled object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
-               pool, pool->size, pool->objects->len, obj);
-#endif
-}
-
-#endif /* BABELTRACE_CTF_WRITER_OBJECT_POOL_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/resolve-internal.h b/include/babeltrace2/ctf-writer/resolve-internal.h
deleted file mode 100644 (file)
index f779238..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_RESOLVE_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_RESOLVE_INTERNAL_H
-
-/*
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Authors: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *          Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <glib.h>
-
-enum bt_ctf_resolve_flag {
-       BT_CTF_RESOLVE_FLAG_PACKET_HEADER       = 0x01,
-       BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT      = 0x02,
-       BT_CTF_RESOLVE_FLAG_EVENT_HEADER        = 0x04,
-       BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX    = 0x08,
-       BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT       = 0x10,
-       BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD       = 0x20,
-};
-
-/*
- * Resolves CTF IR field types: recursively locates the tag and length
- * field types of resp. variant and sequence field types.
- *
- * All `*_type` parameters may be resolved, and may as well serve as
- * resolving targets.
- *
- * Resolving is performed based on the flags in `flags`.
- *
- * It is expected that, amongst all the provided types, no common
- * references to sequence variant field types exist. In other words,
- * this function does not copy field types.
- *
- * All parameters are owned by the caller.
- */
-BT_HIDDEN
-int bt_ctf_resolve_types(struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type,
-               struct bt_ctf_field_type_common *event_context_type,
-               struct bt_ctf_field_type_common *event_payload_type,
-               enum bt_ctf_resolve_flag flags);
-
-#endif /* BABELTRACE_CTF_WRITER_RESOLVE_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/stream-class-internal.h b/include/babeltrace2/ctf-writer/stream-class-internal.h
deleted file mode 100644 (file)
index 0b7fd47..0000000
+++ /dev/null
@@ -1,538 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_STREAM_CLASS_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_STREAM_CLASS_INTERNAL_H
-
-/*
- * Copyright 2014 EfficiOS Inc.
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/ctf-writer/field-types-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/visitor.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <inttypes.h>
-
-struct bt_ctf_stream_class_common {
-       struct bt_ctf_object base;
-       GString *name;
-
-       /* Array of pointers to event class addresses */
-       GPtrArray *event_classes;
-
-       /* event class id (int64_t) to event class address */
-       GHashTable *event_classes_ht;
-       int id_set;
-       int64_t id;
-       int64_t next_event_id;
-       struct bt_ctf_field_type_common *packet_context_field_type;
-       struct bt_ctf_field_type_common *event_header_field_type;
-       struct bt_ctf_field_type_common *event_context_field_type;
-       int frozen;
-       int byte_order;
-
-       /*
-        * This flag indicates if the stream class is valid. A valid
-        * stream class is _always_ frozen.
-        */
-       int valid;
-
-       /*
-        * Unique clock class mapped to any field type within this
-        * stream class, including all the stream class's event class
-        * field types. This is only set if the stream class is frozen.
-        *
-        * If the stream class is frozen and this is still NULL, it is
-        * still possible that it becomes non-NULL because
-        * bt_ctf_stream_class_add_event_class() can add an event class
-        * containing a field type mapped to some clock class. In this
-        * case, this is the mapped clock class, and at this point, both
-        * the new event class and the stream class are frozen, so the
-        * next added event classes are expected to contain field types
-        * which only map to this specific clock class.
-        *
-        * If this is a CTF writer stream class, then this is the
-        * backing clock class of the `clock` member above.
-        */
-       struct bt_ctf_clock_class *clock_class;
-};
-
-struct bt_ctf_event_class_common;
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class,
-               const char *name, bt_ctf_object_release_func release_func);
-
-BT_HIDDEN
-void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class);
-
-BT_HIDDEN
-void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class);
-
-static inline
-const char *bt_ctf_stream_class_common_get_name(
-               struct bt_ctf_stream_class_common *stream_class)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->name->len > 0 ? stream_class->name->str : NULL;
-}
-
-static inline
-int64_t bt_ctf_stream_class_common_get_id(
-               struct bt_ctf_stream_class_common *stream_class)
-{
-       int64_t ret;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-
-       if (!stream_class->id_set) {
-               BT_LOGV("Stream class's ID is not set: addr=%p, name=\"%s\"",
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class));
-               ret = (int64_t) -1;
-               goto end;
-       }
-
-       ret = stream_class->id;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void bt_ctf_stream_class_common_set_byte_order(
-               struct bt_ctf_stream_class_common *stream_class, int byte_order);
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_validate_single_clock_class(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_clock_class **expected_clock_class);
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_add_event_class(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_event_class_common *event_class,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func);
-
-BT_HIDDEN
-int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class,
-               bt_ctf_visitor visitor, void *data);
-
-BT_HIDDEN
-int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
-               bt_ctf_visitor visitor, void *data);
-
-static inline
-struct bt_ctf_trace_common *bt_ctf_stream_class_common_borrow_trace(
-               struct bt_ctf_stream_class_common *stream_class)
-{
-       BT_ASSERT(stream_class);
-       return (void *) bt_ctf_object_borrow_parent(&stream_class->base);
-}
-
-static inline
-int bt_ctf_stream_class_common_set_name(struct bt_ctf_stream_class_common *stream_class,
-               const char *name)
-{
-       int ret = 0;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (!name) {
-               g_string_assign(stream_class->name, "");
-       } else {
-               if (strlen(name) == 0) {
-                       BT_LOGW("Invalid parameter: name is empty.");
-                       ret = -1;
-                       goto end;
-               }
-
-               g_string_assign(stream_class->name, name);
-       }
-
-       BT_LOGV("Set stream class's name: "
-               "addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-end:
-       return ret;
-}
-
-static inline
-void _bt_ctf_stream_class_common_set_id(
-               struct bt_ctf_stream_class_common *stream_class, int64_t id)
-{
-       BT_ASSERT(stream_class);
-       stream_class->id = id;
-       stream_class->id_set = 1;
-       BT_LOGV("Set stream class's ID (internal): "
-               "addr=%p, name=\"%s\", id=%" PRId64,
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class));
-}
-
-static inline
-int bt_ctf_stream_class_common_set_id_no_check(
-               struct bt_ctf_stream_class_common *stream_class, int64_t id)
-{
-       _bt_ctf_stream_class_common_set_id(stream_class, id);
-       return 0;
-}
-
-static inline
-int bt_ctf_stream_class_common_set_id(struct bt_ctf_stream_class_common *stream_class,
-               uint64_t id_param)
-{
-       int ret = 0;
-       int64_t id = (int64_t) id_param;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (id < 0) {
-               BT_LOGW("Invalid parameter: invalid stream class's ID: "
-                       "stream-class-addr=%p, stream-class-name=\"%s\", "
-                       "stream-class-id=%" PRId64 ", id=%" PRIu64,
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class),
-                       id_param);
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_ctf_stream_class_common_set_id_no_check(stream_class, id);
-       if (ret == 0) {
-               BT_LOGV("Set stream class's ID: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class));
-       }
-end:
-       return ret;
-}
-
-static inline
-int64_t bt_ctf_stream_class_common_get_event_class_count(
-               struct bt_ctf_stream_class_common *stream_class)
-{
-       int64_t ret;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = (int64_t) -1;
-               goto end;
-       }
-
-       ret = (int64_t) stream_class->event_classes->len;
-end:
-       return ret;
-}
-
-static inline
-struct bt_ctf_event_class_common *bt_ctf_stream_class_common_borrow_event_class_by_index(
-               struct bt_ctf_stream_class_common *stream_class, uint64_t index)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_CTF_ASSERT_PRE(index < stream_class->event_classes->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u",
-               index, stream_class->event_classes->len);
-       return g_ptr_array_index(stream_class->event_classes, index);
-}
-
-static inline
-struct bt_ctf_event_class_common *bt_ctf_stream_class_common_borrow_event_class_by_id(
-               struct bt_ctf_stream_class_common *stream_class, uint64_t id)
-{
-       int64_t id_key = (int64_t) id;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_CTF_ASSERT_PRE(id_key >= 0,
-               "Invalid event class ID: %" PRIu64, id);
-       return g_hash_table_lookup(stream_class->event_classes_ht,
-                       &id_key);
-}
-
-static inline
-struct bt_ctf_field_type_common *
-bt_ctf_stream_class_common_borrow_packet_context_field_type(
-               struct bt_ctf_stream_class_common *stream_class)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->packet_context_field_type;
-}
-
-static inline
-int bt_ctf_stream_class_common_set_packet_context_field_type(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *packet_context_type)
-{
-       int ret = 0;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (packet_context_type &&
-                       bt_ctf_field_type_common_get_type_id(packet_context_type) !=
-                               BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               /* A packet context must be a structure. */
-               BT_LOGW("Invalid parameter: stream class's packet context field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "packet-context-ft-addr=%p, packet-context-ft-id=%s",
-                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class),
-                       packet_context_type,
-                       bt_ctf_field_type_id_string(
-                               bt_ctf_field_type_common_get_type_id(packet_context_type)));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(stream_class->packet_context_field_type);
-       stream_class->packet_context_field_type = packet_context_type;
-       bt_ctf_object_get_ref(stream_class->packet_context_field_type);
-       BT_LOGV("Set stream class's packet context field type: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", "
-               "packet-context-ft-addr=%p",
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class),
-               packet_context_type);
-
-end:
-       return ret;
-}
-
-static inline
-struct bt_ctf_field_type_common *
-bt_ctf_stream_class_common_borrow_event_header_field_type(
-               struct bt_ctf_stream_class_common *stream_class)
-{
-       struct bt_ctf_field_type_common *ret = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-
-       if (!stream_class->event_header_field_type) {
-               BT_LOGV("Stream class has no event header field type: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class));
-               goto end;
-       }
-
-       ret = stream_class->event_header_field_type;
-
-end:
-       return ret;
-}
-
-static inline
-int bt_ctf_stream_class_common_set_event_header_field_type(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *event_header_type)
-{
-       int ret = 0;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class,
-                       bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (event_header_type &&
-                       bt_ctf_field_type_common_get_type_id(event_header_type) !=
-                               BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               /* An event header must be a structure. */
-               BT_LOGW("Invalid parameter: stream class's event header field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "event-header-ft-addr=%p, event-header-ft-id=%s",
-                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class),
-                       event_header_type,
-                       bt_ctf_field_type_id_string(
-                               bt_ctf_field_type_common_get_type_id(event_header_type)));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(stream_class->event_header_field_type);
-       stream_class->event_header_field_type = event_header_type;
-       bt_ctf_object_get_ref(stream_class->event_header_field_type);
-       BT_LOGV("Set stream class's event header field type: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", "
-               "event-header-ft-addr=%p",
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class),
-               event_header_type);
-end:
-       return ret;
-}
-
-static inline
-struct bt_ctf_field_type_common *
-bt_ctf_stream_class_common_borrow_event_context_field_type(
-               struct bt_ctf_stream_class_common *stream_class)
-{
-       struct bt_ctf_field_type_common *ret = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-
-       if (!stream_class->event_context_field_type) {
-               goto end;
-       }
-
-       ret = stream_class->event_context_field_type;
-
-end:
-       return ret;
-}
-
-static inline
-int bt_ctf_stream_class_common_set_event_context_field_type(
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_field_type_common *event_context_type)
-{
-       int ret = 0;
-
-       if (!stream_class) {
-               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       if (stream_class->frozen) {
-               BT_LOGW("Invalid parameter: stream class is frozen: "
-                       "addr=%p, name=\"%s\", id=%" PRId64,
-                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class));
-               ret = -1;
-               goto end;
-       }
-
-       if (event_context_type &&
-                       bt_ctf_field_type_common_get_type_id(event_context_type) !=
-                               BT_CTF_FIELD_TYPE_ID_STRUCT) {
-               /* A packet context must be a structure. */
-               BT_LOGW("Invalid parameter: stream class's event context field type must be a structure: "
-                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
-                       "event-context-ft-addr=%p, event-context-ft-id=%s",
-                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-                       bt_ctf_stream_class_common_get_id(stream_class),
-                       event_context_type,
-                       bt_ctf_field_type_id_string(
-                               bt_ctf_field_type_common_get_type_id(event_context_type)));
-               ret = -1;
-               goto end;
-       }
-
-       bt_ctf_object_put_ref(stream_class->event_context_field_type);
-       stream_class->event_context_field_type = event_context_type;
-       bt_ctf_object_get_ref(stream_class->event_context_field_type);
-       BT_LOGV("Set stream class's event context field type: "
-               "addr=%p, name=\"%s\", id=%" PRId64 ", "
-               "event-context-ft-addr=%p",
-               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
-               bt_ctf_stream_class_common_get_id(stream_class),
-               event_context_type);
-end:
-       return ret;
-}
-
-struct bt_ctf_stream_class {
-       struct bt_ctf_stream_class_common common;
-       struct bt_ctf_clock *clock;
-       int64_t next_stream_id;
-};
-
-struct metadata_context;
-
-BT_HIDDEN
-int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
-               struct metadata_context *context);
-
-BT_HIDDEN
-int bt_ctf_stream_class_map_clock_class(
-               struct bt_ctf_stream_class *stream_class,
-               struct bt_ctf_field_type *packet_context_type,
-               struct bt_ctf_field_type *event_header_type);
-
-#endif /* BABELTRACE_CTF_WRITER_STREAM_CLASS_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/stream-internal.h b/include/babeltrace2/ctf-writer/stream-internal.h
deleted file mode 100644 (file)
index c7eb9fa..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H
-
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/stream-internal.h>
-#include <babeltrace2/ctf-writer/stream.h>
-#include <babeltrace2/ctf-writer/utils-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <stdint.h>
-
-struct bt_ctf_stream_common;
-
-struct bt_ctf_stream_common {
-       struct bt_ctf_object base;
-       int64_t id;
-       struct bt_ctf_stream_class_common *stream_class;
-       GString *name;
-};
-
-BT_HIDDEN
-int bt_ctf_stream_common_initialize(
-               struct bt_ctf_stream_common *stream,
-               struct bt_ctf_stream_class_common *stream_class, const char *name,
-               uint64_t id, bt_ctf_object_release_func release_func);
-
-BT_HIDDEN
-void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream);
-
-static inline
-struct bt_ctf_stream_class_common *bt_ctf_stream_common_borrow_class(
-               struct bt_ctf_stream_common *stream)
-{
-       BT_ASSERT(stream);
-       return stream->stream_class;
-}
-
-static inline
-const char *bt_ctf_stream_common_get_name(struct bt_ctf_stream_common *stream)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(stream, "Stream");
-       return stream->name ? stream->name->str : NULL;
-}
-
-static inline
-int64_t bt_ctf_stream_common_get_id(struct bt_ctf_stream_common *stream)
-{
-       int64_t ret;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(stream, "Stream");
-       ret = stream->id;
-       if (ret < 0) {
-               BT_LOGV("Stream's ID is not set: addr=%p, name=\"%s\"",
-                       stream, bt_ctf_stream_common_get_name(stream));
-       }
-
-       return ret;
-}
-
-struct bt_ctf_stream {
-       struct bt_ctf_stream_common common;
-       struct bt_ctf_field *packet_header;
-       struct bt_ctf_field *packet_context;
-
-       /* Array of pointers to bt_ctf_event for the current packet */
-       GPtrArray *events;
-       struct bt_ctfser ctfser;
-       unsigned int flushed_packet_count;
-       uint64_t discarded_events;
-       uint64_t last_ts_end;
-};
-
-BT_HIDDEN
-struct bt_ctf_stream *bt_ctf_stream_create_with_id(
-               struct bt_ctf_stream_class *stream_class,
-               const char *name, uint64_t id);
-
-#endif /* BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/trace-internal.h b/include/babeltrace2/ctf-writer/trace-internal.h
deleted file mode 100644 (file)
index 4d3e4d1..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_TRACE_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_TRACE_INTERNAL_H
-
-/*
- * Copyright 2014 EfficiOS Inc.
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <babeltrace2/ctf-writer/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/ctf-writer/attributes-internal.h>
-#include <babeltrace2/ctf-writer/clock-class-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/fields.h>
-#include <babeltrace2/ctf-writer/stream-class-internal.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/validation-internal.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-#include <sys/types.h>
-
-struct bt_ctf_trace_common {
-       struct bt_ctf_object base;
-       GString *name;
-       int frozen;
-       unsigned char uuid[BABELTRACE_UUID_LEN];
-       bt_bool uuid_set;
-       enum bt_ctf_byte_order native_byte_order;
-       struct bt_ctf_private_value *environment;
-       GPtrArray *clock_classes; /* Array of pointers to bt_ctf_clock_class */
-       GPtrArray *stream_classes; /* Array of ptrs to bt_ctf_stream_class_common */
-       GPtrArray *streams; /* Array of ptrs to bt_ctf_stream_common */
-       struct bt_ctf_field_type_common *packet_header_field_type;
-       int64_t next_stream_id;
-
-       /*
-        * This flag indicates if the trace is valid. A valid
-        * trace is _always_ frozen.
-        */
-       int valid;
-};
-
-BT_HIDDEN
-bt_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_clock_class *clock_class);
-
-BT_HIDDEN
-int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace,
-               bt_ctf_object_release_func release_func);
-
-BT_HIDDEN
-void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace);
-
-static inline
-const char *bt_ctf_trace_common_get_name(struct bt_ctf_trace_common *trace)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->name ? trace->name->str : NULL;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char *name);
-
-static inline
-const unsigned char *bt_ctf_trace_common_get_uuid(struct bt_ctf_trace_common *trace)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->uuid_set ? trace->uuid : NULL;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace, const unsigned char *uuid);
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace,
-               const char *name, struct bt_ctf_private_value *value);
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace,
-               const char *name, const char *value);
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_environment_field_integer(struct bt_ctf_trace_common *trace,
-               const char *name, int64_t value);
-
-static inline
-int64_t bt_ctf_trace_common_get_environment_field_count(
-               struct bt_ctf_trace_common *trace)
-{
-       int64_t ret;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       ret = bt_ctf_attributes_get_count(trace->environment);
-       BT_ASSERT(ret >= 0);
-       return ret;
-}
-
-static inline
-const char *
-bt_ctf_trace_common_get_environment_field_name_by_index(
-               struct bt_ctf_trace_common *trace, uint64_t index)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return bt_ctf_attributes_get_field_name(trace->environment, index);
-}
-
-static inline
-struct bt_ctf_private_value *
-bt_ctf_trace_common_borrow_environment_field_value_by_index(
-               struct bt_ctf_trace_common *trace, uint64_t index)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return bt_ctf_attributes_borrow_field_value(trace->environment, index);
-}
-
-static inline
-struct bt_ctf_private_value *
-bt_ctf_trace_common_borrow_environment_field_value_by_name(
-               struct bt_ctf_trace_common *trace, const char *name)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
-       return bt_ctf_attributes_borrow_field_value_by_name(trace->environment,
-               name);
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_clock_class *clock_class);
-
-static inline
-int64_t bt_ctf_trace_common_get_clock_class_count(struct bt_ctf_trace_common *trace)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->clock_classes->len;
-}
-
-static inline
-struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_index(
-               struct bt_ctf_trace_common *trace, uint64_t index)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_CTF_ASSERT_PRE(index < trace->clock_classes->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u",
-               index, trace->clock_classes->len);
-       return g_ptr_array_index(trace->clock_classes, index);
-}
-
-static inline
-int64_t bt_ctf_trace_common_get_stream_count(struct bt_ctf_trace_common *trace)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return (int64_t) trace->streams->len;
-}
-
-static inline
-struct bt_ctf_stream_common *bt_ctf_trace_common_borrow_stream_by_index(
-               struct bt_ctf_trace_common *trace,
-               uint64_t index)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_CTF_ASSERT_PRE(index < trace->streams->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u",
-               index, trace->streams->len);
-       return g_ptr_array_index(trace->streams, index);
-}
-
-static inline
-int64_t bt_ctf_trace_common_get_stream_class_count(struct bt_ctf_trace_common *trace)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return (int64_t) trace->stream_classes->len;
-}
-
-static inline
-struct bt_ctf_stream_class_common *bt_ctf_trace_common_borrow_stream_class_by_index(
-               struct bt_ctf_trace_common *trace, uint64_t index)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_CTF_ASSERT_PRE(index < trace->stream_classes->len,
-               "Index is out of bounds: index=%" PRIu64 ", "
-               "count=%u",
-               index, trace->stream_classes->len);
-       return g_ptr_array_index(trace->stream_classes, index);
-}
-
-static inline
-struct bt_ctf_stream_class_common *bt_ctf_trace_common_borrow_stream_class_by_id(
-               struct bt_ctf_trace_common *trace, uint64_t id_param)
-{
-       int i;
-       struct bt_ctf_stream_class_common *stream_class = NULL;
-       int64_t id = (int64_t) id_param;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_CTF_ASSERT_PRE(id >= 0,
-               "Invalid stream class ID: %" PRIu64, id_param);
-
-       for (i = 0; i < trace->stream_classes->len; i++) {
-               struct bt_ctf_stream_class_common *stream_class_candidate;
-
-               stream_class_candidate =
-                       g_ptr_array_index(trace->stream_classes, i);
-
-               if (bt_ctf_stream_class_common_get_id(stream_class_candidate) ==
-                               (int64_t) id) {
-                       stream_class = stream_class_candidate;
-                       goto end;
-               }
-       }
-
-end:
-       return stream_class;
-}
-
-static inline
-struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_name(
-               struct bt_ctf_trace_common *trace, const char *name)
-{
-       size_t i;
-       struct bt_ctf_clock_class *clock_class = NULL;
-
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
-
-       for (i = 0; i < trace->clock_classes->len; i++) {
-               struct bt_ctf_clock_class *cur_clk =
-                       g_ptr_array_index(trace->clock_classes, i);
-               const char *cur_clk_name = bt_ctf_clock_class_get_name(cur_clk);
-
-               if (!cur_clk_name) {
-                       goto end;
-               }
-
-               if (!strcmp(cur_clk_name, name)) {
-                       clock_class = cur_clk;
-                       goto end;
-               }
-       }
-
-end:
-       return clock_class;
-}
-
-static inline
-enum bt_ctf_byte_order bt_ctf_trace_common_get_native_byte_order(
-               struct bt_ctf_trace_common *trace)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->native_byte_order;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace,
-               enum bt_ctf_byte_order byte_order, bool allow_unspecified);
-
-static inline
-struct bt_ctf_field_type_common *bt_ctf_trace_common_borrow_packet_header_field_type(
-               struct bt_ctf_trace_common *trace)
-{
-       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->packet_header_field_type;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_field_type_common *packet_header_field_type);
-
-static inline
-void bt_ctf_trace_common_freeze(struct bt_ctf_trace_common *trace)
-{
-       int i;
-
-       if (trace->frozen) {
-               return;
-       }
-
-       BT_LOGD("Freezing trace: addr=%p, name=\"%s\"",
-               trace, bt_ctf_trace_common_get_name(trace));
-       BT_LOGD_STR("Freezing packet header field type.");
-       bt_ctf_field_type_common_freeze(trace->packet_header_field_type);
-       BT_LOGD_STR("Freezing environment attributes.");
-       bt_ctf_attributes_freeze(trace->environment);
-
-       if (trace->clock_classes->len > 0) {
-               BT_LOGD_STR("Freezing clock classes.");
-       }
-
-       for (i = 0; i < trace->clock_classes->len; i++) {
-               struct bt_ctf_clock_class *clock_class =
-                       g_ptr_array_index(trace->clock_classes, i);
-
-               bt_ctf_clock_class_freeze(clock_class);
-       }
-
-       trace->frozen = 1;
-}
-
-BT_HIDDEN
-int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func,
-               struct bt_ctf_clock_class *init_expected_clock_class,
-               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
-                       struct bt_ctf_field_type_common *packet_context_field_type,
-                       struct bt_ctf_field_type_common *event_header_field_type),
-               bool check_ts_begin_end_mapped);
-
-struct bt_ctf_trace {
-       struct bt_ctf_trace_common common;
-};
-
-/*
- * bt_ctf_trace_get_metadata_string: get metadata string.
- *
- * Get the trace's TSDL metadata. The caller assumes the ownership of the
- * returned string.
- *
- * @param trace Trace instance.
- *
- * Returns the metadata string on success, NULL on error.
- */
-BT_HIDDEN
-char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace);
-
-BT_HIDDEN
-struct bt_ctf_trace *bt_ctf_trace_create(void);
-
-BT_HIDDEN
-int64_t bt_ctf_trace_get_clock_class_count(
-               struct bt_ctf_trace *trace);
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
-               struct bt_ctf_trace *trace, uint64_t index);
-
-BT_HIDDEN
-struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
-               struct bt_ctf_trace *trace, const char *name);
-
-BT_HIDDEN
-int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
-               struct bt_ctf_clock_class *clock_class);
-
-BT_HIDDEN
-int64_t bt_ctf_trace_get_environment_field_count(
-               struct bt_ctf_trace *trace);
-
-BT_HIDDEN
-const char *bt_ctf_trace_get_environment_field_name_by_index(
-               struct bt_ctf_trace *trace, uint64_t index);
-
-BT_HIDDEN
-struct bt_ctf_value *
-bt_ctf_trace_get_environment_field_value_by_index(struct bt_ctf_trace *trace,
-               uint64_t index);
-
-BT_HIDDEN
-struct bt_ctf_value *
-bt_ctf_trace_get_environment_field_value_by_name(
-               struct bt_ctf_trace *trace, const char *name);
-
-#endif /* BABELTRACE_CTF_WRITER_TRACE_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/utils-internal.h b/include/babeltrace2/ctf-writer/utils-internal.h
deleted file mode 100644 (file)
index d253824..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_UTILS_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_UTILS_INTERNAL_H
-
-/*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/field-types.h>
-#include <babeltrace2/ctf-writer/field-path-internal.h>
-#include <babeltrace2/ctf-writer/event.h>
-#include <stdint.h>
-
-#define BT_CTF_TO_COMMON(_obj)         (&(_obj)->common)
-#define BT_CTF_FROM_COMMON(_obj)       ((void *) _obj)
-
-struct bt_ctf_search_query {
-       gpointer value;
-       int found;
-};
-
-BT_HIDDEN
-const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order);
-
-static inline
-const char *bt_ctf_field_type_id_string(enum bt_ctf_field_type_id type_id)
-{
-       switch (type_id) {
-       case BT_CTF_FIELD_TYPE_ID_UNKNOWN:
-               return "BT_CTF_FIELD_TYPE_ID_UNKNOWN";
-       case BT_CTF_FIELD_TYPE_ID_INTEGER:
-               return "BT_CTF_FIELD_TYPE_ID_INTEGER";
-       case BT_CTF_FIELD_TYPE_ID_FLOAT:
-               return "BT_CTF_FIELD_TYPE_ID_FLOAT";
-       case BT_CTF_FIELD_TYPE_ID_ENUM:
-               return "BT_CTF_FIELD_TYPE_ID_ENUM";
-       case BT_CTF_FIELD_TYPE_ID_STRING:
-               return "BT_CTF_FIELD_TYPE_ID_STRING";
-       case BT_CTF_FIELD_TYPE_ID_STRUCT:
-               return "BT_CTF_FIELD_TYPE_ID_STRUCT";
-       case BT_CTF_FIELD_TYPE_ID_ARRAY:
-               return "BT_CTF_FIELD_TYPE_ID_ARRAY";
-       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
-               return "BT_CTF_FIELD_TYPE_ID_SEQUENCE";
-       case BT_CTF_FIELD_TYPE_ID_VARIANT:
-               return "BT_CTF_FIELD_TYPE_ID_VARIANT";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-const char *bt_ctf_byte_order_string(enum bt_ctf_byte_order bo)
-{
-       switch (bo) {
-       case BT_CTF_BYTE_ORDER_UNKNOWN:
-               return "BT_CTF_BYTE_ORDER_UNKNOWN";
-       case BT_CTF_BYTE_ORDER_UNSPECIFIED:
-               return "BT_CTF_BYTE_ORDER_UNSPECIFIED";
-       case BT_CTF_BYTE_ORDER_NATIVE:
-               return "BT_CTF_BYTE_ORDER_NATIVE";
-       case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
-               return "BT_CTF_BYTE_ORDER_LITTLE_ENDIAN";
-       case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
-               return "BT_CTF_BYTE_ORDER_BIG_ENDIAN";
-       case BT_CTF_BYTE_ORDER_NETWORK:
-               return "BT_CTF_BYTE_ORDER_NETWORK";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-const char *bt_ctf_string_encoding_string(enum bt_ctf_string_encoding encoding)
-{
-       switch (encoding) {
-       case BT_CTF_STRING_ENCODING_UNKNOWN:
-               return "BT_CTF_STRING_ENCODING_UNKNOWN";
-       case BT_CTF_STRING_ENCODING_NONE:
-               return "BT_CTF_STRING_ENCODING_NONE";
-       case BT_CTF_STRING_ENCODING_UTF8:
-               return "BT_CTF_STRING_ENCODING_UTF8";
-       case BT_CTF_STRING_ENCODING_ASCII:
-               return "BT_CTF_STRING_ENCODING_ASCII";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-const char *bt_ctf_integer_base_string(enum bt_ctf_integer_base base)
-{
-       switch (base) {
-       case BT_CTF_INTEGER_BASE_UNKNOWN:
-               return "BT_CTF_INTEGER_BASE_UNKNOWN";
-       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
-               return "BT_CTF_INTEGER_BASE_UNSPECIFIED";
-       case BT_CTF_INTEGER_BASE_BINARY:
-               return "BT_CTF_INTEGER_BASE_BINARY";
-       case BT_CTF_INTEGER_BASE_OCTAL:
-               return "BT_CTF_INTEGER_BASE_OCTAL";
-       case BT_CTF_INTEGER_BASE_DECIMAL:
-               return "BT_CTF_INTEGER_BASE_DECIMAL";
-       case BT_CTF_INTEGER_BASE_HEXADECIMAL:
-               return "BT_CTF_INTEGER_BASE_HEXADECIMAL";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-const char *bt_ctf_scope_string(enum bt_ctf_scope scope)
-{
-       switch (scope) {
-       case BT_CTF_SCOPE_UNKNOWN:
-               return "BT_CTF_SCOPE_UNKNOWN";
-       case BT_CTF_SCOPE_TRACE_PACKET_HEADER:
-               return "BT_CTF_SCOPE_TRACE_PACKET_HEADER";
-       case BT_CTF_SCOPE_STREAM_PACKET_CONTEXT:
-               return "BT_CTF_SCOPE_STREAM_PACKET_CONTEXT";
-       case BT_CTF_SCOPE_STREAM_EVENT_HEADER:
-               return "BT_CTF_SCOPE_STREAM_EVENT_HEADER";
-       case BT_CTF_SCOPE_STREAM_EVENT_CONTEXT:
-               return "BT_CTF_SCOPE_STREAM_EVENT_CONTEXT";
-       case BT_CTF_SCOPE_EVENT_CONTEXT:
-               return "BT_CTF_SCOPE_EVENT_CONTEXT";
-       case BT_CTF_SCOPE_EVENT_PAYLOAD:
-               return "BT_CTF_SCOPE_EVENT_PAYLOAD";
-       case BT_CTF_SCOPE_ENV:
-               return "BT_CTF_SCOPE_ENV";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-const char *bt_ctf_event_class_log_level_string(
-               enum bt_ctf_event_class_log_level level)
-{
-       switch (level) {
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_UNKNOWN:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_UNKNOWN";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_EMERGENCY";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_ALERT:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_ALERT";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_CRITICAL:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_CRITICAL";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_ERROR:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_ERROR";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_WARNING:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_WARNING";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_NOTICE:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_NOTICE";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_INFO:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_INFO";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE";
-       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG:
-               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-GString *bt_ctf_field_path_string(struct bt_ctf_field_path *path)
-{
-       GString *str = g_string_new(NULL);
-       size_t i;
-
-       BT_ASSERT(path);
-
-       if (!str) {
-               goto end;
-       }
-
-       g_string_append_printf(str, "[%s", bt_common_scope_string(
-               bt_ctf_field_path_get_root_scope(path)));
-
-       for (i = 0; i < bt_ctf_field_path_get_index_count(path); i++) {
-               int index = bt_ctf_field_path_get_index(path, i);
-
-               g_string_append_printf(str, ", %d", index);
-       }
-
-       g_string_append(str, "]");
-
-end:
-       return str;
-}
-
-#endif /* BABELTRACE_CTF_WRITER_UTILS_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/validation-internal.h b/include/babeltrace2/ctf-writer/validation-internal.h
deleted file mode 100644 (file)
index 608078f..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_VALIDATION_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_VALIDATION_INTERNAL_H
-
-/*
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/ctf-writer/values-internal.h>
-
-struct bt_ctf_trace_common;
-struct bt_ctf_stream_class_common;
-struct bt_ctf_event_class_common;
-struct bt_ctf_field_type_common;
-
-typedef struct bt_ctf_field_type_common *(*bt_ctf_validation_flag_copy_field_type_func)(
-               struct bt_ctf_field_type_common *);
-
-enum bt_ctf_validation_flag {
-       BT_CTF_VALIDATION_FLAG_TRACE    = 1,
-       BT_CTF_VALIDATION_FLAG_STREAM   = 2,
-       BT_CTF_VALIDATION_FLAG_EVENT    = 4,
-};
-
-/*
- * Validation output structure.
- *
- * This is where the results of the validation function go. The field
- * types are the validated ones which should replace the original field
- * types of a trace, a stream class, and an event class.
- *
- * `valid_flags` contains the results of the validation.
- */
-struct bt_ctf_validation_output {
-       struct bt_ctf_field_type_common *packet_header_type;
-       struct bt_ctf_field_type_common *packet_context_type;
-       struct bt_ctf_field_type_common *event_header_type;
-       struct bt_ctf_field_type_common *stream_event_ctx_type;
-       struct bt_ctf_field_type_common *event_context_type;
-       struct bt_ctf_field_type_common *event_payload_type;
-       enum bt_ctf_validation_flag valid_flags;
-};
-
-/*
- * This function resolves and validates the field types of an event
- * class, a stream class, and a trace. Copies are created if needed
- * and the resulting field types to use are placed in the `output`
- * validation structure, which also contains the results of the
- * validation. Copies can replace the original field types of a trace,
- * a stream class, and an event class using
- * bt_ctf_validation_replace_types().
- *
- * The current known validity of the field types of the trace,
- * stream class, and event class must be indicated with the
- * `trace_valid`, `stream_class_valid`, and `event_class_valid`
- * parameters. If a class is valid, its field types are not copied,
- * validated, or resolved during this call.
- *
- * The validation flags `validate_flags` indicate which classes should
- * have their field types validated.
- *
- * All parameters are owned by the caller.
- */
-BT_HIDDEN
-int bt_ctf_validate_class_types(struct bt_ctf_private_value *environment,
-               struct bt_ctf_field_type_common *packet_header_type,
-               struct bt_ctf_field_type_common *packet_context_type,
-               struct bt_ctf_field_type_common *event_header_type,
-               struct bt_ctf_field_type_common *stream_event_ctx_type,
-               struct bt_ctf_field_type_common *event_context_type,
-               struct bt_ctf_field_type_common *event_payload_type,
-               int trace_valid, int stream_class_valid, int event_class_valid,
-               struct bt_ctf_validation_output *output,
-               enum bt_ctf_validation_flag validate_flags,
-               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func);
-
-/*
- * This function replaces the actual field types of a trace, a stream
- * class, and an event class with the appropriate field types contained
- * in a validation output structure.
- *
- * The replace flags `replace_flags` indicate which classes should have
- * their field types replaced.
- *
- * Note that the field types that are not used in the validation output
- * structure are still owned by it at the end of this call.
- * bt_ctf_validation_output_put_types() should be called to clean the
- * structure.
- *
- * All parameters are owned by the caller.
- */
-BT_HIDDEN
-void bt_ctf_validation_replace_types(struct bt_ctf_trace_common *trace,
-               struct bt_ctf_stream_class_common *stream_class,
-               struct bt_ctf_event_class_common *event_class,
-               struct bt_ctf_validation_output *output,
-               enum bt_ctf_validation_flag replace_flags);
-
-/*
- * This function puts all the field types contained in a given
- * validation output structure.
- *
- * `output` is owned by the caller and is not freed here.
- */
-BT_HIDDEN
-void bt_ctf_validation_output_put_types(
-               struct bt_ctf_validation_output *output);
-
-#endif /* BABELTRACE_CTF_WRITER_VALIDATION_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/values-internal.h b/include/babeltrace2/ctf-writer/values-internal.h
deleted file mode 100644 (file)
index dff4638..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_VALUES_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_VALUES_INTERNAL_H
-
-/*
- * Copyright (c) 2015-2017 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-
-struct bt_ctf_value;
-struct bt_ctf_private_value;
-
-/**
-@brief Status codes.
-*/
-enum bt_ctf_value_status {
-       /// Operation canceled.
-       BT_CTF_VALUE_STATUS_CANCELED    = 125,
-
-       /// Cannot allocate memory.
-       BT_CTF_VALUE_STATUS_NOMEM       = -12,
-
-       /// Okay, no error.
-       BT_CTF_VALUE_STATUS_OK          = 0,
-};
-
-BT_HIDDEN
-enum bt_ctf_value_status _bt_ctf_value_freeze(struct bt_ctf_value *object);
-
-#ifdef BT_DEV_MODE
-# define bt_ctf_value_freeze   _bt_ctf_value_freeze
-#else
-# define bt_ctf_value_freeze(_value)
-#endif /* BT_DEV_MODE */
-
-extern struct bt_ctf_value *const bt_ctf_value_null;
-
-enum bt_ctf_value_type {
-       /// Null value object.
-       BT_CTF_VALUE_TYPE_NULL =                0,
-
-       /// Boolean value object (holds #BT_TRUE or #BT_FALSE).
-       BT_CTF_VALUE_TYPE_BOOL =                1,
-
-       /// Integer value object (holds a signed 64-bit integer raw value).
-       BT_CTF_VALUE_TYPE_INTEGER =             2,
-
-       /// Floating point number value object (holds a \c double raw value).
-       BT_CTF_VALUE_TYPE_REAL =                3,
-
-       /// String value object.
-       BT_CTF_VALUE_TYPE_STRING =              4,
-
-       /// Array value object.
-       BT_CTF_VALUE_TYPE_ARRAY =               5,
-
-       /// Map value object.
-       BT_CTF_VALUE_TYPE_MAP =         6,
-};
-
-BT_HIDDEN
-enum bt_ctf_value_type bt_ctf_value_get_type(const struct bt_ctf_value *object);
-
-static inline
-bt_bool bt_ctf_value_is_null(const struct bt_ctf_value *object)
-{
-       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_NULL;
-}
-
-static inline
-bt_bool bt_ctf_value_is_bool(const struct bt_ctf_value *object)
-{
-       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_BOOL;
-}
-
-static inline
-bt_bool bt_ctf_value_is_integer(const struct bt_ctf_value *object)
-{
-       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_INTEGER;
-}
-
-static inline
-bt_bool bt_ctf_value_is_real(const struct bt_ctf_value *object)
-{
-       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_REAL;
-}
-
-static inline
-bt_bool bt_ctf_value_is_string(const struct bt_ctf_value *object)
-{
-       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_STRING;
-}
-
-static inline
-bt_bool bt_ctf_value_is_array(const struct bt_ctf_value *object)
-{
-       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_ARRAY;
-}
-
-static inline
-bt_bool bt_ctf_value_is_map(const struct bt_ctf_value *object)
-{
-       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_MAP;
-}
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_copy(struct bt_ctf_private_value **copy,
-               const struct bt_ctf_value *object);
-
-BT_HIDDEN
-bt_bool bt_ctf_value_compare(const struct bt_ctf_value *object_a,
-               const struct bt_ctf_value *object_b);
-
-BT_HIDDEN
-bt_bool bt_ctf_value_bool_get(const struct bt_ctf_value *bool_obj);
-
-BT_HIDDEN
-int64_t bt_ctf_value_integer_get(const struct bt_ctf_value *integer_obj);
-
-BT_HIDDEN
-double bt_ctf_value_real_get(const struct bt_ctf_value *real_obj);
-
-BT_HIDDEN
-const char *bt_ctf_value_string_get(const struct bt_ctf_value *string_obj);
-
-BT_HIDDEN
-uint64_t bt_ctf_value_array_get_size(const struct bt_ctf_value *array_obj);
-
-static inline
-bt_bool bt_ctf_value_array_is_empty(const struct bt_ctf_value *array_obj)
-{
-       return bt_ctf_value_array_get_size(array_obj) == 0;
-}
-
-BT_HIDDEN
-struct bt_ctf_value *bt_ctf_value_array_borrow_element_by_index(
-               const struct bt_ctf_value *array_obj, uint64_t index);
-
-BT_HIDDEN
-uint64_t bt_ctf_value_map_get_size(const struct bt_ctf_value *map_obj);
-
-static inline
-bt_bool bt_ctf_value_map_is_empty(const struct bt_ctf_value *map_obj)
-{
-       return bt_ctf_value_map_get_size(map_obj) == 0;
-}
-
-BT_HIDDEN
-struct bt_ctf_value *bt_ctf_value_map_borrow_entry_value(
-               const struct bt_ctf_value *map_obj, const char *key);
-
-typedef bt_bool (* bt_ctf_value_map_foreach_entry_cb)(const char *key,
-       struct bt_ctf_value *object, void *data);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_map_foreach_entry(
-               const struct bt_ctf_value *map_obj,
-               bt_ctf_value_map_foreach_entry_cb cb, void *data);
-
-BT_HIDDEN
-bt_bool bt_ctf_value_map_has_entry(const struct bt_ctf_value *map_obj,
-               const char *key);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_value_map_extend(
-               struct bt_ctf_private_value **extended_map_obj,
-               const struct bt_ctf_value *base_map_obj,
-               const struct bt_ctf_value *extension_map_obj);
-
-
-struct bt_ctf_value;
-struct bt_ctf_private_value;
-
-extern struct bt_ctf_private_value *const bt_ctf_private_value_null;
-
-static inline
-struct bt_ctf_value *bt_ctf_private_value_as_value(
-               struct bt_ctf_private_value *priv_value)
-{
-       return (void *) priv_value;
-}
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_bool_create(void);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_bool_create_init(bt_bool val);
-
-BT_HIDDEN
-void bt_ctf_private_value_bool_set(struct bt_ctf_private_value *bool_obj,
-               bt_bool val);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_integer_create(void);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_integer_create_init(
-               int64_t val);
-
-BT_HIDDEN
-void bt_ctf_private_value_integer_set(
-               struct bt_ctf_private_value *integer_obj, int64_t val);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_real_create(void);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_real_create_init(double val);
-
-BT_HIDDEN
-void bt_ctf_private_value_real_set(
-               struct bt_ctf_private_value *real_obj, double val);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_string_create(void);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_string_create_init(
-               const char *val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_string_set(
-               struct bt_ctf_private_value *string_obj,
-               const char *val);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_array_create(void);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_array_borrow_element_by_index(
-               const struct bt_ctf_private_value *array_obj, uint64_t index);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_element(
-               struct bt_ctf_private_value *array_obj,
-               struct bt_ctf_value *element_obj);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_bool_element(
-               struct bt_ctf_private_value *array_obj,
-               bt_bool val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_integer_element(
-               struct bt_ctf_private_value *array_obj,
-               int64_t val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_real_element(
-               struct bt_ctf_private_value *array_obj,
-               double val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_string_element(
-               struct bt_ctf_private_value *array_obj, const char *val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_array_element(
-               struct bt_ctf_private_value *array_obj);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_map_element(
-               struct bt_ctf_private_value *array_obj);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_array_set_element_by_index(
-               struct bt_ctf_private_value *array_obj, uint64_t index,
-               struct bt_ctf_value *element_obj);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_map_create(void);
-
-BT_HIDDEN
-struct bt_ctf_private_value *bt_ctf_private_value_map_borrow_entry_value(
-               const struct bt_ctf_private_value *map_obj, const char *key);
-
-typedef bt_bool (* bt_ctf_private_value_map_foreach_entry_cb)(const char *key,
-               struct bt_ctf_private_value *object, void *data);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_foreach_entry(
-               const struct bt_ctf_private_value *map_obj,
-               bt_ctf_private_value_map_foreach_entry_cb cb, void *data);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_entry(
-               struct bt_ctf_private_value *map_obj, const char *key,
-               struct bt_ctf_value *element_obj);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_bool_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, bt_bool val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_integer_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, int64_t val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_real_entry(
-               struct bt_ctf_private_value *map_obj, const char *key, double val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_string_entry(
-               struct bt_ctf_private_value *map_obj, const char *key,
-               const char *val);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_array_entry(
-               struct bt_ctf_private_value *map_obj, const char *key);
-
-BT_HIDDEN
-enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_map_entry(
-               struct bt_ctf_private_value *map_obj, const char *key);
-
-static inline
-const char *bt_ctf_value_type_string(enum bt_ctf_value_type type)
-{
-       switch (type) {
-       case BT_CTF_VALUE_TYPE_NULL:
-               return "BT_CTF_VALUE_TYPE_NULL";
-       case BT_CTF_VALUE_TYPE_BOOL:
-               return "BT_CTF_VALUE_TYPE_BOOL";
-       case BT_CTF_VALUE_TYPE_INTEGER:
-               return "BT_CTF_VALUE_TYPE_INTEGER";
-       case BT_CTF_VALUE_TYPE_REAL:
-               return "BT_CTF_VALUE_TYPE_REAL";
-       case BT_CTF_VALUE_TYPE_STRING:
-               return "BT_CTF_VALUE_TYPE_STRING";
-       case BT_CTF_VALUE_TYPE_ARRAY:
-               return "BT_CTF_VALUE_TYPE_ARRAY";
-       case BT_CTF_VALUE_TYPE_MAP:
-               return "BT_CTF_VALUE_TYPE_MAP";
-       default:
-               return "(unknown)";
-       }
-};
-
-#endif /* BABELTRACE_CTF_WRITER_VALUES_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/visitor-internal.h b/include/babeltrace2/ctf-writer/visitor-internal.h
deleted file mode 100644 (file)
index 810628d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_VISITOR_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_VISITOR_INTERNAL_H
-
-/*
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/ctf-writer/visitor.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-typedef void *(*bt_ctf_child_accessor)(void *object, int index);
-typedef int64_t (*bt_ctf_child_count_accessor)(void *object);
-typedef int (*bt_ctf_child_visitor)(void *object, bt_ctf_visitor visitor,
-               void *data);
-
-struct bt_ctf_visitor_object {
-       enum bt_ctf_visitor_object_type type;
-       void *object;
-};
-
-BT_HIDDEN
-int bt_ctf_visitor_helper(struct bt_ctf_visitor_object *root,
-               bt_ctf_child_count_accessor child_counter,
-               bt_ctf_child_accessor child_accessor,
-               bt_ctf_child_visitor child_visitor,
-               bt_ctf_visitor visitor,
-               void *data);
-
-#endif /* BABELTRACE_CTF_WRITER_VISITOR_INTERNAL_H */
diff --git a/include/babeltrace2/ctf-writer/writer-internal.h b/include/babeltrace2/ctf-writer/writer-internal.h
deleted file mode 100644 (file)
index 7969513..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H
-#define BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H
-
-/*
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/ctf-writer/writer.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <glib.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <babeltrace2/ctf-writer/trace.h>
-#include <babeltrace2/ctf-writer/object-internal.h>
-
-struct metadata_context {
-       GString *string;
-       GString *field_name;
-       unsigned int current_indentation_level;
-};
-
-struct bt_ctf_writer {
-       struct bt_ctf_object base;
-       int frozen; /* Protects attributes that can't be changed mid-trace */
-       struct bt_ctf_trace *trace;
-       GString *path;
-       int metadata_fd;
-};
-
-enum field_type_alias {
-       FIELD_TYPE_ALIAS_UINT5_T = 0,
-       FIELD_TYPE_ALIAS_UINT8_T,
-       FIELD_TYPE_ALIAS_UINT16_T,
-       FIELD_TYPE_ALIAS_UINT27_T,
-       FIELD_TYPE_ALIAS_UINT32_T,
-       FIELD_TYPE_ALIAS_UINT64_T,
-       NR_FIELD_TYPE_ALIAS,
-};
-
-BT_HIDDEN
-struct bt_ctf_field_type *get_field_type(enum field_type_alias alias);
-
-BT_HIDDEN
-const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order);
-
-BT_HIDDEN
-void bt_ctf_writer_freeze(struct bt_ctf_writer *writer);
-
-#endif /* BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H */
diff --git a/include/babeltrace2/ctfser-internal.h b/include/babeltrace2/ctfser-internal.h
deleted file mode 100644 (file)
index 983b86f..0000000
+++ /dev/null
@@ -1,576 +0,0 @@
-#ifndef BABELTRACE_CTFSER_INTERNAL_H
-#define BABELTRACE_CTFSER_INTERNAL_H
-
-/*
- * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017-2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <limits.h>
-#include <babeltrace2/compat/mman-internal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/mmap-align-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/bitfield-internal.h>
-#include <glib.h>
-
-struct bt_ctfser {
-       /* Stream file's descriptor */
-       int fd;
-
-       /* Offset (bytes) of memory map (current packet) in the stream file */
-       off_t mmap_offset;
-
-       /* Offset (bytes) of packet's first byte in the memory map */
-       off_t mmap_base_offset;
-
-       /* Current offset (bits) within current packet */
-       uint64_t offset_in_cur_packet_bits;
-
-       /* Current packet size (bytes) */
-       uint64_t cur_packet_size_bytes;
-
-       /* Previous packet size (bytes) */
-       uint64_t prev_packet_size_bytes;
-
-       /* Current stream size (bytes) */
-       uint64_t stream_size_bytes;
-
-       /* Memory map base address */
-       struct mmap_align *base_mma;
-
-       /* Stream file's path (for debugging) */
-       GString *path;
-};
-
-/*
- * Initializes a CTF serializer.
- *
- * This function opens the file `path` for writing.
- */
-BT_HIDDEN
-int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path);
-
-/*
- * Finalizes a CTF serializer.
- *
- * This function truncates the stream file so that there's no extra
- * padding after the last packet, and then closes the file.
- */
-BT_HIDDEN
-int bt_ctfser_fini(struct bt_ctfser *ctfser);
-
-/*
- * Opens a new packet.
- *
- * All the next writing functions are performed within this new packet.
- */
-BT_HIDDEN
-int bt_ctfser_open_packet(struct bt_ctfser *ctfser);
-
-/*
- * Closes the current packet, making its size `packet_size_bytes`.
- */
-BT_HIDDEN
-void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
-               uint64_t packet_size_bytes);
-
-BT_HIDDEN
-int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser);
-
-static inline
-uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser *ctfser)
-{
-       return ctfser->cur_packet_size_bytes * 8;
-}
-
-static inline
-uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser *ctfser)
-{
-       return ctfser->prev_packet_size_bytes * 8;
-}
-
-static inline
-uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser *ctfser)
-{
-       return ctfser->offset_in_cur_packet_bits / 8;
-}
-
-static inline
-uint8_t *_bt_ctfser_get_addr(struct bt_ctfser *ctfser)
-{
-       /* Only makes sense to get the address after aligning on byte */
-       BT_ASSERT(ctfser->offset_in_cur_packet_bits % 8 == 0);
-       return ((uint8_t *) mmap_align_addr(ctfser->base_mma)) +
-               ctfser->mmap_base_offset + _bt_ctfser_offset_bytes(ctfser);
-}
-
-static inline
-bool _bt_ctfser_has_space_left(struct bt_ctfser *ctfser, uint64_t size_bits)
-{
-       bool has_space_left = true;
-
-       if (unlikely((ctfser->offset_in_cur_packet_bits + size_bits >
-                       _bt_ctfser_cur_packet_size_bits(ctfser)))) {
-               has_space_left = false;
-               goto end;
-       }
-
-       if (unlikely(size_bits > UINT64_MAX - ctfser->offset_in_cur_packet_bits)) {
-               has_space_left = false;
-               goto end;
-       }
-
-end:
-       return has_space_left;
-}
-
-static inline
-void _bt_ctfser_incr_offset(struct bt_ctfser *ctfser, uint64_t size_bits)
-{
-       BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
-       ctfser->offset_in_cur_packet_bits += size_bits;
-}
-
-/*
- * Aligns the current offset within the current packet to
- * `alignment_bits` bits (power of two, > 0).
- */
-static inline
-int bt_ctfser_align_offset_in_current_packet(struct bt_ctfser *ctfser,
-               uint64_t alignment_bits)
-{
-       int ret = 0;
-       uint64_t align_size_bits;
-
-       BT_ASSERT(alignment_bits > 0);
-       align_size_bits = ALIGN(ctfser->offset_in_cur_packet_bits,
-                       alignment_bits) - ctfser->offset_in_cur_packet_bits;
-
-       if (unlikely(!_bt_ctfser_has_space_left(ctfser, align_size_bits))) {
-               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       _bt_ctfser_incr_offset(ctfser, align_size_bits);
-
-end:
-       return ret;
-}
-
-static inline
-int _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
-               struct bt_ctfser *ctfser, uint64_t value,
-               unsigned int size_bits, int byte_order)
-{
-       int ret = 0;
-
-       /* Reverse byte order? */
-       bool rbo = byte_order != BYTE_ORDER;
-
-       BT_ASSERT(size_bits % 8 == 0);
-       BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
-
-       switch (size_bits) {
-       case 8:
-       {
-               uint8_t v = (uint8_t) value;
-
-               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
-               break;
-       }
-       case 16:
-       {
-               uint16_t v = (uint16_t) value;
-
-               if (rbo) {
-                       v = GUINT16_SWAP_LE_BE(v);
-               }
-
-               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
-               break;
-       }
-       case 32:
-       {
-               uint32_t v = (uint32_t) value;
-
-               if (rbo) {
-                       v = GUINT32_SWAP_LE_BE(v);
-               }
-
-               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
-               break;
-       }
-       case 64:
-       {
-               uint64_t v = (uint64_t) value;
-
-               if (rbo) {
-                       v = GUINT64_SWAP_LE_BE(v);
-               }
-
-               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
-               break;
-       }
-       default:
-               abort();
-       }
-
-       _bt_ctfser_incr_offset(ctfser, size_bits);
-       return ret;
-}
-
-static inline
-int _bt_ctfser_write_byte_aligned_signed_int_no_align(
-               struct bt_ctfser *ctfser, int64_t value,
-               unsigned int size_bits, int byte_order)
-{
-       int ret = 0;
-
-       /* Reverse byte order? */
-       bool rbo = byte_order != BYTE_ORDER;
-
-       BT_ASSERT(size_bits % 8 == 0);
-       BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
-
-       switch (size_bits) {
-       case 8:
-       {
-               int8_t v = (int8_t) value;
-
-               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
-               break;
-       }
-       case 16:
-       {
-               int16_t v = (int16_t) value;
-
-               if (rbo) {
-                       v = GUINT16_SWAP_LE_BE(v);
-               }
-
-               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
-               break;
-       }
-       case 32:
-       {
-               int32_t v = (int32_t) value;
-
-               if (rbo) {
-                       v = GUINT32_SWAP_LE_BE(v);
-               }
-
-               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
-               break;
-       }
-       case 64:
-       {
-               int64_t v = (int64_t) value;
-
-               if (rbo) {
-                       v = GUINT64_SWAP_LE_BE(v);
-               }
-
-               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
-               break;
-       }
-       default:
-               abort();
-       }
-
-       _bt_ctfser_incr_offset(ctfser, size_bits);
-       return ret;
-}
-
-/*
- * Writes an unsigned integer known to have a size that is a multiple of
- * 8 and an alignment that is >= 8 at the current offset within the
- * current packet.
- */
-static inline
-int bt_ctfser_write_byte_aligned_unsigned_int(struct bt_ctfser *ctfser,
-       uint64_t value, unsigned int alignment_bits,
-       unsigned int size_bits, int byte_order)
-{
-       int ret;
-
-       BT_ASSERT(alignment_bits % 8 == 0);
-       ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-       if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
-               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       ret = _bt_ctfser_write_byte_aligned_unsigned_int_no_align(ctfser, value,
-               size_bits, byte_order);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Writes a signed integer known to have a size that is a multiple of 8
- * and an alignment that is >= 8 at the current offset within the
- * current packet.
- */
-static inline
-int bt_ctfser_write_byte_aligned_signed_int(struct bt_ctfser *ctfser,
-       int64_t value, unsigned int alignment_bits,
-       unsigned int size_bits, int byte_order)
-{
-       int ret;
-
-       BT_ASSERT(alignment_bits % 8 == 0);
-       ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-       if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
-               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       ret = _bt_ctfser_write_byte_aligned_signed_int_no_align(ctfser, value,
-               size_bits, byte_order);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Writes an unsigned integer at the current offset within the current
- * packet.
- */
-static inline
-int bt_ctfser_write_unsigned_int(struct bt_ctfser *ctfser, uint64_t value,
-       unsigned int alignment_bits, unsigned int size_bits,
-       int byte_order)
-{
-       int ret = 0;
-
-       ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-       if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
-               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       if (alignment_bits % 8 == 0 && size_bits % 8 == 0) {
-               ret = _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
-                       ctfser, value, size_bits, byte_order);
-               goto end;
-       }
-
-       if (byte_order == LITTLE_ENDIAN) {
-               bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
-                       ctfser->mmap_base_offset, uint8_t,
-                       ctfser->offset_in_cur_packet_bits, size_bits, value);
-       } else {
-               bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
-                       ctfser->mmap_base_offset, uint8_t,
-                       ctfser->offset_in_cur_packet_bits, size_bits, value);
-       }
-
-       _bt_ctfser_incr_offset(ctfser, size_bits);
-
-end:
-       return ret;
-}
-
-/*
- * Writes a signed integer at the current offset within the current
- * packet.
- */
-static inline
-int bt_ctfser_write_signed_int(struct bt_ctfser *ctfser, int64_t value,
-       unsigned int alignment_bits, unsigned int size_bits,
-       int byte_order)
-{
-       int ret = 0;
-
-       ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-       if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
-               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       if (alignment_bits % 8 == 0 && size_bits % 8 == 0) {
-               ret = _bt_ctfser_write_byte_aligned_signed_int_no_align(
-                       ctfser, value, size_bits, byte_order);
-               goto end;
-       }
-
-       if (byte_order == LITTLE_ENDIAN) {
-               bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
-                       ctfser->mmap_base_offset, uint8_t,
-                       ctfser->offset_in_cur_packet_bits, size_bits, value);
-       } else {
-               bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
-                       ctfser->mmap_base_offset, uint8_t,
-                       ctfser->offset_in_cur_packet_bits, size_bits, value);
-       }
-
-       _bt_ctfser_incr_offset(ctfser, size_bits);
-
-end:
-       return ret;
-}
-
-/*
- * Writes a 32-bit floating point number at the current offset within
- * the current packet.
- */
-static inline
-int bt_ctfser_write_float32(struct bt_ctfser *ctfser, double value,
-       unsigned int alignment_bits, int byte_order)
-{
-       union u32f {
-               uint32_t u;
-               float f;
-       } u32f;
-
-       u32f.f = (float) value;
-       return bt_ctfser_write_unsigned_int(ctfser, (uint64_t) u32f.u,
-               alignment_bits, 32, byte_order);
-}
-
-/*
- * Writes a 64-bit floating point number at the current offset within
- * the current packet.
- */
-static inline
-int bt_ctfser_write_float64(struct bt_ctfser *ctfser, double value,
-       unsigned int alignment_bits, int byte_order)
-{
-       union u64f {
-               uint64_t u;
-               float f;
-       } u64f;
-
-       u64f.f = value;
-       return bt_ctfser_write_unsigned_int(ctfser, u64f.u, alignment_bits,
-               64, byte_order);
-}
-
-/*
- * Writes a C string, including the terminating null character, at the
- * current offset within the current packet.
- */
-static inline
-int bt_ctfser_write_string(struct bt_ctfser *ctfser, const char *value)
-{
-       int ret = 0;
-       const char *at = value;
-
-       ret = bt_ctfser_align_offset_in_current_packet(ctfser, 8);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-       while (true) {
-               if (unlikely(!_bt_ctfser_has_space_left(ctfser, 8))) {
-                       ret = _bt_ctfser_increase_cur_packet_size(ctfser);
-                       if (unlikely(ret)) {
-                               goto end;
-                       }
-               }
-
-               memcpy(_bt_ctfser_get_addr(ctfser), at, sizeof(*at));
-               _bt_ctfser_incr_offset(ctfser, 8);
-
-               if (unlikely(*at == '\0')) {
-                       break;
-               }
-
-               at++;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Returns the current offset within the current packet (bits).
- */
-static inline
-uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser *ctfser)
-{
-       return ctfser->offset_in_cur_packet_bits;
-}
-
-/*
- * Sets the current offset within the current packet (bits).
- */
-static inline
-void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser *ctfser,
-               uint64_t offset_bits)
-{
-       BT_ASSERT(offset_bits <= _bt_ctfser_cur_packet_size_bits(ctfser));
-       ctfser->offset_in_cur_packet_bits = offset_bits;
-}
-
-static inline
-const char *bt_ctfser_get_file_path(struct bt_ctfser *ctfser)
-{
-       return ctfser->path->str;
-}
-
-#endif /* BABELTRACE_CTFSER_INTERNAL_H */
diff --git a/include/babeltrace2/endian-internal.h b/include/babeltrace2/endian-internal.h
deleted file mode 100644 (file)
index 5c74c35..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-#ifndef _BABELTRACE_ENDIAN_H
-#define _BABELTRACE_ENDIAN_H
-
-/*
- * Copyright 2012 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * endian.h compatibility layer.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifdef __FreeBSD__
-#include <machine/endian.h>
-
-#elif defined(__sun__)
-#include <sys/byteorder.h>
-
-#ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN 4321
-#endif
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN 1234
-#endif
-
-#ifdef _LITTLE_ENDIAN
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
-
-#ifdef _BIG_ENDIAN
-#define __BYTE_ORDER __BIG_ENDIAN
-#endif
-
-#define LITTLE_ENDIAN  __LITTLE_ENDIAN
-#define BIG_ENDIAN     __BIG_ENDIAN
-#define BYTE_ORDER     __BYTE_ORDER
-
-#define betoh16(x) BE_16(x)
-#define letoh16(x) LE_16(x)
-#define betoh32(x) BE_32(x)
-#define letoh32(x) LE_32(x)
-#define betoh64(x) BE_64(x)
-#define letoh64(x) LE_64(x)
-#define htobe16(x) BE_16(x)
-#define be16toh(x) BE_16(x)
-#define htobe32(x) BE_32(x)
-#define be32toh(x) BE_32(x)
-#define htobe64(x) BE_64(x)
-#define be64toh(x) BE_64(x)
-
-#elif defined(__MINGW32__)
-#include <stdint.h>
-
-#ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN 4321
-#endif
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN 1234
-#endif
-
-#ifndef __BYTE_ORDER
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
-
-#define LITTLE_ENDIAN  __LITTLE_ENDIAN
-#define BIG_ENDIAN     __BIG_ENDIAN
-#define PDP_ENDIAN     __PDP_ENDIAN
-#define BYTE_ORDER     __BYTE_ORDER
-
-#define htobe16(x) (uint16_t) _byteswap_ushort(x)
-#define htole16(x) (x)
-#define be16toh(x) (uint16_t) _byteswap_ushort(x)
-#define le16toh(x) (x)
-
-#define htobe32(x) (uint32_t) _byteswap_ulong(x)
-#define htole32(x) (x)
-#define be32toh(x) (uint32_t) _byteswap_ulong(x)
-#define le32toh(x) (x)
-
-#define htobe64(x) (uint64_t) _byteswap_uint64(x)
-#define htole64(x) (x)
-#define be64toh(x) (uint64_t) _byteswap_uint64(x)
-#define le64toh(x) (x)
-
-#elif defined(__APPLE__)
-# include <machine/endian.h>
-# include <libkern/OSByteOrder.h>
-
-# if BYTE_ORDER == LITTLE_ENDIAN
-#  define htobe16(x) OSSwapConstInt16(x)
-#  define htole16(x) (x)
-#  define be16toh(x) OSSwapConstInt16(x)
-#  define le16toh(x) (x)
-
-#  define htobe32(x) OSSwapConstInt32(x)
-#  define htole32(x) (x)
-#  define be32toh(x) OSSwapConstInt32(x)
-#  define le32toh(x) (x)
-
-#  define htobe64(x) OSSwapConstInt64(x)
-#  define htole64(x) (x)
-#  define be64toh(x) OSSwapConstInt64(x)
-#  define le64toh(x) (x)
-
-# else /* BYTE_ORDER == LITTLE_ENDIAN */
-#  define htobe16(x) (x)
-#  define htole16(x) OSSwapConstInt16(x)
-#  define be16toh(x) (x)
-#  define le16toh(x) OSSwapConstInt16(x)
-
-#  define htobe32(x) (x)
-#  define htole32(x) OSSwapConstInt32(x)
-#  define be32toh(x) (x)
-#  define le32toh(x) OSSwapConstInt32(x)
-
-#  define htobe64(x) (x)
-#  define htole64(x) OSSwapConstInt64(x)
-#  define be64toh(x) (x)
-#  define le64toh(x) OSSwapConstInt64(x)
-#  endif
-
-#else
-#include <endian.h>
-
-/*
- * htobe/betoh are not defined for glibc < 2.9, so add them explicitly
- * if they are missing.
- */
-# ifdef __USE_BSD
-/* Conversion interfaces. */
-#  include <byteswap.h>
-
-#  if __BYTE_ORDER == __LITTLE_ENDIAN
-#   ifndef htobe16
-#    define htobe16(x) __bswap_16(x)
-#   endif
-#   ifndef htole16
-#    define htole16(x) (x)
-#   endif
-#   ifndef be16toh
-#    define be16toh(x) __bswap_16(x)
-#   endif
-#   ifndef le16toh
-#    define le16toh(x) (x)
-#   endif
-
-#   ifndef htobe32
-#    define htobe32(x) __bswap_32(x)
-#   endif
-#   ifndef htole32
-#    define htole32(x) (x)
-#   endif
-#   ifndef be32toh
-#    define be32toh(x) __bswap_32(x)
-#   endif
-#   ifndef le32toh
-#    define le32toh(x) (x)
-#   endif
-
-#   ifndef htobe64
-#    define htobe64(x) __bswap_64(x)
-#   endif
-#   ifndef htole64
-#    define htole64(x) (x)
-#   endif
-#   ifndef be64toh
-#    define be64toh(x) __bswap_64(x)
-#   endif
-#   ifndef le64toh
-#    define le64toh(x) (x)
-#   endif
-
-#  else /* __BYTE_ORDER == __LITTLE_ENDIAN */
-#   ifndef htobe16
-#    define htobe16(x) (x)
-#   endif
-#   ifndef htole16
-#    define htole16(x) __bswap_16(x)
-#   endif
-#   ifndef be16toh
-#    define be16toh(x) (x)
-#   endif
-#   ifndef le16toh
-#    define le16toh(x) __bswap_16(x)
-#   endif
-
-#   ifndef htobe32
-#    define htobe32(x) (x)
-#   endif
-#   ifndef htole32
-#    define htole32(x) __bswap_32(x)
-#   endif
-#   ifndef be32toh
-#    define be32toh(x) (x)
-#   endif
-#   ifndef le32toh
-#    define le32toh(x) __bswap_32(x)
-#   endif
-
-#   ifndef htobe64
-#    define htobe64(x) (x)
-#   endif
-#   ifndef htole64
-#    define htole64(x) __bswap_64(x)
-#   endif
-#   ifndef be64toh
-#    define be64toh(x) (x)
-#   endif
-#   ifndef le64toh
-#    define le64toh(x) __bswap_64(x)
-#   endif
-
-#  endif /* __BYTE_ORDER == __LITTLE_ENDIAN */
-# endif /* __USE_BSD */
-#endif /* else -- __FreeBSD__ */
-
-#ifndef FLOAT_WORD_ORDER
-#ifdef __FLOAT_WORD_ORDER
-#define FLOAT_WORD_ORDER       __FLOAT_WORD_ORDER
-#else /* __FLOAT_WORD_ORDER */
-#define FLOAT_WORD_ORDER       BYTE_ORDER
-#endif /* __FLOAT_WORD_ORDER */
-#endif /* FLOAT_WORD_ORDER */
-
-#endif /* _BABELTRACE_ENDIAN_H */
diff --git a/include/babeltrace2/fd-cache-internal.h b/include/babeltrace2/fd-cache-internal.h
deleted file mode 100644 (file)
index 546dcfa..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef BABELTRACE_FD_CACHE_INTERNAL_H
-#define BABELTRACE_FD_CACHE_INTERNAL_H
-/*
- * fd-cache-internal.h
- *
- * Babeltrace - File descriptor cache
- *
- * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Author: Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-
-struct bt_fd_cache_handle {
-       int fd;
-};
-
-struct bt_fd_cache {
-       GHashTable *cache;
-};
-
-static inline
-int bt_fd_cache_handle_get_fd(struct bt_fd_cache_handle *handle)
-{
-       return handle->fd;
-}
-
-BT_HIDDEN
-int bt_fd_cache_init(struct bt_fd_cache *fdc);
-
-BT_HIDDEN
-void bt_fd_cache_fini(struct bt_fd_cache *fdc);
-
-BT_HIDDEN
-struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc,
-               const char *path);
-
-BT_HIDDEN
-void bt_fd_cache_put_handle(struct bt_fd_cache *fdc,
-               struct bt_fd_cache_handle *handle);
-
-#endif /* BABELTRACE_FD_CACHE_INTERNAL_H */
diff --git a/include/babeltrace2/graph/component-class-internal.h b/include/babeltrace2/graph/component-class-internal.h
deleted file mode 100644 (file)
index 4e39404..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-#ifndef BABELTRACE_GRAPH_COMPONENT_CLASS_INTERNAL_H
-#define BABELTRACE_GRAPH_COMPONENT_CLASS_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/graph/component-const.h>
-#include <babeltrace2/graph/component-class.h>
-#include <babeltrace2/graph/component-class-source.h>
-#include <babeltrace2/graph/component-class-filter.h>
-#include <babeltrace2/graph/component-class-sink.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/list-internal.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-
-struct bt_component_class;
-struct bt_plugin_so_shared_lib_handle;
-
-typedef void (*bt_component_class_destroy_listener_func)(
-               struct bt_component_class *class, void *data);
-
-struct bt_component_class_destroy_listener {
-       bt_component_class_destroy_listener_func func;
-       void *data;
-};
-
-struct bt_component_class {
-       struct bt_object base;
-       enum bt_component_class_type type;
-       GString *name;
-       GString *description;
-       GString *help;
-
-       /* Array of struct bt_component_class_destroy_listener */
-       GArray *destroy_listeners;
-       bool frozen;
-       struct bt_list_head node;
-       struct bt_plugin_so_shared_lib_handle *so_handle;
-};
-
-struct bt_component_class_source {
-       struct bt_component_class parent;
-       struct {
-               bt_component_class_source_init_method init;
-               bt_component_class_source_finalize_method finalize;
-               bt_component_class_source_message_iterator_init_method msg_iter_init;
-               bt_component_class_source_message_iterator_finalize_method msg_iter_finalize;
-               bt_component_class_source_message_iterator_next_method msg_iter_next;
-               bt_component_class_source_message_iterator_seek_ns_from_origin_method msg_iter_seek_ns_from_origin;
-               bt_component_class_source_message_iterator_seek_beginning_method msg_iter_seek_beginning;
-               bt_component_class_source_message_iterator_can_seek_ns_from_origin_method msg_iter_can_seek_ns_from_origin;
-               bt_component_class_source_message_iterator_can_seek_beginning_method msg_iter_can_seek_beginning;
-               bt_component_class_source_query_method query;
-               bt_component_class_source_accept_output_port_connection_method accept_output_port_connection;
-               bt_component_class_source_output_port_connected_method output_port_connected;
-       } methods;
-};
-
-struct bt_component_class_sink {
-       struct bt_component_class parent;
-       struct {
-               bt_component_class_sink_init_method init;
-               bt_component_class_sink_finalize_method finalize;
-               bt_component_class_sink_query_method query;
-               bt_component_class_sink_accept_input_port_connection_method accept_input_port_connection;
-               bt_component_class_sink_input_port_connected_method input_port_connected;
-               bt_component_class_sink_graph_is_configured_method graph_is_configured;
-               bt_component_class_sink_consume_method consume;
-       } methods;
-};
-
-struct bt_component_class_filter {
-       struct bt_component_class parent;
-       struct {
-               bt_component_class_filter_init_method init;
-               bt_component_class_filter_finalize_method finalize;
-               bt_component_class_filter_message_iterator_init_method msg_iter_init;
-               bt_component_class_filter_message_iterator_finalize_method msg_iter_finalize;
-               bt_component_class_filter_message_iterator_next_method msg_iter_next;
-               bt_component_class_filter_message_iterator_seek_ns_from_origin_method msg_iter_seek_ns_from_origin;
-               bt_component_class_filter_message_iterator_seek_beginning_method msg_iter_seek_beginning;
-               bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method msg_iter_can_seek_ns_from_origin;
-               bt_component_class_filter_message_iterator_can_seek_beginning_method msg_iter_can_seek_beginning;
-               bt_component_class_filter_query_method query;
-               bt_component_class_filter_accept_input_port_connection_method accept_input_port_connection;
-               bt_component_class_filter_accept_output_port_connection_method accept_output_port_connection;
-               bt_component_class_filter_input_port_connected_method input_port_connected;
-               bt_component_class_filter_output_port_connected_method output_port_connected;
-       } methods;
-};
-
-BT_HIDDEN
-void bt_component_class_add_destroy_listener(struct bt_component_class *class,
-               bt_component_class_destroy_listener_func func, void *data);
-
-BT_HIDDEN
-void _bt_component_class_freeze(
-               const struct bt_component_class *component_class);
-
-#ifdef BT_DEV_MODE
-# define bt_component_class_freeze     _bt_component_class_freeze
-#else
-# define bt_component_class_freeze(_cc)
-#endif
-
-static inline
-const char *bt_component_class_type_string(enum bt_component_class_type type)
-{
-       switch (type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-               return "BT_COMPONENT_CLASS_TYPE_SOURCE";
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-               return "BT_COMPONENT_CLASS_TYPE_SINK";
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-               return "BT_COMPONENT_CLASS_TYPE_FILTER";
-       default:
-               return "(unknown)";
-       }
-}
-
-#endif /* BABELTRACE_GRAPH_COMPONENT_CLASS_INTERNAL_H */
diff --git a/include/babeltrace2/graph/component-class-sink-colander-internal.h b/include/babeltrace2/graph/component-class-sink-colander-internal.h
deleted file mode 100644 (file)
index faa7a6e..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H
-#define BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/graph/message-const.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct bt_component_class_sink_colander_priv_data {
-       bt_message_array_const msgs;
-       uint64_t *count_addr;
-       struct bt_self_component_port_input_message_iterator *msg_iter;
-};
-
-struct bt_component_class_sink_colander_data {
-       bt_message_array_const msgs;
-       uint64_t *count_addr;
-};
-
-extern struct bt_component_class_sink *
-bt_component_class_sink_colander_get(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H */
diff --git a/include/babeltrace2/graph/component-filter-internal.h b/include/babeltrace2/graph/component-filter-internal.h
deleted file mode 100644 (file)
index 5d4b4a1..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef BABELTRACE_GRAPH_COMPONENT_FILTER_INTERNAL_H
-#define BABELTRACE_GRAPH_COMPONENT_FILTER_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/graph/component-filter-const.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-
-struct bt_component_filter {
-       struct bt_component parent;
-};
-
-BT_HIDDEN
-struct bt_component *bt_component_filter_create(
-               const struct bt_component_class *class);
-
-BT_HIDDEN
-void bt_component_filter_destroy(struct bt_component *component);
-
-#endif /* BABELTRACE_GRAPH_COMPONENT_FILTER_INTERNAL_H */
diff --git a/include/babeltrace2/graph/component-internal.h b/include/babeltrace2/graph/component-internal.h
deleted file mode 100644 (file)
index 13986c8..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef BABELTRACE_GRAPH_COMPONENT_INTERNAL_H
-#define BABELTRACE_GRAPH_COMPONENT_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/graph/component-const.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/graph/port-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdio.h>
-
-typedef void (*bt_component_destroy_listener_func)(
-               struct bt_component *class, void *data);
-
-struct bt_component_destroy_listener {
-       bt_component_destroy_listener_func func;
-       void *data;
-};
-
-struct bt_graph;
-
-struct bt_component {
-       struct bt_object base;
-       struct bt_component_class *class;
-       GString *name;
-
-       /*
-        * Internal destroy function specific to a source, filter, or
-        * sink component object.
-        */
-       void (*destroy)(struct bt_component *);
-
-       /* User-defined data */
-       void *user_data;
-
-       /* Input and output ports (weak references) */
-       GPtrArray *input_ports;
-       GPtrArray *output_ports;
-
-       /* Array of struct bt_component_destroy_listener */
-       GArray *destroy_listeners;
-
-       bool initialized;
-};
-
-static inline
-struct bt_graph *bt_component_borrow_graph(struct bt_component *comp)
-{
-       BT_ASSERT(comp);
-       return (void *) bt_object_borrow_parent(&comp->base);
-}
-
-BT_HIDDEN
-int bt_component_create(struct bt_component_class *component_class,
-               const char *name, struct bt_component **component);
-
-BT_HIDDEN
-enum bt_self_component_status bt_component_accept_port_connection(
-               struct bt_component *component, struct bt_port *self_port,
-               struct bt_port *other_port);
-
-BT_HIDDEN
-enum bt_self_component_status bt_component_port_connected(
-               struct bt_component *comp,
-               struct bt_port *self_port, struct bt_port *other_port);
-
-BT_HIDDEN
-void bt_component_set_graph(struct bt_component *component,
-               struct bt_graph *graph);
-
-BT_HIDDEN
-uint64_t bt_component_get_input_port_count(const struct bt_component *comp);
-
-BT_HIDDEN
-uint64_t bt_component_get_output_port_count(const struct bt_component *comp);
-
-BT_HIDDEN
-struct bt_port_input *bt_component_borrow_input_port_by_index(
-               struct bt_component *comp, uint64_t index);
-
-BT_HIDDEN
-struct bt_port_output *bt_component_borrow_output_port_by_index(
-               struct bt_component *comp, uint64_t index);
-
-BT_HIDDEN
-struct bt_port_input *bt_component_borrow_input_port_by_name(
-               struct bt_component *comp, const char *name);
-
-BT_HIDDEN
-struct bt_port_output *bt_component_borrow_output_port_by_name(
-               struct bt_component *comp, const char *name);
-
-BT_HIDDEN
-enum bt_self_component_status bt_component_add_input_port(
-               struct bt_component *component, const char *name,
-               void *user_data, struct bt_port **port);
-
-BT_HIDDEN
-enum bt_self_component_status bt_component_add_output_port(
-               struct bt_component *component, const char *name,
-               void *user_data, struct bt_port **port);
-
-BT_HIDDEN
-void bt_component_remove_port(struct bt_component *component,
-               struct bt_port *port);
-
-BT_HIDDEN
-void bt_component_add_destroy_listener(struct bt_component *component,
-               bt_component_destroy_listener_func func, void *data);
-
-BT_HIDDEN
-void bt_component_remove_destroy_listener(struct bt_component *component,
-               bt_component_destroy_listener_func func, void *data);
-
-static inline
-const char *bt_self_component_status_string(
-               enum bt_self_component_status status)
-{
-       switch (status) {
-       case BT_SELF_COMPONENT_STATUS_OK:
-               return "BT_SELF_COMPONENT_STATUS_OK";
-       case BT_SELF_COMPONENT_STATUS_END:
-               return "BT_SELF_COMPONENT_STATUS_END";
-       case BT_SELF_COMPONENT_STATUS_AGAIN:
-               return "BT_SELF_COMPONENT_STATUS_AGAIN";
-       case BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION:
-               return "BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION";
-       case BT_SELF_COMPONENT_STATUS_ERROR:
-               return "BT_SELF_COMPONENT_STATUS_ERROR";
-       case BT_SELF_COMPONENT_STATUS_NOMEM:
-               return "BT_SELF_COMPONENT_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-}
-
-#endif /* BABELTRACE_GRAPH_COMPONENT_INTERNAL_H */
diff --git a/include/babeltrace2/graph/component-sink-internal.h b/include/babeltrace2/graph/component-sink-internal.h
deleted file mode 100644 (file)
index d035711..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef BABELTRACE_GRAPH_COMPONENT_SINK_INTERNAL_H
-#define BABELTRACE_GRAPH_COMPONENT_SINK_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/graph/component-sink-const.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-
-struct bt_component_sink {
-       struct bt_component parent;
-       bool graph_is_configured_method_called;
-};
-
-BT_HIDDEN
-struct bt_component *bt_component_sink_create(
-               const struct bt_component_class *class);
-
-BT_HIDDEN
-void bt_component_sink_destroy(struct bt_component *component);
-
-#endif /* BABELTRACE_GRAPH_COMPONENT_SINK_INTERNAL_H */
diff --git a/include/babeltrace2/graph/component-source-internal.h b/include/babeltrace2/graph/component-source-internal.h
deleted file mode 100644 (file)
index 9106d8a..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef BABELTRACE_GRAPH_COMPONENT_SOURCE_INTERNAL_H
-#define BABELTRACE_GRAPH_COMPONENT_SOURCE_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-
-struct bt_component_source {
-       struct bt_component parent;
-};
-
-BT_HIDDEN
-struct bt_component *bt_component_source_create(
-               const struct bt_component_class *class);
-
-BT_HIDDEN
-void bt_component_source_destroy(struct bt_component *component);
-
-#endif /* BABELTRACE_GRAPH_COMPONENT_SOURCE_INTERNAL_H */
diff --git a/include/babeltrace2/graph/connection-internal.h b/include/babeltrace2/graph/connection-internal.h
deleted file mode 100644 (file)
index 8c3dc17..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef BABELTRACE_GRAPH_CONNECTION_INTERNAL_H
-#define BABELTRACE_GRAPH_CONNECTION_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/graph/connection-const.h>
-#include <babeltrace2/graph/message-iterator-const.h>
-#include <babeltrace2/graph/message-iterator-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdbool.h>
-
-struct bt_graph;
-
-struct bt_connection {
-       /*
-        * The graph is a connection's parent and the connection is the parent
-        * of all iterators it has created.
-        */
-       struct bt_object base;
-       /*
-        * Weak references are held to both ports. Their existence is guaranteed
-        * by the existence of the graph and thus, of their respective
-        * components.
-        */
-       /* Downstream port. */
-       struct bt_port *downstream_port;
-       /* Upstream port. */
-       struct bt_port *upstream_port;
-
-       /*
-        * Weak references to all the message iterators that were
-        * created on this connection.
-        */
-       GPtrArray *iterators;
-
-       bool notified_upstream_port_connected;
-       bool notified_downstream_port_connected;
-       bool notified_graph_ports_connected;
-};
-
-BT_HIDDEN
-struct bt_connection *bt_connection_create(struct bt_graph *graph,
-               struct bt_port *upstream_port,
-               struct bt_port *downstream_port);
-
-BT_HIDDEN
-void bt_connection_end(struct bt_connection *conn, bool try_remove_from_graph);
-
-BT_HIDDEN
-void bt_connection_remove_iterator(struct bt_connection *conn,
-               struct bt_self_component_port_input_message_iterator *iterator);
-
-static inline
-struct bt_graph *bt_connection_borrow_graph(struct bt_connection *conn)
-{
-       BT_ASSERT(conn);
-       return (void *) conn->base.parent;
-}
-
-#endif /* BABELTRACE_GRAPH_CONNECTION_INTERNAL_H */
diff --git a/include/babeltrace2/graph/graph-internal.h b/include/babeltrace2/graph/graph-internal.h
deleted file mode 100644 (file)
index dd7374e..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-#ifndef BABELTRACE_GRAPH_GRAPH_INTERNAL_H
-#define BABELTRACE_GRAPH_GRAPH_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/graph/graph.h>
-#include <babeltrace2/graph/connection-internal.h>
-#include <babeltrace2/graph/message-const.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/component-sink-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdlib.h>
-#include <glib.h>
-
-struct bt_component;
-struct bt_port;
-
-enum bt_graph_configuration_state {
-       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-       BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED,
-       BT_GRAPH_CONFIGURATION_STATE_CONFIGURED,
-       BT_GRAPH_CONFIGURATION_STATE_FAULTY,
-};
-
-struct bt_graph {
-       /**
-        * A component graph contains components and point-to-point connection
-        * between these components.
-        *
-        * In terms of ownership:
-        * 1) The graph is the components' parent,
-        * 2) The graph is the connnections' parent,
-        * 3) Components share the ownership of their connections,
-        * 4) A connection holds weak references to its two component endpoints.
-        */
-       struct bt_object base;
-
-       /* Array of pointers to bt_connection. */
-       GPtrArray *connections;
-       /* Array of pointers to bt_component. */
-       GPtrArray *components;
-       /* Queue of pointers (weak references) to sink bt_components. */
-       GQueue *sinks_to_consume;
-
-       bool canceled;
-       bool in_remove_listener;
-       bool has_sink;
-
-       /*
-        * If this is false, then the public API's consuming
-        * functions (bt_graph_consume() and bt_graph_run()) return
-        * BT_GRAPH_STATUS_CANNOT_CONSUME. The internal "no check"
-        * functions always work.
-        *
-        * In bt_port_output_message_iterator_create(), on success,
-        * this flag is cleared so that the iterator remains the only
-        * consumer for the graph's lifetime.
-        */
-       bool can_consume;
-
-       enum bt_graph_configuration_state config_state;
-
-       struct {
-               GArray *source_output_port_added;
-               GArray *filter_output_port_added;
-               GArray *filter_input_port_added;
-               GArray *sink_input_port_added;
-               GArray *source_filter_ports_connected;
-               GArray *source_sink_ports_connected;
-               GArray *filter_filter_ports_connected;
-               GArray *filter_sink_ports_connected;
-       } listeners;
-
-       /* Pool of `struct bt_message_event *` */
-       struct bt_object_pool event_msg_pool;
-
-       /* Pool of `struct bt_message_packet_beginning *` */
-       struct bt_object_pool packet_begin_msg_pool;
-
-       /* Pool of `struct bt_message_packet_end *` */
-       struct bt_object_pool packet_end_msg_pool;
-
-       /*
-        * Array of `struct bt_message *` (weak).
-        *
-        * This is an array of all the messages ever created from
-        * this graph. Some of them can be in one of the pools above,
-        * some of them can be at large. Because each message has a
-        * weak pointer to the graph containing its pool, we need to
-        * notify each message that the graph is gone on graph
-        * destruction.
-        *
-        * TODO: When we support a maximum size for object pools,
-        * add a way for a message to remove itself from this
-        * array (on destruction).
-        */
-       GPtrArray *messages;
-};
-
-static inline
-void _bt_graph_set_can_consume(struct bt_graph *graph, bool can_consume)
-{
-       BT_ASSERT(graph);
-       graph->can_consume = can_consume;
-}
-
-#ifdef BT_DEV_MODE
-# define bt_graph_set_can_consume      _bt_graph_set_can_consume
-#else
-# define bt_graph_set_can_consume(_graph, _can_consume)
-#endif
-
-BT_HIDDEN
-enum bt_graph_status bt_graph_consume_sink_no_check(struct bt_graph *graph,
-               struct bt_component_sink *sink);
-
-BT_HIDDEN
-enum bt_graph_listener_status bt_graph_notify_port_added(struct bt_graph *graph,
-               struct bt_port *port);
-
-BT_HIDDEN
-enum bt_graph_listener_status bt_graph_notify_ports_connected(
-               struct bt_graph *graph, struct bt_port *upstream_port,
-               struct bt_port *downstream_port);
-
-BT_HIDDEN
-void bt_graph_remove_connection(struct bt_graph *graph,
-               struct bt_connection *connection);
-
-/*
- * This only works with a component which is not connected at this
- * point.
- *
- * Also the reference count of `component` should be 0 when you call
- * this function, which means only `graph` owns the component, so it
- * is safe to destroy.
- */
-BT_HIDDEN
-int bt_graph_remove_unconnected_component(struct bt_graph *graph,
-               struct bt_component *component);
-
-BT_HIDDEN
-void bt_graph_add_message(struct bt_graph *graph,
-               struct bt_message *msg);
-
-static inline
-const char *bt_graph_status_string(enum bt_graph_status status)
-{
-       switch (status) {
-       case BT_GRAPH_STATUS_CANCELED:
-               return "BT_GRAPH_STATUS_CANCELED";
-       case BT_GRAPH_STATUS_AGAIN:
-               return "BT_GRAPH_STATUS_AGAIN";
-       case BT_GRAPH_STATUS_END:
-               return "BT_GRAPH_STATUS_END";
-       case BT_GRAPH_STATUS_OK:
-               return "BT_GRAPH_STATUS_OK";
-       case BT_GRAPH_STATUS_ERROR:
-               return "BT_GRAPH_STATUS_ERROR";
-       case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
-               return "BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION";
-       case BT_GRAPH_STATUS_NOMEM:
-               return "BT_GRAPH_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-const char *bt_graph_configuration_state_string(
-               enum bt_graph_configuration_state state)
-{
-       switch (state) {
-       case BT_GRAPH_CONFIGURATION_STATE_CONFIGURING:
-               return "BT_GRAPH_CONFIGURATION_STATE_CONFIGURING";
-       case BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED:
-               return "BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED";
-       case BT_GRAPH_CONFIGURATION_STATE_CONFIGURED:
-               return "BT_GRAPH_CONFIGURATION_STATE_CONFIGURED";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-enum bt_graph_status bt_graph_configure(struct bt_graph *graph)
-{
-       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
-       uint64_t i;
-
-       BT_ASSERT(graph->config_state != BT_GRAPH_CONFIGURATION_STATE_FAULTY);
-
-       if (likely(graph->config_state ==
-                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURED)) {
-               goto end;
-       }
-
-#ifdef BT_ASSERT_PRE
-       BT_ASSERT_PRE(graph->has_sink, "Graph has no sink component: %!+g", graph);
-#endif
-
-       graph->config_state = BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED;
-
-       for (i = 0; i < graph->components->len; i++) {
-               struct bt_component *comp = graph->components->pdata[i];
-               struct bt_component_sink *comp_sink = (void *) comp;
-               struct bt_component_class_sink *comp_cls_sink =
-                       (void *) comp->class;
-
-               if (comp->class->type != BT_COMPONENT_CLASS_TYPE_SINK) {
-                       continue;
-               }
-
-               if (comp_sink->graph_is_configured_method_called) {
-                       continue;
-               }
-
-               if (comp_cls_sink->methods.graph_is_configured) {
-                       enum bt_self_component_status comp_status;
-
-#ifdef BT_LIB_LOGD
-                       BT_LIB_LOGD("Calling user's \"graph is configured\" method: "
-                               "%![graph-]+g, %![comp-]+c",
-                               graph, comp);
-#endif
-
-                       comp_status = comp_cls_sink->methods.graph_is_configured(
-                               (void *) comp_sink);
-
-#ifdef BT_LIB_LOGD
-                       BT_LIB_LOGD("User method returned: status=%s",
-                               bt_self_component_status_string(comp_status));
-#endif
-
-#ifdef BT_ASSERT_PRE
-                       BT_ASSERT_PRE(comp_status == BT_SELF_COMPONENT_STATUS_OK ||
-                               comp_status == BT_SELF_COMPONENT_STATUS_ERROR ||
-                               comp_status == BT_SELF_COMPONENT_STATUS_NOMEM,
-                               "Unexpected returned status: status=%s",
-                               bt_self_component_status_string(comp_status));
-#endif
-
-                       if (comp_status != BT_SELF_COMPONENT_STATUS_OK) {
-                               status = BT_GRAPH_STATUS_ERROR;
-#ifdef BT_LIB_LOGW
-                               BT_LIB_LOGW("User's \"graph is configured\" method failed: "
-                                       "%![comp-]+c, status=%s",
-                                       comp,
-                                       bt_self_component_status_string(
-                                               comp_status));
-#endif
-
-                               goto end;
-                       }
-               }
-
-               comp_sink->graph_is_configured_method_called = true;
-       }
-
-       graph->config_state = BT_GRAPH_CONFIGURATION_STATE_CONFIGURED;
-
-end:
-       return status;
-}
-
-static inline
-void bt_graph_make_faulty(struct bt_graph *graph)
-{
-       graph->config_state = BT_GRAPH_CONFIGURATION_STATE_FAULTY;
-#ifdef BT_LIB_LOGD
-       BT_LIB_LOGD("Set graph's state to faulty: %![graph-]+g", graph);
-#endif
-}
-
-#endif /* BABELTRACE_GRAPH_GRAPH_INTERNAL_H */
diff --git a/include/babeltrace2/graph/message-discarded-items-internal.h b/include/babeltrace2/graph/message-discarded-items-internal.h
deleted file mode 100644 (file)
index 404a9ee..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef BABELTRACE_GRAPH_MESSAGE_DISCARDED_ITEMS_INTERNAL_H
-#define BABELTRACE_GRAPH_MESSAGE_DISCARDED_ITEMS_INTERNAL_H
-
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/property-internal.h>
-#include <babeltrace2/graph/message-const.h>
-
-struct bt_message_discarded_items {
-       struct bt_message parent;
-       struct bt_stream *stream;
-       struct bt_clock_snapshot *default_begin_cs;
-       struct bt_clock_snapshot *default_end_cs;
-       struct bt_property_uint count;
-};
-
-#endif /* BABELTRACE_GRAPH_MESSAGE_DISCARDED_ITEMS_INTERNAL_H */
diff --git a/include/babeltrace2/graph/message-event-internal.h b/include/babeltrace2/graph/message-event-internal.h
deleted file mode 100644 (file)
index f8b8946..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef BABELTRACE_GRAPH_MESSAGE_EVENT_INTERNAL_H
-#define BABELTRACE_GRAPH_MESSAGE_EVENT_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/event-class.h>
-#include <babeltrace2/trace-ir/event.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct bt_message_event {
-       struct bt_message parent;
-       struct bt_event *event;
-       struct bt_clock_snapshot *default_cs;
-};
-
-BT_HIDDEN
-struct bt_message *bt_message_event_new(struct bt_graph *graph);
-
-BT_HIDDEN
-void bt_message_event_recycle(struct bt_message *msg);
-
-BT_HIDDEN
-void bt_message_event_destroy(struct bt_message *msg);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BABELTRACE_GRAPH_MESSAGE_EVENT_INTERNAL_H */
diff --git a/include/babeltrace2/graph/message-internal.h b/include/babeltrace2/graph/message-internal.h
deleted file mode 100644 (file)
index 28c6616..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-#ifndef BABELTRACE_GRAPH_MESSAGE_MESSAGE_INTERNAL_H
-#define BABELTRACE_GRAPH_MESSAGE_MESSAGE_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/graph/graph.h>
-#include <babeltrace2/graph/message-const.h>
-#include <babeltrace2/trace-ir/stream.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/types.h>
-
-typedef struct bt_stream *(*get_stream_func)(
-               struct bt_message *message);
-
-struct bt_message {
-       struct bt_object base;
-       enum bt_message_type type;
-       bt_bool frozen;
-
-       /* Owned by this; keeps the graph alive while the msg. is alive */
-       struct bt_graph *graph;
-};
-
-#define BT_ASSERT_PRE_MSG_IS_TYPE(_msg, _type)                 \
-       BT_ASSERT_PRE(((struct bt_message *) (_msg))->type == (_type), \
-               "Message has the wrong type: expected-type=%s, "        \
-               "%![msg-]+n", bt_message_type_string(_type),    \
-               (_msg))
-
-BT_HIDDEN
-void bt_message_init(struct bt_message *message,
-               enum bt_message_type type,
-               bt_object_release_func release,
-               struct bt_graph *graph);
-
-static inline
-void bt_message_reset(struct bt_message *message)
-{
-       BT_ASSERT(message);
-
-#ifdef BT_DEV_MODE
-       message->frozen = BT_FALSE;
-#endif
-}
-
-static inline
-struct bt_message *bt_message_create_from_pool(
-               struct bt_object_pool *pool, struct bt_graph *graph)
-{
-       struct bt_message *msg = bt_object_pool_create_object(pool);
-
-       if (unlikely(!msg)) {
-#ifdef BT_LIB_LOGE
-               BT_LIB_LOGE("Cannot allocate one message from message pool: "
-                       "%![pool-]+o, %![graph-]+g", pool, graph);
-#endif
-               goto error;
-       }
-
-       if (likely(!msg->graph)) {
-               msg->graph = graph;
-       }
-
-       goto end;
-
-error:
-       BT_ASSERT(!msg);
-
-end:
-       return msg;
-}
-
-static inline void _bt_message_freeze(struct bt_message *message)
-{
-       message->frozen = BT_TRUE;
-}
-
-BT_HIDDEN
-void bt_message_unlink_graph(struct bt_message *msg);
-
-#ifdef BT_DEV_MODE
-# define bt_message_freeze             _bt_message_freeze
-#else
-# define bt_message_freeze(_x)
-#endif /* BT_DEV_MODE */
-
-static inline
-const char *bt_message_type_string(enum bt_message_type type)
-{
-       switch (type) {
-       case BT_MESSAGE_TYPE_EVENT:
-               return "BT_MESSAGE_TYPE_EVENT";
-       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-               return "BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY";
-       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
-               return "BT_MESSAGE_TYPE_STREAM_BEGINNING";
-       case BT_MESSAGE_TYPE_STREAM_END:
-               return "BT_MESSAGE_TYPE_STREAM_END";
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-               return "BT_MESSAGE_TYPE_PACKET_BEGINNING";
-       case BT_MESSAGE_TYPE_PACKET_END:
-               return "BT_MESSAGE_TYPE_PACKET_END";
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-               return "BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING";
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-               return "BT_MESSAGE_TYPE_STREAM_ACTIVITY_END";
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-               return "BT_MESSAGE_TYPE_DISCARDED_EVENTS";
-       default:
-               return "(unknown)";
-       }
-}
-
-#endif /* BABELTRACE_GRAPH_MESSAGE_MESSAGE_INTERNAL_H */
diff --git a/include/babeltrace2/graph/message-iterator-internal.h b/include/babeltrace2/graph/message-iterator-internal.h
deleted file mode 100644 (file)
index c6ef7b9..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-#ifndef BABELTRACE_GRAPH_MESSAGE_ITERATOR_INTERNAL_H
-#define BABELTRACE_GRAPH_MESSAGE_ITERATOR_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/graph/connection-const.h>
-#include <babeltrace2/graph/message-const.h>
-#include <babeltrace2/graph/message-iterator-const.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdbool.h>
-
-struct bt_port;
-struct bt_graph;
-
-enum bt_message_iterator_type {
-       BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT,
-       BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT,
-};
-
-enum bt_self_component_port_input_message_iterator_state {
-       /* Iterator is not initialized */
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_NON_INITIALIZED,
-
-       /* Iterator is active, not at the end yet, and not finalized */
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE,
-
-       /*
-        * Iterator is ended, not finalized yet: the "next" method
-        * returns BT_MESSAGE_ITERATOR_STATUS_END.
-        */
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED,
-
-       /* Iterator is currently being finalized */
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING,
-
-       /* Iterator is finalized */
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED,
-
-       /* Iterator is seeking */
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING,
-
-       /* Iterator did seek, but returned `BT_MESSAGE_ITERATOR_STATUS_AGAIN` */
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN,
-
-       /* Iterator did seek, but returned error status */
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR,
-};
-
-struct bt_message_iterator {
-       struct bt_object base;
-       enum bt_message_iterator_type type;
-       GPtrArray *msgs;
-};
-
-typedef enum bt_self_message_iterator_status
-(*bt_self_component_port_input_message_iterator_next_method)(
-               void *, bt_message_array_const, uint64_t, uint64_t *);
-
-typedef enum bt_self_message_iterator_status
-(*bt_self_component_port_input_message_iterator_seek_ns_from_origin_method)(
-               void *, int64_t);
-
-typedef enum bt_self_message_iterator_status
-(*bt_self_component_port_input_message_iterator_seek_beginning_method)(
-               void *);
-
-typedef bt_bool
-(*bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method)(
-               void *, int64_t);
-
-typedef bt_bool
-(*bt_self_component_port_input_message_iterator_can_seek_beginning_method)(
-               void *);
-
-struct bt_self_component_port_input_message_iterator {
-       struct bt_message_iterator base;
-       struct bt_component *upstream_component; /* Weak */
-       struct bt_port *upstream_port; /* Weak */
-       struct bt_connection *connection; /* Weak */
-       struct bt_graph *graph; /* Weak */
-
-       struct {
-               bt_self_component_port_input_message_iterator_next_method next;
-               bt_self_component_port_input_message_iterator_seek_ns_from_origin_method seek_ns_from_origin;
-               bt_self_component_port_input_message_iterator_seek_beginning_method seek_beginning;
-               bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method can_seek_ns_from_origin;
-               bt_self_component_port_input_message_iterator_can_seek_beginning_method can_seek_beginning;
-       } methods;
-
-       enum bt_self_component_port_input_message_iterator_state state;
-       GQueue *auto_seek_msgs;
-       void *user_data;
-};
-
-struct bt_port_output_message_iterator {
-       struct bt_message_iterator base;
-       struct bt_graph *graph; /* Owned by this */
-       struct bt_component_sink *colander; /* Owned by this */
-
-       /*
-        * Only used temporarily as a bridge between a colander sink and
-        * the user.
-        */
-       uint64_t count;
-};
-
-BT_HIDDEN
-void bt_self_component_port_input_message_iterator_try_finalize(
-               struct bt_self_component_port_input_message_iterator *iterator);
-
-BT_HIDDEN
-void bt_self_component_port_input_message_iterator_set_connection(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               struct bt_connection *connection);
-
-static inline
-const char *bt_message_iterator_status_string(
-               enum bt_message_iterator_status status)
-{
-       switch (status) {
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               return "BT_MESSAGE_ITERATOR_STATUS_AGAIN";
-       case BT_MESSAGE_ITERATOR_STATUS_END:
-               return "BT_MESSAGE_ITERATOR_STATUS_END";
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-               return "BT_MESSAGE_ITERATOR_STATUS_OK";
-       case BT_MESSAGE_ITERATOR_STATUS_ERROR:
-               return "BT_MESSAGE_ITERATOR_STATUS_ERROR";
-       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               return "BT_MESSAGE_ITERATOR_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline
-const char *bt_self_component_port_input_message_iterator_state_string(
-               enum bt_self_component_port_input_message_iterator_state state)
-{
-       switch (state) {
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE:
-               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE";
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED:
-               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED";
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING:
-               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING";
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED:
-               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED";
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING:
-               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING";
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN:
-               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN";
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR:
-               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR";
-       default:
-               return "(unknown)";
-       }
-};
-
-#endif /* BABELTRACE_GRAPH_MESSAGE_ITERATOR_INTERNAL_H */
diff --git a/include/babeltrace2/graph/message-message-iterator-inactivity-internal.h b/include/babeltrace2/graph/message-message-iterator-inactivity-internal.h
deleted file mode 100644 (file)
index 5e607e2..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef BABELTRACE_GRAPH_MESSAGE_MESSAGE_ITERATOR_INACTIVITY_INTERNAL_H
-#define BABELTRACE_GRAPH_MESSAGE_MESSAGE_ITERATOR_INACTIVITY_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/graph/message-const.h>
-
-struct bt_message_message_iterator_inactivity {
-       struct bt_message parent;
-       struct bt_clock_snapshot *default_cs;
-};
-
-#endif /* BABELTRACE_GRAPH_MESSAGE_MESSAGE_ITERATOR_INACTIVITY_INTERNAL_H */
diff --git a/include/babeltrace2/graph/message-packet-internal.h b/include/babeltrace2/graph/message-packet-internal.h
deleted file mode 100644 (file)
index 6e532bc..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef BABELTRACE_GRAPH_MESSAGE_PACKET_INTERNAL_H
-#define BABELTRACE_GRAPH_MESSAGE_PACKET_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/packet.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-struct bt_message_packet {
-       struct bt_message parent;
-       struct bt_packet *packet;
-       struct bt_clock_snapshot *default_cs;
-};
-
-BT_HIDDEN
-void bt_message_packet_destroy(struct bt_message *msg);
-
-BT_HIDDEN
-struct bt_message *bt_message_packet_beginning_new(
-               struct bt_graph *graph);
-BT_HIDDEN
-void bt_message_packet_beginning_recycle(struct bt_message *msg);
-
-BT_HIDDEN
-struct bt_message *bt_message_packet_end_new(struct bt_graph *graph);
-
-BT_HIDDEN
-void bt_message_packet_end_recycle(struct bt_message *msg);
-
-#endif /* BABELTRACE_GRAPH_MESSAGE_PACKET_INTERNAL_H */
diff --git a/include/babeltrace2/graph/message-stream-activity-internal.h b/include/babeltrace2/graph/message-stream-activity-internal.h
deleted file mode 100644 (file)
index 8298b0c..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef BABELTRACE_GRAPH_MESSAGE_STREAM_ACTIVITY_INTERNAL_H
-#define BABELTRACE_GRAPH_MESSAGE_STREAM_ACTIVITY_INTERNAL_H
-
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/graph/message-const.h>
-#include <babeltrace2/graph/message-stream-activity-const.h>
-
-struct bt_message_stream_activity {
-       struct bt_message parent;
-       struct bt_stream *stream;
-       struct bt_clock_snapshot *default_cs;
-       enum bt_message_stream_activity_clock_snapshot_state default_cs_state;
-};
-
-static inline
-const char *bt_message_stream_activity_clock_snapshot_state_string(
-               enum bt_message_stream_activity_clock_snapshot_state state)
-{
-       switch (state) {
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
-               return "BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN";
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
-               return "BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN";
-       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
-               return "BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE";
-       default:
-               return "(unknown)";
-       }
-}
-
-#endif /* BABELTRACE_GRAPH_MESSAGE_STREAM_ACTIVITY_INTERNAL_H */
diff --git a/include/babeltrace2/graph/message-stream-internal.h b/include/babeltrace2/graph/message-stream-internal.h
deleted file mode 100644 (file)
index 54beef6..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef BABELTRACE_GRAPH_MESSAGE_STREAM_INTERNAL_H
-#define BABELTRACE_GRAPH_MESSAGE_STREAM_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-struct bt_message_stream {
-       struct bt_message parent;
-       struct bt_stream *stream;
-};
-
-#endif /* BABELTRACE_GRAPH_MESSAGE_STREAM_INTERNAL_H */
diff --git a/include/babeltrace2/graph/port-internal.h b/include/babeltrace2/graph/port-internal.h
deleted file mode 100644 (file)
index c1be31a..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef BABELTRACE_GRAPH_PORT_INTERNAL_H
-#define BABELTRACE_GRAPH_PORT_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/graph/port-const.h>
-
-struct bt_port {
-       struct bt_object base;
-       enum bt_port_type type;
-       GString *name;
-       struct bt_connection *connection;
-       void *user_data;
-};
-
-struct bt_component;
-
-BT_HIDDEN
-struct bt_port *bt_port_create(struct bt_component *parent_component,
-               enum bt_port_type type, const char *name, void *user_data);
-
-BT_HIDDEN
-void bt_port_set_connection(struct bt_port *port,
-               struct bt_connection *connection);
-
-static inline
-struct bt_component *bt_port_borrow_component_inline(const struct bt_port *port)
-{
-       BT_ASSERT(port);
-       return (void *) bt_object_borrow_parent(&port->base);
-}
-
-static inline
-const char *bt_port_type_string(enum bt_port_type port_type)
-{
-       switch (port_type) {
-       case BT_PORT_TYPE_INPUT:
-               return "BT_PORT_TYPE_INPUT";
-       case BT_PORT_TYPE_OUTPUT:
-               return "BT_PORT_TYPE_OUTPUT";
-       default:
-               return "(unknown)";
-       }
-}
-
-#endif /* BABELTRACE_GRAPH_PORT_INTERNAL_H */
diff --git a/include/babeltrace2/graph/query-executor-internal.h b/include/babeltrace2/graph/query-executor-internal.h
deleted file mode 100644 (file)
index 2bf9367..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H
-#define BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/types.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/graph/query-executor.h>
-#include <babeltrace2/graph/component-class.h>
-
-struct bt_query_executor {
-       struct bt_object base;
-       bool canceled;
-};
-
-static inline const char *bt_query_status_string(enum bt_query_status status)
-{
-       switch (status) {
-       case BT_QUERY_STATUS_OK:
-               return "BT_QUERY_STATUS_OK";
-       case BT_QUERY_STATUS_AGAIN:
-               return "BT_QUERY_STATUS_AGAIN";
-       case BT_QUERY_STATUS_ERROR:
-               return "BT_QUERY_STATUS_ERROR";
-       case BT_QUERY_STATUS_INVALID_OBJECT:
-               return "BT_QUERY_STATUS_INVALID_OBJECT";
-       case BT_QUERY_STATUS_INVALID_PARAMS:
-               return "BT_QUERY_STATUS_INVALID_PARAMS";
-       case BT_QUERY_STATUS_NOMEM:
-               return "BT_QUERY_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-};
-
-static inline const char *bt_query_executor_status_string(
-               enum bt_query_executor_status status)
-{
-       switch (status) {
-       case BT_QUERY_EXECUTOR_STATUS_OK:
-               return "BT_QUERY_EXECUTOR_STATUS_OK";
-       case BT_QUERY_EXECUTOR_STATUS_AGAIN:
-               return "BT_QUERY_EXECUTOR_STATUS_AGAIN";
-       case BT_QUERY_EXECUTOR_STATUS_CANCELED:
-               return "BT_QUERY_EXECUTOR_STATUS_CANCELED";
-       case BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED:
-               return "BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED";
-       case BT_QUERY_EXECUTOR_STATUS_ERROR:
-               return "BT_QUERY_EXECUTOR_STATUS_ERROR";
-       case BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT:
-               return "BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT";
-       case BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS:
-               return "BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS";
-       case BT_QUERY_EXECUTOR_STATUS_NOMEM:
-               return "BT_QUERY_EXECUTOR_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-};
-
-#endif /* BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H */
diff --git a/include/babeltrace2/lib-logging-internal.h b/include/babeltrace2/lib-logging-internal.h
deleted file mode 100644 (file)
index 3b12756..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-#ifndef BABELTRACE_LIB_LOGGING_INTERNAL_H
-#define BABELTRACE_LIB_LOGGING_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <stdarg.h>
-
-#ifndef BT_LOG_TAG
-# error Please define a tag with BT_LOG_TAG before including this file.
-#endif
-
-#define BT_LOG_OUTPUT_LEVEL bt_lib_log_level
-
-#include <babeltrace2/logging-internal.h>
-
-extern
-int bt_lib_log_level;
-
-#define BT_LIB_LOG(_lvl, _fmt, ...)                                    \
-       do {                                                            \
-               if (BT_LOG_ON(_lvl)) {                                  \
-                       bt_lib_log(_BT_LOG_SRCLOC_FUNCTION, __FILE__,   \
-                               __LINE__, _lvl, _BT_LOG_TAG,            \
-                               (_fmt), ##__VA_ARGS__);                 \
-               }                                                       \
-       } while (0)
-
-/*
- * The six macros below are logging statements which are specialized
- * for the Babeltrace library.
- *
- * `_fmt` is a typical printf()-style format string, with the following
- * limitations:
- *
- * * The `*` width specifier is not accepted.
- * * The `*` precision specifier is not accepted.
- * * The `j` and `t` length modifiers are not accepted.
- * * The `n` format specifier is not accepted.
- * * The format specifiers defined in <inttypes.h> are not accepted
- *   except for `PRId64`, `PRIu64`, `PRIx64`, `PRIX64`, `PRIo64`, and
- *   `PRIi64`.
- *
- * The Babeltrace extension conversion specifier is accepted. Its syntax
- * is either `%!u` to format a UUID (`bt_uuid` type) or:
- *
- * 1. Introductory `%!` sequence.
- *
- * 2. Optional: `[` followed by a custom prefix for the printed fields
- *    of this specifier, followed by `]`. The standard form is to end
- *    this prefix with `-` so that, for example, with the prefix
- *    `prefix-`, the complete field name is `prefix-addr`.
- *
- * 3. Optional: `+` to print extended fields. This depends on the
- *    provided format specifier.
- *
- * 4. Format specifier (see below).
- *
- * The available format specifiers are:
- *
- *   `F`:
- *       Trace IR field class. The parameter type is
- *      `struct bt_field_class *`.
- *
- *   `f`:
- *       Trace IR field. The parameter type is `struct bt_field *`.
- *
- *   `P`:
- *       Field path. The parameter type is `struct bt_field_path *`.
- *
- *   `E`:
- *       Trace IR event class. The parameter type is
- *      `struct bt_event_class *`.
- *
- *   `e`:
- *       Trace IR event. The parameter type is `struct bt_event *`.
- *
- *   `S`:
- *       Trace IR stream class. The parameter type is
- *      `struct bt_stream_class *`.
- *
- *   `s`:
- *       Trace IR stream. The parameter type is `struct bt_stream *`.
- *
- *   `a`:
- *       Packet. The parameter type is `struct bt_packet *`.
- *
- *   `T`:
- *       Trace IR trace class. The parameter type is `struct bt_trace_class *`.
- *
- *   `t`:
- *       Trace IR trace. The parameter type is `struct bt_trace *`.
- *
- *   `K`:
- *       Clock class. The parameter type is `struct bt_clock_class *`.
- *
- *   `k`:
- *       Clock snapshot. The parameter type is `struct bt_clock_snapshot *`.
- *
- *   `v`:
- *       Value. The parameter type is `struct bt_value *`.
- *
- *   `n`:
- *       Message. The parameter type is `struct bt_message *`.
- *
- *   `i`:
- *       Message iterator. The parameter type is
- *       `struct bt_message_iterator *`.
- *
- *   `C`:
- *       Component class. The parameter type is
- *      `struct bt_component_class *`.
- *
- *   `c`:
- *       Component. The parameter type is `struct bt_component *`.
- *
- *   `p`:
- *       Port. The parameter type is `struct bt_port *`.
- *
- *   `x`:
- *       Connection. The parameter type is `struct bt_connection *`.
- *
- *   `g`:
- *       Graph. The parameter type is `struct bt_graph *`.
- *
- *   `l`:
- *       Plugin. The parameter type is `const struct bt_plugin *`.
- *
- *   `o`:
- *       Object pool. The parameter type is `struct bt_object_pool *`.
- *
- *   `O`:
- *       Object. The parameter type is `struct bt_object *`.
- *
- * Conversion specifier examples:
- *
- *     %!f
- *     %![my-event-]+e
- *     %!t
- *     %!+F
- *
- * The string `, ` is printed between individual fields, but not after
- * the last one. Therefore you must put this separator in the format
- * string between two conversion specifiers, e.g.:
- *
- *     BT_LIB_LOGW("Message: count=%u, %!E, %!+K", count, event_class,
- *                 clock_class);
- *
- * Example with a custom prefix:
- *
- *     BT_LIB_LOGI("Some message: %![ec-a-]e, %![ec-b-]+e", ec_a, ec_b);
- *
- * It is safe to pass NULL as any Babeltrace object parameter: the
- * macros only print its null address.
- */
-#define BT_LIB_LOGF(_fmt, ...) BT_LIB_LOG(BT_LOG_FATAL, _fmt, ##__VA_ARGS__)
-#define BT_LIB_LOGE(_fmt, ...) BT_LIB_LOG(BT_LOG_ERROR, _fmt, ##__VA_ARGS__)
-#define BT_LIB_LOGW(_fmt, ...) BT_LIB_LOG(BT_LOG_WARN, _fmt, ##__VA_ARGS__)
-#define BT_LIB_LOGI(_fmt, ...) BT_LIB_LOG(BT_LOG_INFO, _fmt, ##__VA_ARGS__)
-#define BT_LIB_LOGD(_fmt, ...) BT_LIB_LOG(BT_LOG_DEBUG, _fmt, ##__VA_ARGS__)
-#define BT_LIB_LOGV(_fmt, ...) BT_LIB_LOG(BT_LOG_VERBOSE, _fmt, ##__VA_ARGS__)
-
-/*
- * Log statement, specialized for the Babeltrace library.
- *
- * Use one of the BT_LIB_LOGF*() macros above instead of calling this
- * function directly.
- */
-
-void bt_lib_log(const char *func, const char *file, unsigned line,
-               int lvl, const char *tag, const char *fmt, ...);
-
-#endif /* BABELTRACE_LIB_LOGGING_INTERNAL_H */
diff --git a/include/babeltrace2/list-internal.h b/include/babeltrace2/list-internal.h
deleted file mode 100644 (file)
index 48d9bbb..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2002 Free Software Foundation, Inc.
- * This file is part of the GNU C Library.
- * Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; only
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef _BT_LIST_H
-#define _BT_LIST_H     1
-
-/* The definitions of this file are adopted from those which can be
-   found in the Linux kernel headers to enable people familiar with
-   the latter find their way in these sources as well.  */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Basic type for the double-link list.  */
-struct bt_list_head
-{
-  struct bt_list_head *next;
-  struct bt_list_head *prev;
-};
-
-
-/* Define a variable with the head and tail of the list.  */
-#define BT_LIST_HEAD(name) \
-  struct bt_list_head name = { &(name), &(name) }
-
-/* Initialize a new list head.  */
-#define BT_INIT_LIST_HEAD(ptr) \
-  (ptr)->next = (ptr)->prev = (ptr)
-
-#define BT_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) }
-
-/* Add new element at the head of the list.  */
-static inline void
-bt_list_add (struct bt_list_head *newp, struct bt_list_head *head)
-{
-  head->next->prev = newp;
-  newp->next = head->next;
-  newp->prev = head;
-  head->next = newp;
-}
-
-
-/* Add new element at the tail of the list.  */
-static inline void
-bt_list_add_tail (struct bt_list_head *newp, struct bt_list_head *head)
-{
-  head->prev->next = newp;
-  newp->next = head;
-  newp->prev = head->prev;
-  head->prev = newp;
-}
-
-
-/* Remove element from list.  */
-static inline void
-__bt_list_del (struct bt_list_head *prev, struct bt_list_head *next)
-{
-  next->prev = prev;
-  prev->next = next;
-}
-
-/* Remove element from list.  */
-static inline void
-bt_list_del (struct bt_list_head *elem)
-{
-  __bt_list_del (elem->prev, elem->next);
-}
-
-/* delete from list, add to another list as head */
-static inline void
-bt_list_move (struct bt_list_head *elem, struct bt_list_head *head)
-{
-  __bt_list_del (elem->prev, elem->next);
-  bt_list_add (elem, head);
-}
-
-/* replace an old entry.
- */
-static inline void
-bt_list_replace(struct bt_list_head *old, struct bt_list_head *_new)
-{
-       _new->next = old->next;
-       _new->prev = old->prev;
-       _new->prev->next = _new;
-       _new->next->prev = _new;
-}
-
-/* Join two lists.  */
-static inline void
-bt_list_splice (struct bt_list_head *add, struct bt_list_head *head)
-{
-  /* Do nothing if the list which gets added is empty.  */
-  if (add != add->next)
-    {
-      add->next->prev = head;
-      add->prev->next = head->next;
-      head->next->prev = add->prev;
-      head->next = add->next;
-    }
-}
-
-
-/* Get typed element from list at a given position.  */
-#define bt_list_entry(ptr, type, member) \
-  ((type *) ((char *) (ptr) - (uintptr_t) (&((type *) 0)->member)))
-
-
-
-/* Iterate forward over the elements of the list.  */
-#define bt_list_for_each(pos, head) \
-  for (pos = (head)->next; pos != (head); pos = pos->next)
-
-
-/* Iterate forward over the elements of the list.  */
-#define bt_list_for_each_prev(pos, head) \
-  for (pos = (head)->prev; pos != (head); pos = pos->prev)
-
-
-/* Iterate backwards over the elements list.  The list elements can be
-   removed from the list while doing this.  */
-#define bt_list_for_each_prev_safe(pos, p, head) \
-  for (pos = (head)->prev, p = pos->prev; \
-       pos != (head); \
-       pos = p, p = pos->prev)
-
-#define bt_list_for_each_entry(pos, head, member)                              \
-       for (pos = bt_list_entry((head)->next, typeof(*pos), member);   \
-            &pos->member != (head);                                    \
-            pos = bt_list_entry(pos->member.next, typeof(*pos), member))
-
-#define bt_list_for_each_entry_reverse(pos, head, member)                      \
-       for (pos = bt_list_entry((head)->prev, typeof(*pos), member);   \
-            &pos->member != (head);                                    \
-            pos = bt_list_entry(pos->member.prev, typeof(*pos), member))
-
-#define bt_list_for_each_entry_safe(pos, p, head, member)                      \
-       for (pos = bt_list_entry((head)->next, typeof(*pos), member),   \
-                    p = bt_list_entry(pos->member.next,typeof(*pos), member); \
-            &pos->member != (head);                                    \
-            pos = p, p = bt_list_entry(pos->member.next, typeof(*pos), member))
-
-static inline int bt_list_empty(struct bt_list_head *head)
-{
-       return head == head->next;
-}
-
-static inline void bt_list_replace_init(struct bt_list_head *old,
-                                    struct bt_list_head *_new)
-{
-       struct bt_list_head *head = old->next;
-       bt_list_del(old);
-       bt_list_add_tail(_new, head);
-       BT_INIT_LIST_HEAD(old);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _BT_LIST_H */
diff --git a/include/babeltrace2/logging-internal.h b/include/babeltrace2/logging-internal.h
deleted file mode 100644 (file)
index 7aff10b..0000000
+++ /dev/null
@@ -1,1054 +0,0 @@
-/*
- * This is zf_log.h, modified with Babeltrace prefixes.
- * See <https://github.com/wonder-mice/zf_log/>.
- * See logging/LICENSE in the Babeltrace source tree.
- */
-
-#pragma once
-
-#ifndef BABELTRACE_LOGGING_INTERNAL_H
-#define BABELTRACE_LOGGING_INTERNAL_H
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <babeltrace2/logging.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-/* To detect incompatible changes you can define BT_LOG_VERSION_REQUIRED to be
- * the current value of BT_LOG_VERSION before including this file (or via
- * compiler command line):
- *
- *   #define BT_LOG_VERSION_REQUIRED 4
- *   #include <babeltrace2/logging-internal.h>
- *
- * Compilation will fail when included file has different version.
- */
-#define BT_LOG_VERSION 4
-#if defined(BT_LOG_VERSION_REQUIRED)
-       #if BT_LOG_VERSION_REQUIRED != BT_LOG_VERSION
-               #error different bt_log version required
-       #endif
-#endif
-
-/* Log level guideline:
- * - BT_LOG_FATAL - happened something impossible and absolutely unexpected.
- *   Process can't continue and must be terminated.
- *   Example: division by zero, unexpected modifications from other thread.
- * - BT_LOG_ERROR - happened something possible, but highly unexpected. The
- *   process is able to recover and continue execution.
- *   Example: out of memory (could also be FATAL if not handled properly).
- * - BT_LOG_WARN - happened something that *usually* should not happen and
- *   significantly changes application behavior for some period of time.
- *   Example: configuration file not found, auth error.
- * - BT_LOG_INFO - happened significant life cycle event or major state
- *   transition.
- *   Example: app started, user logged in.
- * - BT_LOG_DEBUG - minimal set of events that could help to reconstruct the
- *   execution path. Usually disabled in release builds.
- * - BT_LOG_VERBOSE - all other events. Usually disabled in release builds.
- *
- * *Ideally*, log file of debugged, well tested, production ready application
- * should be empty or very small. Choosing a right log level is as important as
- * providing short and self descriptive log message.
- */
-#define BT_LOG_VERBOSE BT_LOGGING_LEVEL_VERBOSE
-#define BT_LOG_DEBUG   BT_LOGGING_LEVEL_DEBUG
-#define BT_LOG_INFO    BT_LOGGING_LEVEL_INFO
-#define BT_LOG_WARN    BT_LOGGING_LEVEL_WARN
-#define BT_LOG_ERROR   BT_LOGGING_LEVEL_ERROR
-#define BT_LOG_FATAL   BT_LOGGING_LEVEL_FATAL
-#define BT_LOG_NONE    BT_LOGGING_LEVEL_NONE
-
-/* "Current" log level is a compile time check and has no runtime overhead. Log
- * level that is below current log level it said to be "disabled". Otherwise,
- * it's "enabled". Log messages that are disabled has no runtime overhead - they
- * are converted to no-op by preprocessor and then eliminated by compiler.
- * Current log level is configured per compilation module (.c/.cpp/.m file) by
- * defining BT_LOG_DEF_LEVEL or BT_LOG_LEVEL. BT_LOG_LEVEL has higer priority
- * and when defined overrides value provided by BT_LOG_DEF_LEVEL.
- *
- * Common practice is to define default current log level with BT_LOG_DEF_LEVEL
- * in build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
- * project or target:
- *
- *   CC_ARGS := -DBT_LOG_DEF_LEVEL=BT_LOG_INFO
- *
- * And when necessary to override it with BT_LOG_LEVEL in .c/.cpp/.m files
- * before including bt_log.h:
- *
- *   #define BT_LOG_LEVEL BT_LOG_VERBOSE
- *   #include <babeltrace2/logging-internal.h>
- *
- * If both BT_LOG_DEF_LEVEL and BT_LOG_LEVEL are undefined, then BT_LOG_INFO
- * will be used for release builds (NDEBUG is defined) and BT_LOG_DEBUG
- * otherwise (NDEBUG is not defined).
- */
-#if defined(BT_LOG_LEVEL)
-       #define _BT_LOG_LEVEL BT_LOG_LEVEL
-#elif defined(BT_LOG_DEF_LEVEL)
-       #define _BT_LOG_LEVEL BT_LOG_DEF_LEVEL
-#else
-       #ifdef NDEBUG
-               #define _BT_LOG_LEVEL BT_LOG_INFO
-       #else
-               #define _BT_LOG_LEVEL BT_LOG_DEBUG
-       #endif
-#endif
-
-/* "Output" log level is a runtime check. When log level is below output log
- * level it said to be "turned off" (or just "off" for short). Otherwise it's
- * "turned on" (or just "on"). Log levels that were "disabled" (see
- * BT_LOG_LEVEL and BT_LOG_DEF_LEVEL) can't be "turned on", but "enabled" log
- * levels could be "turned off". Only messages with log level which is
- * "turned on" will reach output facility. All other messages will be ignored
- * (and their arguments will not be evaluated). Output log level is a global
- * property and configured per process using bt_log_set_output_level() function
- * which can be called at any time.
- *
- * Though in some cases it could be useful to configure output log level per
- * compilation module or per library. There are two ways to achieve that:
- * - Define BT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired output
- *   log level.
- * - Copy bt_log.h and bt_log.c files into your library and build it with
- *   BT_LOG_LIBRARY_PREFIX defined to library specific prefix. See
- *   BT_LOG_LIBRARY_PREFIX for more details.
- *
- * When defined, BT_LOG_OUTPUT_LEVEL must evaluate to integral value that
- * corresponds to desired output log level. Use it only when compilation module
- * is required to have output log level which is different from global output
- * log level set by bt_log_set_output_level() function. For other cases,
- * consider defining BT_LOG_LEVEL or using bt_log_set_output_level() function.
- *
- * Example:
- *
- *   #define BT_LOG_OUTPUT_LEVEL g_module_log_level
- *   #include <babeltrace2/logging-internal.h>
- *   static int g_module_log_level = BT_LOG_INFO;
- *   static void foo() {
- *       BT_LOGI("Will check g_module_log_level for output log level");
- *   }
- *   void debug_log(bool on) {
- *       g_module_log_level = on? BT_LOG_DEBUG: BT_LOG_INFO;
- *   }
- *
- * Note on performance. This expression will be evaluated each time message is
- * logged (except when message log level is "disabled" - see BT_LOG_LEVEL for
- * details). Keep this expression as simple as possible, otherwise it will not
- * only add runtime overhead, but also will increase size of call site (which
- * will result in larger executable). The prefered way is to use integer
- * variable (as in example above). If structure must be used, log_level field
- * must be the first field in this structure:
- *
- *   #define BT_LOG_OUTPUT_LEVEL (g_config.log_level)
- *   #include <babeltrace2/logging-internal.h>
- *   struct config {
- *       int log_level;
- *       unsigned other_field;
- *       [...]
- *   };
- *   static config g_config = {BT_LOG_INFO, 0, ...};
- *
- * This allows compiler to generate more compact load instruction (no need to
- * specify offset since it's zero). Calling a function to get output log level
- * is generaly a bad idea, since it will increase call site size and runtime
- * overhead even further.
- */
-#if defined(BT_LOG_OUTPUT_LEVEL)
-       #define _BT_LOG_OUTPUT_LEVEL BT_LOG_OUTPUT_LEVEL
-#else
-       /*
-        * We disallow this to make sure Babeltrace modules always
-        * have their own local log level.
-        */
-       #error No log level symbol specified: please define BT_LOG_OUTPUT_LEVEL before including this header.
-#endif
-
-/* "Tag" is a compound string that could be associated with a log message. It
- * consists of tag prefix and tag (both are optional).
- *
- * Tag prefix is a global property and configured per process using
- * bt_log_set_tag_prefix() function. Tag prefix identifies context in which
- * component or module is running (e.g. process name). For example, the same
- * library could be used in both client and server processes that work on the
- * same machine. Tag prefix could be used to easily distinguish between them.
- * For more details about tag prefix see bt_log_set_tag_prefix() function. Tag
- * prefix
- *
- * Tag identifies component or module. It is configured per compilation module
- * (.c/.cpp/.m file) by defining BT_LOG_TAG or BT_LOG_DEF_TAG. BT_LOG_TAG has
- * higer priority and when defined overrides value provided by BT_LOG_DEF_TAG.
- * When defined, value must evaluate to (const char *), so for strings double
- * quotes must be used.
- *
- * Default tag could be defined with BT_LOG_DEF_TAG in build script (e.g.
- * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target:
- *
- *   CC_ARGS := -DBT_LOG_DEF_TAG=\"MISC\"
- *
- * And when necessary could be overriden with BT_LOG_TAG in .c/.cpp/.m files
- * before including bt_log.h:
- *
- *   #define BT_LOG_TAG "MAIN"
- *   #include <babeltrace2/logging-internal.h>
- *
- * If both BT_LOG_DEF_TAG and BT_LOG_TAG are undefined no tag will be added to
- * the log message (tag prefix still could be added though).
- *
- * Output example:
- *
- *   04-29 22:43:20.244 40059  1299 I hello.MAIN Number of arguments: 1
- *                                    |     |
- *                                    |     +- tag (e.g. module)
- *                                    +- tag prefix (e.g. process name)
- */
-#if defined(BT_LOG_TAG)
-       #define _BT_LOG_TAG BT_LOG_TAG
-#elif defined(BT_LOG_DEF_TAG)
-       #define _BT_LOG_TAG BT_LOG_DEF_TAG
-#else
-       #define _BT_LOG_TAG 0
-#endif
-
-/* Source location is part of a log line that describes location (function or
- * method name, file name and line number, e.g. "runloop@main.cpp:68") of a
- * log statement that produced it.
- * Source location formats are:
- * - BT_LOG_SRCLOC_NONE - don't add source location to log line.
- * - BT_LOG_SRCLOC_SHORT - add source location in short form (file and line
- *   number, e.g. "@main.cpp:68").
- * - BT_LOG_SRCLOC_LONG - add source location in long form (function or method
- *   name, file and line number, e.g. "runloop@main.cpp:68").
- */
-#define BT_LOG_SRCLOC_NONE  0
-#define BT_LOG_SRCLOC_SHORT 1
-#define BT_LOG_SRCLOC_LONG  2
-
-/* Source location format is configured per compilation module (.c/.cpp/.m
- * file) by defining BT_LOG_DEF_SRCLOC or BT_LOG_SRCLOC. BT_LOG_SRCLOC has
- * higer priority and when defined overrides value provided by
- * BT_LOG_DEF_SRCLOC.
- *
- * Common practice is to define default format with BT_LOG_DEF_SRCLOC in
- * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
- * project or target:
- *
- *   CC_ARGS := -DBT_LOG_DEF_SRCLOC=BT_LOG_SRCLOC_LONG
- *
- * And when necessary to override it with BT_LOG_SRCLOC in .c/.cpp/.m files
- * before including bt_log.h:
- *
- *   #define BT_LOG_SRCLOC BT_LOG_SRCLOC_NONE
- *   #include <babeltrace2/logging-internal.h>
- *
- * If both BT_LOG_DEF_SRCLOC and BT_LOG_SRCLOC are undefined, then
- * BT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) and
- * BT_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined).
- */
-#if defined(BT_LOG_SRCLOC)
-       #define _BT_LOG_SRCLOC BT_LOG_SRCLOC
-#elif defined(BT_LOG_DEF_SRCLOC)
-       #define _BT_LOG_SRCLOC BT_LOG_DEF_SRCLOC
-#else
-       #ifdef NDEBUG
-               #define _BT_LOG_SRCLOC BT_LOG_SRCLOC_NONE
-       #else
-               #define _BT_LOG_SRCLOC BT_LOG_SRCLOC_LONG
-       #endif
-#endif
-#if BT_LOG_SRCLOC_LONG == _BT_LOG_SRCLOC
-       #define _BT_LOG_SRCLOC_FUNCTION _BT_LOG_FUNCTION
-#else
-       #define _BT_LOG_SRCLOC_FUNCTION 0
-#endif
-
-/* Censoring provides conditional logging of secret information, also known as
- * Personally Identifiable Information (PII) or Sensitive Personal Information
- * (SPI). Censoring can be either enabled (BT_LOG_CENSORED) or disabled
- * (BT_LOG_UNCENSORED). When censoring is enabled, log statements marked as
- * "secrets" will be ignored and will have zero overhead (arguments also will
- * not be evaluated).
- */
-#define BT_LOG_CENSORED   1
-#define BT_LOG_UNCENSORED 0
-
-/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining
- * BT_LOG_DEF_CENSORING or BT_LOG_CENSORING. BT_LOG_CENSORING has higer priority
- * and when defined overrides value provided by BT_LOG_DEF_CENSORING.
- *
- * Common practice is to define default censoring with BT_LOG_DEF_CENSORING in
- * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
- * project or target:
- *
- *   CC_ARGS := -DBT_LOG_DEF_CENSORING=BT_LOG_CENSORED
- *
- * And when necessary to override it with BT_LOG_CENSORING in .c/.cpp/.m files
- * before including bt_log.h (consider doing it only for debug purposes and be
- * very careful not to push such temporary changes to source control):
- *
- *   #define BT_LOG_CENSORING BT_LOG_UNCENSORED
- *   #include <babeltrace2/logging-internal.h>
- *
- * If both BT_LOG_DEF_CENSORING and BT_LOG_CENSORING are undefined, then
- * BT_LOG_CENSORED will be used for release builds (NDEBUG is defined) and
- * BT_LOG_UNCENSORED otherwise (NDEBUG is not defined).
- */
-#if defined(BT_LOG_CENSORING)
-       #define _BT_LOG_CENSORING BT_LOG_CENSORING
-#elif defined(BT_LOG_DEF_CENSORING)
-       #define _BT_LOG_CENSORING BT_LOG_DEF_CENSORING
-#else
-       #ifdef NDEBUG
-               #define _BT_LOG_CENSORING BT_LOG_CENSORED
-       #else
-               #define _BT_LOG_CENSORING BT_LOG_UNCENSORED
-       #endif
-#endif
-
-/* Check censoring at compile time. Evaluates to true when censoring is disabled
- * (i.e. when secrets will be logged). For example:
- *
- *   #if BT_LOG_SECRETS
- *       char ssn[16];
- *       getSocialSecurityNumber(ssn);
- *       BT_LOGI("Customer ssn: %s", ssn);
- *   #endif
- *
- * See BT_LOG_SECRET() macro for a more convenient way of guarding single log
- * statement.
- */
-#define BT_LOG_SECRETS (BT_LOG_UNCENSORED == _BT_LOG_CENSORING)
-
-/* Static (compile-time) initialization support allows to configure logging
- * before entering main() function. This mostly useful in C++ where functions
- * and methods could be called during initialization of global objects. Those
- * functions and methods could record log messages too and for that reason
- * static initialization of logging configuration is customizable.
- *
- * Macros below allow to specify values to use for initial configuration:
- * - BT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none)
- * - BT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see
- *   BT_LOG_MEM_WIDTH in bt_log.c)
- * - BT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: stderr or
- *   platform specific, see BT_LOG_USE_XXX macros in bt_log.c)
- * - BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level (default: 0 -
- *   all levals are "turned on")
- *
- * For example, in log_config.c:
- *
- *   #include <babeltrace2/logging-internal.h>
- *   BT_LOG_DEFINE_TAG_PREFIX = "MyApp";
- *   BT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};
- *   BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_PUT_STD, custom_output_callback, 0};
- *   BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = BT_LOG_INFO;
- *
- * However, to use any of those macros bt_log library must be compiled with
- * following macros defined:
- * - to use BT_LOG_DEFINE_TAG_PREFIX define BT_LOG_EXTERN_TAG_PREFIX
- * - to use BT_LOG_DEFINE_GLOBAL_FORMAT define BT_LOG_EXTERN_GLOBAL_FORMAT
- * - to use BT_LOG_DEFINE_GLOBAL_OUTPUT define BT_LOG_EXTERN_GLOBAL_OUTPUT
- * - to use BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define
- *   BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
- *
- * When bt_log library compiled with one of BT_LOG_EXTERN_XXX macros defined,
- * corresponding BT_LOG_DEFINE_XXX macro MUST be used exactly once somewhere.
- * Otherwise build will fail with link error (undefined symbol).
- */
-#define BT_LOG_DEFINE_TAG_PREFIX BT_HIDDEN const char *_bt_log_tag_prefix
-#define BT_LOG_DEFINE_GLOBAL_FORMAT BT_HIDDEN bt_log_format _bt_log_global_format
-#define BT_LOG_DEFINE_GLOBAL_OUTPUT BT_HIDDEN bt_log_output _bt_log_global_output
-#define BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL BT_HIDDEN int _bt_log_global_output_lvl
-
-/* Pointer to global format options. Direct modification is not allowed. Use
- * bt_log_set_mem_width() instead. Could be used to initialize bt_log_spec
- * structure:
- *
- *   const bt_log_output g_output = {BT_LOG_PUT_STD, output_callback, 0};
- *   const bt_log_spec g_spec = {BT_LOG_GLOBAL_FORMAT, &g_output};
- *   BT_LOGI_AUX(&g_spec, "Hello");
- */
-#define BT_LOG_GLOBAL_FORMAT ((const bt_log_format *)&_bt_log_global_format)
-
-/* Pointer to global output variable. Direct modification is not allowed. Use
- * bt_log_set_output_v() or bt_log_set_output_p() instead. Could be used to
- * initialize bt_log_spec structure:
- *
- *   const bt_log_format g_format = {40};
- *   const bt_log_spec g_spec = {g_format, BT_LOG_GLOBAL_OUTPUT};
- *   BT_LOGI_AUX(&g_spec, "Hello");
- */
-#define BT_LOG_GLOBAL_OUTPUT ((const bt_log_output *)&_bt_log_global_output)
-
-/* When defined, all library symbols produced by linker will be prefixed with
- * provided value. That allows to use bt_log library privately in another
- * libraries without exposing bt_log symbols in their original form (to avoid
- * possible conflicts with other libraries / components that also could use
- * bt_log for logging). Value must be without quotes, for example:
- *
- *   CC_ARGS := -DBT_LOG_LIBRARY_PREFIX=my_lib_
- *
- * Note, that in this mode BT_LOG_LIBRARY_PREFIX must be defined when building
- * bt_log library AND it also must be defined to the same value when building
- * a library that uses it. For example, consider fictional KittyHttp library
- * that wants to use bt_log for logging. First approach that could be taken is
- * to add bt_log.h and bt_log.c to the KittyHttp's source code tree directly.
- * In that case it will be enough just to define BT_LOG_LIBRARY_PREFIX in
- * KittyHttp's build script:
- *
- *   // KittyHttp/CMakeLists.txt
- *   target_compile_definitions(KittyHttp PRIVATE
- *                              "BT_LOG_LIBRARY_PREFIX=KittyHttp_")
- *
- * If KittyHttp doesn't want to include bt_log source code in its source tree
- * and wants to build bt_log as a separate library than bt_log library must be
- * built with BT_LOG_LIBRARY_PREFIX defined to KittyHttp_ AND KittyHttp library
- * itself also needs to define BT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do
- * so either in its build script, as in example above, or by providing a
- * wrapper header that KittyHttp library will need to use instead of bt_log.h:
- *
- *   // KittyHttpLogging.h
- *   #define BT_LOG_LIBRARY_PREFIX KittyHttp_
- *   #include <babeltrace2/logging-internal.h>
- *
- * Regardless of the method chosen, the end result is that bt_log symbols will
- * be prefixed with "KittyHttp_", so if a user of KittyHttp (say DogeBrowser)
- * also uses bt_log for logging, they will not interferer with each other. Both
- * will have their own log level, output facility, format options etc.
- */
-#ifdef BT_LOG_LIBRARY_PREFIX
-       #define _BT_LOG_DECOR__(prefix, name) prefix ## name
-       #define _BT_LOG_DECOR_(prefix, name) _BT_LOG_DECOR__(prefix, name)
-       #define _BT_LOG_DECOR(name) _BT_LOG_DECOR_(BT_LOG_LIBRARY_PREFIX, name)
-
-       #define bt_log_set_tag_prefix _BT_LOG_DECOR(bt_log_set_tag_prefix)
-       #define bt_log_set_mem_width _BT_LOG_DECOR(bt_log_set_mem_width)
-       #define bt_log_set_output_level _BT_LOG_DECOR(bt_log_set_output_level)
-       #define bt_log_set_output_v _BT_LOG_DECOR(bt_log_set_output_v)
-       #define bt_log_set_output_p _BT_LOG_DECOR(bt_log_set_output_p)
-       #define bt_log_out_stderr_callback _BT_LOG_DECOR(bt_log_out_stderr_callback)
-       #define _bt_log_tag_prefix _BT_LOG_DECOR(_bt_log_tag_prefix)
-       #define _bt_log_global_format _BT_LOG_DECOR(_bt_log_global_format)
-       #define _bt_log_global_output _BT_LOG_DECOR(_bt_log_global_output)
-       #define _bt_log_global_output_lvl _BT_LOG_DECOR(_bt_log_global_output_lvl)
-       #define _bt_log_write_d _BT_LOG_DECOR(_bt_log_write_d)
-       #define _bt_log_write_aux_d _BT_LOG_DECOR(_bt_log_write_aux_d)
-       #define _bt_log_write _BT_LOG_DECOR(_bt_log_write)
-       #define _bt_log_write_aux _BT_LOG_DECOR(_bt_log_write_aux)
-       #define _bt_log_write_mem_d _BT_LOG_DECOR(_bt_log_write_mem_d)
-       #define _bt_log_write_mem_aux_d _BT_LOG_DECOR(_bt_log_write_mem_aux_d)
-       #define _bt_log_write_mem _BT_LOG_DECOR(_bt_log_write_mem)
-       #define _bt_log_write_mem_aux _BT_LOG_DECOR(_bt_log_write_mem_aux)
-       #define _bt_log_stderr_spec _BT_LOG_DECOR(_bt_log_stderr_spec)
-#endif
-
-#if defined(__printflike)
-       #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
-               __printflike(str_index, first_to_check)
-#elif defined(__MINGW_PRINTF_FORMAT)
-       #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
-               __attribute__((format(__MINGW_PRINTF_FORMAT, str_index, first_to_check)))
-#elif defined(__GNUC__)
-       #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
-               __attribute__((format(__printf__, str_index, first_to_check)))
-#else
-       #define _BT_LOG_PRINTFLIKE(str_index, first_to_check)
-#endif
-
-#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)
-       #define _BT_LOG_FUNCTION __FUNCTION__
-#else
-       #define _BT_LOG_FUNCTION __func__
-#endif
-
-#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
-       #define _BT_LOG_INLINE __inline
-       #define _BT_LOG_IF(cond) \
-               __pragma(warning(push)) \
-               __pragma(warning(disable:4127)) \
-               if(cond) \
-               __pragma(warning(pop))
-       #define _BT_LOG_WHILE(cond) \
-               __pragma(warning(push)) \
-               __pragma(warning(disable:4127)) \
-               while(cond) \
-               __pragma(warning(pop))
-#else
-       #define _BT_LOG_INLINE inline
-       #define _BT_LOG_IF(cond) if(cond)
-       #define _BT_LOG_WHILE(cond) while(cond)
-#endif
-#define _BT_LOG_NEVER _BT_LOG_IF(0)
-#define _BT_LOG_ONCE _BT_LOG_WHILE(0)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Set tag prefix. Prefix will be separated from the tag with dot ('.').
- * Use 0 or empty string to disable (default). Common use is to set it to
- * the process (or build target) name (e.g. to separate client and server
- * processes). Function will NOT copy provided prefix string, but will store the
- * pointer. Hence specified prefix string must remain valid. See
- * BT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() function.
- * See BT_LOG_TAG for more information about tag and tag prefix.
- */
-void bt_log_set_tag_prefix(const char *const prefix);
-
-/* Set number of bytes per log line in memory (ASCII-HEX) output. Example:
- *
- *   I hello.MAIN 4c6f72656d20697073756d20646f6c6f  Lorem ipsum dolo
- *                |<-          w bytes         ->|  |<-  w chars ->|
- *
- * See BT_LOGF_MEM and BT_LOGF_MEM_AUX for more details.
- */
-void bt_log_set_mem_width(const unsigned w);
-
-/* Set "output" log level. See BT_LOG_LEVEL and BT_LOG_OUTPUT_LEVEL for more
- * info about log levels.
- */
-void bt_log_set_output_level(const int lvl);
-
-/* Put mask is a set of flags that define what fields will be added to each
- * log message. Default value is BT_LOG_PUT_STD and other flags could be used to
- * alter its behavior. See bt_log_set_output_v() for more details.
- *
- * Note about BT_LOG_PUT_SRC: it will be added only in debug builds (NDEBUG is
- * not defined).
- */
-enum
-{
-       BT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */
-       BT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */
-       BT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */
-       BT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */
-       BT_LOG_PUT_STD = 0xffff, /* everything (default) */
-};
-
-typedef struct bt_log_message
-{
-       int lvl; /* Log level of the message */
-       const char *tag; /* Associated tag (without tag prefix) */
-       char *buf; /* Buffer start */
-       char *e; /* Buffer end (last position where EOL with 0 could be written) */
-       char *p; /* Buffer content end (append position) */
-       char *tag_b; /* Prefixed tag start */
-       char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */
-       char *msg_b; /* Message start (expanded format string) */
-}
-bt_log_message;
-
-/* Type of output callback function. It will be called for each log line allowed
- * by both "current" and "output" log levels ("enabled" and "turned on").
- * Callback function is allowed to modify content of the buffers pointed by the
- * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg
- * is UTF-8 encoded (no BOM mark).
- */
-typedef void (*bt_log_output_cb)(const bt_log_message *msg, void *arg);
-
-/* Format options. For more details see bt_log_set_mem_width().
- */
-typedef struct bt_log_format
-{
-       unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */
-}
-bt_log_format;
-
-/* Output facility.
- */
-typedef struct bt_log_output
-{
-       unsigned mask; /* What to put into log line buffer (see BT_LOG_PUT_XXX) */
-       void *arg; /* User provided output callback argument */
-       bt_log_output_cb callback; /* Output callback function */
-}
-bt_log_output;
-
-/* Set output callback function.
- *
- * Mask allows to control what information will be added to the log line buffer
- * before callback function is invoked. Default mask value is BT_LOG_PUT_STD.
- */
-void bt_log_set_output_v(const unsigned mask, void *const arg,
-                                                const bt_log_output_cb callback);
-static _BT_LOG_INLINE void bt_log_set_output_p(const bt_log_output *const output)
-{
-       bt_log_set_output_v(output->mask, output->arg, output->callback);
-}
-
-/* Used with _AUX macros and allows to override global format and output
- * facility. Use BT_LOG_GLOBAL_FORMAT and BT_LOG_GLOBAL_OUTPUT for values from
- * global configuration. Example:
- *
- *   static const bt_log_output module_output = {
- *       BT_LOG_PUT_STD, 0, custom_output_callback
- *   };
- *   static const bt_log_spec module_spec = {
- *       BT_LOG_GLOBAL_FORMAT, &module_output
- *   };
- *   BT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y);
- *
- * See BT_LOGF_AUX and BT_LOGF_MEM_AUX for details.
- */
-typedef struct bt_log_spec
-{
-       const bt_log_format *format;
-       const bt_log_output *output;
-}
-bt_log_spec;
-
-#ifdef __cplusplus
-}
-#endif
-
-/* Execute log statement if condition is true. Example:
- *
- *   BT_LOG_IF(1 < 2, BT_LOGI("Log this"));
- *   BT_LOG_IF(1 > 2, BT_LOGI("Don't log this"));
- *
- * Keep in mind though, that if condition can't be evaluated at compile time,
- * then it will be evaluated at run time. This will increase exectuable size
- * and can have noticeable performance overhead. Try to limit conditions to
- * expressions that can be evaluated at compile time.
- */
-#define BT_LOG_IF(cond, f) do { _BT_LOG_IF((cond)) { f; } } _BT_LOG_ONCE
-
-/* Mark log statement as "secret". Log statements that are marked as secrets
- * will NOT be executed when censoring is enabled (see BT_LOG_CENSORED).
- * Example:
- *
- *   BT_LOG_SECRET(BT_LOGI("Credit card: %s", credit_card));
- *   BT_LOG_SECRET(BT_LOGD_MEM(cipher, cipher_sz, "Cipher bytes:"));
- */
-#define BT_LOG_SECRET(f) BT_LOG_IF(BT_LOG_SECRETS, f)
-
-/* Check "current" log level at compile time (ignoring "output" log level).
- * Evaluates to true when specified log level is enabled. For example:
- *
- *   #if BT_LOG_ENABLED_DEBUG
- *       const char *const g_enum_strings[] = {
- *           "enum_value_0", "enum_value_1", "enum_value_2"
- *       };
- *   #endif
- *   // ...
- *   #if BT_LOG_ENABLED_DEBUG
- *       BT_LOGD("enum value: %s", g_enum_strings[v]);
- *   #endif
- *
- * See BT_LOG_LEVEL for details.
- */
-#define BT_LOG_ENABLED(lvl)     ((lvl) >= _BT_LOG_LEVEL)
-#define BT_LOG_ENABLED_VERBOSE  BT_LOG_ENABLED(BT_LOG_VERBOSE)
-#define BT_LOG_ENABLED_DEBUG    BT_LOG_ENABLED(BT_LOG_DEBUG)
-#define BT_LOG_ENABLED_INFO     BT_LOG_ENABLED(BT_LOG_INFO)
-#define BT_LOG_ENABLED_WARN     BT_LOG_ENABLED(BT_LOG_WARN)
-#define BT_LOG_ENABLED_ERROR    BT_LOG_ENABLED(BT_LOG_ERROR)
-#define BT_LOG_ENABLED_FATAL    BT_LOG_ENABLED(BT_LOG_FATAL)
-
-/* Check "output" log level at run time (taking into account "current" log
- * level as well). Evaluates to true when specified log level is turned on AND
- * enabled. For example:
- *
- *   if (BT_LOG_ON_DEBUG)
- *   {
- *       char hash[65];
- *       sha256(data_ptr, data_sz, hash);
- *       BT_LOGD("data: len=%u, sha256=%s", data_sz, hash);
- *   }
- *
- * See BT_LOG_OUTPUT_LEVEL for details.
- */
-#define BT_LOG_ON(lvl) \
-               (BT_LOG_ENABLED((lvl)) && (lvl) >= _BT_LOG_OUTPUT_LEVEL)
-#define BT_LOG_ON_VERBOSE   BT_LOG_ON(BT_LOG_VERBOSE)
-#define BT_LOG_ON_DEBUG     BT_LOG_ON(BT_LOG_DEBUG)
-#define BT_LOG_ON_INFO      BT_LOG_ON(BT_LOG_INFO)
-#define BT_LOG_ON_WARN      BT_LOG_ON(BT_LOG_WARN)
-#define BT_LOG_ON_ERROR     BT_LOG_ON(BT_LOG_ERROR)
-#define BT_LOG_ON_FATAL     BT_LOG_ON(BT_LOG_FATAL)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern const char *_bt_log_tag_prefix;
-extern bt_log_format _bt_log_global_format;
-extern bt_log_output _bt_log_global_output;
-extern int _bt_log_global_output_lvl;
-extern const bt_log_spec _bt_log_stderr_spec;
-
-BT_HIDDEN
-void _bt_log_write_d(
-               const char *const func, const char *const file, const unsigned line,
-               const int lvl, const char *const tag,
-               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(6, 7);
-
-BT_HIDDEN
-void _bt_log_write_aux_d(
-               const char *const func, const char *const file, const unsigned line,
-               const bt_log_spec *const log, const int lvl, const char *const tag,
-               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(7, 8);
-
-BT_HIDDEN
-void _bt_log_write(
-               const int lvl, const char *const tag,
-               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(3, 4);
-
-BT_HIDDEN
-void _bt_log_write_aux(
-               const bt_log_spec *const log, const int lvl, const char *const tag,
-               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(4, 5);
-
-BT_HIDDEN
-void _bt_log_write_mem_d(
-               const char *const func, const char *const file, const unsigned line,
-               const int lvl, const char *const tag,
-               const void *const d, const unsigned d_sz,
-               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(8, 9);
-
-BT_HIDDEN
-void _bt_log_write_mem_aux_d(
-               const char *const func, const char *const file, const unsigned line,
-               const bt_log_spec *const log, const int lvl, const char *const tag,
-               const void *const d, const unsigned d_sz,
-               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(9, 10);
-
-BT_HIDDEN
-void _bt_log_write_mem(
-               const int lvl, const char *const tag,
-               const void *const d, const unsigned d_sz,
-               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(5, 6);
-
-BT_HIDDEN
-void _bt_log_write_mem_aux(
-               const bt_log_spec *const log, const int lvl, const char *const tag,
-               const void *const d, const unsigned d_sz,
-               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(6, 7);
-
-#ifdef __cplusplus
-}
-#endif
-
-/* Message logging macros:
- * - BT_LOGV("format string", args, ...)
- * - BT_LOGD("format string", args, ...)
- * - BT_LOGI("format string", args, ...)
- * - BT_LOGW("format string", args, ...)
- * - BT_LOGE("format string", args, ...)
- * - BT_LOGF("format string", args, ...)
- *
- * Message and error string (errno) logging macros:
- * - BT_LOGV_ERRNO("initial message", "format string", args, ...)
- * - BT_LOGD_ERRNO("initial message", "format string", args, ...)
- * - BT_LOGI_ERRNO("initial message", "format string", args, ...)
- * - BT_LOGW_ERRNO("initial message", "format string", args, ...)
- * - BT_LOGE_ERRNO("initial message", "format string", args, ...)
- * - BT_LOGF_ERRNO("initial message", "format string", args, ...)
- *
- * Memory logging macros:
- * - BT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...)
- *
- * Auxiliary logging macros:
- * - BT_LOGV_AUX(&log_instance, "format string", args, ...)
- * - BT_LOGD_AUX(&log_instance, "format string", args, ...)
- * - BT_LOGI_AUX(&log_instance, "format string", args, ...)
- * - BT_LOGW_AUX(&log_instance, "format string", args, ...)
- * - BT_LOGE_AUX(&log_instance, "format string", args, ...)
- * - BT_LOGF_AUX(&log_instance, "format string", args, ...)
- *
- * Auxiliary memory logging macros:
- * - BT_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
- * - BT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
- *
- * Preformatted string logging macros:
- * - BT_LOGV_STR("preformatted string");
- * - BT_LOGD_STR("preformatted string");
- * - BT_LOGI_STR("preformatted string");
- * - BT_LOGW_STR("preformatted string");
- * - BT_LOGE_STR("preformatted string");
- * - BT_LOGF_STR("preformatted string");
- *
- * Explicit log level and tag macros:
- * - BT_LOG_WRITE(level, tag, "format string", args, ...)
- * - BT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string", args, ...)
- * - BT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args, ...)
- * - BT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz,
- *                        "format string", args, ...)
- *
- * Format string follows printf() conventions. Both data_ptr and data_sz could
- * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments
- * match format specifiers in format string.
- *
- * Library assuming UTF-8 encoding for all strings (char *), including format
- * string itself.
- */
-#if BT_LOG_SRCLOC_NONE == _BT_LOG_SRCLOC
-       #define BT_LOG_WRITE(lvl, tag, ...) \
-                       do { \
-                               if (BT_LOG_ON(lvl)) \
-                                       _bt_log_write(lvl, tag, __VA_ARGS__); \
-                       } _BT_LOG_ONCE
-       #define BT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
-                       do { \
-                               if (BT_LOG_ON(lvl)) \
-                                       _bt_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \
-                       } _BT_LOG_ONCE
-       #define BT_LOG_WRITE_AUX(log, lvl, tag, ...) \
-                       do { \
-                               if (BT_LOG_ON(lvl)) \
-                                       _bt_log_write_aux(log, lvl, tag, __VA_ARGS__); \
-                       } _BT_LOG_ONCE
-       #define BT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
-                       do { \
-                               if (BT_LOG_ON(lvl)) \
-                                       _bt_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \
-                       } _BT_LOG_ONCE
-#else
-       #define BT_LOG_WRITE(lvl, tag, ...) \
-                       do { \
-                               if (BT_LOG_ON(lvl)) \
-                                       _bt_log_write_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
-                                                       lvl, tag, __VA_ARGS__); \
-                       } _BT_LOG_ONCE
-       #define BT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
-                       do { \
-                               if (BT_LOG_ON(lvl)) \
-                                       _bt_log_write_mem_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
-                                                       lvl, tag, d, d_sz, __VA_ARGS__); \
-                       } _BT_LOG_ONCE
-       #define BT_LOG_WRITE_AUX(log, lvl, tag, ...) \
-                       do { \
-                               if (BT_LOG_ON(lvl)) \
-                                       _bt_log_write_aux_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
-                                                       log, lvl, tag, __VA_ARGS__); \
-                       } _BT_LOG_ONCE
-       #define BT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
-                       do { \
-                               if (BT_LOG_ON(lvl)) \
-                                       _bt_log_write_mem_aux_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
-                                                       log, lvl, tag, d, d_sz, __VA_ARGS__); \
-                       } _BT_LOG_ONCE
-#endif
-
-#define BT_LOG_WRITE_ERRNO(lvl, tag, _msg, _fmt, args...) \
-               do { \
-                       const char *error_str; \
-                       error_str = g_strerror(errno); \
-                       BT_LOG_WRITE(lvl, tag, _msg ": %s" _fmt, error_str, ## args); \
-               } _BT_LOG_ONCE
-
-static _BT_LOG_INLINE void _bt_log_unused(const int dummy, ...) {(void)dummy;}
-
-#define _BT_LOG_UNUSED(...) \
-               do { _BT_LOG_NEVER _bt_log_unused(0, __VA_ARGS__); } _BT_LOG_ONCE
-
-#if BT_LOG_ENABLED_VERBOSE
-       #define BT_LOGV(...) \
-                       BT_LOG_WRITE(BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGV_ERRNO(...) \
-                       BT_LOG_WRITE_ERRNO(BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGV_AUX(log, ...) \
-                       BT_LOG_WRITE_AUX(log, BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGV_MEM(d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM(BT_LOG_VERBOSE, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-       #define BT_LOGV_MEM_AUX(log, d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM(log, BT_LOG_VERBOSE, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-#else
-       #define BT_LOGV(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGV_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGV_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGV_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-#endif
-
-#if BT_LOG_ENABLED_DEBUG
-       #define BT_LOGD(...) \
-                       BT_LOG_WRITE(BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGD_ERRNO(...) \
-                       BT_LOG_WRITE_ERRNO(BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGD_AUX(log, ...) \
-                       BT_LOG_WRITE_AUX(log, BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGD_MEM(d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM(BT_LOG_DEBUG, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-       #define BT_LOGD_MEM_AUX(log, d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_DEBUG, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-#else
-       #define BT_LOGD(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGD_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGD_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGD_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-#endif
-
-#if BT_LOG_ENABLED_INFO
-       #define BT_LOGI(...) \
-                       BT_LOG_WRITE(BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGI_ERRNO(...) \
-                       BT_LOG_WRITE_ERRNO(BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGI_AUX(log, ...) \
-                       BT_LOG_WRITE_AUX(log, BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGI_MEM(d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM(BT_LOG_INFO, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-       #define BT_LOGI_MEM_AUX(log, d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_INFO, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-#else
-       #define BT_LOGI(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGI_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGI_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGI_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-#endif
-
-#if BT_LOG_ENABLED_WARN
-       #define BT_LOGW(...) \
-                       BT_LOG_WRITE(BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGW_ERRNO(...) \
-                       BT_LOG_WRITE_ERRNO(BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGW_AUX(log, ...) \
-                       BT_LOG_WRITE_AUX(log, BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGW_MEM(d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM(BT_LOG_WARN, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-       #define BT_LOGW_MEM_AUX(log, d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_WARN, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-#else
-       #define BT_LOGW(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGW_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGW_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGW_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-#endif
-
-#if BT_LOG_ENABLED_ERROR
-       #define BT_LOGE(...) \
-                       BT_LOG_WRITE(BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGE_ERRNO(...) \
-                       BT_LOG_WRITE_ERRNO(BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGE_AUX(log, ...) \
-                       BT_LOG_WRITE_AUX(log, BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGE_MEM(d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM(BT_LOG_ERROR, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-       #define BT_LOGE_MEM_AUX(log, d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_ERROR, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-#else
-       #define BT_LOGE(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGE_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGE_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGE_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-#endif
-
-#if BT_LOG_ENABLED_FATAL
-       #define BT_LOGF(...) \
-                       BT_LOG_WRITE(BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGF_ERRNO(...) \
-                       BT_LOG_WRITE_ERRNO(BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGF_AUX(log, ...) \
-                       BT_LOG_WRITE_AUX(log, BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
-       #define BT_LOGF_MEM(d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM(BT_LOG_FATAL, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-       #define BT_LOGF_MEM_AUX(log, d, d_sz, ...) \
-                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_FATAL, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
-#else
-       #define BT_LOGF(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGF_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGF_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
-       #define BT_LOGF_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
-#endif
-
-#define BT_LOGV_STR(s) BT_LOGV("%s", (s))
-#define BT_LOGD_STR(s) BT_LOGD("%s", (s))
-#define BT_LOGI_STR(s) BT_LOGI("%s", (s))
-#define BT_LOGW_STR(s) BT_LOGW("%s", (s))
-#define BT_LOGE_STR(s) BT_LOGE("%s", (s))
-#define BT_LOGF_STR(s) BT_LOGF("%s", (s))
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Output to standard error stream. Library uses it by default, though in few
- * cases it could be necessary to specify it explicitly. For example, when
- * bt_log library is compiled with BT_LOG_EXTERN_GLOBAL_OUTPUT, application must
- * define and initialize global output variable:
- *
- *   BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_OUT_STDERR};
- *
- * Another example is when using custom output, stderr could be used as a
- * fallback when custom output facility failed to initialize:
- *
- *   bt_log_set_output_v(BT_LOG_OUT_STDERR);
- */
-enum { BT_LOG_OUT_STDERR_MASK = BT_LOG_PUT_STD };
-
-BT_HIDDEN
-void bt_log_out_stderr_callback(const bt_log_message *const msg, void *arg);
-#define BT_LOG_OUT_STDERR BT_LOG_OUT_STDERR_MASK, 0, bt_log_out_stderr_callback
-
-/* Predefined spec for stderr. Uses global format options (BT_LOG_GLOBAL_FORMAT)
- * and BT_LOG_OUT_STDERR. Could be used to force output to stderr for a
- * particular message. Example:
- *
- *   f = fopen("foo.log", "w");
- *   if (!f)
- *       BT_LOGE_AUX(BT_LOG_STDERR, "Failed to open log file");
- */
-#define BT_LOG_STDERR (&_bt_log_stderr_spec)
-
-static inline
-int bt_log_get_level_from_env(const char *var)
-{
-       const char *varval = getenv(var);
-       int level = BT_LOG_NONE;
-
-       if (!varval) {
-               goto end;
-       }
-
-       if (strcmp(varval, "VERBOSE") == 0 ||
-                       strcmp(varval, "V") == 0) {
-               level = BT_LOG_VERBOSE;
-       } else if (strcmp(varval, "DEBUG") == 0 ||
-                       strcmp(varval, "D") == 0) {
-               level = BT_LOG_DEBUG;
-       } else if (strcmp(varval, "INFO") == 0 ||
-                       strcmp(varval, "I") == 0) {
-               level = BT_LOG_INFO;
-       } else if (strcmp(varval, "WARN") == 0 ||
-                       strcmp(varval, "WARNING") == 0 ||
-                       strcmp(varval, "W") == 0) {
-               level = BT_LOG_WARN;
-       } else if (strcmp(varval, "ERROR") == 0 ||
-                       strcmp(varval, "E") == 0) {
-               level = BT_LOG_ERROR;
-       } else if (strcmp(varval, "FATAL") == 0 ||
-                       strcmp(varval, "F") == 0) {
-               level = BT_LOG_FATAL;
-       } else if (strcmp(varval, "NONE") == 0 ||
-                       strcmp(varval, "N") == 0) {
-               level = BT_LOG_NONE;
-       } else {
-               /* Should we warn here? How? */
-       }
-
-end:
-       return level;
-}
-
-#define BT_LOG_LEVEL_EXTERN_SYMBOL(_level_sym)                         \
-       extern int _level_sym
-
-#define BT_LOG_INIT_LOG_LEVEL(_level_sym, _env_var)                    \
-       BT_HIDDEN int _level_sym = BT_LOG_NONE;                         \
-       static                                                          \
-       void __attribute__((constructor)) _bt_log_level_ctor(void)      \
-       {                                                               \
-               _level_sym = bt_log_get_level_from_env(_env_var);       \
-       }
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BABELTRACE_LOGGING_INTERNAL_H */
diff --git a/include/babeltrace2/mmap-align-internal.h b/include/babeltrace2/mmap-align-internal.h
deleted file mode 100644 (file)
index 1f99ca6..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef _BABELTRACE_MMAP_ALIGN_H
-#define _BABELTRACE_MMAP_ALIGN_H
-
-/*
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/align-internal.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <babeltrace2/compat/mman-internal.h>
-#include <babeltrace2/common-internal.h>
-
-/*
- * This header implements a wrapper over mmap (mmap_align) that memory
- * maps a file region that is not necessarily multiple of the page size.
- * It returns a structure (instead of a pointer) that contains the mmap
- * pointer (page-aligned) and a pointer to the offset requested within
- * that page. Note: in the current implementation, the "addr" parameter
- * cannot be forced, so we allocate at an address chosen by the OS.
- */
-
-struct mmap_align {
-       void *page_aligned_addr;        /* mmap address, aligned to floor */
-       size_t page_aligned_length;     /* mmap length, containing range */
-
-       void *addr;                     /* virtual mmap address */
-       size_t length;                  /* virtual mmap length */
-};
-
-#ifdef __WIN32__
-#include <windows.h>
-
-/*
- * On windows the memory mapping offset must be aligned to the memory
- * allocator allocation granularity and not the page size.
- */
-static inline
-off_t get_page_aligned_offset(off_t offset, size_t page_size)
-{
-       SYSTEM_INFO sysinfo;
-
-       GetNativeSystemInfo(&sysinfo);
-
-       return ALIGN_FLOOR(offset, sysinfo.dwAllocationGranularity);
-}
-#else
-static inline
-off_t get_page_aligned_offset(off_t offset, size_t page_size)
-{
-       return ALIGN_FLOOR(offset, page_size);
-}
-#endif
-
-static inline
-struct mmap_align *mmap_align(size_t length, int prot,
-               int flags, int fd, off_t offset)
-{
-       struct mmap_align *mma;
-       off_t page_aligned_offset;      /* mmap offset, aligned to floor */
-       size_t page_size;
-
-       page_size = bt_common_get_page_size();
-
-       mma = malloc(sizeof(*mma));
-       if (!mma)
-               return MAP_FAILED;
-       mma->length = length;
-       page_aligned_offset = get_page_aligned_offset(offset, page_size);
-       /*
-        * Page aligned length needs to contain the requested range.
-        * E.g., for a small range that fits within a single page, we might
-        * require a 2 pages page_aligned_length if the range crosses a page
-        * boundary.
-        */
-       mma->page_aligned_length = ALIGN(length + offset - page_aligned_offset, page_size);
-       mma->page_aligned_addr = bt_mmap(NULL, mma->page_aligned_length,
-               prot, flags, fd, page_aligned_offset);
-       if (mma->page_aligned_addr == MAP_FAILED) {
-               free(mma);
-               return MAP_FAILED;
-       }
-       mma->addr = ((uint8_t *) mma->page_aligned_addr) + (offset - page_aligned_offset);
-       return mma;
-}
-
-static inline
-int munmap_align(struct mmap_align *mma)
-{
-       void *page_aligned_addr;
-       size_t page_aligned_length;
-
-       page_aligned_addr = mma->page_aligned_addr;
-       page_aligned_length = mma->page_aligned_length;
-       free(mma);
-       return bt_munmap(page_aligned_addr, page_aligned_length);
-}
-
-static inline
-void *mmap_align_addr(struct mmap_align *mma)
-{
-       return mma->addr;
-}
-
-/*
- * Helper for special-cases, normally unused.
- */
-static inline
-void mmap_align_set_addr(struct mmap_align *mma, void *addr)
-{
-       mma->addr = addr;
-}
-
-#endif /* _BABELTRACE_MMAP_ALIGN_H */
diff --git a/include/babeltrace2/object-internal.h b/include/babeltrace2/object-internal.h
deleted file mode 100644 (file)
index 9573fb2..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-#ifndef BABELTRACE_OBJECT_INTERNAL_H
-#define BABELTRACE_OBJECT_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdbool.h>
-
-struct bt_object;
-
-typedef void (*bt_object_release_func)(struct bt_object *);
-typedef void (*bt_object_parent_is_owner_listener_func)(
-               struct bt_object *);
-
-static inline
-void bt_object_get_no_null_check(const void *obj);
-
-static inline
-void bt_object_put_no_null_check(const void *obj);
-
-/*
- * Babeltrace object base.
- *
- * All objects publicly exposed by Babeltrace APIs must contain this
- * object as their first member.
- */
-struct bt_object {
-       /*
-        * True if this object is shared, that is, it has a reference
-        * count.
-        */
-       bool is_shared;
-
-       /*
-        * Current reference count.
-        */
-       unsigned long long ref_count;
-
-       /*
-        * Release function called when the object's reference count
-        * falls to zero. For an object with a parent, this function is
-        * bt_object_with_parent_release_func(), which calls
-        * `spec_release_func` below if there's no current parent.
-        */
-       bt_object_release_func release_func;
-
-       /*
-        * Specific release function called by
-        * bt_object_with_parent_release_func() or directly by a
-        * parent object.
-        */
-       bt_object_release_func spec_release_func;
-
-       /*
-        * Optional callback for an object with a parent, called by
-        * bt_object_with_parent_release_func() to indicate to the
-        * object that its parent is its owner.
-        */
-       bt_object_parent_is_owner_listener_func
-               parent_is_owner_listener_func;
-
-       /*
-        * Optional parent object.
-        */
-       struct bt_object *parent;
-};
-
-static inline
-unsigned long long bt_object_get_ref_count(const struct bt_object *c_obj)
-{
-       struct bt_object *obj = (void *) c_obj;
-
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       return obj->ref_count;
-}
-
-static inline
-struct bt_object *bt_object_borrow_parent(const struct bt_object *c_obj)
-{
-       struct bt_object *obj = (void *) c_obj;
-
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       return obj->parent;
-}
-
-static inline
-struct bt_object *bt_object_get_parent(const struct bt_object *c_obj)
-{
-       struct bt_object *obj = (void *) c_obj;
-       struct bt_object *parent = bt_object_borrow_parent(obj);
-
-       if (parent) {
-               bt_object_get_no_null_check(parent);
-       }
-
-       return parent;
-}
-
-static inline
-void bt_object_set_parent(struct bt_object *child, struct bt_object *parent)
-{
-       BT_ASSERT(child);
-       BT_ASSERT(child->is_shared);
-
-#ifdef BT_LOGV
-       BT_LOGV("Setting object's parent: addr=%p, parent-addr=%p",
-               child, parent);
-#endif
-
-       /*
-        * It is assumed that a "child" having a parent is publicly
-        * reachable. Therefore, a reference to its parent must be
-        * taken. The reference to the parent will be released once the
-        * object's reference count falls to zero.
-        */
-       if (parent) {
-               BT_ASSERT(!child->parent);
-               child->parent = parent;
-               bt_object_get_no_null_check(parent);
-       } else {
-               if (child->parent) {
-                       bt_object_put_no_null_check(child->parent);
-               }
-
-               child->parent = NULL;
-       }
-}
-
-static inline
-void bt_object_try_spec_release(struct bt_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       BT_ASSERT(obj->spec_release_func);
-
-       if (bt_object_get_ref_count(obj) == 0) {
-               obj->spec_release_func(obj);
-       }
-}
-
-static inline
-void bt_object_with_parent_release_func(struct bt_object *obj)
-{
-       if (obj->parent) {
-               /*
-                * Keep our own copy of the parent address because `obj`
-                * could be destroyed in
-                * obj->parent_is_owner_listener_func().
-                */
-               struct bt_object *parent = obj->parent;
-
-#ifdef BT_LOGV
-               BT_LOGV("Releasing parented object: addr=%p, ref-count=%llu, "
-                       "parent-addr=%p, parent-ref-count=%llu",
-                       obj, obj->ref_count,
-                       parent, parent->ref_count);
-#endif
-
-               if (obj->parent_is_owner_listener_func) {
-                       /*
-                        * Object has a chance to destroy itself here
-                        * under certain conditions and notify its
-                        * parent. At this point the parent is
-                        * guaranteed to exist because it's not put yet.
-                        */
-                       obj->parent_is_owner_listener_func(obj);
-               }
-
-               /* The release function will be invoked by the parent. */
-               bt_object_put_no_null_check(parent);
-       } else {
-               bt_object_try_spec_release(obj);
-       }
-}
-
-static inline
-void bt_object_init(struct bt_object *obj, bool is_shared,
-               bt_object_release_func release_func)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(!is_shared || release_func);
-       obj->is_shared = is_shared;
-       obj->release_func = release_func;
-       obj->parent_is_owner_listener_func = NULL;
-       obj->spec_release_func = NULL;
-       obj->parent = NULL;
-       obj->ref_count = 1;
-}
-
-static inline
-void bt_object_init_shared(struct bt_object *obj,
-               bt_object_release_func release_func)
-{
-       bt_object_init(obj, true, release_func);
-}
-
-static inline
-void bt_object_init_unique(struct bt_object *obj)
-{
-       bt_object_init(obj, false, NULL);
-}
-
-static inline
-void bt_object_init_shared_with_parent(struct bt_object *obj,
-               bt_object_release_func spec_release_func)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(spec_release_func);
-       bt_object_init_shared(obj, bt_object_with_parent_release_func);
-       obj->spec_release_func = spec_release_func;
-}
-
-static inline
-void bt_object_set_parent_is_owner_listener_func(struct bt_object *obj,
-               bt_object_parent_is_owner_listener_func func)
-{
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       BT_ASSERT(obj->spec_release_func);
-       ((struct bt_object *) obj)->parent_is_owner_listener_func = func;
-}
-
-static inline
-void bt_object_inc_ref_count(const struct bt_object *c_obj)
-{
-       struct bt_object *obj = (void *) c_obj;
-
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       obj->ref_count++;
-       BT_ASSERT(obj->ref_count != 0);
-}
-
-static inline
-void bt_object_get_no_null_check_no_parent_check(const struct bt_object *c_obj)
-{
-       struct bt_object *obj = (void *) c_obj;
-
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-
-#ifdef BT_LOGV
-       BT_LOGV("Incrementing object's reference count: %llu -> %llu: "
-               "addr=%p, cur-count=%llu, new-count=%llu",
-               obj->ref_count, obj->ref_count + 1,
-               obj, obj->ref_count, obj->ref_count + 1);
-#endif
-
-       bt_object_inc_ref_count(obj);
-}
-
-static inline
-void bt_object_get_no_null_check(const void *c_obj)
-{
-       struct bt_object *obj = (void *) c_obj;
-
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-
-       if (unlikely(obj->parent && bt_object_get_ref_count(obj) == 0)) {
-#ifdef BT_LOGV
-               BT_LOGV("Incrementing object's parent's reference count: "
-                       "addr=%p, parent-addr=%p", obj, obj->parent);
-#endif
-
-               bt_object_get_no_null_check(obj->parent);
-       }
-
-#ifdef BT_LOGV
-       BT_LOGV("Incrementing object's reference count: %llu -> %llu: "
-               "addr=%p, cur-count=%llu, new-count=%llu",
-               obj->ref_count, obj->ref_count + 1,
-               obj, obj->ref_count, obj->ref_count + 1);
-#endif
-
-       bt_object_inc_ref_count(obj);
-}
-
-static inline
-void bt_object_put_no_null_check(const void *c_obj)
-{
-       struct bt_object *obj = (void *) c_obj;
-
-       BT_ASSERT(obj);
-       BT_ASSERT(obj->is_shared);
-       BT_ASSERT(obj->ref_count > 0);
-
-#ifdef BT_LOGV
-       BT_LOGV("Decrementing object's reference count: %llu -> %llu: "
-               "addr=%p, cur-count=%llu, new-count=%llu",
-               obj->ref_count, obj->ref_count - 1,
-               obj, obj->ref_count, obj->ref_count - 1);
-#endif
-
-       obj->ref_count--;
-
-       if (obj->ref_count == 0) {
-               BT_ASSERT(obj->release_func);
-               obj->release_func(obj);
-       }
-}
-
-static inline
-void bt_object_get_ref(const void *ptr)
-{
-       struct bt_object *obj = (void *) ptr;
-
-       if (unlikely(!obj)) {
-               return;
-       }
-
-#ifdef BT_ASSERT_PRE
-       BT_ASSERT_PRE(obj->is_shared, "Object is not shared: %!+O", obj);
-#endif
-
-       bt_object_get_no_null_check(obj);
-}
-
-static inline
-void bt_object_put_ref(const void *ptr)
-{
-       struct bt_object *obj = (void *) ptr;
-
-       if (unlikely(!obj)) {
-               return;
-       }
-
-#ifdef BT_ASSERT_PRE
-       BT_ASSERT_PRE(obj->is_shared, "Object is not shared: %!+O", obj);
-       BT_ASSERT_PRE(bt_object_get_ref_count(obj) > 0,
-               "Decrementing a reference count set to 0: %!+O", ptr);
-#endif
-
-       bt_object_put_no_null_check(obj);
-}
-
-#define BT_OBJECT_PUT_REF_AND_RESET(_var)      \
-       do {                                    \
-               bt_object_put_ref(_var);        \
-               (_var) = NULL;                  \
-       } while (0)
-
-#define BT_OBJECT_MOVE_REF(_var_dst, _var_src) \
-       do {                                    \
-               bt_object_put_ref(_var_dst);    \
-               (_var_dst) = (_var_src);        \
-               (_var_src) = NULL;              \
-       } while (0)
-
-#endif /* BABELTRACE_OBJECT_INTERNAL_H */
diff --git a/include/babeltrace2/object-pool-internal.h b/include/babeltrace2/object-pool-internal.h
deleted file mode 100644 (file)
index 5a99f96..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-#ifndef BABELTRACE_OBJECT_POOL_INTERNAL_H
-#define BABELTRACE_OBJECT_POOL_INTERNAL_H
-
-/*
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * This is a generic object pool to avoid memory allocation/deallocation
- * for objects of which the lifespan is typically short, but which are
- * created a lot.
- *
- * The object pool, thanks to two user functions, knows how to allocate
- * a brand new object in memory when the pool is empty and how to
- * destroy an object when we destroy the pool.
- *
- * The object pool's user is responsible for:
- *
- * * Setting whatever references the object needs to keep and reset some
- *   properties _after_ calling bt_object_pool_create_object(). This is
- *   typically done in the bt_*_create() function which calls
- *   bt_object_pool_create_object() (which could call the user-provided
- *   allocation function if the pool is empty) and then sets the
- *   appropriate properties on the possibly recycled object.
- *
- * * Releasing whatever references the object keeps _before_ calling
- *   bt_object_pool_recycle_object(). This is typically done in a custom
- *   bt_*_recycle() function which does the necessary before calling
- *   bt_object_pool_recycle_object() with an object ready to be reused
- *   at any time.
- */
-
-#include <glib.h>
-#include <babeltrace2/object-internal.h>
-
-typedef void *(*bt_object_pool_new_object_func)(void *data);
-typedef void *(*bt_object_pool_destroy_object_func)(void *obj, void *data);
-
-struct bt_object_pool {
-       /*
-        * Container of recycled objects, owned by this. The array's size
-        * is the pool's capacity.
-        */
-       GPtrArray *objects;
-
-       /*
-        * Pool's size, that is, number of elements in the array above,
-        * starting at index 0, which exist as recycled objects.
-        */
-       size_t size;
-
-       /* User functions */
-       struct {
-               /* Allocate a new object in memory */
-               bt_object_pool_new_object_func new_object;
-
-               /* Free direct and indirect memory occupied by object */
-               bt_object_pool_destroy_object_func destroy_object;
-       } funcs;
-
-       /* User data passed to user functions */
-       void *data;
-};
-
-/*
- * Initializes an object pool which is already allocated.
- */
-int bt_object_pool_initialize(struct bt_object_pool *pool,
-               bt_object_pool_new_object_func new_object_func,
-               bt_object_pool_destroy_object_func destroy_object_func,
-               void *data);
-
-/*
- * Finalizes an object pool without deallocating it.
- */
-void bt_object_pool_finalize(struct bt_object_pool *pool);
-
-/*
- * Creates an object from an object pool. If the pool is empty, this
- * function calls the "new" user function to allocate a new object
- * before returning it. Otherwise this function returns a recycled
- * object, removing it from the pool.
- *
- * The returned object is owned by the caller.
- */
-static inline
-void *bt_object_pool_create_object(struct bt_object_pool *pool)
-{
-       struct bt_object *obj;
-
-       BT_ASSERT(pool);
-
-#ifdef BT_LOGV
-       BT_LOGV("Creating object from pool: pool-addr=%p, pool-size=%zu, pool-cap=%u",
-               pool, pool->size, pool->objects->len);
-#endif
-
-       if (pool->size > 0) {
-               /* Pick one from the pool */
-               pool->size--;
-               obj = pool->objects->pdata[pool->size];
-               pool->objects->pdata[pool->size] = NULL;
-               goto end;
-       }
-
-       /* Pool is empty: create a brand new object */
-#ifdef BT_LOGV
-       BT_LOGV("Pool is empty: allocating new object: pool-addr=%p",
-               pool);
-#endif
-
-       obj = pool->funcs.new_object(pool->data);
-
-end:
-#ifdef BT_LOGV
-       BT_LOGV("Created one object from pool: pool-addr=%p, obj-addr=%p",
-               pool, obj);
-#endif
-
-       return obj;
-}
-
-/*
- * Recycles an object, that is, puts it back into the pool.
- *
- * The pool becomes the sole owner of the object to recycle.
- */
-static inline
-void bt_object_pool_recycle_object(struct bt_object_pool *pool, void *obj)
-{
-       struct bt_object *bt_obj = obj;
-
-       BT_ASSERT(pool);
-       BT_ASSERT(obj);
-
-#ifdef BT_LOGV
-       BT_LOGV("Recycling object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
-               pool, pool->size, pool->objects->len, obj);
-#endif
-
-       if (pool->size == pool->objects->len) {
-               /* Backing array is full: make place for recycled object */
-#ifdef BT_LOGV
-               BT_LOGV("Object pool is full: increasing object pool capacity: "
-                       "pool-addr=%p, old-pool-cap=%u, new-pool-cap=%u",
-                       pool, pool->objects->len, pool->objects->len + 1);
-#endif
-               g_ptr_array_set_size(pool->objects, pool->size + 1);
-       }
-
-       /* Reset reference count to 1 since it could be 0 now */
-       bt_obj->ref_count = 1;
-
-       /* Back to the pool */
-       pool->objects->pdata[pool->size] = obj;
-       pool->size++;
-
-#ifdef BT_LOGV
-       BT_LOGV("Recycled object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
-               pool, pool->size, pool->objects->len, obj);
-#endif
-}
-
-#endif /* BABELTRACE_OBJECT_POOL_INTERNAL_H */
diff --git a/include/babeltrace2/plugin/plugin-internal.h b/include/babeltrace2/plugin/plugin-internal.h
deleted file mode 100644 (file)
index f2a78fe..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_PLUGIN_INTERNAL_H
-#define BABELTRACE_PLUGIN_PLUGIN_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/plugin/plugin-const.h>
-#include <babeltrace2/plugin/plugin-dev.h>
-#include <babeltrace2/plugin/plugin-so-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/lib-logging-internal.h>
-#include <glib.h>
-
-enum bt_plugin_type {
-       BT_PLUGIN_TYPE_SO = 0,
-       BT_PLUGIN_TYPE_PYTHON = 1,
-};
-
-enum bt_plugin_status {
-       BT_PLUGIN_STATUS_OK = 0,
-       BT_PLUGIN_STATUS_ERROR = -1,
-       BT_PLUGIN_STATUS_NOMEM = -12,
-};
-
-struct bt_plugin {
-       struct bt_object base;
-       enum bt_plugin_type type;
-
-       /* Arrays of `struct bt_component_class *` (owned by this) */
-       GPtrArray *src_comp_classes;
-       GPtrArray *flt_comp_classes;
-       GPtrArray *sink_comp_classes;
-
-       /* Info (owned by this) */
-       struct {
-               GString *path;
-               GString *name;
-               GString *author;
-               GString *license;
-               GString *description;
-               struct {
-                       unsigned int major;
-                       unsigned int minor;
-                       unsigned int patch;
-                       GString *extra;
-               } version;
-               bool path_set;
-               bool name_set;
-               bool author_set;
-               bool license_set;
-               bool description_set;
-               bool version_set;
-       } info;
-
-       /* Value depends on the specific plugin type */
-       void *spec_data;
-       void (*destroy_spec_data)(struct bt_plugin *);
-};
-
-struct bt_plugin_set {
-       struct bt_object base;
-
-       /* Array of struct bt_plugin * */
-       GPtrArray *plugins;
-};
-
-static inline
-const char *bt_plugin_status_string(enum bt_plugin_status status)
-{
-       switch (status) {
-       case BT_PLUGIN_STATUS_OK:
-               return "BT_PLUGIN_STATUS_OK";
-       case BT_PLUGIN_STATUS_ERROR:
-               return "BT_PLUGIN_STATUS_ERROR";
-       case BT_PLUGIN_STATUS_NOMEM:
-               return "BT_PLUGIN_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-const char *bt_plugin_type_string(enum bt_plugin_type type)
-{
-       switch (type) {
-       case BT_PLUGIN_TYPE_SO:
-               return "BT_PLUGIN_TYPE_SO";
-       case BT_PLUGIN_TYPE_PYTHON:
-               return "BT_PLUGIN_TYPE_PYTHON";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-void bt_plugin_destroy(struct bt_object *obj)
-{
-       struct bt_plugin *plugin;
-
-       BT_ASSERT(obj);
-       plugin = container_of(obj, struct bt_plugin, base);
-       BT_LIB_LOGD("Destroying plugin object: %!+l", plugin);
-
-       if (plugin->destroy_spec_data) {
-               plugin->destroy_spec_data(plugin);
-       }
-
-       if (plugin->src_comp_classes) {
-               BT_LOGD_STR("Putting source component classes.");
-               g_ptr_array_free(plugin->src_comp_classes, TRUE);
-               plugin->src_comp_classes = NULL;
-       }
-
-       if (plugin->flt_comp_classes) {
-               BT_LOGD_STR("Putting filter component classes.");
-               g_ptr_array_free(plugin->flt_comp_classes, TRUE);
-               plugin->flt_comp_classes = NULL;
-       }
-
-       if (plugin->sink_comp_classes) {
-               BT_LOGD_STR("Putting sink component classes.");
-               g_ptr_array_free(plugin->sink_comp_classes, TRUE);
-               plugin->sink_comp_classes = NULL;
-       }
-
-       if (plugin->info.name) {
-               g_string_free(plugin->info.name, TRUE);
-               plugin->info.name = NULL;
-       }
-
-       if (plugin->info.path) {
-               g_string_free(plugin->info.path, TRUE);
-               plugin->info.path = NULL;
-       }
-
-       if (plugin->info.description) {
-               g_string_free(plugin->info.description, TRUE);
-               plugin->info.description = NULL;
-       }
-
-       if (plugin->info.author) {
-               g_string_free(plugin->info.author, TRUE);
-               plugin->info.author = NULL;
-       }
-
-       if (plugin->info.license) {
-               g_string_free(plugin->info.license, TRUE);
-               plugin->info.license = NULL;
-       }
-
-       if (plugin->info.version.extra) {
-               g_string_free(plugin->info.version.extra, TRUE);
-               plugin->info.version.extra = NULL;
-       }
-
-       g_free(plugin);
-}
-
-static inline
-struct bt_plugin *bt_plugin_create_empty(enum bt_plugin_type type)
-{
-       struct bt_plugin *plugin = NULL;
-
-       BT_LOGD("Creating empty plugin object: type=%s",
-               bt_plugin_type_string(type));
-
-       plugin = g_new0(struct bt_plugin, 1);
-       if (!plugin) {
-               BT_LOGE_STR("Failed to allocate one plugin.");
-               goto error;
-       }
-
-       bt_object_init_shared(&plugin->base, bt_plugin_destroy);
-       plugin->type = type;
-
-       /* Create empty arrays of component classes */
-       plugin->src_comp_classes =
-               g_ptr_array_new_with_free_func(
-                       (GDestroyNotify) bt_object_put_ref);
-       if (!plugin->src_comp_classes) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       plugin->flt_comp_classes =
-               g_ptr_array_new_with_free_func(
-                       (GDestroyNotify) bt_object_put_ref);
-       if (!plugin->flt_comp_classes) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       plugin->sink_comp_classes =
-               g_ptr_array_new_with_free_func(
-                       (GDestroyNotify) bt_object_put_ref);
-       if (!plugin->sink_comp_classes) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       /* Create empty info */
-       plugin->info.name = g_string_new(NULL);
-       if (!plugin->info.name) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       plugin->info.path = g_string_new(NULL);
-       if (!plugin->info.path) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       plugin->info.description = g_string_new(NULL);
-       if (!plugin->info.description) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       plugin->info.author = g_string_new(NULL);
-       if (!plugin->info.author) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       plugin->info.license = g_string_new(NULL);
-       if (!plugin->info.license) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       plugin->info.version.extra = g_string_new(NULL);
-       if (!plugin->info.version.extra) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       BT_LIB_LOGD("Created empty plugin object: %!+l", plugin);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(plugin);
-
-end:
-       return plugin;
-}
-
-static inline
-void bt_plugin_set_path(struct bt_plugin *plugin, const char *path)
-{
-       BT_ASSERT(plugin);
-       BT_ASSERT(path);
-       g_string_assign(plugin->info.path, path);
-       plugin->info.path_set = BT_TRUE;
-       BT_LIB_LOGV("Set plugin's path: %![plugin-]+l, path=\"%s\"",
-               plugin, path);
-}
-
-static inline
-void bt_plugin_set_name(struct bt_plugin *plugin, const char *name)
-{
-       BT_ASSERT(plugin);
-       BT_ASSERT(name);
-       g_string_assign(plugin->info.name, name);
-       plugin->info.name_set = BT_TRUE;
-       BT_LIB_LOGV("Set plugin's name: %![plugin-]+l, name=\"%s\"",
-               plugin, name);
-}
-
-static inline
-void bt_plugin_set_description(struct bt_plugin *plugin,
-               const char *description)
-{
-       BT_ASSERT(plugin);
-       BT_ASSERT(description);
-       g_string_assign(plugin->info.description, description);
-       plugin->info.description_set = BT_TRUE;
-       BT_LIB_LOGV("Set plugin's description: %![plugin-]+l", plugin);
-}
-
-static inline
-void bt_plugin_set_author(struct bt_plugin *plugin, const char *author)
-{
-       BT_ASSERT(plugin);
-       BT_ASSERT(author);
-       g_string_assign(plugin->info.author, author);
-       plugin->info.author_set = BT_TRUE;
-       BT_LIB_LOGV("Set plugin's author: %![plugin-]+l, author=\"%s\"",
-               plugin, author);
-}
-
-static inline
-void bt_plugin_set_license(struct bt_plugin *plugin, const char *license)
-{
-       BT_ASSERT(plugin);
-       BT_ASSERT(license);
-       g_string_assign(plugin->info.license, license);
-       plugin->info.license_set = BT_TRUE;
-       BT_LIB_LOGV("Set plugin's path: %![plugin-]+l, license=\"%s\"",
-               plugin, license);
-}
-
-static inline
-void bt_plugin_set_version(struct bt_plugin *plugin, unsigned int major,
-               unsigned int minor, unsigned int patch, const char *extra)
-{
-       BT_ASSERT(plugin);
-       plugin->info.version.major = major;
-       plugin->info.version.minor = minor;
-       plugin->info.version.patch = patch;
-
-       if (extra) {
-               g_string_assign(plugin->info.version.extra, extra);
-       }
-
-       plugin->info.version_set = BT_TRUE;
-       BT_LIB_LOGV("Set plugin's version: %![plugin-]+l, "
-               "major=%u, minor=%u, patch=%u, extra=\"%s\"",
-               plugin, major, minor, patch, extra);
-}
-
-static inline
-enum bt_plugin_status bt_plugin_add_component_class(
-       struct bt_plugin *plugin, struct bt_component_class *comp_class)
-{
-       GPtrArray *comp_classes;
-
-       BT_ASSERT(plugin);
-       BT_ASSERT(comp_class);
-
-       switch (comp_class->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-               comp_classes = plugin->src_comp_classes;
-               break;
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-               comp_classes = plugin->flt_comp_classes;
-               break;
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-               comp_classes = plugin->sink_comp_classes;
-               break;
-       default:
-               abort();
-       }
-
-       /* Add new component class */
-       bt_object_get_ref(comp_class);
-       g_ptr_array_add(comp_classes, comp_class);
-
-       /* Special case for a shared object plugin */
-       if (plugin->type == BT_PLUGIN_TYPE_SO) {
-               bt_plugin_so_on_add_component_class(plugin, comp_class);
-       }
-
-       BT_LIB_LOGD("Added component class to plugin: "
-               "%![plugin-]+l, %![cc-]+C", plugin, comp_class);
-       return BT_PLUGIN_STATUS_OK;
-}
-
-static
-void bt_plugin_set_destroy(struct bt_object *obj)
-{
-       struct bt_plugin_set *plugin_set =
-               container_of(obj, struct bt_plugin_set, base);
-
-       if (!plugin_set) {
-               return;
-       }
-
-       BT_LOGD("Destroying plugin set: addr=%p", plugin_set);
-
-       if (plugin_set->plugins) {
-               BT_LOGD_STR("Putting plugins.");
-               g_ptr_array_free(plugin_set->plugins, TRUE);
-       }
-
-       g_free(plugin_set);
-}
-
-static inline
-struct bt_plugin_set *bt_plugin_set_create(void)
-{
-       struct bt_plugin_set *plugin_set = g_new0(struct bt_plugin_set, 1);
-
-       if (!plugin_set) {
-               goto end;
-       }
-
-       BT_LOGD_STR("Creating empty plugin set.");
-       bt_object_init_shared(&plugin_set->base, bt_plugin_set_destroy);
-
-       plugin_set->plugins = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_put_ref);
-       if (!plugin_set->plugins) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
-               goto end;
-       }
-
-       BT_LOGD("Created empty plugin set: addr=%p", plugin_set);
-
-end:
-       return plugin_set;
-}
-
-static inline
-void bt_plugin_set_add_plugin(struct bt_plugin_set *plugin_set,
-               struct bt_plugin *plugin)
-{
-       BT_ASSERT(plugin_set);
-       BT_ASSERT(plugin);
-       bt_object_get_ref(plugin);
-       g_ptr_array_add(plugin_set->plugins, plugin);
-       BT_LIB_LOGV("Added plugin to plugin set: "
-               "plugin-set-addr=%p, %![plugin-]+l",
-               plugin_set, plugin);
-}
-
-#endif /* BABELTRACE_PLUGIN_PLUGIN_INTERNAL_H */
diff --git a/include/babeltrace2/plugin/plugin-so-internal.h b/include/babeltrace2/plugin/plugin-so-internal.h
deleted file mode 100644 (file)
index 094b87a..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H
-#define BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include <gmodule.h>
-#include <babeltrace2/types.h>
-
-struct bt_plugin;
-struct bt_component_class;
-
-struct bt_plugin_so_shared_lib_handle {
-       struct bt_object base;
-       GString *path;
-       GModule *module;
-
-       /* True if initialization function was called */
-       bt_bool init_called;
-       bt_plugin_exit_func exit;
-};
-
-struct bt_plugin_so_spec_data {
-       /* Shared lib. handle: owned by this */
-       struct bt_plugin_so_shared_lib_handle *shared_lib_handle;
-
-       /* Pointers to plugin's memory: do NOT free */
-       const struct __bt_plugin_descriptor *descriptor;
-       bt_plugin_init_func init;
-       const struct __bt_plugin_descriptor_version *version;
-};
-
-BT_HIDDEN
-struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path);
-
-BT_HIDDEN
-struct bt_plugin_set *bt_plugin_so_create_all_from_static(void);
-
-void bt_plugin_so_on_add_component_class(struct bt_plugin *plugin,
-               struct bt_component_class *comp_class);
-
-#endif /* BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H */
diff --git a/include/babeltrace2/plugin/python-plugin-provider-internal.h b/include/babeltrace2/plugin/python-plugin-provider-internal.h
deleted file mode 100644 (file)
index 1d7aa2c..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H
-#define BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/plugin/plugin-const.h>
-
-extern
-struct bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path);
-
-#endif /* BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H */
diff --git a/include/babeltrace2/prio-heap-internal.h b/include/babeltrace2/prio-heap-internal.h
deleted file mode 100644 (file)
index e6c6a1a..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef _BABELTRACE_PRIO_HEAP_H
-#define _BABELTRACE_PRIO_HEAP_H
-
-/*
- * Static-sized priority heap containing pointers. Based on CLRS,
- * chapter 6.
- *
- * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <unistd.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-struct ptr_heap {
-       size_t len, alloc_len;
-       void **ptrs;
-       int (*gt)(void *a, void *b);
-};
-
-#ifdef DEBUG_HEAP
-void check_heap(const struct ptr_heap *heap);
-#else
-static inline
-void check_heap(const struct ptr_heap *heap)
-{
-}
-#endif
-
-/**
- * bt_heap_maximum - return the largest element in the heap
- * @heap: the heap to be operated on
- *
- * Returns the largest element in the heap, without performing any modification
- * to the heap structure. Returns NULL if the heap is empty.
- */
-static inline void *bt_heap_maximum(const struct ptr_heap *heap)
-{
-       check_heap(heap);
-       return likely(heap->len) ? heap->ptrs[0] : NULL;
-}
-
-/**
- * bt_heap_init - initialize the heap
- * @heap: the heap to initialize
- * @alloc_len: number of elements initially allocated
- * @gt: function to compare the elements
- *
- * Returns -ENOMEM if out of memory.
- */
-extern int bt_heap_init(struct ptr_heap *heap,
-                    size_t alloc_len,
-                    int gt(void *a, void *b));
-
-/**
- * bt_heap_free - free the heap
- * @heap: the heap to free
- */
-extern void bt_heap_free(struct ptr_heap *heap);
-
-/**
- * bt_heap_insert - insert an element into the heap
- * @heap: the heap to be operated on
- * @p: the element to add
- *
- * Insert an element into the heap.
- *
- * Returns -ENOMEM if out of memory.
- */
-extern int bt_heap_insert(struct ptr_heap *heap, void *p);
-
-/**
- * bt_heap_remove - remove the largest element from the heap
- * @heap: the heap to be operated on
- *
- * Returns the largest element in the heap. It removes this element from the
- * heap. Returns NULL if the heap is empty.
- */
-extern void *bt_heap_remove(struct ptr_heap *heap);
-
-/**
- * bt_heap_cherrypick - remove a given element from the heap
- * @heap: the heap to be operated on
- * @p: the element
- *
- * Remove the given element from the heap. Return the element if present, else
- * return NULL. This algorithm has a complexity of O(n), which is higher than
- * O(log(n)) provided by the rest of this API.
- */
-extern void *bt_heap_cherrypick(struct ptr_heap *heap, void *p);
-
-/**
- * bt_heap_replace_max - replace the the largest element from the heap
- * @heap: the heap to be operated on
- * @p: the pointer to be inserted as topmost element replacement
- *
- * Returns the largest element in the heap. It removes this element from the
- * heap. The heap is rebalanced only once after the insertion. Returns NULL if
- * the heap is empty.
- *
- * This is the equivalent of calling bt_heap_remove() and then bt_heap_insert(), but
- * it only rebalances the heap once. It never allocates memory.
- */
-extern void *bt_heap_replace_max(struct ptr_heap *heap, void *p);
-
-/**
- * bt_heap_copy - copy a heap
- * @dst: the destination heap (must be allocated)
- * @src: the source heap
- *
- * Returns -ENOMEM if out of memory.
- */
-extern int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src);
-
-#endif /* _BABELTRACE_PRIO_HEAP_H */
diff --git a/include/babeltrace2/property-internal.h b/include/babeltrace2/property-internal.h
deleted file mode 100644 (file)
index 575bf6e..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef BABELTRACE_PROPERTY_INTERNAL_H
-#define BABELTRACE_PROPERTY_INTERNAL_H
-
-/*
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/property.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-
-struct bt_property {
-       enum bt_property_availability avail;
-};
-
-struct bt_property_uint {
-       struct bt_property base;
-       uint64_t value;
-};
-
-static inline
-void bt_property_uint_set(struct bt_property_uint *prop, uint64_t value)
-{
-       BT_ASSERT(prop);
-       prop->base.avail = BT_PROPERTY_AVAILABILITY_AVAILABLE;
-       prop->value = value;
-}
-
-static inline
-void bt_property_uint_init(struct bt_property_uint *prop,
-               enum bt_property_availability avail, uint64_t value)
-{
-       BT_ASSERT(prop);
-       prop->base.avail = avail;
-       prop->value = value;
-}
-
-#endif /* BABELTRACE_PROPERTY_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/attributes-internal.h b/include/babeltrace2/trace-ir/attributes-internal.h
deleted file mode 100644 (file)
index 1784b35..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_ATTRIBUTES_H
-#define BABELTRACE_TRACE_IR_ATTRIBUTES_H
-
-/*
- * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/value.h>
-
-BT_HIDDEN
-struct bt_value *bt_attributes_create(void);
-
-BT_HIDDEN
-void bt_attributes_destroy(struct bt_value *attr_obj);
-
-BT_HIDDEN
-int64_t bt_attributes_get_count(const struct bt_value *attr_obj);
-
-BT_HIDDEN
-const char *bt_attributes_get_field_name(const struct bt_value *attr_obj,
-               uint64_t index);
-
-BT_HIDDEN
-struct bt_value *bt_attributes_borrow_field_value(
-               struct bt_value *attr_obj,
-               uint64_t index);
-
-BT_HIDDEN
-int bt_attributes_set_field_value(struct bt_value *attr_obj,
-               const char *name, struct bt_value *value_obj);
-
-BT_HIDDEN
-struct bt_value *bt_attributes_borrow_field_value_by_name(
-               struct bt_value *attr_obj, const char *name);
-
-BT_HIDDEN
-int bt_attributes_freeze(const struct bt_value *attr_obj);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BABELTRACE_TRACE_IR_ATTRIBUTES_H */
diff --git a/include/babeltrace2/trace-ir/clock-class-internal.h b/include/babeltrace2/trace-ir/clock-class-internal.h
deleted file mode 100644 (file)
index 7b74830..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_CLOCK_CLASS_INTERNAL_H
-#define BABELTRACE_TRACE_IR_CLOCK_CLASS_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/trace-ir/clock-class.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/property-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <glib.h>
-
-struct bt_clock_class {
-       struct bt_object base;
-
-       struct {
-               GString *str;
-
-               /* NULL or `str->str` above */
-               const char *value;
-       } name;
-
-       struct {
-               GString *str;
-
-               /* NULL or `str->str` above */
-               const char *value;
-       } description;
-
-       uint64_t frequency;
-       uint64_t precision;
-       int64_t offset_seconds;
-       uint64_t offset_cycles;
-
-       struct {
-               uint8_t uuid[BABELTRACE_UUID_LEN];
-
-               /* NULL or `uuid` above */
-               bt_uuid value;
-       } uuid;
-
-       bool origin_is_unix_epoch;
-
-       /*
-        * This is computed every time you call
-        * bt_clock_class_set_frequency() or
-        * bt_clock_class_set_offset(), as well as initially. It is the
-        * base offset in nanoseconds including both `offset_seconds`
-        * and `offset_cycles` above in the result. It is used to
-        * accelerate future calls to
-        * bt_clock_snapshot_get_ns_from_origin() and
-        * bt_clock_class_cycles_to_ns_from_origin().
-        *
-        * `overflows` is true if the base offset cannot be computed
-        * because of an overflow.
-        */
-       struct {
-               int64_t value_ns;
-               bool overflows;
-       } base_offset;
-
-       /* Pool of `struct bt_clock_snapshot *` */
-       struct bt_object_pool cs_pool;
-
-       bool frozen;
-};
-
-BT_HIDDEN
-void _bt_clock_class_freeze(const struct bt_clock_class *clock_class);
-
-#ifdef BT_DEV_MODE
-# define bt_clock_class_freeze         _bt_clock_class_freeze
-#else
-# define bt_clock_class_freeze(_cc)
-#endif
-
-BT_HIDDEN
-bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class);
-
-static inline
-int bt_clock_class_clock_value_from_ns_from_origin(
-               struct bt_clock_class *cc, int64_t ns_from_origin,
-               uint64_t *raw_value)
-{
-       BT_ASSERT(cc);
-
-       return bt_common_clock_value_from_ns_from_origin(cc->offset_seconds,
-               cc->offset_cycles, cc->frequency, ns_from_origin,
-               raw_value);
-}
-
-#endif /* BABELTRACE_TRACE_IR_CLOCK_CLASS_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/clock-snapshot-internal.h b/include/babeltrace2/trace-ir/clock-snapshot-internal.h
deleted file mode 100644 (file)
index 049d7fd..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_CLOCK_SNAPSHOT_INTERNAL_H
-#define BABELTRACE_TRACE_IR_CLOCK_SNAPSHOT_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-struct bt_clock_class;
-
-struct bt_clock_snapshot {
-       struct bt_object base;
-       struct bt_clock_class *clock_class;
-       uint64_t value_cycles;
-       bool ns_from_origin_overflows;
-       int64_t ns_from_origin;
-       bool is_set;
-};
-
-static inline
-void bt_clock_snapshot_set(struct bt_clock_snapshot *clock_snapshot)
-{
-       BT_ASSERT(clock_snapshot);
-       clock_snapshot->is_set = true;
-}
-
-static inline
-void bt_clock_snapshot_reset(struct bt_clock_snapshot *clock_snapshot)
-{
-       BT_ASSERT(clock_snapshot);
-       clock_snapshot->is_set = false;
-}
-
-static inline
-void set_ns_from_origin(struct bt_clock_snapshot *clock_snapshot)
-{
-       if (bt_util_ns_from_origin_clock_class(clock_snapshot->clock_class,
-                       clock_snapshot->value_cycles,
-                       &clock_snapshot->ns_from_origin)) {
-               clock_snapshot->ns_from_origin_overflows = true;
-       }
-}
-
-static inline
-void bt_clock_snapshot_set_raw_value(struct bt_clock_snapshot *clock_snapshot,
-               uint64_t cycles)
-{
-       BT_ASSERT(clock_snapshot);
-       clock_snapshot->value_cycles = cycles;
-       set_ns_from_origin(clock_snapshot);
-       bt_clock_snapshot_set(clock_snapshot);
-}
-
-BT_HIDDEN
-void bt_clock_snapshot_destroy(struct bt_clock_snapshot *clock_snapshot);
-
-BT_HIDDEN
-struct bt_clock_snapshot *bt_clock_snapshot_new(struct bt_clock_class *clock_class);
-
-BT_HIDDEN
-struct bt_clock_snapshot *bt_clock_snapshot_create(
-               struct bt_clock_class *clock_class);
-
-BT_HIDDEN
-void bt_clock_snapshot_recycle(struct bt_clock_snapshot *clock_snapshot);
-
-#endif /* BABELTRACE_TRACE_IR_CLOCK_SNAPSHOT_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/clock-snapshot-set-internal.h b/include/babeltrace2/trace-ir/clock-snapshot-set-internal.h
deleted file mode 100644 (file)
index 59e51b8..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-#ifndef BABELTRACE_GRAPH_CLOCK_SNAPSHOT_SET_H
-#define BABELTRACE_GRAPH_CLOCK_SNAPSHOT_SET_H
-
-/*
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <glib.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-struct bt_clock_snapshot_set {
-       /* Unique objects owned by this */
-       GPtrArray *clock_snapshots;
-
-       /* Weak; points to one of the clock snapshots above */
-       struct bt_clock_snapshot *default_cs;
-};
-
-static inline
-int bt_clock_snapshot_set_initialize(struct bt_clock_snapshot_set *cs_set)
-{
-       int ret = 0;
-
-       cs_set->clock_snapshots = g_ptr_array_sized_new(1);
-       if (!cs_set->clock_snapshots) {
-#ifdef BT_LOGE_STR
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-#endif
-
-               ret = -1;
-               goto end;
-       }
-
-       cs_set->default_cs = NULL;
-
-end:
-       return ret;
-}
-
-static inline
-void bt_clock_snapshot_set_reset(struct bt_clock_snapshot_set *cs_set)
-{
-       uint64_t i;
-
-       BT_ASSERT(cs_set);
-       BT_ASSERT(cs_set->clock_snapshots);
-
-       for (i = 0; i < cs_set->clock_snapshots->len; i++) {
-               struct bt_clock_snapshot *cs = cs_set->clock_snapshots->pdata[i];
-
-               BT_ASSERT(cs);
-               bt_clock_snapshot_reset(cs);
-       }
-
-       cs_set->default_cs = NULL;
-}
-
-static inline
-void bt_clock_snapshot_set_finalize(struct bt_clock_snapshot_set *cs_set)
-{
-       uint64_t i;
-
-       BT_ASSERT(cs_set);
-
-       if (cs_set->clock_snapshots) {
-               for (i = 0; i < cs_set->clock_snapshots->len; i++) {
-                       struct bt_clock_snapshot *cs =
-                               cs_set->clock_snapshots->pdata[i];
-
-                       BT_ASSERT(cs);
-                       bt_clock_snapshot_recycle(cs);
-               }
-
-               g_ptr_array_free(cs_set->clock_snapshots, TRUE);
-       }
-
-       cs_set->default_cs = NULL;
-}
-
-static inline
-int bt_clock_snapshot_set_set_clock_snapshot(struct bt_clock_snapshot_set *cs_set,
-               struct bt_clock_class *cc, uint64_t raw_value)
-{
-       int ret = 0;
-       struct bt_clock_snapshot *clock_snapshot = NULL;
-       uint64_t i;
-
-       BT_ASSERT(cs_set);
-       BT_ASSERT(cc);
-
-       /*
-        * Check if we already have a value for this clock class.
-        *
-        * TODO: When we have many clock classes, make this more
-        * efficient.
-        */
-       for (i = 0; i < cs_set->clock_snapshots->len; i++) {
-               struct bt_clock_snapshot *cs = cs_set->clock_snapshots->pdata[i];
-
-               BT_ASSERT(cs);
-
-               if (cs->clock_class == cc) {
-                       clock_snapshot = cs;
-                       break;
-               }
-       }
-
-       if (!clock_snapshot) {
-               clock_snapshot = bt_clock_snapshot_create(cc);
-               if (!clock_snapshot) {
-#ifdef BT_LIB_LOGE
-                       BT_LIB_LOGE("Cannot create a clock snapshot from a clock class: "
-                               "%![cc-]+K", cc);
-#endif
-
-                       ret = -1;
-                       goto end;
-               }
-
-               g_ptr_array_add(cs_set->clock_snapshots, clock_snapshot);
-       }
-
-       bt_clock_snapshot_set_raw_value(clock_snapshot, raw_value);
-
-end:
-       return ret;
-}
-
-static inline
-void  bt_clock_snapshot_set_set_default_clock_snapshot(
-               struct bt_clock_snapshot_set *cs_set, uint64_t raw_value)
-{
-       BT_ASSERT(cs_set);
-       BT_ASSERT(cs_set->default_cs);
-       bt_clock_snapshot_set_raw_value(cs_set->default_cs, raw_value);
-}
-
-#endif /* BABELTRACE_GRAPH_CLOCK_SNAPSHOT_SET_H */
diff --git a/include/babeltrace2/trace-ir/event-class-internal.h b/include/babeltrace2/trace-ir/event-class-internal.h
deleted file mode 100644 (file)
index 5d673a9..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_EVENT_CLASS_INTERNAL_H
-#define BABELTRACE_TRACE_IR_EVENT_CLASS_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/field-class.h>
-#include <babeltrace2/trace-ir/field.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/trace-ir/stream.h>
-#include <babeltrace2/trace-ir/event-class.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/property-internal.h>
-#include <glib.h>
-#include <stdbool.h>
-
-struct bt_event_class {
-       struct bt_object base;
-       struct bt_field_class *specific_context_fc;
-       struct bt_field_class *payload_fc;
-
-       struct {
-               GString *str;
-
-               /* NULL or `str->str` above */
-               const char *value;
-       } name;
-
-       uint64_t id;
-       struct bt_property_uint log_level;
-
-       struct {
-               GString *str;
-
-               /* NULL or `str->str` above */
-               const char *value;
-       } emf_uri;
-
-       /* Pool of `struct bt_event *` */
-       struct bt_object_pool event_pool;
-
-       bool frozen;
-};
-
-BT_HIDDEN
-void _bt_event_class_freeze(const struct bt_event_class *event_class);
-
-#ifdef BT_DEV_MODE
-# define bt_event_class_freeze         _bt_event_class_freeze
-#else
-# define bt_event_class_freeze(_ec)
-#endif
-
-static inline
-struct bt_stream_class *bt_event_class_borrow_stream_class_inline(
-               const struct bt_event_class *event_class)
-{
-       BT_ASSERT(event_class);
-       return (void *) bt_object_borrow_parent(&event_class->base);
-}
-
-#endif /* BABELTRACE_TRACE_IR_EVENT_CLASS_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/event-internal.h b/include/babeltrace2/trace-ir/event-internal.h
deleted file mode 100644 (file)
index 46533e8..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_EVENT_INTERNAL_H
-#define BABELTRACE_TRACE_IR_EVENT_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/* Protection: this file uses BT_LIB_LOG*() macros directly */
-#ifndef BABELTRACE_LIB_LOGGING_INTERNAL_H
-# error Please define include <babeltrace2/lib-logging-internal.h> before including this file.
-#endif
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/trace-ir/stream.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/packet.h>
-#include <babeltrace2/trace-ir/packet-internal.h>
-#include <babeltrace2/trace-ir/field.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/event-class-internal.h>
-#include <babeltrace2/trace-ir/field-wrapper-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-
-#define BT_ASSERT_PRE_EVENT_HOT(_event) \
-       BT_ASSERT_PRE_HOT(((const struct bt_event *) (_event)),         \
-               "Event", ": %!+e", (_event))
-
-struct bt_event {
-       struct bt_object base;
-
-       /* Owned by this */
-       struct bt_event_class *class;
-
-       /* Owned by this */
-       struct bt_packet *packet;
-
-       struct bt_field *common_context_field;
-       struct bt_field *specific_context_field;
-       struct bt_field *payload_field;
-       bool frozen;
-};
-
-BT_HIDDEN
-void bt_event_destroy(struct bt_event *event);
-
-BT_HIDDEN
-struct bt_event *bt_event_new(struct bt_event_class *event_class);
-
-BT_HIDDEN
-void _bt_event_set_is_frozen(const struct bt_event *event, bool is_frozen);
-
-#ifdef BT_DEV_MODE
-# define bt_event_set_is_frozen                _bt_event_set_is_frozen
-#else
-# define bt_event_set_is_frozen(_event, _is_frozen)
-#endif
-
-BT_UNUSED
-static inline
-void _bt_event_reset_dev_mode(struct bt_event *event)
-{
-       BT_ASSERT(event);
-
-       if (event->common_context_field) {
-               bt_field_set_is_frozen(
-                       event->common_context_field, false);
-               bt_field_reset(
-                       event->common_context_field);
-       }
-
-       if (event->specific_context_field) {
-               bt_field_set_is_frozen(
-                       event->specific_context_field, false);
-               bt_field_reset(event->specific_context_field);
-       }
-
-       if (event->payload_field) {
-               bt_field_set_is_frozen(
-                       event->payload_field, false);
-               bt_field_reset(event->payload_field);
-       }
-}
-
-#ifdef BT_DEV_MODE
-# define bt_event_reset_dev_mode       _bt_event_reset_dev_mode
-#else
-# define bt_event_reset_dev_mode(_x)
-#endif
-
-static inline
-void bt_event_reset(struct bt_event *event)
-{
-       BT_ASSERT(event);
-       BT_LIB_LOGD("Resetting event: %!+e", event);
-       bt_event_set_is_frozen(event, false);
-       bt_object_put_no_null_check(&event->packet->base);
-       event->packet = NULL;
-}
-
-static inline
-void bt_event_recycle(struct bt_event *event)
-{
-       struct bt_event_class *event_class;
-
-       BT_ASSERT(event);
-       BT_LIB_LOGD("Recycling event: %!+e", event);
-
-       /*
-        * Those are the important ordered steps:
-        *
-        * 1. Reset the event object (put any permanent reference it
-        *    has, unfreeze it and its fields in developer mode, etc.),
-        *    but do NOT put its class's reference. This event class
-        *    contains the pool to which we're about to recycle this
-        *    event object, so we must guarantee its existence thanks
-        *    to this existing reference.
-        *
-        * 2. Move the event class reference to our `event_class`
-        *    variable so that we can set the event's class member
-        *    to NULL before recycling it. We CANNOT do this after
-        *    we put the event class reference because this bt_object_put_ref()
-        *    could destroy the event class, also destroying its
-        *    event pool, thus also destroying our event object (this
-        *    would result in an invalid write access).
-        *
-        * 3. Recycle the event object.
-        *
-        * 4. Put our event class reference.
-        */
-       bt_event_reset(event);
-       event_class = event->class;
-       BT_ASSERT(event_class);
-       event->class = NULL;
-       bt_object_pool_recycle_object(&event_class->event_pool, event);
-       bt_object_put_no_null_check(&event_class->base);
-}
-
-static inline
-void bt_event_set_packet(struct bt_event *event, struct bt_packet *packet)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_EVENT_HOT(event);
-       BT_ASSERT_PRE(bt_event_class_borrow_stream_class(
-               event->class) == packet->stream->class,
-               "Packet's stream class and event's stream class differ: "
-               "%![event-]+e, %![packet-]+a", event, packet);
-
-       BT_ASSERT(!event->packet);
-       event->packet = packet;
-       bt_object_get_no_null_check_no_parent_check(&event->packet->base);
-       BT_LIB_LOGV("Set event's packet: %![event-]+e, %![packet-]+a",
-               event, packet);
-}
-
-static inline
-struct bt_event *bt_event_create(struct bt_event_class *event_class,
-               struct bt_packet *packet)
-{
-       struct bt_event *event = NULL;
-
-       BT_ASSERT(event_class);
-       event = bt_object_pool_create_object(&event_class->event_pool);
-       if (unlikely(!event)) {
-               BT_LIB_LOGE("Cannot allocate one event from event class's event pool: "
-                       "%![ec-]+E", event_class);
-               goto end;
-       }
-
-       if (likely(!event->class)) {
-               event->class = event_class;
-               bt_object_get_no_null_check(&event_class->base);
-       }
-
-       BT_ASSERT(packet);
-       bt_event_set_packet(event, packet);
-       goto end;
-
-end:
-       return event;
-}
-
-#endif /* BABELTRACE_TRACE_IR_EVENT_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/field-class-internal.h b/include/babeltrace2/trace-ir/field-class-internal.h
deleted file mode 100644 (file)
index b6ba729..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_FIELD_CLASSES_INTERNAL_H
-#define BABELTRACE_TRACE_IR_FIELD_CLASSES_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/clock-class.h>
-#include <babeltrace2/trace-ir/field-class.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/types.h>
-#include <stdint.h>
-#include <glib.h>
-
-#define BT_ASSERT_PRE_FC_IS_INT(_fc, _name)                            \
-       BT_ASSERT_PRE(                                                  \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER || \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER || \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION || \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, \
-               _name " is not an integer field class: %![fc-]+F", (_fc))
-
-#define BT_ASSERT_PRE_FC_IS_UNSIGNED_INT(_fc, _name)                   \
-       BT_ASSERT_PRE(                                                  \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER || \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, \
-               _name " is not an unsigned integer field class: %![fc-]+F", (_fc))
-
-#define BT_ASSERT_PRE_FC_IS_ENUM(_fc, _name)                           \
-       BT_ASSERT_PRE(                                                  \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION || \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, \
-               _name " is not an enumeration field class: %![fc-]+F", (_fc))
-
-#define BT_ASSERT_PRE_FC_IS_ARRAY(_fc, _name)                          \
-       BT_ASSERT_PRE(                                                  \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY || \
-               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, \
-               _name " is not an array field class: %![fc-]+F", (_fc))
-
-#define BT_ASSERT_PRE_FC_HAS_ID(_fc, _type, _name)                     \
-       BT_ASSERT_PRE(((const struct bt_field_class *) (_fc))->type == (_type),         \
-               _name " has the wrong type: expected-type=%s, "         \
-               "%![fc-]+F", bt_common_field_class_type_string(_type), (_fc))
-
-#define BT_ASSERT_PRE_FC_HOT(_fc, _name)                               \
-       BT_ASSERT_PRE_HOT((const struct bt_field_class *) (_fc),                \
-               (_name), ": %!+F", (_fc))
-
-#define BT_FIELD_CLASS_NAMED_FC_AT_INDEX(_fc, _index)          \
-       (&g_array_index(((struct bt_field_class_named_field_class_container *) (_fc))->named_fcs, \
-               struct bt_named_field_class, (_index)))
-
-#define BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(_fc, _index)              \
-       (&g_array_index(((struct bt_field_class_enumeration *) (_fc))->mappings, \
-               struct bt_field_class_enumeration_mapping, (_index)))
-
-#define BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(_mapping, _index)   \
-       (&g_array_index((_mapping)->ranges,                             \
-               struct bt_field_class_enumeration_mapping_range, (_index)))
-
-struct bt_field;
-struct bt_field_class;
-
-struct bt_field_class {
-       struct bt_object base;
-       enum bt_field_class_type type;
-       bool frozen;
-
-       /*
-        * Only used in developer mode, this flag indicates whether or
-        * not this field class is part of a trace class.
-        */
-       bool part_of_trace_class;
-};
-
-struct bt_field_class_integer {
-       struct bt_field_class common;
-
-       /*
-        * Value range of fields built from this integer field class:
-        * this is an equivalent integer size in bits. More formally,
-        * `range` is `n` in:
-        *
-        * Unsigned range: [0, 2^n - 1]
-        * Signed range: [-2^(n - 1), 2^(n - 1) - 1]
-        */
-       uint64_t range;
-
-       enum bt_field_class_integer_preferred_display_base base;
-};
-
-struct bt_field_class_enumeration_mapping_range {
-       union {
-               uint64_t u;
-               int64_t i;
-       } lower;
-
-       union {
-               uint64_t u;
-               int64_t i;
-       } upper;
-};
-
-struct bt_field_class_enumeration_mapping {
-       GString *label;
-
-       /* Array of `struct bt_field_class_enumeration_mapping_range` */
-       GArray *ranges;
-};
-
-struct bt_field_class_unsigned_enumeration_mapping;
-struct bt_field_class_signed_enumeration_mapping;
-
-struct bt_field_class_enumeration {
-       struct bt_field_class_integer common;
-
-       /* Array of `struct bt_field_class_enumeration_mapping *` */
-       GArray *mappings;
-
-       /*
-        * This is an array of `const char *` which acts as a temporary
-        * (potentially growing) buffer for
-        * bt_field_class_unsigned_enumeration_get_mapping_labels_by_value()
-        * and
-        * bt_field_class_signed_enumeration_get_mapping_labels_by_value().
-        *
-        * The actual strings are owned by the mappings above.
-        */
-       GPtrArray *label_buf;
-};
-
-struct bt_field_class_real {
-       struct bt_field_class common;
-       bool is_single_precision;
-};
-
-struct bt_field_class_string {
-       struct bt_field_class common;
-};
-
-/* A named field class is a (name, field class) pair */
-struct bt_named_field_class {
-       GString *name;
-
-       /* Owned by this */
-       struct bt_field_class *fc;
-
-       bool frozen;
-};
-
-struct bt_field_class_structure_member;
-struct bt_field_class_variant_option;
-
-/*
- * This is the base field class for a container of named field classes.
- * Structure and variant field classes inherit this.
- */
-struct bt_field_class_named_field_class_container {
-       struct bt_field_class common;
-
-       /*
-        * Key: `const char *`, not owned by this (owned by named field
-        * type objects contained in `named_fcs` below).
-        */
-       GHashTable *name_to_index;
-
-       /* Array of `struct bt_named_field_class` */
-       GArray *named_fcs;
-};
-
-struct bt_field_class_structure {
-       struct bt_field_class_named_field_class_container common;
-};
-
-struct bt_field_class_array {
-       struct bt_field_class common;
-
-       /* Owned by this */
-       struct bt_field_class *element_fc;
-};
-
-struct bt_field_class_static_array {
-       struct bt_field_class_array common;
-       uint64_t length;
-};
-
-struct bt_field_class_dynamic_array {
-       struct bt_field_class_array common;
-
-       /* Weak: never dereferenced, only use to find it elsewhere */
-       struct bt_field_class *length_fc;
-
-       /* Owned by this */
-       struct bt_field_path *length_field_path;
-};
-
-struct bt_field_class_variant {
-       struct bt_field_class_named_field_class_container common;
-
-       /* Weak: never dereferenced, only use to find it elsewhere */
-       struct bt_field_class *selector_fc;
-
-       /* Owned by this */
-       struct bt_field_path *selector_field_path;
-};
-
-static inline
-bool bt_field_class_has_known_type(const struct bt_field_class *fc)
-{
-       return fc->type >= BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER &&
-               fc->type <= BT_FIELD_CLASS_TYPE_VARIANT;
-}
-
-BT_HIDDEN
-void _bt_field_class_freeze(const struct bt_field_class *field_class);
-
-#ifdef BT_DEV_MODE
-# define bt_field_class_freeze         _bt_field_class_freeze
-#else
-# define bt_field_class_freeze(_fc)    ((void) _fc)
-#endif
-
-BT_HIDDEN
-void _bt_named_field_class_freeze(const struct bt_named_field_class *named_fc);
-
-#ifdef BT_DEV_MODE
-# define bt_named_field_class_freeze           _bt_named_field_class_freeze
-#else
-# define bt_named_field_class_freeze(_named_fc)        ((void) _named_fc)
-#endif
-
-/*
- * This function recursively marks `field_class` and its children as
- * being part of a trace. This is used to validate that all field classes
- * are used at a single location within trace objects even if they are
- * shared objects for other purposes.
- */
-BT_HIDDEN
-void _bt_field_class_make_part_of_trace_class(
-               const struct bt_field_class *field_class);
-
-#ifdef BT_DEV_MODE
-# define bt_field_class_make_part_of_trace_class       _bt_field_class_make_part_of_trace_class
-#else
-# define bt_field_class_make_part_of_trace_class(_fc)  ((void) _fc)
-#endif
-
-#endif /* BABELTRACE_TRACE_IR_FIELD_CLASSES_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/field-internal.h b/include/babeltrace2/trace-ir/field-internal.h
deleted file mode 100644 (file)
index 3da46b5..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_FIELDS_INTERNAL_H
-#define BABELTRACE_TRACE_IR_FIELDS_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/types.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <glib.h>
-
-#define BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(_field, _cls_type, _name)   \
-       BT_ASSERT_PRE(((const struct bt_field *) (_field))->class->type == (_cls_type), \
-               _name " has the wrong class type: expected-class-type=%s, " \
-               "%![field-]+f",                                         \
-               bt_common_field_class_type_string(_cls_type), (_field))
-
-#define BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(_field, _name)             \
-       BT_ASSERT_PRE(                                                  \
-               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER || \
-               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, \
-               _name " is not an unsigned integer field: %![field-]+f", \
-               (_field))
-
-#define BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(_field, _name)               \
-       BT_ASSERT_PRE(                                                  \
-               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER || \
-               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, \
-               _name " is not a signed integer field: %![field-]+f", \
-               (_field))
-
-#define BT_ASSERT_PRE_FIELD_IS_ARRAY(_field, _name)                    \
-       BT_ASSERT_PRE(                                                  \
-               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY || \
-               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, \
-               _name " is not an array field: %![field-]+f", (_field))
-
-#define BT_ASSERT_PRE_FIELD_IS_SET(_field, _name)                      \
-       BT_ASSERT_PRE(bt_field_is_set(_field),                          \
-               _name " is not set: %!+f", (_field))
-
-#define BT_ASSERT_PRE_FIELD_HOT(_field, _name)                         \
-       BT_ASSERT_PRE_HOT((const struct bt_field *) (_field), (_name),  \
-               ": %!+f", (_field))
-
-struct bt_field;
-
-typedef struct bt_field *(* bt_field_create_func)(struct bt_field_class *);
-typedef void (*bt_field_method_set_is_frozen)(struct bt_field *, bool);
-typedef bool (*bt_field_method_is_set)(const struct bt_field *);
-typedef void (*bt_field_method_reset)(struct bt_field *);
-
-struct bt_field_methods {
-       bt_field_method_set_is_frozen set_is_frozen;
-       bt_field_method_is_set is_set;
-       bt_field_method_reset reset;
-};
-
-struct bt_field {
-       struct bt_object base;
-
-       /* Owned by this */
-       struct bt_field_class *class;
-
-       /* Virtual table for slow path (dev mode) operations */
-       struct bt_field_methods *methods;
-
-       bool is_set;
-       bool frozen;
-};
-
-struct bt_field_integer {
-       struct bt_field common;
-
-       union {
-               uint64_t u;
-               int64_t i;
-       } value;
-};
-
-struct bt_field_real {
-       struct bt_field common;
-       double value;
-};
-
-struct bt_field_structure {
-       struct bt_field common;
-
-       /* Array of `struct bt_field *`, owned by this */
-       GPtrArray *fields;
-};
-
-struct bt_field_variant {
-       struct bt_field common;
-
-       /* Weak: belongs to `fields` below */
-       struct bt_field *selected_field;
-
-       /* Index of currently selected field */
-       uint64_t selected_index;
-
-       /* Array of `struct bt_field *`, owned by this */
-       GPtrArray *fields;
-};
-
-struct bt_field_array {
-       struct bt_field common;
-
-       /* Array of `struct bt_field *`, owned by this */
-       GPtrArray *fields;
-
-       /* Current effective length */
-       uint64_t length;
-};
-
-struct bt_field_string {
-       struct bt_field common;
-       GArray *buf;
-       uint64_t length;
-};
-
-#ifdef BT_DEV_MODE
-# define bt_field_set_is_frozen                _bt_field_set_is_frozen
-# define bt_field_is_set               _bt_field_is_set
-# define bt_field_reset                        _bt_field_reset
-# define bt_field_set_single           _bt_field_set_single
-#else
-# define bt_field_set_is_frozen(_field, _is_frozen)
-# define bt_field_is_set(_field)       (BT_FALSE)
-# define bt_field_reset(_field)
-# define bt_field_set_single(_field, _val)
-#endif
-
-BT_HIDDEN
-void _bt_field_set_is_frozen(const struct bt_field *field, bool is_frozen);
-
-static inline
-void _bt_field_reset(const struct bt_field *field)
-{
-       BT_ASSERT(field);
-       BT_ASSERT(field->methods->reset);
-       field->methods->reset((void *) field);
-}
-
-static inline
-void _bt_field_set_single(struct bt_field *field, bool value)
-{
-       BT_ASSERT(field);
-       field->is_set = value;
-}
-
-static inline
-bt_bool _bt_field_is_set(const struct bt_field *field)
-{
-       bt_bool is_set = BT_FALSE;
-
-       if (!field) {
-               goto end;
-       }
-
-       BT_ASSERT(bt_field_class_has_known_type(field->class));
-       BT_ASSERT(field->methods->is_set);
-       is_set = field->methods->is_set(field);
-
-end:
-       return is_set;
-}
-
-BT_HIDDEN
-struct bt_field *bt_field_create(struct bt_field_class *class);
-
-BT_HIDDEN
-void bt_field_destroy(struct bt_field *field);
-
-#endif /* BABELTRACE_TRACE_IR_FIELDS_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/field-path-internal.h b/include/babeltrace2/trace-ir/field-path-internal.h
deleted file mode 100644 (file)
index ef98835..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_FIELD_PATH_INTERNAL
-#define BABELTRACE_TRACE_IR_FIELD_PATH_INTERNAL
-
-/*
- * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/trace-ir/field-path-const.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-
-struct bt_field_path_item {
-       enum bt_field_path_item_type type;
-       uint64_t index;
-};
-
-struct bt_field_path {
-       struct bt_object base;
-       enum bt_scope root;
-
-       /* Array of `struct bt_field_path_item` (items) */
-       GArray *items;
-};
-
-BT_HIDDEN
-struct bt_field_path *bt_field_path_create(void);
-
-static inline
-struct bt_field_path_item *bt_field_path_borrow_item_by_index_inline(
-               const struct bt_field_path *field_path, uint64_t index)
-{
-       BT_ASSERT(field_path);
-       BT_ASSERT(index < field_path->items->len);
-       return &g_array_index(field_path->items, struct bt_field_path_item,
-               index);
-}
-
-static inline
-void bt_field_path_append_item(struct bt_field_path *field_path,
-               struct bt_field_path_item *item)
-{
-       BT_ASSERT(field_path);
-       BT_ASSERT(item);
-       g_array_append_val(field_path->items, *item);
-}
-
-static inline
-void bt_field_path_remove_last_item(struct bt_field_path *field_path)
-{
-       BT_ASSERT(field_path);
-       BT_ASSERT(field_path->items->len > 0);
-       g_array_set_size(field_path->items, field_path->items->len - 1);
-}
-
-static inline
-const char *bt_field_path_item_type_string(enum bt_field_path_item_type type)
-{
-       switch (type) {
-       case BT_FIELD_PATH_ITEM_TYPE_INDEX:
-               return "BT_FIELD_PATH_ITEM_TYPE_INDEX";
-       case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
-               return "BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT";
-       default:
-               return "(unknown)";
-       }
-};
-
-#endif /* BABELTRACE_TRACE_IR_FIELD_PATH_INTERNAL */
diff --git a/include/babeltrace2/trace-ir/field-wrapper-internal.h b/include/babeltrace2/trace-ir/field-wrapper-internal.h
deleted file mode 100644 (file)
index ed16c3f..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_FIELD_WRAPPER_INTERNAL_H
-#define BABELTRACE_TRACE_IR_FIELD_WRAPPER_INTERNAL_H
-
-/*
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/object-internal.h>
-
-struct bt_field_wrapper {
-       struct bt_object base;
-
-       /* Owned by this */
-       struct bt_field *field;
-};
-
-BT_HIDDEN
-struct bt_field_wrapper *bt_field_wrapper_new(void *data);
-
-BT_HIDDEN
-void bt_field_wrapper_destroy(struct bt_field_wrapper *field);
-
-BT_HIDDEN
-struct bt_field_wrapper *bt_field_wrapper_create(
-               struct bt_object_pool *pool, struct bt_field_class *fc);
-
-#endif /* BABELTRACE_TRACE_IR_FIELD_WRAPPER_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/packet-internal.h b/include/babeltrace2/trace-ir/packet-internal.h
deleted file mode 100644 (file)
index 677c9fb..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_PACKET_INTERNAL_H
-#define BABELTRACE_TRACE_IR_PACKET_INTERNAL_H
-
-/*
- * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdbool.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-const.h>
-#include <babeltrace2/trace-ir/packet.h>
-#include <babeltrace2/trace-ir/field.h>
-#include <babeltrace2/trace-ir/stream.h>
-#include <babeltrace2/trace-ir/field-wrapper-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/property-internal.h>
-
-struct bt_packet {
-       struct bt_object base;
-       struct bt_field_wrapper *context_field;
-       struct bt_stream *stream;
-       bool frozen;
-};
-
-BT_HIDDEN
-void _bt_packet_set_is_frozen(const struct bt_packet *packet, bool is_frozen);
-
-#ifdef BT_DEV_MODE
-# define bt_packet_set_is_frozen       _bt_packet_set_is_frozen
-#else
-# define bt_packet_set_is_frozen(_packet, _is_frozen)
-#endif /* BT_DEV_MODE */
-
-BT_HIDDEN
-struct bt_packet *bt_packet_new(struct bt_stream *stream);
-
-BT_HIDDEN
-void bt_packet_recycle(struct bt_packet *packet);
-
-BT_HIDDEN
-void bt_packet_destroy(struct bt_packet *packet);
-
-#endif /* BABELTRACE_TRACE_IR_PACKET_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/resolve-field-path-internal.h b/include/babeltrace2/trace-ir/resolve-field-path-internal.h
deleted file mode 100644 (file)
index 2b6052f..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_RESOLVE_FIELD_PATH_INTERNAL
-#define BABELTRACE_TRACE_IR_RESOLVE_FIELD_PATH_INTERNAL
-
-/*
- * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * The Common Trace Format (CTF) Specification is available at
- * http://www.efficios.com/ctf
- */
-
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/trace-ir/field-class-const.h>
-#include <babeltrace2/trace-ir/field-path-const.h>
-#include <glib.h>
-
-struct bt_resolve_field_path_context {
-       struct bt_field_class *packet_context;
-       struct bt_field_class *event_common_context;
-       struct bt_field_class *event_specific_context;
-       struct bt_field_class *event_payload;
-};
-
-BT_HIDDEN
-int bt_resolve_field_paths(struct bt_field_class *field_class,
-               struct bt_resolve_field_path_context *ctx);
-
-#endif /* BABELTRACE_TRACE_IR_RESOLVE_FIELD_PATH_INTERNAL */
diff --git a/include/babeltrace2/trace-ir/stream-class-internal.h b/include/babeltrace2/trace-ir/stream-class-internal.h
deleted file mode 100644 (file)
index f573c01..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_STREAM_CLASS_INTERNAL_H
-#define BABELTRACE_TRACE_IR_STREAM_CLASS_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <glib.h>
-#include <inttypes.h>
-
-struct bt_stream_class {
-       struct bt_object base;
-
-       struct {
-               GString *str;
-
-               /* NULL or `str->str` above */
-               const char *value;
-       } name;
-
-       uint64_t id;
-       bool assigns_automatic_event_class_id;
-       bool assigns_automatic_stream_id;
-       bool packets_have_beginning_default_clock_snapshot;
-       bool packets_have_end_default_clock_snapshot;
-       bool supports_discarded_events;
-       bool supports_discarded_packets;
-       bool discarded_events_have_default_clock_snapshots;
-       bool discarded_packets_have_default_clock_snapshots;
-       struct bt_field_class *packet_context_fc;
-       struct bt_field_class *event_common_context_fc;
-       struct bt_clock_class *default_clock_class;
-
-       /* Array of `struct bt_event_class *` */
-       GPtrArray *event_classes;
-
-       /* Pool of `struct bt_field_wrapper *` */
-       struct bt_object_pool packet_context_field_pool;
-
-       bool frozen;
-};
-
-BT_HIDDEN
-void _bt_stream_class_freeze(const struct bt_stream_class *stream_class);
-
-#ifdef BT_DEV_MODE
-# define bt_stream_class_freeze                _bt_stream_class_freeze
-#else
-# define bt_stream_class_freeze(_sc)
-#endif
-
-static inline
-struct bt_trace_class *bt_stream_class_borrow_trace_class_inline(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT(stream_class);
-       return (void *) bt_object_borrow_parent(&stream_class->base);
-}
-
-#endif /* BABELTRACE_TRACE_IR_STREAM_CLASS_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/stream-internal.h b/include/babeltrace2/trace-ir/stream-internal.h
deleted file mode 100644 (file)
index 820a5a2..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_STREAM_INTERNAL_H
-#define BABELTRACE_TRACE_IR_STREAM_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/trace-ir/stream.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <glib.h>
-
-struct bt_stream_class;
-struct bt_stream;
-
-struct bt_stream {
-       struct bt_object base;
-
-       /* Owned by this */
-       struct bt_stream_class *class;
-
-       struct {
-               GString *str;
-
-               /* NULL or `str->str` above */
-               const char *value;
-       } name;
-
-       uint64_t id;
-
-       /* Pool of `struct bt_packet *` */
-       struct bt_object_pool packet_pool;
-
-       bool frozen;
-};
-
-BT_HIDDEN
-void _bt_stream_freeze(const struct bt_stream *stream);
-
-#ifdef BT_DEV_MODE
-# define bt_stream_freeze              _bt_stream_freeze
-#else
-# define bt_stream_freeze(_stream)
-#endif
-
-static inline
-struct bt_trace *bt_stream_borrow_trace_inline(const struct bt_stream *stream)
-{
-       BT_ASSERT(stream);
-       return (void *) bt_object_borrow_parent(&stream->base);
-}
-
-#endif /* BABELTRACE_TRACE_IR_STREAM_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/trace-class-internal.h b/include/babeltrace2/trace-ir/trace-class-internal.h
deleted file mode 100644 (file)
index 50bb1a8..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_TRACE_CLASS_INTERNAL_H
-#define BABELTRACE_TRACE_IR_TRACE_CLASS_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/trace-class.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/field-class.h>
-#include <babeltrace2/trace-ir/field.h>
-#include <babeltrace2/trace-ir/attributes-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-#include <sys/types.h>
-#include <babeltrace2/compat/uuid-internal.h>
-
-struct bt_trace_class {
-       struct bt_object base;
-
-       struct {
-               GString *str;
-
-               /* NULL or `str->str` above */
-               const char *value;
-       } name;
-
-       struct {
-               uint8_t uuid[BABELTRACE_UUID_LEN];
-
-               /* NULL or `uuid` above */
-               bt_uuid value;
-       } uuid;
-
-       struct bt_value *environment;
-
-       /* Array of `struct bt_stream_class *` */
-       GPtrArray *stream_classes;
-
-       bool assigns_automatic_stream_class_id;
-       GArray *destruction_listeners;
-       bool frozen;
-};
-
-BT_HIDDEN
-void _bt_trace_class_freeze(const struct bt_trace_class *trace_class);
-
-#ifdef BT_DEV_MODE
-# define bt_trace_class_freeze         _bt_trace_class_freeze
-#else
-# define bt_trace_class_freeze(_tc)
-#endif
-
-#endif /* BABELTRACE_TRACE_IR_TRACE_CLASS_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/trace-internal.h b/include/babeltrace2/trace-ir/trace-internal.h
deleted file mode 100644 (file)
index 2476aa4..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_TRACE_INTERNAL_H
-#define BABELTRACE_TRACE_IR_TRACE_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/trace-class-internal.h>
-#include <babeltrace2/trace-ir/trace.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/field-class.h>
-#include <babeltrace2/trace-ir/field.h>
-#include <babeltrace2/trace-ir/attributes-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-#include <sys/types.h>
-#include <babeltrace2/compat/uuid-internal.h>
-
-struct bt_trace {
-       struct bt_object base;
-
-       /* Owned by this */
-       struct bt_trace_class *class;
-
-       struct {
-               GString *str;
-
-               /* NULL or `str->str` above */
-               const char *value;
-       } name;
-
-       /* Array of `struct bt_stream *` */
-       GPtrArray *streams;
-
-       /*
-        * Stream class (weak, owned by owned trace class) to number of
-        * instantiated streams, used to automatically assign stream IDs
-        * per stream class within this trace.
-        */
-       GHashTable *stream_classes_stream_count;
-
-       GArray *destruction_listeners;
-       bool frozen;
-};
-
-BT_HIDDEN
-void _bt_trace_freeze(const struct bt_trace *trace);
-
-#ifdef BT_DEV_MODE
-# define bt_trace_freeze               _bt_trace_freeze
-#else
-# define bt_trace_freeze(_trace)
-#endif
-
-BT_HIDDEN
-void bt_trace_add_stream(struct bt_trace *trace, struct bt_stream *stream);
-
-BT_HIDDEN
-uint64_t bt_trace_get_automatic_stream_id(const struct bt_trace *trace,
-               const struct bt_stream_class *stream_class);
-
-#endif /* BABELTRACE_TRACE_IR_TRACE_INTERNAL_H */
diff --git a/include/babeltrace2/trace-ir/utils-internal.h b/include/babeltrace2/trace-ir/utils-internal.h
deleted file mode 100644 (file)
index 18014d6..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-#ifndef BABELTRACE_TRACE_IR_UTILS_INTERNAL_H
-#define BABELTRACE_TRACE_IR_UTILS_INTERNAL_H
-
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/trace-ir/field-class.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <stdint.h>
-
-struct search_query {
-       gpointer value;
-       int found;
-};
-
-static inline
-uint64_t bt_util_ns_from_value(uint64_t frequency, uint64_t value_cycles)
-{
-       uint64_t ns;
-
-       if (frequency == UINT64_C(1000000000)) {
-               ns = value_cycles;
-       } else {
-               double dblres = ((1e9 * (double) value_cycles) / (double) frequency);
-
-               if (dblres >= (double) UINT64_MAX) {
-                       /* Overflows uint64_t */
-                       ns = UINT64_C(-1);
-               } else {
-                       ns = (uint64_t) dblres;
-               }
-       }
-
-       return ns;
-}
-
-static inline
-bool bt_util_get_base_offset_ns(int64_t offset_seconds, uint64_t offset_cycles,
-               uint64_t frequency, int64_t *base_offset_ns)
-{
-       bool overflows = false;
-       uint64_t offset_cycles_ns;
-
-       BT_ASSERT(base_offset_ns);
-
-       /* Initialize nanosecond timestamp to clock's offset in seconds */
-       if (offset_seconds <= (INT64_MIN / INT64_C(1000000000) - 1) ||
-                       offset_seconds >= (INT64_MAX / INT64_C(1000000000)) - 1) {
-               /*
-                * Overflow: offset in seconds converted to nanoseconds
-                * is outside the int64_t range. We also subtract 1 here
-                * to leave "space" for the offset in cycles converted
-                * to nanoseconds (which is always less than 1 second by
-                * contract).
-                */
-               overflows = true;
-               goto end;
-       }
-
-       /* Offset (seconds) to nanoseconds */
-       *base_offset_ns = offset_seconds * INT64_C(1000000000);
-
-       /* Add offset in cycles */
-       BT_ASSERT(offset_cycles < frequency);
-       offset_cycles_ns = bt_util_ns_from_value(frequency,
-               offset_cycles);
-       BT_ASSERT(offset_cycles_ns < 1000000000);
-       *base_offset_ns += (int64_t) offset_cycles_ns;
-
-end:
-       return overflows;
-}
-
-static inline
-int bt_util_ns_from_origin_inline(int64_t base_offset_ns,
-               int64_t offset_seconds, uint64_t offset_cycles,
-               uint64_t frequency, uint64_t value, int64_t *ns_from_origin)
-{
-       int ret = 0;
-       uint64_t value_ns_unsigned;
-       int64_t value_ns_signed;
-
-       /* Initialize to clock class's base offset */
-       *ns_from_origin = base_offset_ns;
-
-       /* Add given value in cycles */
-       value_ns_unsigned = bt_util_ns_from_value(frequency, value);
-       if (value_ns_unsigned >= (uint64_t) INT64_MAX) {
-               /*
-                * FIXME: `value_ns_unsigned` could be greater than
-                * `INT64_MAX` in fact: in this case, we need to
-                * subtract `INT64_MAX` from `value_ns_unsigned`, make
-                * sure that the difference is less than `INT64_MAX`,
-                * and try to add them one after the other to
-                * `*ns_from_origin`.
-                */
-               ret = -1;
-               goto end;
-       }
-
-       value_ns_signed = (int64_t) value_ns_unsigned;
-       BT_ASSERT(value_ns_signed >= 0);
-
-       if (*ns_from_origin <= 0) {
-               goto add_value;
-       }
-
-       if (value_ns_signed > INT64_MAX - *ns_from_origin) {
-               ret = -1;
-               goto end;
-       }
-
-add_value:
-       *ns_from_origin += value_ns_signed;
-
-end:
-       return ret;
-}
-
-static inline
-int bt_util_ns_from_origin_clock_class(const struct bt_clock_class *clock_class,
-               uint64_t value, int64_t *ns_from_origin)
-{
-       int ret = 0;
-
-       if (clock_class->base_offset.overflows) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_util_ns_from_origin_inline(clock_class->base_offset.value_ns,
-               clock_class->offset_seconds, clock_class->offset_cycles,
-               clock_class->frequency, value, ns_from_origin);
-
-end:
-       return ret;
-}
-
-static inline
-bool bt_util_value_is_in_range_signed(uint64_t size, int64_t value)
-{
-       int64_t min_value = UINT64_C(-1) << (size - 1);
-       int64_t max_value = (UINT64_C(1) << (size - 1)) - 1;
-       return value >= min_value && value <= max_value;
-}
-
-static inline
-bool bt_util_value_is_in_range_unsigned(unsigned int size, uint64_t value)
-{
-       uint64_t max_value = (size == 64) ? UINT64_MAX :
-               (UINT64_C(1) << size) - 1;
-       return value <= max_value;
-}
-
-#endif /* BABELTRACE_TRACE_IR_UTILS_INTERNAL_H */
diff --git a/include/babeltrace2/value-internal.h b/include/babeltrace2/value-internal.h
deleted file mode 100644 (file)
index abd607a..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef BABELTRACE_VALUES_INTERNAL_H
-#define BABELTRACE_VALUES_INTERNAL_H
-
-/*
- * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/value-const.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-
-struct bt_value {
-       struct bt_object base;
-       enum bt_value_type type;
-       bt_bool frozen;
-};
-
-struct bt_value_bool {
-       struct bt_value base;
-       bt_bool value;
-};
-
-struct bt_value_integer {
-       struct bt_value base;
-       union {
-               uint64_t i;
-               int64_t u;
-       } value;
-};
-
-struct bt_value_real {
-       struct bt_value base;
-       double value;
-};
-
-struct bt_value_string {
-       struct bt_value base;
-       GString *gstr;
-};
-
-struct bt_value_array {
-       struct bt_value base;
-       GPtrArray *garray;
-};
-
-struct bt_value_map {
-       struct bt_value base;
-       GHashTable *ght;
-};
-
-BT_HIDDEN
-enum bt_value_status _bt_value_freeze(const struct bt_value *object);
-
-#ifdef BT_DEV_MODE
-# define bt_value_freeze       _bt_value_freeze
-#else
-# define bt_value_freeze(_value)
-#endif /* BT_DEV_MODE */
-
-#endif /* BABELTRACE_VALUES_INTERNAL_H */
diff --git a/include/version.h b/include/version.h
deleted file mode 100644 (file)
index 4f80251..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef VERSION_H
-#define VERSION_H
-
-/*
- * Copyright (C) 2018 Michael Jeanson <mjeanson@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "version.i"
-
-#endif /* VERSION_H */
diff --git a/lib/Makefile.am b/lib/Makefile.am
deleted file mode 100644 (file)
index 39b956a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-SUBDIRS = trace-ir prio_heap plugin graph
-
-lib_LTLIBRARIES = libbabeltrace2.la
-
-libbabeltrace2_la_SOURCES = \
-       babeltrace2.c \
-       value.c \
-       util.c \
-       lib-logging.c \
-       logging.c \
-       object-pool.c
-libbabeltrace2_la_LDFLAGS = $(LT_NO_UNDEFINED) \
-                       -version-info $(BABELTRACE_LIBRARY_VERSION)
-
-libbabeltrace2_la_LIBADD = \
-       prio_heap/libprio_heap.la \
-       graph/libgraph.la \
-       plugin/libplugin.la \
-       trace-ir/libtrace-ir.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/compat/libcompat.la
-
-if ENABLE_BUILT_IN_PYTHON_PLUGIN_SUPPORT
-libbabeltrace2_la_LIBADD += $(top_builddir)/python-plugin-provider/libbabeltrace2-python-plugin-provider.la
-endif
diff --git a/lib/babeltrace2.c b/lib/babeltrace2.c
deleted file mode 100644 (file)
index 4a74214..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
- *
- * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/version.h>
-#include <babeltrace2/types.h>
-#include <stdlib.h>
-
-int bt_version_get_major(void)
-{
-       return BT_VERSION_MAJOR;
-}
-
-int bt_version_get_minor(void)
-{
-       return BT_VERSION_MINOR;
-}
-
-int bt_version_get_patch(void) {
-       return BT_VERSION_PATCH;
-}
-
-const char *bt_version_get_extra(void)
-{
-       return BT_VERSION_EXTRA;
-}
diff --git a/lib/graph/Makefile.am b/lib/graph/Makefile.am
deleted file mode 100644 (file)
index bd373ef..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-SUBDIRS = message
-
-noinst_LTLIBRARIES = libgraph.la
-
-# Graph library
-libgraph_la_SOURCES = \
-       component-class-sink-colander.c \
-       component-class.c \
-       component-filter.c \
-       component-sink.c \
-       component-source.c \
-       component.c \
-       connection.c \
-       graph.c \
-       iterator.c \
-       port.c \
-       query-executor.c
-
-libgraph_la_LIBADD = \
-       message/libgraph-message.la
diff --git a/lib/graph/component-class-sink-colander.c b/lib/graph/component-class-sink-colander.c
deleted file mode 100644 (file)
index 6a9d287..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COLANDER"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/graph/component-class-sink.h>
-#include <babeltrace2/graph/self-component-sink.h>
-#include <babeltrace2/graph/self-component-port.h>
-#include <babeltrace2/graph/self-component-port-input-message-iterator.h>
-#include <babeltrace2/graph/self-component.h>
-#include <babeltrace2/graph/component-class-sink-colander-internal.h>
-#include <glib.h>
-
-static
-struct bt_component_class_sink *colander_comp_cls;
-
-static
-enum bt_self_component_status colander_init(
-               struct bt_self_component_sink *self_comp,
-               const struct bt_value *params, void *init_method_data)
-{
-       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct bt_component_class_sink_colander_priv_data *colander_data = NULL;
-       struct bt_component_class_sink_colander_data *user_provided_data =
-               init_method_data;
-
-       if (!init_method_data) {
-               BT_LOGW_STR("Component initialization method data is NULL.");
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       colander_data = g_new0(
-               struct bt_component_class_sink_colander_priv_data, 1);
-       if (!colander_data) {
-               BT_LOGE_STR("Failed to allocate colander data.");
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       colander_data->msgs = user_provided_data->msgs;
-       colander_data->count_addr = user_provided_data->count_addr;
-       status = bt_self_component_sink_add_input_port(self_comp, "in",
-               NULL, NULL);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               BT_LOGE_STR("Cannot add input port.");
-               goto end;
-       }
-
-       bt_self_component_set_data(
-               bt_self_component_sink_as_self_component(self_comp),
-               colander_data);
-
-end:
-       return status;
-}
-
-static
-void colander_finalize(struct bt_self_component_sink *self_comp)
-{
-       struct bt_component_class_sink_colander_priv_data *colander_data =
-               bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(self_comp));
-
-       if (!colander_data) {
-               return;
-       }
-
-       BT_OBJECT_PUT_REF_AND_RESET(colander_data->msg_iter);
-       g_free(colander_data);
-}
-
-static
-enum bt_self_component_status colander_graph_is_configured(
-       bt_self_component_sink *self_comp)
-{
-       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct bt_component_class_sink_colander_priv_data *colander_data =
-               bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(self_comp));
-
-       struct bt_self_component_port_input *self_port =
-               bt_self_component_sink_borrow_input_port_by_name(self_comp, "in");
-       BT_ASSERT(self_port);
-
-       BT_ASSERT(colander_data);
-       BT_OBJECT_PUT_REF_AND_RESET(colander_data->msg_iter);
-       colander_data->msg_iter =
-               bt_self_component_port_input_message_iterator_create(
-                       self_port);
-       if (!colander_data->msg_iter) {
-               BT_LIB_LOGE("Cannot create message iterator on "
-                       "self component input port: %![port-]+p",
-                       self_port);
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_self_component_status colander_consume(
-               struct bt_self_component_sink *self_comp)
-{
-       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       enum bt_message_iterator_status msg_iter_status;
-       struct bt_component_class_sink_colander_priv_data *colander_data =
-               bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(self_comp));
-       bt_message_array_const msgs;
-
-       BT_ASSERT(colander_data);
-
-       if (!colander_data->msg_iter) {
-               BT_LIB_LOGW("Trying to consume without an "
-                       "upstream message iterator: %![comp-]+c",
-                       self_comp);
-               goto end;
-       }
-
-       msg_iter_status =
-               bt_self_component_port_input_message_iterator_next(
-                       colander_data->msg_iter, &msgs,
-                       colander_data->count_addr);
-       switch (msg_iter_status) {
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               status = BT_SELF_COMPONENT_STATUS_AGAIN;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_END:
-               status = BT_SELF_COMPONENT_STATUS_END;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-               /* Move messages to user (count already set) */
-               memcpy(colander_data->msgs, msgs,
-                       sizeof(*msgs) * *colander_data->count_addr);
-               break;
-       default:
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-struct bt_component_class_sink *bt_component_class_sink_colander_get(void)
-{
-       if (colander_comp_cls) {
-               goto end;
-       }
-
-       colander_comp_cls = bt_component_class_sink_create("colander",
-               colander_consume);
-       if (!colander_comp_cls) {
-               BT_LOGE_STR("Cannot create sink colander component class.");
-               goto end;
-       }
-
-       (void) bt_component_class_sink_set_init_method(
-               colander_comp_cls, colander_init);
-       (void) bt_component_class_sink_set_finalize_method(
-               colander_comp_cls, colander_finalize);
-       (void) bt_component_class_sink_set_graph_is_configured_method(
-               colander_comp_cls, colander_graph_is_configured);
-
-end:
-       bt_object_get_ref(colander_comp_cls);
-       return (void *) colander_comp_cls;
-}
-
-__attribute__((destructor)) static
-void put_colander(void) {
-       BT_OBJECT_PUT_REF_AND_RESET(colander_comp_cls);
-}
diff --git a/lib/graph/component-class.c b/lib/graph/component-class.c
deleted file mode 100644 (file)
index 4cfc3dc..0000000
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COMP-CLASS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/graph/component-class.h>
-#include <babeltrace2/graph/component-class-const.h>
-#include <babeltrace2/graph/component-class-source.h>
-#include <babeltrace2/graph/component-class-source-const.h>
-#include <babeltrace2/graph/component-class-filter.h>
-#include <babeltrace2/graph/component-class-filter-const.h>
-#include <babeltrace2/graph/component-class-sink.h>
-#include <babeltrace2/graph/component-class-sink-const.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-
-#define BT_ASSERT_PRE_COMP_CLS_HOT(_cc) \
-       BT_ASSERT_PRE_HOT(((const struct bt_component_class *) (_cc)),  \
-               "Component class", ": %!+C", (_cc))
-
-static
-void destroy_component_class(struct bt_object *obj)
-{
-       struct bt_component_class *class;
-       int i;
-
-       BT_ASSERT(obj);
-       class = container_of(obj, struct bt_component_class, base);
-
-       BT_LIB_LOGD("Destroying component class: %!+C", class);
-
-       /* Call destroy listeners in reverse registration order */
-       for (i = class->destroy_listeners->len - 1; i >= 0; i--) {
-               struct bt_component_class_destroy_listener *listener =
-                       &g_array_index(class->destroy_listeners,
-                               struct bt_component_class_destroy_listener,
-                               i);
-
-               BT_LOGD("Calling destroy listener: func-addr=%p, data-addr=%p",
-                       listener->func, listener->data);
-               listener->func(class, listener->data);
-       }
-
-       if (class->name) {
-               g_string_free(class->name, TRUE);
-               class->name = NULL;
-       }
-
-       if (class->description) {
-               g_string_free(class->description, TRUE);
-               class->description = NULL;
-       }
-
-       if (class->help) {
-               g_string_free(class->help, TRUE);
-               class->help = NULL;
-       }
-
-       if (class->destroy_listeners) {
-               g_array_free(class->destroy_listeners, TRUE);
-               class->destroy_listeners = NULL;
-       }
-
-       g_free(class);
-}
-
-static
-int bt_component_class_init(struct bt_component_class *class,
-               enum bt_component_class_type type, const char *name)
-{
-       int ret = 0;
-
-       bt_object_init_shared(&class->base, destroy_component_class);
-       class->type = type;
-       class->name = g_string_new(name);
-       if (!class->name) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       class->description = g_string_new(NULL);
-       if (!class->description) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       class->help = g_string_new(NULL);
-       if (!class->help) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       class->destroy_listeners = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_component_class_destroy_listener));
-       if (!class->destroy_listeners) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(class);
-       ret = -1;
-
-end:
-       return ret;
-}
-
-struct bt_component_class_source *bt_component_class_source_create(
-               const char *name,
-               bt_component_class_source_message_iterator_next_method method)
-{
-       struct bt_component_class_source *source_class = NULL;
-       int ret;
-
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_NON_NULL(method, "Message iterator next method");
-       BT_LOGD("Creating source component class: "
-               "name=\"%s\", msg-iter-next-method-addr=%p",
-               name, method);
-       source_class = g_new0(struct bt_component_class_source, 1);
-       if (!source_class) {
-               BT_LOGE_STR("Failed to allocate one source component class.");
-               goto end;
-       }
-
-       /* bt_component_class_init() logs errors */
-       ret = bt_component_class_init(&source_class->parent,
-               BT_COMPONENT_CLASS_TYPE_SOURCE, name);
-       if (ret) {
-               /*
-                * If bt_component_class_init() fails, the component
-                * class is put, therefore its memory is already
-                * freed.
-                */
-               source_class = NULL;
-               goto end;
-       }
-
-       source_class->methods.msg_iter_next = method;
-       BT_LIB_LOGD("Created source component class: %!+C", source_class);
-
-end:
-       return (void *) source_class;
-}
-
-struct bt_component_class_filter *bt_component_class_filter_create(
-               const char *name,
-               bt_component_class_filter_message_iterator_next_method method)
-{
-       struct bt_component_class_filter *filter_class = NULL;
-       int ret;
-
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_NON_NULL(method, "Message iterator next method");
-       BT_LOGD("Creating filter component class: "
-               "name=\"%s\", msg-iter-next-method-addr=%p",
-               name, method);
-       filter_class = g_new0(struct bt_component_class_filter, 1);
-       if (!filter_class) {
-               BT_LOGE_STR("Failed to allocate one filter component class.");
-               goto end;
-       }
-
-       /* bt_component_class_init() logs errors */
-       ret = bt_component_class_init(&filter_class->parent,
-               BT_COMPONENT_CLASS_TYPE_FILTER, name);
-       if (ret) {
-               /*
-                * If bt_component_class_init() fails, the component
-                * class is put, therefore its memory is already
-                * freed.
-                */
-               filter_class = NULL;
-               goto end;
-       }
-
-       filter_class->methods.msg_iter_next = method;
-       BT_LIB_LOGD("Created filter component class: %!+C", filter_class);
-
-end:
-       return (void *) filter_class;
-}
-
-struct bt_component_class_sink *bt_component_class_sink_create(
-               const char *name, bt_component_class_sink_consume_method method)
-{
-       struct bt_component_class_sink *sink_class = NULL;
-       int ret;
-
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_NON_NULL(method, "Consume next method");
-       BT_LOGD("Creating sink component class: "
-               "name=\"%s\", consume-method-addr=%p",
-               name, method);
-       sink_class = g_new0(struct bt_component_class_sink, 1);
-       if (!sink_class) {
-               BT_LOGE_STR("Failed to allocate one sink component class.");
-               goto end;
-       }
-
-       /* bt_component_class_init() logs errors */
-       ret = bt_component_class_init(&sink_class->parent,
-               BT_COMPONENT_CLASS_TYPE_SINK, name);
-       if (ret) {
-               /*
-                * If bt_component_class_init() fails, the component
-                * class is put, therefore its memory is already
-                * freed.
-                */
-               sink_class = NULL;
-               goto end;
-       }
-
-       sink_class->methods.consume = method;
-       BT_LIB_LOGD("Created sink component class: %!+C", sink_class);
-
-end:
-       return (void *) sink_class;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_init_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_init_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.init = method;
-       BT_LIB_LOGV("Set source component class's initialization method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_init_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_init_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.init = method;
-       BT_LIB_LOGV("Set filter component class's initialization method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_sink_set_init_method(
-               struct bt_component_class_sink *comp_cls,
-               bt_component_class_sink_init_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.init = method;
-       BT_LIB_LOGV("Set sink component class's initialization method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_finalize_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_finalize_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.finalize = method;
-       BT_LIB_LOGV("Set source component class's finalization method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_finalize_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_finalize_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.finalize = method;
-       BT_LIB_LOGV("Set filter component class's finalization method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_sink_set_finalize_method(
-               struct bt_component_class_sink *comp_cls,
-               bt_component_class_sink_finalize_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.finalize = method;
-       BT_LIB_LOGV("Set sink component class's finalization method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_query_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_query_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.query = method;
-       BT_LIB_LOGV("Set source component class's query method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_query_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_query_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.query = method;
-       BT_LIB_LOGV("Set filter component class's query method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_sink_set_query_method(
-               struct bt_component_class_sink *comp_cls,
-               bt_component_class_sink_query_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.query = method;
-       BT_LIB_LOGV("Set sink component class's query method: "
-               "%!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_accept_input_port_connection_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_accept_input_port_connection_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.accept_input_port_connection = method;
-       BT_LIB_LOGV("Set filter component class's \"accept input port connection\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_sink_set_accept_input_port_connection_method(
-               struct bt_component_class_sink *comp_cls,
-               bt_component_class_sink_accept_input_port_connection_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.accept_input_port_connection = method;
-       BT_LIB_LOGV("Set sink component class's \"accept input port connection\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_accept_output_port_connection_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_accept_output_port_connection_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.accept_output_port_connection = method;
-       BT_LIB_LOGV("Set source component class's \"accept output port connection\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_accept_output_port_connection_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_accept_output_port_connection_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.accept_output_port_connection = method;
-       BT_LIB_LOGV("Set filter component class's \"accept output port connection\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_input_port_connected_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_input_port_connected_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.input_port_connected = method;
-       BT_LIB_LOGV("Set filter component class's \"input port connected\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_sink_set_input_port_connected_method(
-               struct bt_component_class_sink *comp_cls,
-               bt_component_class_sink_input_port_connected_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.input_port_connected = method;
-       BT_LIB_LOGV("Set sink component class's \"input port connected\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_output_port_connected_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_output_port_connected_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.output_port_connected = method;
-       BT_LIB_LOGV("Set source component class's \"output port connected\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_output_port_connected_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_output_port_connected_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.output_port_connected = method;
-       BT_LIB_LOGV("Set filter component class's \"output port connected\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_sink_set_graph_is_configured_method(
-               struct bt_component_class_sink *comp_cls,
-               bt_component_class_sink_graph_is_configured_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.graph_is_configured = method;
-       BT_LIB_LOGV("Set sink component class's \"graph is configured\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-int bt_component_class_source_set_message_iterator_init_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_message_iterator_init_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_init = method;
-       BT_LIB_LOGV("Set source component class's message iterator initialization method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_message_iterator_init_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_message_iterator_init_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_init = method;
-       BT_LIB_LOGV("Set filter component class's message iterator initialization method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_message_iterator_finalize_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_message_iterator_finalize_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_finalize = method;
-       BT_LIB_LOGV("Set source component class's message iterator finalization method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_message_iterator_finalize_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_message_iterator_finalize_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_finalize = method;
-       BT_LIB_LOGV("Set filter component class's message iterator finalization method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_message_iterator_seek_ns_from_origin_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_message_iterator_seek_ns_from_origin_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_seek_ns_from_origin = method;
-       BT_LIB_LOGV("Set filter component class's message iterator \"seek nanoseconds from origin\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_message_iterator_seek_ns_from_origin_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_message_iterator_seek_ns_from_origin_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_seek_ns_from_origin = method;
-       BT_LIB_LOGV("Set source component class's message iterator \"seek nanoseconds from origin\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_message_iterator_seek_beginning_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_message_iterator_seek_beginning_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_seek_beginning = method;
-       BT_LIB_LOGV("Set filter component class's message iterator \"seek beginning\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_message_iterator_seek_beginning_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_message_iterator_seek_beginning_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_seek_beginning = method;
-       BT_LIB_LOGV("Set source component class's message iterator \"seek beginning\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_message_iterator_can_seek_beginning_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_message_iterator_can_seek_beginning_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_can_seek_beginning = method;
-       BT_LIB_LOGV("Set filter component class's message iterator \"can seek beginning\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_message_iterator_can_seek_beginning_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_message_iterator_can_seek_beginning_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_can_seek_beginning = method;
-       BT_LIB_LOGV("Set source component class's message iterator \"can seek beginning\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_filter_set_message_iterator_can_seek_ns_from_origin_method(
-               struct bt_component_class_filter *comp_cls,
-               bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_can_seek_ns_from_origin = method;
-       BT_LIB_LOGV("Set filter component class's message iterator \"can seek nanoseconds from origin\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-enum bt_component_class_status
-bt_component_class_source_set_message_iterator_can_seek_ns_from_origin_method(
-               struct bt_component_class_source *comp_cls,
-               bt_component_class_source_message_iterator_can_seek_ns_from_origin_method method)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(method, "Method");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       comp_cls->methods.msg_iter_can_seek_ns_from_origin = method;
-       BT_LIB_LOGV("Set source component class's message iterator \"can seek nanoseconds from origin\" method"
-               ": %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-bt_component_class_status bt_component_class_set_description(
-               struct bt_component_class *comp_cls,
-               const char *description)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(description, "Description");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       g_string_assign(comp_cls->description, description);
-       BT_LIB_LOGV("Set component class's description: "
-               "addr=%p, name=\"%s\", type=%s",
-               comp_cls,
-               bt_component_class_get_name(comp_cls),
-               bt_component_class_type_string(comp_cls->type));
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-bt_component_class_status bt_component_class_set_help(
-               struct bt_component_class *comp_cls,
-               const char *help)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(help, "Help");
-       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
-       g_string_assign(comp_cls->help, help);
-       BT_LIB_LOGV("Set component class's help text: %!+C", comp_cls);
-       return BT_COMPONENT_CLASS_STATUS_OK;
-}
-
-const char *bt_component_class_get_name(const struct bt_component_class *comp_cls)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       return comp_cls->name->str;
-}
-
-enum bt_component_class_type bt_component_class_get_type(
-               const struct bt_component_class *comp_cls)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       return comp_cls->type;
-}
-
-const char *bt_component_class_get_description(
-               const struct bt_component_class *comp_cls)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       return comp_cls->description &&
-               comp_cls->description->str[0] != '\0' ?
-               comp_cls->description->str : NULL;
-}
-
-const char *bt_component_class_get_help(
-               const struct bt_component_class *comp_cls)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       return comp_cls->help &&
-               comp_cls->help->str[0] != '\0' ? comp_cls->help->str : NULL;
-}
-
-BT_HIDDEN
-void bt_component_class_add_destroy_listener(
-               struct bt_component_class *comp_cls,
-               bt_component_class_destroy_listener_func func, void *data)
-{
-       struct bt_component_class_destroy_listener listener;
-
-       BT_ASSERT(comp_cls);
-       BT_ASSERT(func);
-       listener.func = func;
-       listener.data = data;
-       g_array_append_val(comp_cls->destroy_listeners, listener);
-       BT_LIB_LOGV("Added destroy listener to component class: "
-               "%![cc-]+C, listener-func-addr=%p", comp_cls, func);
-}
-
-BT_HIDDEN
-void _bt_component_class_freeze(const struct bt_component_class *comp_cls)
-{
-       BT_ASSERT(comp_cls);
-       BT_LIB_LOGD("Freezing component class: %!+C", comp_cls);
-       ((struct bt_component_class *) comp_cls)->frozen = true;
-}
-
-void bt_component_class_get_ref(
-               const struct bt_component_class *component_class)
-{
-       bt_object_get_ref(component_class);
-}
-
-void bt_component_class_put_ref(
-               const struct bt_component_class *component_class)
-{
-       bt_object_put_ref(component_class);
-}
-
-void bt_component_class_source_get_ref(
-               const struct bt_component_class_source *component_class_source)
-{
-       bt_object_get_ref(component_class_source);
-}
-
-void bt_component_class_source_put_ref(
-               const struct bt_component_class_source *component_class_source)
-{
-       bt_object_put_ref(component_class_source);
-}
-
-void bt_component_class_filter_get_ref(
-               const struct bt_component_class_filter *component_class_filter)
-{
-       bt_object_get_ref(component_class_filter);
-}
-
-void bt_component_class_filter_put_ref(
-               const struct bt_component_class_filter *component_class_filter)
-{
-       bt_object_put_ref(component_class_filter);
-}
-
-void bt_component_class_sink_get_ref(
-               const struct bt_component_class_sink *component_class_sink)
-{
-       bt_object_get_ref(component_class_sink);
-}
-
-void bt_component_class_sink_put_ref(
-               const struct bt_component_class_sink *component_class_sink)
-{
-       bt_object_put_ref(component_class_sink);
-}
diff --git a/lib/graph/component-filter.c b/lib/graph/component-filter.c
deleted file mode 100644 (file)
index 8c79b63..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COMP-FILTER"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/graph/self-component-filter.h>
-#include <babeltrace2/graph/component-filter-const.h>
-#include <babeltrace2/graph/component-filter-internal.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/graph/graph.h>
-
-BT_HIDDEN
-void bt_component_filter_destroy(struct bt_component *component)
-{
-}
-
-BT_HIDDEN
-struct bt_component *bt_component_filter_create(
-               const struct bt_component_class *class)
-{
-       struct bt_component_filter *filter = NULL;
-
-       filter = g_new0(struct bt_component_filter, 1);
-       if (!filter) {
-               BT_LOGE_STR("Failed to allocate one filter component.");
-               goto end;
-       }
-
-end:
-       return (void *) filter;
-}
-
-const bt_component_class_filter *
-bt_component_filter_borrow_class_const(
-               const bt_component_filter *component)
-{
-       struct bt_component_class *cls;
-
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-
-       cls = component->parent.class;
-
-       BT_ASSERT(cls);
-       BT_ASSERT(cls->type == BT_COMPONENT_CLASS_TYPE_FILTER);
-
-       return (bt_component_class_filter *) cls;
-}
-
-uint64_t bt_component_filter_get_output_port_count(
-               const struct bt_component_filter *comp)
-{
-       return bt_component_get_output_port_count((void *) comp);
-}
-
-const struct bt_port_output *
-bt_component_filter_borrow_output_port_by_name_const(
-               const struct bt_component_filter *comp, const char *name)
-{
-       return bt_component_borrow_output_port_by_name(
-               (void *) comp, name);
-}
-
-struct bt_self_component_port_output *
-bt_self_component_filter_borrow_output_port_by_name(
-               struct bt_self_component_filter *comp, const char *name)
-{
-       return (void *) bt_component_borrow_output_port_by_name(
-               (void *) comp, name);
-}
-
-const struct bt_port_output *
-bt_component_filter_borrow_output_port_by_index_const(
-               const struct bt_component_filter *comp, uint64_t index)
-{
-       return bt_component_borrow_output_port_by_index(
-               (void *) comp, index);
-}
-
-struct bt_self_component_port_output *
-bt_self_component_filter_borrow_output_port_by_index(
-               struct bt_self_component_filter *comp, uint64_t index)
-{
-       return (void *) bt_component_borrow_output_port_by_index(
-               (void *) comp, index);
-}
-
-enum bt_self_component_status bt_self_component_filter_add_output_port(
-               struct bt_self_component_filter *self_comp,
-               const char *name, void *user_data,
-               struct bt_self_component_port_output **self_port)
-{
-       struct bt_component *comp = (void *) self_comp;
-       enum bt_self_component_status status;
-       struct bt_port *port = NULL;
-
-       /* bt_component_add_output_port() logs details and errors */
-       status = bt_component_add_output_port(comp, name, user_data, &port);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto end;
-       }
-
-       if (self_port) {
-               /* Move reference to user */
-               *self_port = (void *) port;
-               port = NULL;
-       }
-
-end:
-       bt_object_put_ref(port);
-       return status;
-}
-
-uint64_t bt_component_filter_get_input_port_count(
-               const struct bt_component_filter *component)
-{
-       /* bt_component_get_input_port_count() logs details/errors */
-       return bt_component_get_input_port_count((void *) component);
-}
-
-const struct bt_port_input *bt_component_filter_borrow_input_port_by_name_const(
-               const struct bt_component_filter *component, const char *name)
-{
-       /* bt_component_borrow_input_port_by_name() logs details/errors */
-       return bt_component_borrow_input_port_by_name(
-               (void *) component, name);
-}
-
-struct bt_self_component_port_input *
-bt_self_component_filter_borrow_input_port_by_name(
-               struct bt_self_component_filter *component, const char *name)
-{
-       /* bt_component_borrow_input_port_by_name() logs details/errors */
-       return (void *) bt_component_borrow_input_port_by_name(
-               (void *) component, name);
-}
-
-const struct bt_port_input *
-bt_component_filter_borrow_input_port_by_index_const(
-               const struct bt_component_filter *component, uint64_t index)
-{
-       /* bt_component_borrow_input_port_by_index() logs details/errors */
-       return bt_component_borrow_input_port_by_index(
-               (void *) component, index);
-}
-
-struct bt_self_component_port_input *
-bt_self_component_filter_borrow_input_port_by_index(
-               struct bt_self_component_filter *component, uint64_t index)
-{
-       /* bt_component_borrow_input_port_by_index() logs details/errors */
-       return (void *) bt_component_borrow_input_port_by_index(
-               (void *) component, index);
-}
-
-enum bt_self_component_status bt_self_component_filter_add_input_port(
-               struct bt_self_component_filter *self_comp,
-               const char *name, void *user_data,
-               struct bt_self_component_port_input **self_port)
-{
-       enum bt_self_component_status status;
-       struct bt_port *port = NULL;
-       struct bt_component *comp = (void *) self_comp;
-
-       /* bt_component_add_input_port() logs details/errors */
-       status = bt_component_add_input_port(comp, name, user_data, &port);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto end;
-       }
-
-       if (self_port) {
-               /* Move reference to user */
-               *self_port = (void *) port;
-               port = NULL;
-       }
-
-end:
-       bt_object_put_ref(port);
-       return status;
-}
-
-void bt_component_filter_get_ref(
-               const struct bt_component_filter *component_filter)
-{
-       bt_object_get_ref(component_filter);
-}
-
-void bt_component_filter_put_ref(
-               const struct bt_component_filter *component_filter)
-{
-       bt_object_put_ref(component_filter);
-}
diff --git a/lib/graph/component-sink.c b/lib/graph/component-sink.c
deleted file mode 100644 (file)
index 1887fbf..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COMP-SINK"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/graph/self-component-sink.h>
-#include <babeltrace2/graph/component-sink-const.h>
-#include <babeltrace2/graph/component-sink-internal.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/graph.h>
-
-BT_HIDDEN
-void bt_component_sink_destroy(struct bt_component *component)
-{
-}
-
-BT_HIDDEN
-struct bt_component *bt_component_sink_create(
-               const struct bt_component_class *class)
-{
-       struct bt_component_sink *sink = NULL;
-
-       sink = g_new0(struct bt_component_sink, 1);
-       if (!sink) {
-               BT_LOGE_STR("Failed to allocate one sink component.");
-               goto end;
-       }
-
-end:
-       return (void *) sink;
-}
-
-const bt_component_class_sink *
-bt_component_sink_borrow_class_const(
-               const bt_component_sink *component)
-{
-       struct bt_component_class *cls;
-
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-
-       cls = component->parent.class;
-
-       BT_ASSERT(cls);
-       BT_ASSERT(cls->type == BT_COMPONENT_CLASS_TYPE_SINK);
-
-       return (bt_component_class_sink *) cls;
-}
-
-uint64_t bt_component_sink_get_input_port_count(
-               const struct bt_component_sink *component)
-{
-       /* bt_component_get_input_port_count() logs details/errors */
-       return bt_component_get_input_port_count((void *) component);
-}
-
-const struct bt_port_input *
-bt_component_sink_borrow_input_port_by_name_const(
-               const struct bt_component_sink *component, const char *name)
-{
-       /* bt_component_borrow_input_port_by_name() logs details/errors */
-       return bt_component_borrow_input_port_by_name((void *) component, name);
-}
-
-struct bt_self_component_port_input *
-bt_self_component_sink_borrow_input_port_by_name(
-               struct bt_self_component_sink *component, const char *name)
-{
-       /* bt_component_borrow_input_port_by_name() logs details/errors */
-       return (void *) bt_component_borrow_input_port_by_name(
-               (void *) component, name);
-}
-
-const struct bt_port_input *bt_component_sink_borrow_input_port_by_index_const(
-               const struct bt_component_sink *component, uint64_t index)
-{
-       /* bt_component_borrow_input_port_by_index() logs details/errors */
-       return bt_component_borrow_input_port_by_index(
-               (void *) component, index);
-}
-
-struct bt_self_component_port_input *
-bt_self_component_sink_borrow_input_port_by_index(
-               struct bt_self_component_sink *component, uint64_t index)
-{
-       /* bt_component_borrow_input_port_by_index() logs details/errors */
-       return (void *) bt_component_borrow_input_port_by_index(
-               (void *) component, index);
-}
-
-enum bt_self_component_status bt_self_component_sink_add_input_port(
-               struct bt_self_component_sink *self_comp,
-               const char *name, void *user_data,
-               struct bt_self_component_port_input **self_port)
-{
-       enum bt_self_component_status status;
-       struct bt_port *port = NULL;
-       struct bt_component *comp = (void *) self_comp;
-
-       /* bt_component_add_input_port() logs details/errors */
-       status = bt_component_add_input_port(comp, name, user_data, &port);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto end;
-       }
-
-       if (self_port) {
-               /* Move reference to user */
-               *self_port = (void *) port;
-               port = NULL;
-       }
-
-end:
-       bt_object_put_ref(port);
-       return status;
-}
-
-void bt_component_sink_get_ref(
-               const struct bt_component_sink *component_sink)
-{
-       bt_object_get_ref(component_sink);
-}
-
-void bt_component_sink_put_ref(
-               const struct bt_component_sink *component_sink)
-{
-       bt_object_put_ref(component_sink);
-}
diff --git a/lib/graph/component-source.c b/lib/graph/component-source.c
deleted file mode 100644 (file)
index 73740cd..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COMP-SOURCE"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/graph/self-component-source.h>
-#include <babeltrace2/graph/component-source-const.h>
-#include <babeltrace2/graph/component-source-internal.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/port-internal.h>
-#include <babeltrace2/graph/message-iterator-const.h>
-#include <babeltrace2/graph/message-iterator-internal.h>
-#include <babeltrace2/graph/graph.h>
-
-BT_HIDDEN
-void bt_component_source_destroy(struct bt_component *component)
-{
-}
-
-BT_HIDDEN
-struct bt_component *bt_component_source_create(
-               const struct bt_component_class *class)
-{
-       struct bt_component_source *source = NULL;
-
-       source = g_new0(struct bt_component_source, 1);
-       if (!source) {
-               BT_LOGE_STR("Failed to allocate one source component.");
-               goto end;
-       }
-
-end:
-       return (void *) source;
-}
-
-const bt_component_class_source *
-bt_component_source_borrow_class_const(
-               const bt_component_source *component)
-{
-       struct bt_component_class *cls;
-
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-
-       cls = component->parent.class;
-
-       BT_ASSERT(cls);
-       BT_ASSERT(cls->type == BT_COMPONENT_CLASS_TYPE_SOURCE);
-
-       return (bt_component_class_source *) cls;
-}
-
-uint64_t bt_component_source_get_output_port_count(
-               const struct bt_component_source *comp)
-{
-       return bt_component_get_output_port_count((void *) comp);
-}
-
-const struct bt_port_output *
-bt_component_source_borrow_output_port_by_name_const(
-               const struct bt_component_source *comp, const char *name)
-{
-       return bt_component_borrow_output_port_by_name((void *) comp, name);
-}
-
-struct bt_self_component_port_output *
-bt_self_component_source_borrow_output_port_by_name(
-               struct bt_self_component_source *comp, const char *name)
-{
-       return (void *) bt_component_borrow_output_port_by_name(
-               (void *) comp, name);
-}
-
-const struct bt_port_output *
-bt_component_source_borrow_output_port_by_index_const(
-               const struct bt_component_source *comp, uint64_t index)
-{
-       return bt_component_borrow_output_port_by_index((void *) comp, index);
-}
-
-struct bt_self_component_port_output *
-bt_self_component_source_borrow_output_port_by_index(
-               struct bt_self_component_source *comp, uint64_t index)
-{
-       return (void *) bt_component_borrow_output_port_by_index(
-               (void *) comp, index);
-}
-
-enum bt_self_component_status bt_self_component_source_add_output_port(
-               struct bt_self_component_source *self_comp,
-               const char *name, void *user_data,
-               struct bt_self_component_port_output **self_port)
-{
-       struct bt_component *comp = (void *) self_comp;
-       enum bt_self_component_status status;
-       struct bt_port *port = NULL;
-
-       /* bt_component_add_output_port() logs details and errors */
-       status = bt_component_add_output_port(comp, name, user_data, &port);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto end;
-       }
-
-       if (self_port) {
-               /* Move reference to user */
-               *self_port = (void *) port;
-               port = NULL;
-       }
-
-end:
-       bt_object_put_ref(port);
-       return status;
-}
-
-void bt_component_source_get_ref(
-               const struct bt_component_source *component_source)
-{
-       bt_object_get_ref(component_source);
-}
-
-void bt_component_source_put_ref(
-               const struct bt_component_source *component_source)
-{
-       bt_object_put_ref(component_source);
-}
diff --git a/lib/graph/component.c b/lib/graph/component.c
deleted file mode 100644 (file)
index 6494f64..0000000
+++ /dev/null
@@ -1,684 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "COMP"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/graph/self-component.h>
-#include <babeltrace2/graph/component-const.h>
-#include <babeltrace2/graph/component-source-const.h>
-#include <babeltrace2/graph/component-filter-const.h>
-#include <babeltrace2/graph/component-sink-const.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/graph/component-source-internal.h>
-#include <babeltrace2/graph/component-filter-internal.h>
-#include <babeltrace2/graph/component-sink-internal.h>
-#include <babeltrace2/graph/connection-internal.h>
-#include <babeltrace2/graph/graph-internal.h>
-#include <babeltrace2/graph/message-iterator-internal.h>
-#include <babeltrace2/graph/port-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/value-internal.h>
-#include <stdint.h>
-#include <inttypes.h>
-
-static
-struct bt_component * (* const component_create_funcs[])(
-               const struct bt_component_class *) = {
-       [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_create,
-       [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_create,
-       [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_create,
-};
-
-static
-void (*component_destroy_funcs[])(struct bt_component *) = {
-       [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_destroy,
-       [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_destroy,
-       [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_destroy,
-};
-
-static
-void finalize_component(struct bt_component *comp)
-{
-       typedef void (*method_t)(void *);
-
-       method_t method = NULL;
-
-       BT_ASSERT(comp);
-
-       switch (comp->class->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               struct bt_component_class_source *src_cc = (void *) comp->class;
-
-               method = (method_t) src_cc->methods.finalize;
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               struct bt_component_class_filter *flt_cc = (void *) comp->class;
-
-               method = (method_t) flt_cc->methods.finalize;
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-       {
-               struct bt_component_class_sink *sink_cc = (void *) comp->class;
-
-               method = (method_t) sink_cc->methods.finalize;
-               break;
-       }
-       default:
-               abort();
-       }
-
-       if (method) {
-               BT_LIB_LOGD("Calling user's finalization method: "
-                       "%![comp-]+c", comp);
-               method(comp);
-       }
-}
-
-static
-void destroy_component(struct bt_object *obj)
-{
-       struct bt_component *component = NULL;
-       int i;
-
-       if (!obj) {
-               return;
-       }
-
-       /*
-        * The component's reference count is 0 if we're here. Increment
-        * it to avoid a double-destroy (possibly infinitely recursive).
-        * This could happen for example if the component's finalization
-        * function does bt_object_get_ref() (or anything that causes
-        * bt_object_get_ref() to be called) on itself (ref. count goes
-        * from 0 to 1), and then bt_object_put_ref(): the reference
-        * count would go from 1 to 0 again and this function would be
-        * called again.
-        */
-       obj->ref_count++;
-       component = container_of(obj, struct bt_component, base);
-       BT_LIB_LOGD("Destroying component: %![comp-]+c, %![graph-]+g",
-               component, bt_component_borrow_graph(component));
-
-       /* Call destroy listeners in reverse registration order */
-       BT_LOGD_STR("Calling destroy listeners.");
-
-       for (i = component->destroy_listeners->len - 1; i >= 0; i--) {
-               struct bt_component_destroy_listener *listener =
-                       &g_array_index(component->destroy_listeners,
-                               struct bt_component_destroy_listener, i);
-
-               listener->func(component, listener->data);
-       }
-
-       /*
-        * User data is destroyed first, followed by the concrete
-        * component instance. Do not finalize if the component's user
-        * initialization method failed in the first place.
-        */
-       if (component->initialized) {
-               finalize_component(component);
-       }
-
-       if (component->destroy) {
-               BT_LOGD_STR("Destroying type-specific data.");
-               component->destroy(component);
-       }
-
-       if (component->input_ports) {
-               BT_LOGD_STR("Destroying input ports.");
-               g_ptr_array_free(component->input_ports, TRUE);
-               component->input_ports = NULL;
-       }
-
-       if (component->output_ports) {
-               BT_LOGD_STR("Destroying output ports.");
-               g_ptr_array_free(component->output_ports, TRUE);
-               component->output_ports = NULL;
-       }
-
-       if (component->destroy_listeners) {
-               g_array_free(component->destroy_listeners, TRUE);
-               component->destroy_listeners = NULL;
-       }
-
-       if (component->name) {
-               g_string_free(component->name, TRUE);
-               component->name = NULL;
-       }
-
-       BT_LOGD_STR("Putting component class.");
-       BT_OBJECT_PUT_REF_AND_RESET(component->class);
-       g_free(component);
-}
-
-enum bt_component_class_type bt_component_get_class_type(
-               const struct bt_component *component)
-{
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-       return component->class->type;
-}
-
-static
-enum bt_self_component_status add_port(
-               struct bt_component *component, GPtrArray *ports,
-               enum bt_port_type port_type, const char *name, void *user_data,
-               struct bt_port **port)
-{
-       struct bt_port *new_port = NULL;
-       struct bt_graph *graph = NULL;
-       enum bt_self_component_status status;
-
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE(strlen(name) > 0, "Name is empty");
-       graph = bt_component_borrow_graph(component);
-       BT_ASSERT_PRE(graph && !bt_graph_is_canceled(graph),
-               "Component's graph is canceled: %![comp-]+c, %![graph-]+g",
-               component, graph);
-       BT_ASSERT_PRE(
-               graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Component's graph is already configured: "
-               "%![comp-]+c, %![graph-]+g", component, graph);
-
-       // TODO: Validate that the name is not already used.
-
-       BT_LIB_LOGD("Adding port to component: %![comp-]+c, "
-               "port-type=%s, port-name=\"%s\"", component,
-               bt_port_type_string(port_type), name);
-
-       new_port = bt_port_create(component, port_type, name, user_data);
-       if (!new_port) {
-               BT_LOGE_STR("Cannot create port object.");
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto error;
-       }
-
-       /*
-        * No name clash, add the port.
-        * The component is now the port's parent; it should _not_
-        * hold a reference to the port since the port's lifetime
-        * is now protected by the component's own lifetime.
-        */
-       g_ptr_array_add(ports, new_port);
-
-       /*
-        * Notify the graph's creator that a new port was added.
-        */
-       graph = bt_component_borrow_graph(component);
-       if (graph) {
-               enum bt_graph_listener_status listener_status;
-
-               listener_status = bt_graph_notify_port_added(graph, new_port);
-               if (listener_status != BT_GRAPH_LISTENER_STATUS_OK) {
-                       bt_graph_make_faulty(graph);
-                       status = listener_status;
-                       goto error;
-               }
-       }
-
-       BT_LIB_LOGD("Created and added port to component: "
-               "%![comp-]+c, %![port-]+p", component, new_port);
-
-       *port = new_port;
-       status = BT_SELF_COMPONENT_STATUS_OK;
-
-       goto end;
-error:
-       /*
-        * We need to release the reference that we would otherwise have
-        * returned to the caller.
-        */
-       BT_PORT_PUT_REF_AND_RESET(new_port);
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-uint64_t bt_component_get_input_port_count(const struct bt_component *comp)
-{
-       BT_ASSERT_PRE_NON_NULL(comp, "Component");
-       return (uint64_t) comp->input_ports->len;
-}
-
-BT_HIDDEN
-uint64_t bt_component_get_output_port_count(const struct bt_component *comp)
-{
-       BT_ASSERT_PRE_NON_NULL(comp, "Component");
-       return (uint64_t) comp->output_ports->len;
-}
-
-BT_HIDDEN
-int bt_component_create(struct bt_component_class *component_class,
-               const char *name, struct bt_component **user_component)
-{
-       int ret = 0;
-       struct bt_component *component = NULL;
-       enum bt_component_class_type type;
-
-       BT_ASSERT(user_component);
-       BT_ASSERT(component_class);
-       BT_ASSERT(name);
-       type = bt_component_class_get_type(component_class);
-       BT_LIB_LOGD("Creating empty component from component class: %![cc-]+C, "
-               "comp-name=\"%s\"", component_class, name);
-       component = component_create_funcs[type](component_class);
-       if (!component) {
-               BT_LOGE_STR("Cannot create specific component object.");
-               ret = -1;
-               goto end;
-       }
-
-       bt_object_init_shared_with_parent(&component->base, destroy_component);
-       component->class = component_class;
-       bt_object_get_no_null_check(component->class);
-       component->destroy = component_destroy_funcs[type];
-       component->name = g_string_new(name);
-       if (!component->name) {
-               BT_LOGE_STR("Failed to allocate one GString.");
-               ret = -1;
-               goto end;
-       }
-
-       component->input_ports = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!component->input_ports) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               ret = -1;
-               goto end;
-       }
-
-       component->output_ports = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!component->output_ports) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               ret = -1;
-               goto end;
-       }
-
-       component->destroy_listeners = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_component_destroy_listener));
-       if (!component->destroy_listeners) {
-               BT_LOGE_STR("Failed to allocate one GArray.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LIB_LOGD("Created empty component from component class: "
-               "%![cc-]+C, %![comp-]+c", component_class, component);
-       BT_OBJECT_MOVE_REF(*user_component, component);
-
-end:
-       bt_object_put_ref(component);
-       return ret;
-}
-
-const char *bt_component_get_name(const struct bt_component *component)
-{
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-       return component->name->str;
-}
-
-const struct bt_component_class *bt_component_borrow_class_const(
-               const struct bt_component *component)
-{
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-       return component->class;
-}
-
-void *bt_self_component_get_data(const struct bt_self_component *self_comp)
-{
-       struct bt_component *component = (void *) self_comp;
-
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-       return component->user_data;
-}
-
-void bt_self_component_set_data(struct bt_self_component *self_comp,
-               void *data)
-{
-       struct bt_component *component = (void *) self_comp;
-
-       BT_ASSERT_PRE_NON_NULL(component, "Component");
-       component->user_data = data;
-       BT_LIB_LOGV("Set component's user data: %!+c", component);
-}
-
-BT_HIDDEN
-void bt_component_set_graph(struct bt_component *component,
-               struct bt_graph *graph)
-{
-       bt_object_set_parent(&component->base,
-               graph ? &graph->base : NULL);
-}
-
-bt_bool bt_component_graph_is_canceled(const struct bt_component *component)
-{
-       return bt_graph_is_canceled(
-               (void *) bt_object_borrow_parent(&component->base));
-}
-
-static
-struct bt_port *borrow_port_by_name(GPtrArray *ports,
-               const char *name)
-{
-       uint64_t i;
-       struct bt_port *ret_port = NULL;
-
-       BT_ASSERT(name);
-
-       for (i = 0; i < ports->len; i++) {
-               struct bt_port *port = g_ptr_array_index(ports, i);
-
-               if (!strcmp(name, port->name->str)) {
-                       ret_port = port;
-                       break;
-               }
-       }
-
-       return ret_port;
-}
-
-BT_HIDDEN
-struct bt_port_input *bt_component_borrow_input_port_by_name(
-               struct bt_component *comp, const char *name)
-{
-       BT_ASSERT(comp);
-       return (void *) borrow_port_by_name(comp->input_ports, name);
-}
-
-BT_HIDDEN
-struct bt_port_output *bt_component_borrow_output_port_by_name(
-               struct bt_component *comp, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(comp, "Component");
-       return (void *)
-               borrow_port_by_name(comp->output_ports, name);
-}
-
-static
-struct bt_port *borrow_port_by_index(GPtrArray *ports, uint64_t index)
-{
-       BT_ASSERT(index < ports->len);
-       return g_ptr_array_index(ports, index);
-}
-
-BT_HIDDEN
-struct bt_port_input *bt_component_borrow_input_port_by_index(
-               struct bt_component *comp, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(comp, "Component");
-       BT_ASSERT_PRE_VALID_INDEX(index, comp->input_ports->len);
-       return (void *)
-               borrow_port_by_index(comp->input_ports, index);
-}
-
-BT_HIDDEN
-struct bt_port_output *bt_component_borrow_output_port_by_index(
-               struct bt_component *comp, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(comp, "Component");
-       BT_ASSERT_PRE_VALID_INDEX(index, comp->output_ports->len);
-       return (void *)
-               borrow_port_by_index(comp->output_ports, index);
-}
-
-BT_HIDDEN
-enum bt_self_component_status bt_component_add_input_port(
-               struct bt_component *component, const char *name,
-               void *user_data, struct bt_port **port)
-{
-       /* add_port() logs details */
-       return add_port(component, component->input_ports,
-               BT_PORT_TYPE_INPUT, name, user_data, port);
-}
-
-BT_HIDDEN
-enum bt_self_component_status bt_component_add_output_port(
-               struct bt_component *component, const char *name,
-               void *user_data, struct bt_port **port)
-{
-       /* add_port() logs details */
-       return add_port(component, component->output_ports,
-               BT_PORT_TYPE_OUTPUT, name, user_data, port);
-}
-
-BT_HIDDEN
-enum bt_self_component_status bt_component_accept_port_connection(
-               struct bt_component *comp, struct bt_port *self_port,
-               struct bt_port *other_port)
-{
-       typedef enum bt_self_component_status (*method_t)(
-               void *, void *, const void *);
-
-       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       method_t method = NULL;
-
-       BT_ASSERT(comp);
-       BT_ASSERT(self_port);
-       BT_ASSERT(other_port);
-
-       switch (comp->class->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               struct bt_component_class_source *src_cc = (void *) comp->class;
-
-               switch (self_port->type) {
-               case BT_PORT_TYPE_OUTPUT:
-                       method = (method_t) src_cc->methods.accept_output_port_connection;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               struct bt_component_class_filter *flt_cc = (void *) comp->class;
-
-               switch (self_port->type) {
-               case BT_PORT_TYPE_INPUT:
-                       method = (method_t) flt_cc->methods.accept_input_port_connection;
-                       break;
-               case BT_PORT_TYPE_OUTPUT:
-                       method = (method_t) flt_cc->methods.accept_output_port_connection;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-       {
-               struct bt_component_class_sink *sink_cc = (void *) comp->class;
-
-               switch (self_port->type) {
-               case BT_PORT_TYPE_INPUT:
-                       method = (method_t) sink_cc->methods.accept_input_port_connection;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       default:
-               abort();
-       }
-
-       if (method) {
-               BT_LIB_LOGD("Calling user's \"accept port connection\" method: "
-                       "%![comp-]+c, %![self-port-]+p, %![other-port-]+p",
-                       comp, self_port, other_port);
-               status = method(comp, self_port, (void *) other_port);
-               BT_LOGD("User method returned: status=%s",
-                       bt_self_component_status_string(status));
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-enum bt_self_component_status bt_component_port_connected(
-               struct bt_component *comp, struct bt_port *self_port,
-               struct bt_port *other_port)
-{
-       typedef enum bt_self_component_status (*method_t)(
-               void *, void *, const void *);
-
-       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       method_t method = NULL;
-
-       BT_ASSERT(comp);
-       BT_ASSERT(self_port);
-       BT_ASSERT(other_port);
-
-       switch (comp->class->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               struct bt_component_class_source *src_cc = (void *) comp->class;
-
-               switch (self_port->type) {
-               case BT_PORT_TYPE_OUTPUT:
-                       method = (method_t) src_cc->methods.output_port_connected;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               struct bt_component_class_filter *flt_cc = (void *) comp->class;
-
-               switch (self_port->type) {
-               case BT_PORT_TYPE_INPUT:
-                       method = (method_t) flt_cc->methods.input_port_connected;
-                       break;
-               case BT_PORT_TYPE_OUTPUT:
-                       method = (method_t) flt_cc->methods.output_port_connected;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-       {
-               struct bt_component_class_sink *sink_cc = (void *) comp->class;
-
-               switch (self_port->type) {
-               case BT_PORT_TYPE_INPUT:
-                       method = (method_t) sink_cc->methods.input_port_connected;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       default:
-               abort();
-       }
-
-       if (method) {
-               BT_LIB_LOGD("Calling user's \"port connected\" method: "
-                       "%![comp-]+c, %![self-port-]+p, %![other-port-]+p",
-                       comp, self_port, other_port);
-               status = method(comp, self_port, (void *) other_port);
-               BT_LOGD("User method returned: status=%s",
-                       bt_self_component_status_string(status));
-               BT_ASSERT_PRE(status == BT_SELF_COMPONENT_STATUS_OK ||
-                       status == BT_SELF_COMPONENT_STATUS_ERROR ||
-                       status == BT_SELF_COMPONENT_STATUS_NOMEM,
-                       "Unexpected returned component status: status=%s",
-                       bt_self_component_status_string(status));
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-void bt_component_add_destroy_listener(struct bt_component *component,
-               bt_component_destroy_listener_func func, void *data)
-{
-       struct bt_component_destroy_listener listener;
-
-       BT_ASSERT(component);
-       BT_ASSERT(func);
-       listener.func = func;
-       listener.data = data;
-       g_array_append_val(component->destroy_listeners, listener);
-       BT_LIB_LOGV("Added destroy listener: %![comp-]+c, "
-               "func-addr=%p, data-addr=%p",
-               component, func, data);
-}
-
-BT_HIDDEN
-void bt_component_remove_destroy_listener(struct bt_component *component,
-               bt_component_destroy_listener_func func, void *data)
-{
-       uint64_t i;
-
-       BT_ASSERT(component);
-       BT_ASSERT(func);
-
-       for (i = 0; i < component->destroy_listeners->len; i++) {
-               struct bt_component_destroy_listener *listener =
-                       &g_array_index(component->destroy_listeners,
-                               struct bt_component_destroy_listener, i);
-
-               if (listener->func == func && listener->data == data) {
-                       g_array_remove_index(component->destroy_listeners, i);
-                       i--;
-                       BT_LIB_LOGV("Removed destroy listener: %![comp-]+c, "
-                               "func-addr=%p, data-addr=%p",
-                               component, func, data);
-               }
-       }
-}
-
-void bt_component_get_ref(const struct bt_component *component)
-{
-       bt_object_get_ref(component);
-}
-
-void bt_component_put_ref(const struct bt_component *component)
-{
-       bt_object_put_ref(component);
-}
diff --git a/lib/graph/connection.c b/lib/graph/connection.c
deleted file mode 100644 (file)
index 00b3a2a..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CONNECTION"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/graph/message-iterator-internal.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/connection-internal.h>
-#include <babeltrace2/graph/connection-const.h>
-#include <babeltrace2/graph/graph-internal.h>
-#include <babeltrace2/graph/port-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <stdlib.h>
-#include <glib.h>
-
-static
-void destroy_connection(struct bt_object *obj)
-{
-       struct bt_connection *connection = container_of(obj,
-                       struct bt_connection, base);
-
-       BT_LIB_LOGD("Destroying connection: %!+x", connection);
-
-       /*
-        * Make sure that each message iterator which was created for
-        * this connection is finalized before we destroy it. Once a
-        * message iterator is finalized, all its method return NULL or
-        * the BT_MESSAGE_ITERATOR_STATUS_CANCELED status.
-        *
-        * Because connections are destroyed before components within a
-        * graph, this ensures that message iterators are always
-        * finalized before their upstream component.
-        *
-        * Ending the connection does exactly this. We pass `false` to
-        * bt_connection_end() here to avoid removing this connection
-        * from the graph: if we're here, we're already in the graph's
-        * destructor.
-        */
-       bt_connection_end(connection, false);
-       g_ptr_array_free(connection->iterators, TRUE);
-       connection->iterators = NULL;
-
-       /*
-        * No bt_object_put_ref on ports as a connection only holds _weak_
-        * references to them.
-        */
-       g_free(connection);
-}
-
-static
-void try_remove_connection_from_graph(struct bt_connection *connection)
-{
-       void *graph = (void *) bt_object_borrow_parent(&connection->base);
-
-       if (connection->base.ref_count > 0 ||
-                       connection->downstream_port ||
-                       connection->upstream_port ||
-                       connection->iterators->len > 0) {
-               return;
-       }
-
-       /*
-        * At this point we know that:
-        *
-        * 1. The connection is ended (ports were disconnected).
-        * 2. All the message iterators that this connection
-        *    created, if any, are finalized.
-        * 3. The connection's reference count is 0, so only the
-        *    parent (graph) owns this connection after this call.
-        *
-        * In other words, no other object than the graph knows this
-        * connection.
-        *
-        * It is safe to remove the connection from the graph, therefore
-        * destroying it.
-        */
-       BT_LIB_LOGD("Removing self from graph's connections: "
-               "%![graph-]+g, %![conn-]+x", graph, connection);
-       bt_graph_remove_connection(graph, connection);
-}
-
-static
-void parent_is_owner(struct bt_object *obj)
-{
-       struct bt_connection *connection = container_of(obj,
-                       struct bt_connection, base);
-
-       try_remove_connection_from_graph(connection);
-}
-
-BT_HIDDEN
-struct bt_connection *bt_connection_create(struct bt_graph *graph,
-               struct bt_port *upstream_port,
-               struct bt_port *downstream_port)
-{
-       struct bt_connection *connection = NULL;
-
-       BT_LIB_LOGD("Creating connection: "
-               "%![graph-]+g, %![up-port-]+p, %![down-port-]+p",
-               graph, upstream_port, downstream_port);
-       connection = g_new0(struct bt_connection, 1);
-       if (!connection) {
-               BT_LOGE_STR("Failed to allocate one connection.");
-               goto end;
-       }
-
-       bt_object_init_shared_with_parent(&connection->base,
-               destroy_connection);
-       bt_object_set_parent_is_owner_listener_func(&connection->base,
-               parent_is_owner);
-       connection->iterators = g_ptr_array_new();
-       if (!connection->iterators) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               BT_OBJECT_PUT_REF_AND_RESET(connection);
-               goto end;
-       }
-
-       /* Weak references are taken, see comment in header. */
-       connection->upstream_port = upstream_port;
-       connection->downstream_port = downstream_port;
-       BT_LIB_LOGD("Setting upstream port's connection: %!+p", upstream_port);
-       bt_port_set_connection(upstream_port, connection);
-       BT_LIB_LOGD("Setting downstream port's connection: %!+p",
-               downstream_port);
-       bt_port_set_connection(downstream_port, connection);
-       bt_object_set_parent(&connection->base, &graph->base);
-       BT_LIB_LOGD("Created connection: %!+x", connection);
-
-end:
-       return connection;
-}
-
-BT_HIDDEN
-void bt_connection_end(struct bt_connection *conn, bool try_remove_from_graph)
-{
-       struct bt_port *downstream_port = conn->downstream_port;
-       struct bt_port *upstream_port = conn->upstream_port;
-       size_t i;
-
-       BT_LIB_LOGD("Ending connection: %!+x, try-remove-from-graph=%d",
-               conn, try_remove_from_graph);
-
-       /*
-        * Any of the following message callback functions could
-        * remove one of the connection's ports from its component. To
-        * make sure that at least logging in called functions works
-        * with existing objects, get a local reference on both ports.
-        */
-       bt_object_get_ref(downstream_port);
-       bt_object_get_ref(upstream_port);
-
-       if (downstream_port) {
-               BT_LIB_LOGD("Disconnecting connection's downstream port: %!+p",
-                       downstream_port);
-               bt_port_set_connection(downstream_port, NULL);
-               conn->downstream_port = NULL;
-       }
-
-       if (upstream_port) {
-               BT_LIB_LOGD("Disconnecting connection's upstream port: %!+p",
-                       upstream_port);
-               bt_port_set_connection(upstream_port, NULL);
-               conn->upstream_port = NULL;
-       }
-
-       /*
-        * It is safe to put the local port references now that we don't
-        * need them anymore. This could indeed destroy them.
-        */
-       bt_object_put_ref(downstream_port);
-       bt_object_put_ref(upstream_port);
-
-       /*
-        * Because this connection is ended, finalize each message
-        * iterator created from it.
-        *
-        * In practice, this only happens when the connection is
-        * destroyed and not all its message iterators were finalized,
-        * which is on graph destruction.
-        */
-       for (i = 0; i < conn->iterators->len; i++) {
-               struct bt_self_component_port_input_message_iterator *iterator =
-                       g_ptr_array_index(conn->iterators, i);
-
-               BT_LIB_LOGD("Finalizing message iterator created by "
-                       "this ended connection: %![iter-]+i", iterator);
-               bt_self_component_port_input_message_iterator_try_finalize(
-                       iterator);
-
-               /*
-                * Make sure this iterator does not try to remove itself
-                * from this connection's iterators on destruction
-                * because this connection won't exist anymore.
-                */
-               bt_self_component_port_input_message_iterator_set_connection(
-                       iterator, NULL);
-       }
-
-       g_ptr_array_set_size(conn->iterators, 0);
-
-       if (try_remove_from_graph) {
-               try_remove_connection_from_graph(conn);
-       }
-}
-
-const struct bt_port_output *bt_connection_borrow_upstream_port_const(
-               const struct bt_connection *connection)
-{
-       BT_ASSERT_PRE_NON_NULL(connection, "Connection");
-       return (void *) connection->upstream_port;
-}
-
-const struct bt_port_input *bt_connection_borrow_downstream_port_const(
-               const struct bt_connection *connection)
-{
-       BT_ASSERT_PRE_NON_NULL(connection, "Connection");
-       return (void *) connection->downstream_port;
-}
-
-BT_HIDDEN
-void bt_connection_remove_iterator(struct bt_connection *conn,
-               struct bt_self_component_port_input_message_iterator *iterator)
-{
-       g_ptr_array_remove(conn->iterators, iterator);
-       BT_LIB_LOGV("Removed message iterator from connection: "
-               "%![conn-]+x, %![iter-]+i", conn, iterator);
-       try_remove_connection_from_graph(conn);
-}
-
-void bt_connection_get_ref(const struct bt_connection *connection)
-{
-       bt_object_get_ref(connection);
-}
-
-void bt_connection_put_ref(const struct bt_connection *connection)
-{
-       bt_object_put_ref(connection);
-}
diff --git a/lib/graph/graph.c b/lib/graph/graph.c
deleted file mode 100644 (file)
index f7b02a1..0000000
+++ /dev/null
@@ -1,1556 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "GRAPH"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/graph.h>
-#include <babeltrace2/graph/graph-const.h>
-#include <babeltrace2/graph/graph-internal.h>
-#include <babeltrace2/graph/connection-internal.h>
-#include <babeltrace2/graph/component-sink-internal.h>
-#include <babeltrace2/graph/component-source-const.h>
-#include <babeltrace2/graph/component-filter-const.h>
-#include <babeltrace2/graph/port-const.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/graph/message-event-internal.h>
-#include <babeltrace2/graph/message-packet-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/value-const.h>
-#include <babeltrace2/value-internal.h>
-#include <unistd.h>
-#include <glib.h>
-
-typedef enum bt_graph_listener_status (*port_added_func_t)(
-               const void *, const void *, void *);
-
-typedef enum bt_graph_listener_status (*ports_connected_func_t)(
-               const void *, const void *, const void *, const void *, void *);
-
-typedef enum bt_self_component_status (*comp_init_method_t)(const void *,
-               const void *, void *);
-
-struct bt_graph_listener {
-       bt_graph_listener_removed_func removed;
-       void *data;
-};
-
-struct bt_graph_listener_port_added {
-       struct bt_graph_listener base;
-       port_added_func_t func;
-};
-
-struct bt_graph_listener_ports_connected {
-       struct bt_graph_listener base;
-       ports_connected_func_t func;
-};
-
-#define INIT_LISTENERS_ARRAY(_type, _listeners)                                \
-       do {                                                            \
-               _listeners = g_array_new(FALSE, TRUE, sizeof(_type));   \
-               if (!(_listeners)) {                                    \
-                       BT_LOGE_STR("Failed to allocate one GArray.");  \
-               }                                                       \
-       } while (0)
-
-#define CALL_REMOVE_LISTENERS(_type, _listeners)                       \
-       do {                                                            \
-               size_t i;                                               \
-                                                                       \
-               if (!_listeners) {                                      \
-                       break;                                          \
-               }                                                       \
-               for (i = 0; i < (_listeners)->len; i++) {               \
-                       _type *listener =                               \
-                               &g_array_index((_listeners), _type, i); \
-                                                                       \
-                       if (listener->base.removed) {                   \
-                               listener->base.removed(listener->base.data); \
-                       }                                               \
-               }                                                       \
-       } while (0)
-
-static
-void destroy_graph(struct bt_object *obj)
-{
-       struct bt_graph *graph = container_of(obj, struct bt_graph, base);
-
-       /*
-        * The graph's reference count is 0 if we're here. Increment
-        * it to avoid a double-destroy (possibly infinitely recursive)
-        * in this situation:
-        *
-        * 1. We put and destroy a connection.
-        * 2. This connection's destructor finalizes its active message
-        *    iterators.
-        * 3. A message iterator's finalization function gets a new
-        *    reference on its component (reference count goes from 0 to
-        *    1).
-        * 4. Since this component's reference count goes to 1, it takes
-        *    a reference on its parent (this graph). This graph's
-        *    reference count goes from 0 to 1.
-        * 5. The message iterator's finalization function puts its
-        *    component reference (reference count goes from 1 to 0).
-        * 6. Since this component's reference count goes from 1 to 0,
-        *    it puts its parent (this graph). This graph's reference
-        *    count goes from 1 to 0.
-        * 7. Since this graph's reference count goes from 1 to 0, its
-        *    destructor is called (this function).
-        *
-        * With the incrementation below, the graph's reference count at
-        * step 4 goes from 1 to 2, and from 2 to 1 at step 6. This
-        * ensures that this function is not called two times.
-        */
-       BT_LIB_LOGD("Destroying graph: %!+g", graph);
-       obj->ref_count++;
-
-       /*
-        * Cancel the graph to disallow some operations, like creating
-        * message iterators and adding ports to components.
-        */
-       (void) bt_graph_cancel((void *) graph);
-
-       /* Call all remove listeners */
-       CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
-               graph->listeners.source_output_port_added);
-       CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
-               graph->listeners.filter_output_port_added);
-       CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
-               graph->listeners.filter_input_port_added);
-       CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
-               graph->listeners.sink_input_port_added);
-       CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
-               graph->listeners.source_filter_ports_connected);
-       CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
-               graph->listeners.filter_filter_ports_connected);
-       CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
-               graph->listeners.source_sink_ports_connected);
-       CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
-               graph->listeners.filter_sink_ports_connected);
-
-       if (graph->messages) {
-               g_ptr_array_free(graph->messages, TRUE);
-               graph->messages = NULL;
-       }
-
-       if (graph->connections) {
-               BT_LOGD_STR("Destroying connections.");
-               g_ptr_array_free(graph->connections, TRUE);
-               graph->connections = NULL;
-       }
-
-       if (graph->components) {
-               BT_LOGD_STR("Destroying components.");
-               g_ptr_array_free(graph->components, TRUE);
-               graph->components = NULL;
-       }
-
-       if (graph->sinks_to_consume) {
-               g_queue_free(graph->sinks_to_consume);
-               graph->sinks_to_consume = NULL;
-       }
-
-       if (graph->listeners.source_output_port_added) {
-               g_array_free(graph->listeners.source_output_port_added, TRUE);
-               graph->listeners.source_output_port_added = NULL;
-       }
-
-       if (graph->listeners.filter_output_port_added) {
-               g_array_free(graph->listeners.filter_output_port_added, TRUE);
-               graph->listeners.filter_output_port_added = NULL;
-       }
-
-       if (graph->listeners.filter_input_port_added) {
-               g_array_free(graph->listeners.filter_input_port_added, TRUE);
-               graph->listeners.filter_input_port_added = NULL;
-       }
-
-       if (graph->listeners.sink_input_port_added) {
-               g_array_free(graph->listeners.sink_input_port_added, TRUE);
-               graph->listeners.sink_input_port_added = NULL;
-       }
-
-       if (graph->listeners.source_filter_ports_connected) {
-               g_array_free(graph->listeners.source_filter_ports_connected,
-                       TRUE);
-               graph->listeners.source_filter_ports_connected = NULL;
-       }
-
-       if (graph->listeners.filter_filter_ports_connected) {
-               g_array_free(graph->listeners.filter_filter_ports_connected,
-                       TRUE);
-               graph->listeners.filter_filter_ports_connected = NULL;
-       }
-
-       if (graph->listeners.source_sink_ports_connected) {
-               g_array_free(graph->listeners.source_sink_ports_connected,
-                       TRUE);
-               graph->listeners.source_sink_ports_connected = NULL;
-       }
-
-       if (graph->listeners.filter_sink_ports_connected) {
-               g_array_free(graph->listeners.filter_sink_ports_connected,
-                       TRUE);
-               graph->listeners.filter_sink_ports_connected = NULL;
-       }
-
-       bt_object_pool_finalize(&graph->event_msg_pool);
-       bt_object_pool_finalize(&graph->packet_begin_msg_pool);
-       bt_object_pool_finalize(&graph->packet_end_msg_pool);
-       g_free(graph);
-}
-
-static
-void destroy_message_event(struct bt_message *msg,
-               struct bt_graph *graph)
-{
-       bt_message_event_destroy(msg);
-}
-
-static
-void destroy_message_packet_begin(struct bt_message *msg,
-               struct bt_graph *graph)
-{
-       bt_message_packet_destroy(msg);
-}
-
-static
-void destroy_message_packet_end(struct bt_message *msg,
-               struct bt_graph *graph)
-{
-       bt_message_packet_destroy(msg);
-}
-
-static
-void notify_message_graph_is_destroyed(struct bt_message *msg)
-{
-       bt_message_unlink_graph(msg);
-}
-
-struct bt_graph *bt_graph_create(void)
-{
-       struct bt_graph *graph;
-       int ret;
-
-       BT_LOGD_STR("Creating graph object.");
-       graph = g_new0(struct bt_graph, 1);
-       if (!graph) {
-               BT_LOGE_STR("Failed to allocate one graph.");
-               goto end;
-       }
-
-       bt_object_init_shared(&graph->base, destroy_graph);
-       graph->connections = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!graph->connections) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-       graph->components = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!graph->components) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-       graph->sinks_to_consume = g_queue_new();
-       if (!graph->sinks_to_consume) {
-               BT_LOGE_STR("Failed to allocate one GQueue.");
-               goto error;
-       }
-
-       bt_graph_set_can_consume(graph, true);
-       INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
-               graph->listeners.source_output_port_added);
-
-       if (!graph->listeners.source_output_port_added) {
-               ret = -1;
-               goto error;
-       }
-
-       INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
-               graph->listeners.filter_output_port_added);
-
-       if (!graph->listeners.filter_output_port_added) {
-               ret = -1;
-               goto error;
-       }
-
-       INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
-               graph->listeners.filter_input_port_added);
-
-       if (!graph->listeners.filter_input_port_added) {
-               ret = -1;
-               goto error;
-       }
-
-       INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
-               graph->listeners.sink_input_port_added);
-
-       if (!graph->listeners.sink_input_port_added) {
-               ret = -1;
-               goto error;
-       }
-
-       INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
-               graph->listeners.source_filter_ports_connected);
-
-       if (!graph->listeners.source_filter_ports_connected) {
-               ret = -1;
-               goto error;
-       }
-
-       INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
-               graph->listeners.source_sink_ports_connected);
-
-       if (!graph->listeners.source_sink_ports_connected) {
-               ret = -1;
-               goto error;
-       }
-
-       INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
-               graph->listeners.filter_filter_ports_connected);
-
-       if (!graph->listeners.filter_filter_ports_connected) {
-               ret = -1;
-               goto error;
-       }
-
-       INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
-               graph->listeners.filter_sink_ports_connected);
-
-       if (!graph->listeners.filter_sink_ports_connected) {
-               ret = -1;
-               goto error;
-       }
-
-       ret = bt_object_pool_initialize(&graph->event_msg_pool,
-               (bt_object_pool_new_object_func) bt_message_event_new,
-               (bt_object_pool_destroy_object_func) destroy_message_event,
-               graph);
-       if (ret) {
-               BT_LOGE("Failed to initialize event message pool: ret=%d",
-                       ret);
-               goto error;
-       }
-
-       ret = bt_object_pool_initialize(&graph->packet_begin_msg_pool,
-               (bt_object_pool_new_object_func) bt_message_packet_beginning_new,
-               (bt_object_pool_destroy_object_func) destroy_message_packet_begin,
-               graph);
-       if (ret) {
-               BT_LOGE("Failed to initialize packet beginning message pool: ret=%d",
-                       ret);
-               goto error;
-       }
-
-       ret = bt_object_pool_initialize(&graph->packet_end_msg_pool,
-               (bt_object_pool_new_object_func) bt_message_packet_end_new,
-               (bt_object_pool_destroy_object_func) destroy_message_packet_end,
-               graph);
-       if (ret) {
-               BT_LOGE("Failed to initialize packet end message pool: ret=%d",
-                       ret);
-               goto error;
-       }
-
-       graph->messages = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) notify_message_graph_is_destroyed);
-       BT_LIB_LOGD("Created graph object: %!+g", graph);
-
-end:
-       return (void *) graph;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(graph);
-       goto end;
-}
-
-enum bt_graph_status bt_graph_connect_ports(
-               struct bt_graph *graph,
-               const struct bt_port_output *upstream_port_out,
-               const struct bt_port_input *downstream_port_in,
-               const struct bt_connection **user_connection)
-{
-       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
-       enum bt_graph_listener_status listener_status;
-       struct bt_connection *connection = NULL;
-       struct bt_port *upstream_port = (void *) upstream_port_out;
-       struct bt_port *downstream_port = (void *) downstream_port_in;
-       struct bt_component *upstream_component = NULL;
-       struct bt_component *downstream_component = NULL;
-       enum bt_self_component_status component_status;
-       bool init_can_consume;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(upstream_port, "Upstream port");
-       BT_ASSERT_PRE_NON_NULL(downstream_port, "Downstream port port");
-       BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
-       BT_ASSERT_PRE(
-               graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not in the \"configuring\" state: %!+g", graph);
-       BT_ASSERT_PRE(!bt_port_is_connected(upstream_port),
-               "Upstream port is already connected: %!+p", upstream_port);
-       BT_ASSERT_PRE(!bt_port_is_connected(downstream_port),
-               "Downstream port is already connected: %!+p", downstream_port);
-       BT_ASSERT_PRE(bt_port_borrow_component_inline((void *) upstream_port),
-               "Upstream port does not belong to a component: %!+p",
-               upstream_port);
-       BT_ASSERT_PRE(bt_port_borrow_component_inline((void *) downstream_port),
-               "Downstream port does not belong to a component: %!+p",
-               downstream_port);
-       init_can_consume = graph->can_consume;
-       BT_LIB_LOGD("Connecting component ports within graph: "
-               "%![graph-]+g, %![up-port-]+p, %![down-port-]+p",
-               graph, upstream_port, downstream_port);
-       bt_graph_set_can_consume(graph, false);
-       upstream_component = bt_port_borrow_component_inline(
-               (void *) upstream_port);
-       downstream_component = bt_port_borrow_component_inline(
-               (void *) downstream_port);
-
-       /*
-        * At this point the ports are not connected yet. Both
-        * components need to accept an eventual connection to their
-        * port by the other port before we continue.
-        */
-       BT_LIB_LOGD("Asking upstream component to accept the connection: "
-               "%![comp-]+c", upstream_component);
-       component_status = bt_component_accept_port_connection(
-               upstream_component, (void *) upstream_port,
-               (void *) downstream_port);
-       if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
-               if (component_status == BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
-                       BT_LOGD_STR("Upstream component refused the connection.");
-               } else {
-                       BT_LOGW("Cannot ask upstream component to accept the connection: "
-                               "status=%s", bt_self_component_status_string(component_status));
-               }
-
-               status = (int) component_status;
-               goto end;
-       }
-
-       BT_LIB_LOGD("Asking downstream component to accept the connection: "
-               "%![comp-]+c", downstream_component);
-       component_status = bt_component_accept_port_connection(
-               downstream_component, (void *) downstream_port,
-               (void *) upstream_port);
-       if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
-               if (component_status == BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
-                       BT_LOGD_STR("Downstream component refused the connection.");
-               } else {
-                       BT_LOGW("Cannot ask downstream component to accept the connection: "
-                               "status=%s", bt_self_component_status_string(component_status));
-               }
-
-               status = (int) component_status;
-               goto end;
-       }
-
-       BT_LOGD_STR("Creating connection.");
-       connection = bt_connection_create(graph, (void *) upstream_port,
-               (void *) downstream_port);
-       if (!connection) {
-               BT_LOGW("Cannot create connection object.");
-               status = BT_GRAPH_STATUS_NOMEM;
-               goto end;
-       }
-
-       BT_LIB_LOGD("Connection object created: %!+x", connection);
-
-       /*
-        * Ownership of upstream_component/downstream_component and of
-        * the connection object is transferred to the graph.
-        */
-       g_ptr_array_add(graph->connections, connection);
-
-       /*
-        * Notify both components that their port is connected.
-        */
-       BT_LIB_LOGD("Notifying upstream component that its port is connected: "
-               "%![comp-]+c, %![port-]+p", upstream_component, upstream_port);
-       component_status = bt_component_port_connected(upstream_component,
-               (void *) upstream_port, (void *) downstream_port);
-       if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
-               BT_LIB_LOGW("Error while notifying upstream component that its port is connected: "
-                       "status=%s, %![graph-]+g, %![up-comp-]+c, "
-                       "%![down-comp-]+c, %![up-port-]+p, %![down-port-]+p",
-                       bt_self_component_status_string(component_status),
-                       graph, upstream_component, downstream_component,
-                       upstream_port, downstream_port);
-               bt_connection_end(connection, true);
-               status = (int) component_status;
-               goto end;
-       }
-
-       connection->notified_upstream_port_connected = true;
-       BT_LIB_LOGD("Notifying downstream component that its port is connected: "
-               "%![comp-]+c, %![port-]+p", downstream_component,
-               downstream_port);
-       component_status = bt_component_port_connected(downstream_component,
-               (void *) downstream_port, (void *) upstream_port);
-       if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
-               BT_LIB_LOGW("Error while notifying downstream component that its port is connected: "
-                       "status=%s, %![graph-]+g, %![up-comp-]+c, "
-                       "%![down-comp-]+c, %![up-port-]+p, %![down-port-]+p",
-                       bt_self_component_status_string(component_status),
-                       graph, upstream_component, downstream_component,
-                       upstream_port, downstream_port);
-               bt_connection_end(connection, true);
-               status = (int) component_status;
-               goto end;
-       }
-
-       connection->notified_downstream_port_connected = true;
-
-       /*
-        * Notify the graph's creator that both ports are connected.
-        */
-       BT_LOGD_STR("Notifying graph's user that new component ports are connected.");
-       listener_status = bt_graph_notify_ports_connected(graph, upstream_port, downstream_port);
-       if (listener_status != BT_GRAPH_LISTENER_STATUS_OK) {
-               status = (int) listener_status;
-               goto end;
-       }
-
-       connection->notified_graph_ports_connected = true;
-       BT_LIB_LOGD("Connected component ports within graph: "
-               "%![graph-]+g, %![up-comp-]+c, %![down-comp-]+c, "
-               "%![up-port-]+p, %![down-port-]+p",
-               graph, upstream_component, downstream_component,
-               upstream_port, downstream_port);
-
-       if (user_connection) {
-               /* Move reference to user */
-               *user_connection = connection;
-               connection = NULL;
-       }
-
-end:
-       if (status != BT_GRAPH_STATUS_OK) {
-               bt_graph_make_faulty(graph);
-       }
-
-       bt_object_put_ref(connection);
-       (void) init_can_consume;
-       bt_graph_set_can_consume(graph, init_can_consume);
-       return status;
-}
-
-static inline
-enum bt_graph_status consume_graph_sink(struct bt_component_sink *comp)
-{
-       enum bt_self_component_status comp_status;
-       struct bt_component_class_sink *sink_class = NULL;
-
-       BT_ASSERT(comp);
-       sink_class = (void *) comp->parent.class;
-       BT_ASSERT(sink_class->methods.consume);
-       BT_LIB_LOGD("Calling user's consume method: %!+c", comp);
-       comp_status = sink_class->methods.consume((void *) comp);
-       BT_LOGD("User method returned: status=%s",
-               bt_self_component_status_string(comp_status));
-       BT_ASSERT_PRE(comp_status == BT_SELF_COMPONENT_STATUS_OK ||
-               comp_status == BT_SELF_COMPONENT_STATUS_END ||
-               comp_status == BT_SELF_COMPONENT_STATUS_AGAIN ||
-               comp_status == BT_SELF_COMPONENT_STATUS_ERROR ||
-               comp_status == BT_SELF_COMPONENT_STATUS_NOMEM,
-               "Invalid component status returned by consuming method: "
-               "status=%s", bt_self_component_status_string(comp_status));
-       if (comp_status < 0) {
-               BT_LOGW_STR("Consume method failed.");
-               goto end;
-       }
-
-       BT_LIB_LOGV("Consumed from sink: %![comp-]+c, status=%s",
-               comp, bt_self_component_status_string(comp_status));
-
-end:
-       return (int) comp_status;
-}
-
-/*
- * `node` is removed from the queue of sinks to consume when passed to
- * this function. This function adds it back to the queue if there's
- * still something to consume afterwards.
- */
-static inline
-enum bt_graph_status consume_sink_node(struct bt_graph *graph, GList *node)
-{
-       enum bt_graph_status status;
-       struct bt_component_sink *sink;
-
-       sink = node->data;
-       status = consume_graph_sink(sink);
-       if (unlikely(status != BT_GRAPH_STATUS_END)) {
-               g_queue_push_tail_link(graph->sinks_to_consume, node);
-               goto end;
-       }
-
-       /* End reached, the node is not added back to the queue and free'd. */
-       g_queue_delete_link(graph->sinks_to_consume, node);
-
-       /* Don't forward an END status if there are sinks left to consume. */
-       if (!g_queue_is_empty(graph->sinks_to_consume)) {
-               status = BT_GRAPH_STATUS_OK;
-               goto end;
-       }
-
-end:
-       BT_LIB_LOGV("Consumed sink node: %![comp-]+c, status=%s",
-               sink, bt_graph_status_string(status));
-       return status;
-}
-
-BT_HIDDEN
-enum bt_graph_status bt_graph_consume_sink_no_check(struct bt_graph *graph,
-               struct bt_component_sink *sink)
-{
-       enum bt_graph_status status;
-       GList *sink_node;
-       int index;
-
-       BT_LIB_LOGV("Making specific sink consume: %![comp-]+c", sink);
-       BT_ASSERT(bt_component_borrow_graph((void *) sink) == graph);
-
-       if (g_queue_is_empty(graph->sinks_to_consume)) {
-               BT_LOGV_STR("Graph's sink queue is empty: end of graph.");
-               status = BT_GRAPH_STATUS_END;
-               goto end;
-       }
-
-       index = g_queue_index(graph->sinks_to_consume, sink);
-       if (index < 0) {
-               BT_LOGV_STR("Sink is not marked as consumable: sink is ended.");
-               status = BT_GRAPH_STATUS_END;
-               goto end;
-       }
-
-       sink_node = g_queue_pop_nth_link(graph->sinks_to_consume, index);
-       BT_ASSERT(sink_node);
-       status = consume_sink_node(graph, sink_node);
-
-end:
-       return status;
-}
-
-static inline
-enum bt_graph_status consume_no_check(struct bt_graph *graph)
-{
-       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
-       struct bt_component *sink;
-       GList *current_node;
-
-       BT_ASSERT_PRE(graph->has_sink,
-               "Graph has no sink component: %!+g", graph);
-       BT_LIB_LOGV("Making next sink consume: %![graph-]+g", graph);
-
-       if (unlikely(g_queue_is_empty(graph->sinks_to_consume))) {
-               BT_LOGV_STR("Graph's sink queue is empty: end of graph.");
-               status = BT_GRAPH_STATUS_END;
-               goto end;
-       }
-
-       current_node = g_queue_pop_head_link(graph->sinks_to_consume);
-       sink = current_node->data;
-       BT_LIB_LOGV("Chose next sink to consume: %!+c", sink);
-       status = consume_sink_node(graph, current_node);
-
-end:
-       return status;
-}
-
-enum bt_graph_status bt_graph_consume(struct bt_graph *graph)
-{
-       enum bt_graph_status status;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
-       BT_ASSERT_PRE(graph->can_consume,
-               "Cannot consume graph in its current state: %!+g", graph);
-       BT_ASSERT_PRE(graph->config_state != BT_GRAPH_CONFIGURATION_STATE_FAULTY,
-               "Graph is in a faulty state: %!+g", graph);
-       bt_graph_set_can_consume(graph, false);
-       status = bt_graph_configure(graph);
-       if (unlikely(status)) {
-               /* bt_graph_configure() logs errors */
-               goto end;
-       }
-
-       status = consume_no_check(graph);
-       bt_graph_set_can_consume(graph, true);
-
-end:
-       return status;
-}
-
-enum bt_graph_status bt_graph_run(struct bt_graph *graph)
-{
-       enum bt_graph_status status;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
-       BT_ASSERT_PRE(graph->can_consume,
-               "Cannot consume graph in its current state: %!+g", graph);
-       BT_ASSERT_PRE(graph->config_state != BT_GRAPH_CONFIGURATION_STATE_FAULTY,
-               "Graph is in a faulty state: %!+g", graph);
-       bt_graph_set_can_consume(graph, false);
-       status = bt_graph_configure(graph);
-       if (unlikely(status)) {
-               /* bt_graph_configure() logs errors */
-               goto end;
-       }
-
-       BT_LIB_LOGV("Running graph: %!+g", graph);
-
-       do {
-               /*
-                * Check if the graph is canceled at each iteration. If
-                * the graph was canceled by another thread or by a
-                * signal handler, this is not a warning nor an error,
-                * it was intentional: log with a DEBUG level only.
-                */
-               if (unlikely(graph->canceled)) {
-                       BT_LIB_LOGD("Stopping the graph: graph is canceled: "
-                               "%!+g", graph);
-                       status = BT_GRAPH_STATUS_CANCELED;
-                       goto end;
-               }
-
-               status = consume_no_check(graph);
-               if (unlikely(status == BT_GRAPH_STATUS_AGAIN)) {
-                       /*
-                        * If AGAIN is received and there are multiple
-                        * sinks, go ahead and consume from the next
-                        * sink.
-                        *
-                        * However, in the case where a single sink is
-                        * left, the caller can decide to busy-wait and
-                        * call bt_graph_run() continuously
-                        * until the source is ready or it can decide to
-                        * sleep for an arbitrary amount of time.
-                        */
-                       if (graph->sinks_to_consume->length > 1) {
-                               status = BT_GRAPH_STATUS_OK;
-                       }
-               }
-       } while (status == BT_GRAPH_STATUS_OK);
-
-       if (g_queue_is_empty(graph->sinks_to_consume)) {
-               status = BT_GRAPH_STATUS_END;
-       }
-
-end:
-       BT_LIB_LOGV("Graph ran: %![graph-]+g, status=%s", graph,
-               bt_graph_status_string(status));
-       bt_graph_set_can_consume(graph, true);
-       return status;
-}
-
-enum bt_graph_status
-bt_graph_add_source_component_output_port_added_listener(
-               struct bt_graph *graph,
-               bt_graph_source_component_output_port_added_listener_func func,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *out_listener_id)
-{
-       struct bt_graph_listener_port_added listener = {
-               .base = {
-                       .removed = listener_removed,
-                       .data = data,
-               },
-               .func = (port_added_func_t) func,
-       };
-       int listener_id;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(func, "Listener");
-       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
-       BT_ASSERT_PRE(!graph->in_remove_listener,
-               "Graph currently executing a \"listener removed\" listener: "
-               "%!+g", graph);
-       g_array_append_val(graph->listeners.source_output_port_added, listener);
-       listener_id = graph->listeners.source_output_port_added->len - 1;
-       BT_LIB_LOGV("Added \"source component output port added\" listener to graph: "
-               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
-               listener_id);
-
-       if (listener_id) {
-               *out_listener_id = listener_id;
-       }
-
-       return BT_GRAPH_STATUS_OK;
-}
-
-enum bt_graph_status
-bt_graph_add_filter_component_output_port_added_listener(
-               struct bt_graph *graph,
-               bt_graph_filter_component_output_port_added_listener_func func,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *out_listener_id)
-{
-       struct bt_graph_listener_port_added listener = {
-               .base = {
-                       .removed = listener_removed,
-                       .data = data,
-               },
-               .func = (port_added_func_t) func,
-       };
-       int listener_id;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(func, "Listener");
-       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
-       BT_ASSERT_PRE(!graph->in_remove_listener,
-               "Graph currently executing a \"listener removed\" listener: "
-               "%!+g", graph);
-       g_array_append_val(graph->listeners.filter_output_port_added, listener);
-       listener_id = graph->listeners.filter_output_port_added->len - 1;
-       BT_LIB_LOGV("Added \"filter component output port added\" listener to graph: "
-               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
-               listener_id);
-
-       if (listener_id) {
-               *out_listener_id = listener_id;
-       }
-
-       return BT_GRAPH_STATUS_OK;
-}
-
-enum bt_graph_status
-bt_graph_add_filter_component_input_port_added_listener(
-               struct bt_graph *graph,
-               bt_graph_filter_component_input_port_added_listener_func func,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *out_listener_id)
-{
-       struct bt_graph_listener_port_added listener = {
-               .base = {
-                       .removed = listener_removed,
-                       .data = data,
-               },
-               .func = (port_added_func_t) func,
-       };
-       int listener_id;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(func, "Listener");
-       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
-       BT_ASSERT_PRE(!graph->in_remove_listener,
-               "Graph currently executing a \"listener removed\" listener: "
-               "%!+g", graph);
-       g_array_append_val(graph->listeners.filter_input_port_added, listener);
-       listener_id = graph->listeners.filter_input_port_added->len - 1;
-       BT_LIB_LOGV("Added \"filter component input port added\" listener to graph: "
-               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
-               listener_id);
-
-       if (listener_id) {
-               *out_listener_id = listener_id;
-       }
-
-       return BT_GRAPH_STATUS_OK;
-}
-
-enum bt_graph_status
-bt_graph_add_sink_component_input_port_added_listener(
-               struct bt_graph *graph,
-               bt_graph_sink_component_input_port_added_listener_func func,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *out_listener_id)
-{
-       struct bt_graph_listener_port_added listener = {
-               .base = {
-                       .removed = listener_removed,
-                       .data = data,
-               },
-               .func = (port_added_func_t) func,
-       };
-       int listener_id;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(func, "Listener");
-       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
-       BT_ASSERT_PRE(!graph->in_remove_listener,
-               "Graph currently executing a \"listener removed\" listener: "
-               "%!+g", graph);
-       g_array_append_val(graph->listeners.sink_input_port_added, listener);
-       listener_id = graph->listeners.sink_input_port_added->len - 1;
-       BT_LIB_LOGV("Added \"sink component input port added\" listener to graph: "
-               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
-               listener_id);
-
-       if (listener_id) {
-               *out_listener_id = listener_id;
-       }
-
-       return BT_GRAPH_STATUS_OK;
-}
-
-enum bt_graph_status
-bt_graph_add_source_filter_component_ports_connected_listener(
-               struct bt_graph *graph,
-               bt_graph_source_filter_component_ports_connected_listener_func func,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *out_listener_id)
-{
-       struct bt_graph_listener_ports_connected listener = {
-               .base = {
-                       .removed = listener_removed,
-                       .data = data,
-               },
-               .func = (ports_connected_func_t) func,
-       };
-       int listener_id;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(func, "Listener");
-       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
-       BT_ASSERT_PRE(!graph->in_remove_listener,
-               "Graph currently executing a \"listener removed\" listener: "
-               "%!+g", graph);
-       g_array_append_val(graph->listeners.source_filter_ports_connected,
-               listener);
-       listener_id = graph->listeners.source_filter_ports_connected->len - 1;
-       BT_LIB_LOGV("Added \"source to filter component ports connected\" listener to graph: "
-               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
-               listener_id);
-
-       if (listener_id) {
-               *out_listener_id = listener_id;
-       }
-
-       return BT_GRAPH_STATUS_OK;
-}
-
-enum bt_graph_status
-bt_graph_add_source_sink_component_ports_connected_listener(
-               struct bt_graph *graph,
-               bt_graph_source_sink_component_ports_connected_listener_func func,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *out_listener_id)
-{
-       struct bt_graph_listener_ports_connected listener = {
-               .base = {
-                       .removed = listener_removed,
-                       .data = data,
-               },
-               .func = (ports_connected_func_t) func,
-       };
-       int listener_id;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(func, "Listener");
-       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
-       BT_ASSERT_PRE(!graph->in_remove_listener,
-               "Graph currently executing a \"listener removed\" listener: "
-               "%!+g", graph);
-       g_array_append_val(graph->listeners.source_sink_ports_connected,
-               listener);
-       listener_id = graph->listeners.source_sink_ports_connected->len - 1;
-       BT_LIB_LOGV("Added \"source to sink component ports connected\" listener to graph: "
-               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
-               listener_id);
-
-       if (listener_id) {
-               *out_listener_id = listener_id;
-       }
-
-       return BT_GRAPH_STATUS_OK;
-}
-
-enum bt_graph_status
-bt_graph_add_filter_filter_component_ports_connected_listener(
-               struct bt_graph *graph,
-               bt_graph_filter_filter_component_ports_connected_listener_func func,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *out_listener_id)
-{
-       struct bt_graph_listener_ports_connected listener = {
-               .base = {
-                       .removed = listener_removed,
-                       .data = data,
-               },
-               .func = (ports_connected_func_t) func,
-       };
-       int listener_id;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(func, "Listener");
-       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
-       BT_ASSERT_PRE(!graph->in_remove_listener,
-               "Graph currently executing a \"listener removed\" listener: "
-               "%!+g", graph);
-       g_array_append_val(graph->listeners.filter_filter_ports_connected,
-               listener);
-       listener_id = graph->listeners.filter_filter_ports_connected->len - 1;
-       BT_LIB_LOGV("Added \"filter to filter component ports connected\" listener to graph: "
-               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
-               listener_id);
-
-       if (listener_id) {
-               *out_listener_id = listener_id;
-       }
-
-       return BT_GRAPH_STATUS_OK;
-}
-
-enum bt_graph_status
-bt_graph_add_filter_sink_component_ports_connected_listener(
-               struct bt_graph *graph,
-               bt_graph_filter_sink_component_ports_connected_listener_func func,
-               bt_graph_listener_removed_func listener_removed, void *data,
-               int *out_listener_id)
-{
-       struct bt_graph_listener_ports_connected listener = {
-               .base = {
-                       .removed = listener_removed,
-                       .data = data,
-               },
-               .func = (ports_connected_func_t) func,
-       };
-       int listener_id;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(func, "Listener");
-       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
-       BT_ASSERT_PRE(!graph->in_remove_listener,
-               "Graph currently executing a \"listener removed\" listener: "
-               "%!+g", graph);
-       g_array_append_val(graph->listeners.filter_sink_ports_connected,
-               listener);
-       listener_id = graph->listeners.filter_sink_ports_connected->len - 1;
-       BT_LIB_LOGV("Added \"filter to sink component ports connected\" listener to graph: "
-               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
-               listener_id);
-
-       if (listener_id) {
-               *out_listener_id = listener_id;
-       }
-
-       return BT_GRAPH_STATUS_OK;
-}
-
-BT_HIDDEN
-enum bt_graph_listener_status bt_graph_notify_port_added(
-               struct bt_graph *graph, struct bt_port *port)
-{
-       uint64_t i;
-       GArray *listeners;
-       struct bt_component *comp;
-       enum bt_graph_listener_status status = BT_GRAPH_LISTENER_STATUS_OK;
-
-       BT_ASSERT(graph);
-       BT_ASSERT(port);
-       BT_LIB_LOGV("Notifying graph listeners that a port was added: "
-               "%![graph-]+g, %![port-]+p", graph, port);
-       comp = bt_port_borrow_component_inline(port);
-       BT_ASSERT(comp);
-
-       switch (comp->class->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               switch (port->type) {
-               case BT_PORT_TYPE_OUTPUT:
-                       listeners = graph->listeners.source_output_port_added;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               switch (port->type) {
-               case BT_PORT_TYPE_INPUT:
-                       listeners = graph->listeners.filter_input_port_added;
-                       break;
-               case BT_PORT_TYPE_OUTPUT:
-                       listeners = graph->listeners.filter_output_port_added;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-       {
-               switch (port->type) {
-               case BT_PORT_TYPE_INPUT:
-                       listeners = graph->listeners.sink_input_port_added;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       default:
-               abort();
-       }
-
-       for (i = 0; i < listeners->len; i++) {
-               struct bt_graph_listener_port_added *listener =
-                       &g_array_index(listeners,
-                               struct bt_graph_listener_port_added, i);
-
-
-               BT_ASSERT(listener->func);
-               status = listener->func(comp, port, listener->base.data);
-               if (status != BT_GRAPH_LISTENER_STATUS_OK) {
-                       goto end;
-               }
-       }
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-enum bt_graph_listener_status bt_graph_notify_ports_connected(
-               struct bt_graph *graph, struct bt_port *upstream_port,
-               struct bt_port *downstream_port)
-{
-       uint64_t i;
-       GArray *listeners;
-       struct bt_component *upstream_comp;
-       struct bt_component *downstream_comp;
-       enum bt_graph_listener_status status = BT_GRAPH_LISTENER_STATUS_OK;
-
-       BT_ASSERT(graph);
-       BT_ASSERT(upstream_port);
-       BT_ASSERT(downstream_port);
-       BT_LIB_LOGV("Notifying graph listeners that ports were connected: "
-               "%![graph-]+g, %![up-port-]+p, %![down-port-]+p",
-               graph, upstream_port, downstream_port);
-       upstream_comp = bt_port_borrow_component_inline(upstream_port);
-       BT_ASSERT(upstream_comp);
-       downstream_comp = bt_port_borrow_component_inline(downstream_port);
-       BT_ASSERT(downstream_comp);
-
-       switch (upstream_comp->class->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               switch (downstream_comp->class->type) {
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       listeners =
-                               graph->listeners.source_filter_ports_connected;
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       listeners =
-                               graph->listeners.source_sink_ports_connected;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               switch (downstream_comp->class->type) {
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       listeners =
-                               graph->listeners.filter_filter_ports_connected;
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       listeners =
-                               graph->listeners.filter_sink_ports_connected;
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       default:
-               abort();
-       }
-
-       for (i = 0; i < listeners->len; i++) {
-               struct bt_graph_listener_ports_connected *listener =
-                       &g_array_index(listeners,
-                               struct bt_graph_listener_ports_connected, i);
-
-               BT_ASSERT(listener->func);
-               status = listener->func(upstream_comp, downstream_comp,
-                       upstream_port, downstream_port, listener->base.data);
-               if (status != BT_GRAPH_LISTENER_STATUS_OK) {
-                       goto end;
-               }
-       }
-
-end:
-       return status;
-}
-
-enum bt_graph_status bt_graph_cancel(struct bt_graph *graph)
-{
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       graph->canceled = true;
-       BT_LIB_LOGV("Canceled graph: %!+i", graph);
-       return BT_GRAPH_STATUS_OK;
-}
-
-bt_bool bt_graph_is_canceled(const struct bt_graph *graph)
-{
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       return graph->canceled ? BT_TRUE : BT_FALSE;
-}
-
-BT_HIDDEN
-void bt_graph_remove_connection(struct bt_graph *graph,
-               struct bt_connection *connection)
-{
-       BT_ASSERT(graph);
-       BT_ASSERT(connection);
-       BT_LIB_LOGV("Removing graph's connection: %![graph-]+g, %![conn-]+x",
-               graph, connection);
-       g_ptr_array_remove(graph->connections, connection);
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-bool component_name_exists(struct bt_graph *graph, const char *name)
-{
-       bool exists = false;
-       uint64_t i;
-
-       for (i = 0; i < graph->components->len; i++) {
-               struct bt_component *other_comp = graph->components->pdata[i];
-
-               if (strcmp(name, bt_component_get_name(other_comp)) == 0) {
-                       BT_ASSERT_PRE_MSG("Another component with the same name already exists in the graph: "
-                               "%![other-comp-]+c, name=\"%s\"",
-                               other_comp, name);
-                       exists = true;
-                       goto end;
-               }
-       }
-
-end:
-       return exists;
-}
-
-static
-enum bt_graph_status add_component_with_init_method_data(
-               struct bt_graph *graph,
-               struct bt_component_class *comp_cls,
-               comp_init_method_t init_method,
-               const char *name, const struct bt_value *params,
-               void *init_method_data, struct bt_component **user_component)
-{
-       enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
-       enum bt_self_component_status comp_status;
-       struct bt_component *component = NULL;
-       int ret;
-       bool init_can_consume;
-       struct bt_value *new_params = NULL;
-
-       BT_ASSERT(comp_cls);
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
-       BT_ASSERT_PRE(
-               graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not in the \"configuring\" state: %!+g", graph);
-       BT_ASSERT_PRE(!component_name_exists(graph, name),
-               "Duplicate component name: %!+g, name=\"%s\"", graph, name);
-       BT_ASSERT_PRE(!params || bt_value_is_map(params),
-               "Parameter value is not a map value: %!+v", params);
-       init_can_consume = graph->can_consume;
-       bt_graph_set_can_consume(graph, false);
-       BT_LIB_LOGD("Adding component to graph: "
-               "%![graph-]+g, %![cc-]+C, name=\"%s\", %![params-]+v, "
-               "init-method-data-addr=%p",
-               graph, comp_cls, name, params, init_method_data);
-
-       if (!params) {
-               new_params = bt_value_map_create();
-               if (!new_params) {
-                       BT_LOGE_STR("Cannot create map value object.");
-                       graph_status = BT_GRAPH_STATUS_NOMEM;
-                       goto end;
-               }
-
-               params = new_params;
-       }
-
-       ret = bt_component_create(comp_cls, name, &component);
-       if (ret) {
-               BT_LOGE("Cannot create empty component object: ret=%d",
-                       ret);
-               graph_status = BT_GRAPH_STATUS_NOMEM;
-               goto end;
-       }
-
-       /*
-        * The user's initialization method needs to see that this
-        * component is part of the graph. If the user method fails, we
-        * immediately remove the component from the graph's components.
-        */
-       g_ptr_array_add(graph->components, component);
-       bt_component_set_graph(component, graph);
-       bt_value_freeze(params);
-
-       if (init_method) {
-               BT_LOGD_STR("Calling user's initialization method.");
-               comp_status = init_method(component, params, init_method_data);
-               BT_LOGD("User method returned: status=%s",
-                       bt_self_component_status_string(comp_status));
-               if (comp_status != BT_SELF_COMPONENT_STATUS_OK) {
-                       BT_LOGW_STR("Initialization method failed.");
-                       graph_status = (int) comp_status;
-                       bt_component_set_graph(component, NULL);
-                       g_ptr_array_remove_fast(graph->components, component);
-                       goto end;
-               }
-       }
-
-       /*
-        * Mark the component as initialized so that its finalization
-        * method is called when it is destroyed.
-        */
-       component->initialized = true;
-
-       /*
-        * If it's a sink component, it needs to be part of the graph's
-        * sink queue to be consumed by bt_graph_consume().
-        */
-       if (bt_component_is_sink(component)) {
-               graph->has_sink = true;
-               g_queue_push_tail(graph->sinks_to_consume, component);
-       }
-
-       /*
-        * Freeze the component class now that it's instantiated at
-        * least once.
-        */
-       BT_LOGD_STR("Freezing component class.");
-       bt_component_class_freeze(comp_cls);
-       BT_LIB_LOGD("Added component to graph: "
-               "%![graph-]+g, %![cc-]+C, name=\"%s\", %![params-]+v, "
-               "init-method-data-addr=%p, %![comp-]+c",
-               graph, comp_cls, name, params, init_method_data, component);
-
-       if (user_component) {
-               /* Move reference to user */
-               *user_component = component;
-               component = NULL;
-       }
-
-end:
-       if (graph_status != BT_GRAPH_STATUS_OK) {
-               bt_graph_make_faulty(graph);
-       }
-
-       bt_object_put_ref(component);
-       bt_object_put_ref(new_params);
-       (void) init_can_consume;
-       bt_graph_set_can_consume(graph, init_can_consume);
-       return graph_status;
-}
-
-enum bt_graph_status
-bt_graph_add_source_component_with_init_method_data(
-               struct bt_graph *graph,
-               const struct bt_component_class_source *comp_cls,
-               const char *name, const struct bt_value *params,
-               void *init_method_data,
-               const struct bt_component_source **component)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       return add_component_with_init_method_data(graph,
-               (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
-               name, params, init_method_data, (void *) component);
-}
-
-enum bt_graph_status bt_graph_add_source_component(
-               struct bt_graph *graph,
-               const struct bt_component_class_source *comp_cls,
-               const char *name, const struct bt_value *params,
-               const struct bt_component_source **component)
-{
-       return bt_graph_add_source_component_with_init_method_data(
-               graph, comp_cls, name, params, NULL, component);
-}
-
-enum bt_graph_status
-bt_graph_add_filter_component_with_init_method_data(
-               struct bt_graph *graph,
-               const struct bt_component_class_filter *comp_cls,
-               const char *name, const struct bt_value *params,
-               void *init_method_data,
-               const struct bt_component_filter **component)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       return add_component_with_init_method_data(graph,
-               (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
-               name, params, init_method_data, (void *) component);
-}
-
-enum bt_graph_status bt_graph_add_filter_component(
-               struct bt_graph *graph,
-               const struct bt_component_class_filter *comp_cls,
-               const char *name, const struct bt_value *params,
-               const struct bt_component_filter **component)
-{
-       return bt_graph_add_filter_component_with_init_method_data(
-               graph, comp_cls, name, params, NULL, component);
-}
-
-enum bt_graph_status
-bt_graph_add_sink_component_with_init_method_data(
-               struct bt_graph *graph,
-               const struct bt_component_class_sink *comp_cls,
-               const char *name, const struct bt_value *params,
-               void *init_method_data,
-               const struct bt_component_sink **component)
-{
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       return add_component_with_init_method_data(graph,
-               (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
-               name, params, init_method_data, (void *) component);
-}
-
-enum bt_graph_status bt_graph_add_sink_component(
-               struct bt_graph *graph,
-               const struct bt_component_class_sink *comp_cls,
-               const char *name, const struct bt_value *params,
-               const struct bt_component_sink **component)
-{
-       return bt_graph_add_sink_component_with_init_method_data(
-               graph, comp_cls, name, params, NULL, component);
-}
-
-BT_HIDDEN
-int bt_graph_remove_unconnected_component(struct bt_graph *graph,
-               struct bt_component *component)
-{
-       bool init_can_consume;
-       uint64_t count;
-       uint64_t i;
-       int ret = 0;
-
-       BT_ASSERT(graph);
-       BT_ASSERT(component);
-       BT_ASSERT(component->base.ref_count == 0);
-       BT_ASSERT(bt_component_borrow_graph(component) == graph);
-
-       init_can_consume = graph->can_consume;
-       count = bt_component_get_input_port_count(component);
-
-       for (i = 0; i < count; i++) {
-               struct bt_port *port = (void *)
-                       bt_component_borrow_input_port_by_index(component, i);
-
-               BT_ASSERT(port);
-
-               if (bt_port_is_connected(port)) {
-                       BT_LIB_LOGW("Cannot remove component from graph: "
-                               "an input port is connected: "
-                               "%![graph-]+g, %![comp-]+c, %![port-]+p",
-                               graph, component, port);
-                       goto error;
-               }
-       }
-
-       count = bt_component_get_output_port_count(component);
-
-       for (i = 0; i < count; i++) {
-               struct bt_port *port = (void *)
-                       bt_component_borrow_output_port_by_index(component, i);
-
-               BT_ASSERT(port);
-
-               if (bt_port_is_connected(port)) {
-                       BT_LIB_LOGW("Cannot remove component from graph: "
-                               "an output port is connected: "
-                               "%![graph-]+g, %![comp-]+c, %![port-]+p",
-                               graph, component, port);
-                       goto error;
-               }
-       }
-
-       bt_graph_set_can_consume(graph, false);
-
-       /* Possibly remove from sinks to consume */
-       (void) g_queue_remove(graph->sinks_to_consume, component);
-
-       if (graph->sinks_to_consume->length == 0) {
-               graph->has_sink = false;
-       }
-
-       /*
-        * This calls bt_object_try_spec_release() on the component, and
-        * since its reference count is 0, its destructor is called. Its
-        * destructor calls the user's finalization method (if set).
-        */
-       g_ptr_array_remove(graph->components, component);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       (void) init_can_consume;
-       bt_graph_set_can_consume(graph, init_can_consume);
-       return ret;
-}
-
-BT_HIDDEN
-void bt_graph_add_message(struct bt_graph *graph,
-               struct bt_message *msg)
-{
-       BT_ASSERT(graph);
-       BT_ASSERT(msg);
-
-       /*
-        * It's okay not to take a reference because, when a
-        * message's reference count drops to 0, either:
-        *
-        * * It is recycled back to one of this graph's pool.
-        * * It is destroyed because it doesn't have any link to any
-        *   graph, which means the original graph is already destroyed.
-        */
-       g_ptr_array_add(graph->messages, msg);
-}
-
-void bt_graph_get_ref(const struct bt_graph *graph)
-{
-       bt_object_get_ref(graph);
-}
-
-void bt_graph_put_ref(const struct bt_graph *graph)
-{
-       bt_object_put_ref(graph);
-}
diff --git a/lib/graph/iterator.c b/lib/graph/iterator.c
deleted file mode 100644 (file)
index aec91f1..0000000
+++ /dev/null
@@ -1,1472 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "MSG-ITER"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/field.h>
-#include <babeltrace2/trace-ir/event-const.h>
-#include <babeltrace2/trace-ir/event-internal.h>
-#include <babeltrace2/trace-ir/packet-const.h>
-#include <babeltrace2/trace-ir/packet-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/graph/connection-const.h>
-#include <babeltrace2/graph/connection-internal.h>
-#include <babeltrace2/graph/component-const.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/component-source-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/graph/component-class-sink-colander-internal.h>
-#include <babeltrace2/graph/component-sink-const.h>
-#include <babeltrace2/graph/component-sink-internal.h>
-#include <babeltrace2/graph/message-const.h>
-#include <babeltrace2/graph/message-iterator-const.h>
-#include <babeltrace2/graph/message-iterator-internal.h>
-#include <babeltrace2/graph/self-component-port-input-message-iterator.h>
-#include <babeltrace2/graph/port-output-message-iterator.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/graph/message-event-const.h>
-#include <babeltrace2/graph/message-event-internal.h>
-#include <babeltrace2/graph/message-packet-beginning-const.h>
-#include <babeltrace2/graph/message-packet-end-const.h>
-#include <babeltrace2/graph/message-packet-internal.h>
-#include <babeltrace2/graph/message-stream-beginning-const.h>
-#include <babeltrace2/graph/message-stream-end-const.h>
-#include <babeltrace2/graph/message-stream-internal.h>
-#include <babeltrace2/graph/message-message-iterator-inactivity-internal.h>
-#include <babeltrace2/graph/message-discarded-items-internal.h>
-#include <babeltrace2/graph/message-stream-activity-internal.h>
-#include <babeltrace2/graph/port-const.h>
-#include <babeltrace2/graph/graph.h>
-#include <babeltrace2/graph/graph-const.h>
-#include <babeltrace2/graph/graph-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-/*
- * TODO: Use graph's state (number of active iterators, etc.) and
- * possibly system specifications to make a better guess than this.
- */
-#define MSG_BATCH_SIZE 15
-
-#define BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(_iter)                    \
-       BT_ASSERT_PRE((_iter)->state == BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE || \
-               (_iter)->state == BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED || \
-               (_iter)->state == BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN || \
-               (_iter)->state == BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR, \
-               "Message iterator is in the wrong state: %!+i", _iter)
-
-static inline
-void set_self_comp_port_input_msg_iterator_state(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               enum bt_self_component_port_input_message_iterator_state state)
-{
-       BT_ASSERT(iterator);
-       BT_LIB_LOGD("Updating message iterator's state: new-state=%s",
-               bt_self_component_port_input_message_iterator_state_string(state));
-       iterator->state = state;
-}
-
-static
-void destroy_base_message_iterator(struct bt_object *obj)
-{
-       struct bt_message_iterator *iterator = (void *) obj;
-
-       BT_ASSERT(iterator);
-
-       if (iterator->msgs) {
-               g_ptr_array_free(iterator->msgs, TRUE);
-               iterator->msgs = NULL;
-       }
-
-       g_free(iterator);
-}
-
-static
-void bt_self_component_port_input_message_iterator_destroy(struct bt_object *obj)
-{
-       struct bt_self_component_port_input_message_iterator *iterator;
-
-       BT_ASSERT(obj);
-
-       /*
-        * The message iterator's reference count is 0 if we're
-        * here. Increment it to avoid a double-destroy (possibly
-        * infinitely recursive). This could happen for example if the
-        * message iterator's finalization function does
-        * bt_object_get_ref() (or anything that causes
-        * bt_object_get_ref() to be called) on itself (ref. count goes
-        * from 0 to 1), and then bt_object_put_ref(): the reference
-        * count would go from 1 to 0 again and this function would be
-        * called again.
-        */
-       obj->ref_count++;
-       iterator = (void *) obj;
-       BT_LIB_LOGD("Destroying self component input port message iterator object: "
-               "%!+i", iterator);
-       bt_self_component_port_input_message_iterator_try_finalize(iterator);
-
-       if (iterator->connection) {
-               /*
-                * Remove ourself from the originating connection so
-                * that it does not try to finalize a dangling pointer
-                * later.
-                */
-               bt_connection_remove_iterator(iterator->connection, iterator);
-               iterator->connection = NULL;
-       }
-
-       if (iterator->auto_seek_msgs) {
-               while (!g_queue_is_empty(iterator->auto_seek_msgs)) {
-                       bt_object_put_no_null_check(
-                               g_queue_pop_tail(iterator->auto_seek_msgs));
-               }
-
-               g_queue_free(iterator->auto_seek_msgs);
-               iterator->auto_seek_msgs = NULL;
-       }
-
-       destroy_base_message_iterator(obj);
-}
-
-BT_HIDDEN
-void bt_self_component_port_input_message_iterator_try_finalize(
-               struct bt_self_component_port_input_message_iterator *iterator)
-{
-       typedef void (*method_t)(void *);
-
-       struct bt_component_class *comp_class = NULL;
-       method_t method = NULL;
-
-       BT_ASSERT(iterator);
-
-       switch (iterator->state) {
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_NON_INITIALIZED:
-               /* Skip user finalization if user initialization failed */
-               BT_LIB_LOGD("Not finalizing non-initialized message iterator: "
-                       "%!+i", iterator);
-               goto end;
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED:
-               /* Already finalized */
-               BT_LIB_LOGD("Not finalizing message iterator: already finalized: "
-                       "%!+i", iterator);
-               goto end;
-       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING:
-               /* Already finalized */
-               BT_LIB_LOGF("Message iterator is already being finalized: "
-                       "%!+i", iterator);
-               abort();
-       default:
-               break;
-       }
-
-       BT_LIB_LOGD("Finalizing message iterator: %!+i", iterator);
-       set_self_comp_port_input_msg_iterator_state(iterator,
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING);
-       BT_ASSERT(iterator->upstream_component);
-       comp_class = iterator->upstream_component->class;
-
-       /* Call user-defined destroy method */
-       switch (comp_class->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               struct bt_component_class_source *src_comp_cls =
-                       (void *) comp_class;
-
-               method = (method_t) src_comp_cls->methods.msg_iter_finalize;
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               struct bt_component_class_filter *flt_comp_cls =
-                       (void *) comp_class;
-
-               method = (method_t) flt_comp_cls->methods.msg_iter_finalize;
-               break;
-       }
-       default:
-               /* Unreachable */
-               abort();
-       }
-
-       if (method) {
-               BT_LIB_LOGD("Calling user's finalization method: %!+i",
-                       iterator);
-               method(iterator);
-       }
-
-       iterator->upstream_component = NULL;
-       iterator->upstream_port = NULL;
-       set_self_comp_port_input_msg_iterator_state(iterator,
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED);
-       BT_LIB_LOGD("Finalized message iterator: %!+i", iterator);
-
-end:
-       return;
-}
-
-BT_HIDDEN
-void bt_self_component_port_input_message_iterator_set_connection(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               struct bt_connection *connection)
-{
-       BT_ASSERT(iterator);
-       iterator->connection = connection;
-       BT_LIB_LOGV("Set message iterator's connection: "
-               "%![iter-]+i, %![conn-]+x", iterator, connection);
-}
-
-static
-int init_message_iterator(struct bt_message_iterator *iterator,
-               enum bt_message_iterator_type type,
-               bt_object_release_func destroy)
-{
-       int ret = 0;
-
-       bt_object_init_shared(&iterator->base, destroy);
-       iterator->type = type;
-       iterator->msgs = g_ptr_array_new();
-       if (!iterator->msgs) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_set_size(iterator->msgs, MSG_BATCH_SIZE);
-
-end:
-       return ret;
-}
-
-static
-bt_bool can_seek_ns_from_origin_true(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin)
-{
-       return BT_TRUE;
-}
-
-static
-bt_bool can_seek_beginning_true(
-               struct bt_self_component_port_input_message_iterator *iterator)
-{
-       return BT_TRUE;
-}
-
-static
-struct bt_self_component_port_input_message_iterator *
-bt_self_component_port_input_message_iterator_create_initial(
-               struct bt_component *upstream_comp,
-               struct bt_port *upstream_port)
-{
-       int ret;
-       struct bt_self_component_port_input_message_iterator *iterator = NULL;
-
-       BT_ASSERT(upstream_comp);
-       BT_ASSERT(upstream_port);
-       BT_ASSERT(bt_port_is_connected(upstream_port));
-       BT_LIB_LOGD("Creating initial message iterator on self component input port: "
-               "%![up-comp-]+c, %![up-port-]+p", upstream_comp, upstream_port);
-       BT_ASSERT(bt_component_get_class_type(upstream_comp) ==
-               BT_COMPONENT_CLASS_TYPE_SOURCE ||
-               bt_component_get_class_type(upstream_comp) ==
-               BT_COMPONENT_CLASS_TYPE_FILTER);
-       iterator = g_new0(
-               struct bt_self_component_port_input_message_iterator, 1);
-       if (!iterator) {
-               BT_LOGE_STR("Failed to allocate one self component input port "
-                       "message iterator.");
-               goto end;
-       }
-
-       ret = init_message_iterator((void *) iterator,
-               BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT,
-               bt_self_component_port_input_message_iterator_destroy);
-       if (ret) {
-               /* init_message_iterator() logs errors */
-               BT_OBJECT_PUT_REF_AND_RESET(iterator);
-               goto end;
-       }
-
-       iterator->auto_seek_msgs = g_queue_new();
-       if (!iterator->auto_seek_msgs) {
-               BT_LOGE_STR("Failed to allocate a GQueue.");
-               ret = -1;
-               goto end;
-       }
-
-       iterator->upstream_component = upstream_comp;
-       iterator->upstream_port = upstream_port;
-       iterator->connection = iterator->upstream_port->connection;
-       iterator->graph = bt_component_borrow_graph(upstream_comp);
-       set_self_comp_port_input_msg_iterator_state(iterator,
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_NON_INITIALIZED);
-
-       switch (iterator->upstream_component->class->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               struct bt_component_class_source *src_comp_cls =
-                       (void *) iterator->upstream_component->class;
-
-               iterator->methods.next =
-                       (bt_self_component_port_input_message_iterator_next_method)
-                               src_comp_cls->methods.msg_iter_next;
-               iterator->methods.seek_ns_from_origin =
-                       (bt_self_component_port_input_message_iterator_seek_ns_from_origin_method)
-                               src_comp_cls->methods.msg_iter_seek_ns_from_origin;
-               iterator->methods.seek_beginning =
-                       (bt_self_component_port_input_message_iterator_seek_beginning_method)
-                               src_comp_cls->methods.msg_iter_seek_beginning;
-               iterator->methods.can_seek_ns_from_origin =
-                       (bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method)
-                               src_comp_cls->methods.msg_iter_can_seek_ns_from_origin;
-               iterator->methods.can_seek_beginning =
-                       (bt_self_component_port_input_message_iterator_can_seek_beginning_method)
-                               src_comp_cls->methods.msg_iter_can_seek_beginning;
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               struct bt_component_class_filter *flt_comp_cls =
-                       (void *) iterator->upstream_component->class;
-
-               iterator->methods.next =
-                       (bt_self_component_port_input_message_iterator_next_method)
-                               flt_comp_cls->methods.msg_iter_next;
-               iterator->methods.seek_ns_from_origin =
-                       (bt_self_component_port_input_message_iterator_seek_ns_from_origin_method)
-                               flt_comp_cls->methods.msg_iter_seek_ns_from_origin;
-               iterator->methods.seek_beginning =
-                       (bt_self_component_port_input_message_iterator_seek_beginning_method)
-                               flt_comp_cls->methods.msg_iter_seek_beginning;
-               iterator->methods.can_seek_ns_from_origin =
-                       (bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method)
-                               flt_comp_cls->methods.msg_iter_can_seek_ns_from_origin;
-               iterator->methods.can_seek_beginning =
-                       (bt_self_component_port_input_message_iterator_can_seek_beginning_method)
-                               flt_comp_cls->methods.msg_iter_can_seek_beginning;
-               break;
-       }
-       default:
-               abort();
-       }
-
-       if (iterator->methods.seek_ns_from_origin &&
-                       !iterator->methods.can_seek_ns_from_origin) {
-               iterator->methods.can_seek_ns_from_origin =
-                       (bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method)
-                               can_seek_ns_from_origin_true;
-       }
-
-       if (iterator->methods.seek_beginning &&
-                       !iterator->methods.can_seek_beginning) {
-               iterator->methods.can_seek_beginning =
-                       (bt_self_component_port_input_message_iterator_seek_beginning_method)
-                               can_seek_beginning_true;
-       }
-
-       BT_LIB_LOGD("Created initial message iterator on self component input port: "
-               "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
-               upstream_port, upstream_comp, iterator);
-
-end:
-       return iterator;
-}
-
-struct bt_self_component_port_input_message_iterator *
-bt_self_component_port_input_message_iterator_create(
-               struct bt_self_component_port_input *self_port)
-{
-       typedef enum bt_self_message_iterator_status (*init_method_t)(
-                       void *, void *, void *);
-
-       init_method_t init_method = NULL;
-       struct bt_self_component_port_input_message_iterator *iterator =
-               NULL;
-       struct bt_port *port = (void *) self_port;
-       struct bt_port *upstream_port;
-       struct bt_component *comp;
-       struct bt_component *upstream_comp;
-       struct bt_component_class *upstream_comp_cls;
-
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       comp = bt_port_borrow_component_inline(port);
-       BT_ASSERT_PRE(bt_port_is_connected(port),
-               "Port is not connected: %![port-]+p", port);
-       BT_ASSERT_PRE(comp, "Port is not part of a component: %![port-]+p",
-               port);
-       BT_ASSERT_PRE(!bt_component_graph_is_canceled(comp),
-               "Port's component's graph is canceled: "
-               "%![port-]+p, %![comp-]+c", port, comp);
-       BT_ASSERT(port->connection);
-       upstream_port = port->connection->upstream_port;
-       BT_ASSERT(upstream_port);
-       upstream_comp = bt_port_borrow_component_inline(upstream_port);
-       BT_ASSERT(upstream_comp);
-       BT_ASSERT_PRE(
-               bt_component_borrow_graph(upstream_comp)->config_state !=
-                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not configured: %!+g",
-               bt_component_borrow_graph(upstream_comp));
-       upstream_comp_cls = upstream_comp->class;
-       BT_ASSERT(upstream_comp->class->type ==
-               BT_COMPONENT_CLASS_TYPE_SOURCE ||
-               upstream_comp->class->type ==
-               BT_COMPONENT_CLASS_TYPE_FILTER);
-       iterator = bt_self_component_port_input_message_iterator_create_initial(
-               upstream_comp, upstream_port);
-       if (!iterator) {
-               BT_LOGW_STR("Cannot create self component input port "
-                       "message iterator.");
-               goto end;
-       }
-
-       switch (upstream_comp_cls->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               struct bt_component_class_source *src_comp_cls =
-                       (void *) upstream_comp_cls;
-
-               init_method =
-                       (init_method_t) src_comp_cls->methods.msg_iter_init;
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               struct bt_component_class_filter *flt_comp_cls =
-                       (void *) upstream_comp_cls;
-
-               init_method =
-                       (init_method_t) flt_comp_cls->methods.msg_iter_init;
-               break;
-       }
-       default:
-               /* Unreachable */
-               abort();
-       }
-
-       if (init_method) {
-               int iter_status;
-
-               BT_LIB_LOGD("Calling user's initialization method: %!+i", iterator);
-               iter_status = init_method(iterator, upstream_comp,
-                       upstream_port);
-               BT_LOGD("User method returned: status=%s",
-                       bt_message_iterator_status_string(iter_status));
-               if (iter_status != BT_MESSAGE_ITERATOR_STATUS_OK) {
-                       BT_LOGW_STR("Initialization method failed.");
-                       BT_OBJECT_PUT_REF_AND_RESET(iterator);
-                       goto end;
-               }
-       }
-
-       set_self_comp_port_input_msg_iterator_state(iterator,
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE);
-       g_ptr_array_add(port->connection->iterators, iterator);
-       BT_LIB_LOGD("Created message iterator on self component input port: "
-               "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
-               upstream_port, upstream_comp, iterator);
-
-end:
-       return iterator;
-}
-
-void *bt_self_message_iterator_get_data(
-               const struct bt_self_message_iterator *self_iterator)
-{
-       struct bt_self_component_port_input_message_iterator *iterator =
-               (void *) self_iterator;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return iterator->user_data;
-}
-
-void bt_self_message_iterator_set_data(
-               struct bt_self_message_iterator *self_iterator, void *data)
-{
-       struct bt_self_component_port_input_message_iterator *iterator =
-               (void *) self_iterator;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       iterator->user_data = data;
-       BT_LIB_LOGV("Set message iterator's user data: "
-               "%!+i, user-data-addr=%p", iterator, data);
-}
-
-enum bt_message_iterator_status
-bt_self_component_port_input_message_iterator_next(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               bt_message_array_const *msgs, uint64_t *user_count)
-{
-       int status = BT_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       BT_ASSERT_PRE_NON_NULL(msgs, "Message array (output)");
-       BT_ASSERT_PRE_NON_NULL(user_count, "Message count (output)");
-       BT_ASSERT_PRE(iterator->state ==
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE,
-               "Message iterator's \"next\" called, but "
-               "message iterator is in the wrong state: %!+i", iterator);
-       BT_ASSERT(iterator->upstream_component);
-       BT_ASSERT(iterator->upstream_component->class);
-       BT_ASSERT_PRE(
-               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
-                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not configured: %!+g",
-               bt_component_borrow_graph(iterator->upstream_component));
-       BT_LIB_LOGD("Getting next self component input port "
-               "message iterator's messages: %!+i", iterator);
-
-       /*
-        * Call the user's "next" method to get the next messages
-        * and status.
-        */
-       BT_ASSERT(iterator->methods.next);
-       BT_LOGD_STR("Calling user's \"next\" method.");
-       status = iterator->methods.next(iterator,
-               (void *) iterator->base.msgs->pdata, MSG_BATCH_SIZE,
-               user_count);
-       BT_LOGD("User method returned: status=%s",
-               bt_message_iterator_status_string(status));
-       if (status < 0) {
-               BT_LOGW_STR("User method failed.");
-               goto end;
-       }
-
-       /*
-        * There is no way that this iterator could have been finalized
-        * during its "next" method, as the only way to do this is to
-        * put the last iterator's reference, and this can only be done
-        * by its downstream owner.
-        *
-        * For the same reason, there is no way that this iterator could
-        * have seeked (cannot seek a self message iterator).
-        */
-       BT_ASSERT(iterator->state ==
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE);
-
-       switch (status) {
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-               BT_ASSERT_PRE(*user_count <= MSG_BATCH_SIZE,
-                       "Invalid returned message count: greater than "
-                       "batch size: count=%" PRIu64 ", batch-size=%u",
-                       *user_count, MSG_BATCH_SIZE);
-               *msgs = (void *) iterator->base.msgs->pdata;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_END:
-               set_self_comp_port_input_msg_iterator_state(iterator,
-                       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED);
-               goto end;
-       default:
-               /* Unknown non-error status */
-               abort();
-       }
-
-end:
-       return status;
-}
-
-enum bt_message_iterator_status bt_port_output_message_iterator_next(
-               struct bt_port_output_message_iterator *iterator,
-               bt_message_array_const *msgs_to_user,
-               uint64_t *count_to_user)
-{
-       enum bt_message_iterator_status status;
-       enum bt_graph_status graph_status;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       BT_ASSERT_PRE_NON_NULL(msgs_to_user, "Message array (output)");
-       BT_ASSERT_PRE_NON_NULL(count_to_user, "Message count (output)");
-       BT_LIB_LOGD("Getting next output port message iterator's messages: "
-               "%!+i", iterator);
-       graph_status = bt_graph_consume_sink_no_check(iterator->graph,
-               iterator->colander);
-       switch (graph_status) {
-       case BT_GRAPH_STATUS_CANCELED:
-       case BT_GRAPH_STATUS_AGAIN:
-       case BT_GRAPH_STATUS_END:
-       case BT_GRAPH_STATUS_NOMEM:
-               status = (int) graph_status;
-               break;
-       case BT_GRAPH_STATUS_OK:
-               status = BT_MESSAGE_ITERATOR_STATUS_OK;
-
-               /*
-                * On success, the colander sink moves the messages
-                * to this iterator's array and sets this iterator's
-                * message count: move them to the user.
-                */
-               *msgs_to_user = (void *) iterator->base.msgs->pdata;
-               *count_to_user = iterator->count;
-               break;
-       default:
-               /* Other errors */
-               status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
-       }
-
-       return status;
-}
-
-struct bt_component *
-bt_self_component_port_input_message_iterator_borrow_component(
-               struct bt_self_component_port_input_message_iterator *iterator)
-{
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return iterator->upstream_component;
-}
-
-const struct bt_component *
-bt_self_component_port_input_message_iterator_borrow_component_const(
-               const struct bt_self_component_port_input_message_iterator *iterator)
-{
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return iterator->upstream_component;
-}
-
-struct bt_self_component *bt_self_message_iterator_borrow_component(
-               struct bt_self_message_iterator *self_iterator)
-{
-       struct bt_self_component_port_input_message_iterator *iterator =
-               (void *) self_iterator;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return (void *) iterator->upstream_component;
-}
-
-struct bt_self_port_output *bt_self_message_iterator_borrow_port(
-               struct bt_self_message_iterator *self_iterator)
-{
-       struct bt_self_component_port_input_message_iterator *iterator =
-               (void *) self_iterator;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return (void *) iterator->upstream_port;
-}
-
-static
-void bt_port_output_message_iterator_destroy(struct bt_object *obj)
-{
-       struct bt_port_output_message_iterator *iterator = (void *) obj;
-
-       BT_LIB_LOGD("Destroying output port message iterator object: %!+i",
-               iterator);
-       BT_LOGD_STR("Putting graph.");
-       BT_OBJECT_PUT_REF_AND_RESET(iterator->graph);
-       BT_LOGD_STR("Putting colander sink component.");
-       BT_OBJECT_PUT_REF_AND_RESET(iterator->colander);
-       destroy_base_message_iterator(obj);
-}
-
-struct bt_port_output_message_iterator *
-bt_port_output_message_iterator_create(struct bt_graph *graph,
-               const struct bt_port_output *output_port)
-{
-       struct bt_port_output_message_iterator *iterator = NULL;
-       struct bt_component_class_sink *colander_comp_cls = NULL;
-       struct bt_component *output_port_comp = NULL;
-       struct bt_component_sink *colander_comp;
-       enum bt_graph_status graph_status;
-       struct bt_port_input *colander_in_port = NULL;
-       struct bt_component_class_sink_colander_data colander_data;
-       int ret;
-
-       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
-       BT_ASSERT_PRE_NON_NULL(output_port, "Output port");
-       output_port_comp = bt_port_borrow_component_inline(
-               (const void *) output_port);
-       BT_ASSERT_PRE(output_port_comp,
-               "Output port has no component: %!+p", output_port);
-       BT_ASSERT_PRE(bt_component_borrow_graph(output_port_comp) ==
-               (void *) graph,
-               "Output port is not part of graph: %![graph-]+g, %![port-]+p",
-               graph, output_port);
-       BT_ASSERT_PRE(!graph->has_sink,
-               "Graph already has a sink component: %![graph-]+g");
-
-       /* Create message iterator */
-       BT_LIB_LOGD("Creating message iterator on output port: "
-               "%![port-]+p, %![comp-]+c", output_port, output_port_comp);
-       iterator = g_new0(struct bt_port_output_message_iterator, 1);
-       if (!iterator) {
-               BT_LOGE_STR("Failed to allocate one output port message iterator.");
-               goto error;
-       }
-
-       ret = init_message_iterator((void *) iterator,
-               BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT,
-               bt_port_output_message_iterator_destroy);
-       if (ret) {
-               /* init_message_iterator() logs errors */
-               BT_OBJECT_PUT_REF_AND_RESET(iterator);
-               goto end;
-       }
-
-       /* Create colander component */
-       colander_comp_cls = bt_component_class_sink_colander_get();
-       if (!colander_comp_cls) {
-               BT_LOGW("Cannot get colander sink component class.");
-               goto error;
-       }
-
-       iterator->graph = graph;
-       bt_object_get_no_null_check(iterator->graph);
-       colander_data.msgs = (void *) iterator->base.msgs->pdata;
-       colander_data.count_addr = &iterator->count;
-
-       /* Hope that nobody uses this very unique name */
-       graph_status =
-               bt_graph_add_sink_component_with_init_method_data(
-                       (void *) graph, colander_comp_cls,
-                       "colander-36ac3409-b1a8-4d60-ab1f-4fdf341a8fb1",
-                       NULL, &colander_data, (void *) &iterator->colander);
-       if (graph_status != BT_GRAPH_STATUS_OK) {
-               BT_LIB_LOGW("Cannot add colander sink component to graph: "
-                       "%1[graph-]+g, status=%s", graph,
-                       bt_graph_status_string(graph_status));
-               goto error;
-       }
-
-       /*
-        * Connect provided output port to the colander component's
-        * input port.
-        */
-       colander_in_port =
-               (void *) bt_component_sink_borrow_input_port_by_index_const(
-                       (void *) iterator->colander, 0);
-       BT_ASSERT(colander_in_port);
-       graph_status = bt_graph_connect_ports(graph,
-               output_port, colander_in_port, NULL);
-       if (graph_status != BT_GRAPH_STATUS_OK) {
-               BT_LIB_LOGW("Cannot add colander sink component to graph: "
-                       "%![graph-]+g, %![comp-]+c, status=%s", graph,
-                       iterator->colander,
-                       bt_graph_status_string(graph_status));
-               goto error;
-       }
-
-       /*
-        * At this point everything went fine. Make the graph
-        * nonconsumable forever so that only this message iterator
-        * can consume (thanks to bt_graph_consume_sink_no_check()).
-        * This avoids leaking the message created by the colander
-        * sink and moved to the message iterator's message
-        * member.
-        */
-       bt_graph_set_can_consume(iterator->graph, false);
-
-       /* Also set the graph as being configured. */
-       graph_status = bt_graph_configure(graph);
-       if (graph_status != BT_GRAPH_STATUS_OK) {
-               BT_LIB_LOGW("Cannot configure graph after having added colander: "
-                       "%![graph-]+g, status=%s", graph,
-                       bt_graph_status_string(graph_status));
-               goto error;
-       }
-       goto end;
-
-error:
-       if (iterator && iterator->graph && iterator->colander) {
-               int ret;
-
-               /* Remove created colander component from graph if any */
-               colander_comp = iterator->colander;
-               BT_OBJECT_PUT_REF_AND_RESET(iterator->colander);
-
-               /*
-                * At this point the colander component's reference
-                * count is 0 because iterator->colander was the only
-                * owner. We also know that it is not connected because
-                * this is the last operation before this function
-                * succeeds.
-                *
-                * Since we honor the preconditions here,
-                * bt_graph_remove_unconnected_component() always
-                * succeeds.
-                */
-               ret = bt_graph_remove_unconnected_component(iterator->graph,
-                       (void *) colander_comp);
-               BT_ASSERT(ret == 0);
-       }
-
-       BT_OBJECT_PUT_REF_AND_RESET(iterator);
-
-end:
-       bt_object_put_ref(colander_comp_cls);
-       return (void *) iterator;
-}
-
-bt_bool bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin)
-{
-       bt_bool can = BT_FALSE;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
-       BT_ASSERT_PRE(
-               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
-                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not configured: %!+g",
-               bt_component_borrow_graph(iterator->upstream_component));
-
-       if (iterator->methods.can_seek_ns_from_origin) {
-               can = iterator->methods.can_seek_ns_from_origin(iterator,
-                       ns_from_origin);
-               goto end;
-       }
-
-       /*
-        * Automatic seeking fall back: if we can seek to the beginning,
-        * then we can automatically seek to any message.
-        */
-       if (iterator->methods.can_seek_beginning) {
-               can = iterator->methods.can_seek_beginning(iterator);
-       }
-
-end:
-       return can;
-}
-
-bt_bool bt_self_component_port_input_message_iterator_can_seek_beginning(
-               struct bt_self_component_port_input_message_iterator *iterator)
-{
-       bt_bool can = BT_FALSE;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
-       BT_ASSERT_PRE(
-               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
-                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not configured: %!+g",
-               bt_component_borrow_graph(iterator->upstream_component));
-
-       if (iterator->methods.can_seek_beginning) {
-               can = iterator->methods.can_seek_beginning(iterator);
-       }
-
-       return can;
-}
-
-static inline
-void set_iterator_state_after_seeking(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               enum bt_message_iterator_status status)
-{
-       enum bt_self_component_port_input_message_iterator_state new_state = 0;
-
-       /* Set iterator's state depending on seeking status */
-       switch (status) {
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-               new_state = BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               new_state = BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_ERROR:
-       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               new_state = BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_END:
-               new_state = BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED;
-               break;
-       default:
-               abort();
-       }
-
-       set_self_comp_port_input_msg_iterator_state(iterator, new_state);
-}
-
-enum bt_message_iterator_status
-bt_self_component_port_input_message_iterator_seek_beginning(
-               struct bt_self_component_port_input_message_iterator *iterator)
-{
-       int status;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
-       BT_ASSERT_PRE(
-               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
-                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not configured: %!+g",
-               bt_component_borrow_graph(iterator->upstream_component));
-       BT_ASSERT_PRE(
-               bt_self_component_port_input_message_iterator_can_seek_beginning(
-                       iterator),
-               "Message iterator cannot seek beginning: %!+i", iterator);
-       BT_LIB_LOGD("Calling user's \"seek beginning\" method: %!+i", iterator);
-       set_self_comp_port_input_msg_iterator_state(iterator,
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING);
-       status = iterator->methods.seek_beginning(iterator);
-       BT_LOGD("User method returned: status=%s",
-               bt_message_iterator_status_string(status));
-       BT_ASSERT_PRE(status == BT_MESSAGE_ITERATOR_STATUS_OK ||
-               status == BT_MESSAGE_ITERATOR_STATUS_ERROR ||
-               status == BT_MESSAGE_ITERATOR_STATUS_NOMEM ||
-               status == BT_MESSAGE_ITERATOR_STATUS_AGAIN,
-               "Unexpected status: %![iter-]+i, status=%s",
-               iterator, bt_common_self_message_iterator_status_string(status));
-       set_iterator_state_after_seeking(iterator, status);
-       return status;
-}
-
-static inline
-enum bt_message_iterator_status auto_seek_handle_message(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin, const struct bt_message *msg,
-               bool *got_first)
-{
-       enum bt_message_iterator_status status = BT_MESSAGE_ITERATOR_STATUS_OK;
-       int64_t msg_ns_from_origin;
-       const struct bt_clock_snapshot *clk_snapshot = NULL;
-       int ret;
-
-       BT_ASSERT(msg);
-       BT_ASSERT(got_first);
-
-       switch (msg->type) {
-       case BT_MESSAGE_TYPE_EVENT:
-       {
-               const struct bt_message_event *event_msg =
-                       (const void *) msg;
-
-               clk_snapshot = event_msg->default_cs;
-               BT_ASSERT_PRE(clk_snapshot,
-                       "Event message has no default clock snapshot: %!+n",
-                       event_msg);
-               break;
-       }
-       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-       {
-               const struct bt_message_message_iterator_inactivity *inactivity_msg =
-                       (const void *) msg;
-
-               clk_snapshot = inactivity_msg->default_cs;
-               BT_ASSERT(clk_snapshot);
-               break;
-       }
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-       case BT_MESSAGE_TYPE_PACKET_END:
-       {
-               const struct bt_message_packet *packet_msg =
-                       (const void *) msg;
-
-               clk_snapshot = packet_msg->default_cs;
-               BT_ASSERT_PRE(clk_snapshot,
-                       "Packet message has no default clock snapshot: %!+n",
-                       packet_msg);
-               break;
-       }
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-       {
-               struct bt_message_discarded_items *msg_disc_items =
-                       (void *) msg;
-
-               BT_ASSERT_PRE(msg_disc_items->default_begin_cs &&
-                       msg_disc_items->default_end_cs,
-                       "Discarded events/packets message has no default clock snapshots: %!+n",
-                       msg_disc_items);
-               ret = bt_clock_snapshot_get_ns_from_origin(
-                       msg_disc_items->default_begin_cs,
-                       &msg_ns_from_origin);
-               if (ret) {
-                       status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
-                       goto end;
-               }
-
-               if (msg_ns_from_origin >= ns_from_origin) {
-                       *got_first = true;
-                       goto push_msg;
-               }
-
-               ret = bt_clock_snapshot_get_ns_from_origin(
-                       msg_disc_items->default_end_cs,
-                       &msg_ns_from_origin);
-               if (ret) {
-                       status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
-                       goto end;
-               }
-
-               if (msg_ns_from_origin >= ns_from_origin) {
-                       /*
-                        * The discarded items message's beginning time
-                        * is before the requested seeking time, but its
-                        * end time is after. Modify the message so as
-                        * to set its beginning time to the requested
-                        * seeking time, and make its item count unknown
-                        * as we don't know if items were really
-                        * discarded within the new time range.
-                        */
-                       uint64_t new_begin_raw_value;
-
-                       ret = bt_clock_class_clock_value_from_ns_from_origin(
-                               msg_disc_items->default_end_cs->clock_class,
-                               ns_from_origin, &new_begin_raw_value);
-                       if (ret) {
-                               status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       bt_clock_snapshot_set_raw_value(
-                               msg_disc_items->default_begin_cs,
-                               new_begin_raw_value);
-                       msg_disc_items->count.base.avail =
-                               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-
-                       /*
-                        * It is safe to push it because its beginning
-                        * time is exactly the requested seeking time.
-                        */
-                       goto push_msg;
-               } else {
-                       goto skip_msg;
-               }
-       }
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-       {
-               const struct bt_message_stream_activity *stream_act_msg =
-                       (const void *) msg;
-
-               switch (stream_act_msg->default_cs_state) {
-               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
-               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
-                       /*
-                        * -inf is always less than any requested time,
-                        * and we can't assume any specific time for an
-                        * unknown clock snapshot, so skip this.
-                        */
-                       goto skip_msg;
-               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
-                       clk_snapshot = stream_act_msg->default_cs;
-                       BT_ASSERT(clk_snapshot);
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-       {
-               const struct bt_message_stream_activity *stream_act_msg =
-                       (const void *) msg;
-
-               switch (stream_act_msg->default_cs_state) {
-               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
-                       /*
-                        * We can't assume any specific time for an
-                        * unknown clock snapshot, so skip this.
-                        */
-                       goto skip_msg;
-               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
-                       /*
-                        * +inf is always greater than any requested
-                        * time.
-                        */
-                       *got_first = true;
-                       goto push_msg;
-               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
-                       clk_snapshot = stream_act_msg->default_cs;
-                       BT_ASSERT(clk_snapshot);
-                       break;
-               default:
-                       abort();
-               }
-
-               break;
-       }
-       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
-       case BT_MESSAGE_TYPE_STREAM_END:
-               /* Ignore */
-               goto skip_msg;
-       default:
-               abort();
-       }
-
-       BT_ASSERT(clk_snapshot);
-       ret = bt_clock_snapshot_get_ns_from_origin(clk_snapshot,
-               &msg_ns_from_origin);
-       if (ret) {
-               status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       if (msg_ns_from_origin >= ns_from_origin) {
-               *got_first = true;
-               goto push_msg;
-       }
-
-skip_msg:
-       bt_object_put_no_null_check(msg);
-       msg = NULL;
-       goto end;
-
-push_msg:
-       g_queue_push_head(iterator->auto_seek_msgs, (void *) msg);
-       msg = NULL;
-
-end:
-       BT_ASSERT(!msg || status != BT_MESSAGE_ITERATOR_STATUS_OK);
-       return status;
-}
-
-static
-enum bt_message_iterator_status find_message_ge_ns_from_origin(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin)
-{
-       int status;
-       enum bt_self_component_port_input_message_iterator_state init_state =
-               iterator->state;
-       const struct bt_message *messages[MSG_BATCH_SIZE];
-       uint64_t user_count = 0;
-       uint64_t i;
-       bool got_first = false;
-
-       BT_ASSERT(iterator);
-       memset(&messages[0], 0, sizeof(messages[0]) * MSG_BATCH_SIZE);
-
-       /*
-        * Make this iterator temporarily active (not seeking) to call
-        * the "next" method.
-        */
-       set_self_comp_port_input_msg_iterator_state(iterator,
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE);
-
-       BT_ASSERT(iterator->methods.next);
-
-       while (!got_first) {
-               /*
-                * Call the user's "next" method to get the next
-                * messages and status.
-                */
-               BT_LOGD_STR("Calling user's \"next\" method.");
-               status = iterator->methods.next(iterator,
-                       &messages[0], MSG_BATCH_SIZE, &user_count);
-               BT_LOGD("User method returned: status=%s",
-                       bt_message_iterator_status_string(status));
-
-               /*
-                * The user's "next" method must not do any action which
-                * would change the iterator's state.
-                */
-               BT_ASSERT(iterator->state ==
-                       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE);
-
-               switch (status) {
-               case BT_MESSAGE_ITERATOR_STATUS_OK:
-                       BT_ASSERT_PRE(user_count <= MSG_BATCH_SIZE,
-                               "Invalid returned message count: greater than "
-                               "batch size: count=%" PRIu64 ", batch-size=%u",
-                               user_count, MSG_BATCH_SIZE);
-                       break;
-               case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               case BT_MESSAGE_ITERATOR_STATUS_ERROR:
-               case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               case BT_MESSAGE_ITERATOR_STATUS_END:
-                       goto end;
-               default:
-                       abort();
-               }
-
-               for (i = 0; i < user_count; i++) {
-                       if (got_first) {
-                               g_queue_push_head(iterator->auto_seek_msgs,
-                                       (void *) messages[i]);
-                               messages[i] = NULL;
-                               continue;
-                       }
-
-                       status = auto_seek_handle_message(iterator,
-                               ns_from_origin, messages[i], &got_first);
-                       if (status == BT_MESSAGE_ITERATOR_STATUS_OK) {
-                               /* Message was either pushed or moved */
-                               messages[i] = NULL;
-                       } else {
-                               goto end;
-                       }
-               }
-       }
-
-end:
-       for (i = 0; i < user_count; i++) {
-               if (messages[i]) {
-                       bt_object_put_no_null_check(messages[i]);
-               }
-       }
-
-       set_self_comp_port_input_msg_iterator_state(iterator, init_state);
-       return status;
-}
-
-static
-enum bt_self_message_iterator_status post_auto_seek_next(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       BT_ASSERT(!g_queue_is_empty(iterator->auto_seek_msgs));
-       *count = 0;
-
-       /*
-        * Move auto-seek messages to the output array (which is this
-        * iterator's base message array).
-        */
-       while (capacity > 0 && !g_queue_is_empty(iterator->auto_seek_msgs)) {
-               msgs[*count] = g_queue_pop_tail(iterator->auto_seek_msgs);
-               capacity--;
-               (*count)++;
-       }
-
-       BT_ASSERT(*count > 0);
-
-       if (g_queue_is_empty(iterator->auto_seek_msgs)) {
-               /* No more auto-seek messages */
-               switch (iterator->upstream_component->class->type) {
-               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-               {
-                       struct bt_component_class_source *src_comp_cls =
-                               (void *) iterator->upstream_component->class;
-
-                       iterator->methods.next =
-                               (bt_self_component_port_input_message_iterator_next_method)
-                                       src_comp_cls->methods.msg_iter_next;
-                       break;
-               }
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-               {
-                       struct bt_component_class_filter *flt_comp_cls =
-                               (void *) iterator->upstream_component->class;
-
-                       iterator->methods.next =
-                               (bt_self_component_port_input_message_iterator_next_method)
-                                       flt_comp_cls->methods.msg_iter_next;
-                       break;
-               }
-               default:
-                       abort();
-               }
-       }
-
-       return BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-}
-
-enum bt_message_iterator_status
-bt_self_component_port_input_message_iterator_seek_ns_from_origin(
-               struct bt_self_component_port_input_message_iterator *iterator,
-               int64_t ns_from_origin)
-{
-       int status;
-
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
-       BT_ASSERT_PRE(
-               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
-                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
-               "Graph is not configured: %!+g",
-               bt_component_borrow_graph(iterator->upstream_component));
-       BT_ASSERT_PRE(
-               bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
-                       iterator, ns_from_origin),
-               "Message iterator cannot seek nanoseconds from origin: %!+i, "
-               "ns-from-origin=%" PRId64, iterator, ns_from_origin);
-       set_self_comp_port_input_msg_iterator_state(iterator,
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING);
-
-       if (iterator->methods.seek_ns_from_origin) {
-               BT_LIB_LOGD("Calling user's \"seek nanoseconds from origin\" method: "
-                       "%![iter-]+i, ns=%" PRId64, iterator, ns_from_origin);
-               status = iterator->methods.seek_ns_from_origin(iterator,
-                       ns_from_origin);
-               BT_LOGD("User method returned: status=%s",
-                       bt_message_iterator_status_string(status));
-               BT_ASSERT_PRE(status == BT_MESSAGE_ITERATOR_STATUS_OK ||
-                       status == BT_MESSAGE_ITERATOR_STATUS_ERROR ||
-                       status == BT_MESSAGE_ITERATOR_STATUS_NOMEM ||
-                       status == BT_MESSAGE_ITERATOR_STATUS_AGAIN,
-                       "Unexpected status: %![iter-]+i, status=%s",
-                       iterator,
-                       bt_common_self_message_iterator_status_string(status));
-       } else {
-               /* Start automatic seeking: seek beginning first */
-               BT_ASSERT(iterator->methods.can_seek_beginning(iterator));
-               BT_ASSERT(iterator->methods.seek_beginning);
-               BT_LIB_LOGD("Calling user's \"seek beginning\" method: %!+i",
-                       iterator);
-               status = iterator->methods.seek_beginning(iterator);
-               BT_LOGD("User method returned: status=%s",
-                       bt_message_iterator_status_string(status));
-               BT_ASSERT_PRE(status == BT_MESSAGE_ITERATOR_STATUS_OK ||
-                       status == BT_MESSAGE_ITERATOR_STATUS_ERROR ||
-                       status == BT_MESSAGE_ITERATOR_STATUS_NOMEM ||
-                       status == BT_MESSAGE_ITERATOR_STATUS_AGAIN,
-                       "Unexpected status: %![iter-]+i, status=%s",
-                       iterator,
-                       bt_common_self_message_iterator_status_string(status));
-               switch (status) {
-               case BT_MESSAGE_ITERATOR_STATUS_OK:
-                       break;
-               case BT_MESSAGE_ITERATOR_STATUS_ERROR:
-               case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-                       goto end;
-               default:
-                       abort();
-               }
-
-               /*
-                * Find the first message which has a default clock
-                * snapshot greater than or equal to the requested
-                * seeking time, and move the received messages from
-                * this point in the batch to this iterator's auto-seek
-                * message queue.
-                */
-               while (!g_queue_is_empty(iterator->auto_seek_msgs)) {
-                       bt_object_put_no_null_check(
-                               g_queue_pop_tail(iterator->auto_seek_msgs));
-               }
-
-               status = find_message_ge_ns_from_origin(iterator,
-                       ns_from_origin);
-               switch (status) {
-               case BT_MESSAGE_ITERATOR_STATUS_OK:
-               case BT_MESSAGE_ITERATOR_STATUS_END:
-                       /*
-                        * If there are messages in the auto-seek
-                        * message queue, replace the user's "next"
-                        * method with a custom, temporary "next" method
-                        * which returns them.
-                        */
-                       if (!g_queue_is_empty(iterator->auto_seek_msgs)) {
-                               iterator->methods.next =
-                                       (bt_self_component_port_input_message_iterator_next_method)
-                                               post_auto_seek_next;
-                       }
-
-                       /*
-                        * `BT_MESSAGE_ITERATOR_STATUS_END` becomes
-                        * `BT_MESSAGE_ITERATOR_STATUS_OK`: the next
-                        * time this iterator's "next" method is called,
-                        * it will return
-                        * `BT_MESSAGE_ITERATOR_STATUS_END`.
-                        */
-                       status = BT_MESSAGE_ITERATOR_STATUS_OK;
-                       break;
-               case BT_MESSAGE_ITERATOR_STATUS_ERROR:
-               case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-                       goto end;
-               default:
-                       abort();
-               }
-       }
-
-end:
-       set_iterator_state_after_seeking(iterator, status);
-       return status;
-}
-
-static inline
-bt_self_component_port_input_message_iterator *
-borrow_output_port_message_iterator_upstream_iterator(
-               struct bt_port_output_message_iterator *iterator)
-{
-       struct bt_component_class_sink_colander_priv_data *colander_data;
-
-       BT_ASSERT(iterator);
-       colander_data = (void *) iterator->colander->parent.user_data;
-       BT_ASSERT(colander_data);
-       BT_ASSERT(colander_data->msg_iter);
-       return colander_data->msg_iter;
-}
-
-bt_bool bt_port_output_message_iterator_can_seek_ns_from_origin(
-               struct bt_port_output_message_iterator *iterator,
-               int64_t ns_from_origin)
-{
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
-               borrow_output_port_message_iterator_upstream_iterator(
-                       iterator), ns_from_origin);
-}
-
-bt_bool bt_port_output_message_iterator_can_seek_beginning(
-               struct bt_port_output_message_iterator *iterator)
-{
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return bt_self_component_port_input_message_iterator_can_seek_beginning(
-               borrow_output_port_message_iterator_upstream_iterator(
-                       iterator));
-}
-
-enum bt_message_iterator_status bt_port_output_message_iterator_seek_ns_from_origin(
-               struct bt_port_output_message_iterator *iterator,
-               int64_t ns_from_origin)
-{
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return bt_self_component_port_input_message_iterator_seek_ns_from_origin(
-               borrow_output_port_message_iterator_upstream_iterator(iterator),
-               ns_from_origin);
-}
-
-enum bt_message_iterator_status bt_port_output_message_iterator_seek_beginning(
-               struct bt_port_output_message_iterator *iterator)
-{
-       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
-       return bt_self_component_port_input_message_iterator_seek_beginning(
-               borrow_output_port_message_iterator_upstream_iterator(
-                       iterator));
-}
-
-void bt_port_output_message_iterator_get_ref(
-               const struct bt_port_output_message_iterator *iterator)
-{
-       bt_object_get_ref(iterator);
-}
-
-void bt_port_output_message_iterator_put_ref(
-               const struct bt_port_output_message_iterator *iterator)
-{
-       bt_object_put_ref(iterator);
-}
-
-void bt_self_component_port_input_message_iterator_get_ref(
-               const struct bt_self_component_port_input_message_iterator *iterator)
-{
-       bt_object_get_ref(iterator);
-}
-
-void bt_self_component_port_input_message_iterator_put_ref(
-               const struct bt_self_component_port_input_message_iterator *iterator)
-{
-       bt_object_put_ref(iterator);
-}
diff --git a/lib/graph/message/Makefile.am b/lib/graph/message/Makefile.am
deleted file mode 100644 (file)
index 9c69099..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-noinst_LTLIBRARIES = libgraph-message.la
-
-libgraph_message_la_SOURCES = \
-       message.c \
-       packet.c \
-       event.c \
-       stream.c \
-       message-iterator-inactivity.c \
-       stream-activity.c \
-       discarded-items.c
diff --git a/lib/graph/message/discarded-items.c b/lib/graph/message/discarded-items.c
deleted file mode 100644 (file)
index 36bdc36..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "MSG-DISCARDED-ITEMS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/clock-class.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/property-internal.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/graph/message-discarded-items-internal.h>
-#include <babeltrace2/graph/message-discarded-events.h>
-#include <babeltrace2/graph/message-discarded-events-const.h>
-#include <babeltrace2/graph/message-discarded-packets.h>
-#include <babeltrace2/graph/message-discarded-packets-const.h>
-
-static
-void destroy_discarded_items_message(struct bt_object *obj)
-{
-       struct bt_message_discarded_items *message = (void *) obj;
-
-       BT_LIB_LOGD("Destroying discarded items message: %!+n", message);
-       BT_LIB_LOGD("Putting stream: %!+s", message->stream);
-       BT_OBJECT_PUT_REF_AND_RESET(message->stream);
-
-       if (message->default_begin_cs) {
-               bt_clock_snapshot_recycle(message->default_begin_cs);
-               message->default_begin_cs = NULL;
-       }
-
-       if (message->default_end_cs) {
-               bt_clock_snapshot_recycle(message->default_end_cs);
-               message->default_end_cs = NULL;
-       }
-
-       g_free(message);
-}
-
-static inline
-struct bt_message *create_discarded_items_message(
-               struct bt_self_message_iterator *self_msg_iter,
-               enum bt_message_type type, struct bt_stream *stream,
-               bool with_cs,
-               uint64_t beginning_raw_value, uint64_t end_raw_value)
-{
-       struct bt_message_discarded_items *message;
-       struct bt_stream_class *stream_class;
-       bool has_support;
-       bool need_cs;
-
-       BT_ASSERT_PRE_NON_NULL(self_msg_iter, "Message iterator");
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       stream_class = bt_stream_borrow_class(stream);
-       BT_ASSERT(stream_class);
-
-       if (type == BT_MESSAGE_TYPE_DISCARDED_EVENTS) {
-               has_support = stream_class->supports_discarded_events;
-               need_cs = stream_class->discarded_events_have_default_clock_snapshots;
-       } else {
-               has_support = stream_class->supports_discarded_packets;
-               need_cs = stream_class->discarded_packets_have_default_clock_snapshots;
-       }
-
-       BT_ASSERT_PRE(has_support,
-               "Stream class does not support discarded events or packets: "
-               "type=%s, %![stream-]+s, %![sc-]+S",
-               bt_message_type_string(type), stream, stream_class);
-       BT_ASSERT_PRE(need_cs ? with_cs : true,
-               "Unexpected stream class configuration when creating "
-               "a discarded events or discarded packets message: "
-               "default clock snapshots are needed, but none was provided: "
-               "type=%s, %![stream-]+s, %![sc-]+S, with-cs=%d, "
-               "cs-begin-val=%" PRIu64 ", cs-end-val=%" PRIu64,
-               bt_message_type_string(type), stream, stream_class,
-               with_cs, beginning_raw_value, end_raw_value);
-       BT_ASSERT_PRE(!need_cs ? !with_cs : true,
-               "Unexpected stream class configuration when creating "
-               "a discarded events or discarded packets message: "
-               "no default clock snapshots are needed, but two were provided: "
-               "type=%s, %![stream-]+s, %![sc-]+S, with-cs=%d, "
-               "cs-begin-val=%" PRIu64 ", cs-end-val=%" PRIu64,
-               bt_message_type_string(type), stream, stream_class,
-               with_cs, beginning_raw_value, end_raw_value);
-       BT_LIB_LOGD("Creating discarded items message object: "
-               "type=%s, %![stream-]+s, %![sc-]+S, with-cs=%d, "
-               "cs-begin-val=%" PRIu64 ", cs-end-val=%" PRIu64,
-               bt_message_type_string(type), stream, stream_class,
-               with_cs, beginning_raw_value, end_raw_value);
-       message = g_new0(struct bt_message_discarded_items, 1);
-       if (!message) {
-               BT_LOGE_STR("Failed to allocate one discarded items message.");
-               goto error;
-       }
-
-       bt_message_init(&message->parent, type,
-               destroy_discarded_items_message, NULL);
-       message->stream = stream;
-       bt_object_get_no_null_check(message->stream);
-
-       if (with_cs) {
-               BT_ASSERT(stream_class->default_clock_class);
-               message->default_begin_cs = bt_clock_snapshot_create(
-                       stream_class->default_clock_class);
-               if (!message->default_begin_cs) {
-                       goto error;
-               }
-
-               bt_clock_snapshot_set_raw_value(message->default_begin_cs,
-                       beginning_raw_value);
-
-               message->default_end_cs = bt_clock_snapshot_create(
-                       stream_class->default_clock_class);
-               if (!message->default_end_cs) {
-                       goto error;
-               }
-
-               bt_clock_snapshot_set_raw_value(message->default_end_cs,
-                       end_raw_value);
-       }
-
-       bt_property_uint_init(&message->count,
-               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE, 0);
-       BT_LIB_LOGD("Created discarded items message object: "
-               "%![msg-]+n, %![stream-]+s, %![sc-]+S", message,
-               stream, stream_class);
-
-       return (void *) &message->parent;
-
-error:
-       return NULL;
-}
-
-static inline
-struct bt_stream *borrow_discarded_items_message_stream(
-               struct bt_message *message)
-{
-       struct bt_message_discarded_items *disc_items_msg = (void *) message;
-
-       BT_ASSERT(message);
-       return disc_items_msg->stream;
-}
-
-static inline
-void set_discarded_items_message_count(struct bt_message *message,
-               uint64_t count)
-{
-       struct bt_message_discarded_items *disc_items_msg = (void *) message;
-
-       BT_ASSERT(message);
-       BT_ASSERT_PRE_HOT(message, "Message", ": %!+n", message);
-       bt_property_uint_set(&disc_items_msg->count, count);
-}
-
-static inline
-enum bt_property_availability get_discarded_items_message_count(
-               const struct bt_message *message, uint64_t *count)
-{
-       struct bt_message_discarded_items *disc_items_msg = (void *) message;
-
-       BT_ASSERT_PRE_NON_NULL(count, "Count (output)");
-       BT_ASSERT(message);
-       *count = disc_items_msg->count.value;
-       return disc_items_msg->count.base.avail;
-}
-
-static inline
-const struct bt_clock_snapshot *
-borrow_discarded_items_message_beginning_default_clock_snapshot_const(
-               const struct bt_message *message)
-{
-       struct bt_message_discarded_items *disc_items_msg = (void *) message;
-
-       BT_ASSERT(message);
-       BT_ASSERT_PRE(disc_items_msg->stream->class->default_clock_class,
-               "Message's stream's class has no default clock class: "
-               "%![msg-]+n, %![sc-]+S",
-               message, disc_items_msg->stream->class);
-       return disc_items_msg->default_begin_cs;
-}
-
-static inline
-const struct bt_clock_snapshot *
-borrow_discarded_items_message_end_default_clock_snapshot_const(
-               const struct bt_message *message)
-{
-       struct bt_message_discarded_items *disc_items_msg = (void *) message;
-
-       BT_ASSERT(message);
-       BT_ASSERT_PRE(disc_items_msg->stream->class->default_clock_class,
-               "Message's stream's class has no default clock class: "
-               "%![msg-]+n, %![sc-]+S",
-               message, disc_items_msg->stream->class);
-       return disc_items_msg->default_end_cs;
-}
-
-struct bt_message *bt_message_discarded_events_create(
-               struct bt_self_message_iterator *message_iterator,
-               const struct bt_stream *stream)
-{
-       return create_discarded_items_message(message_iterator,
-               BT_MESSAGE_TYPE_DISCARDED_EVENTS, (void *) stream,
-               false, 0, 0);
-}
-
-struct bt_message *bt_message_discarded_events_create_with_default_clock_snapshots(
-               struct bt_self_message_iterator *message_iterator,
-               const struct bt_stream *stream, uint64_t beginning_raw_value,
-               uint64_t end_raw_value)
-{
-       return create_discarded_items_message(message_iterator,
-               BT_MESSAGE_TYPE_DISCARDED_EVENTS, (void *) stream,
-               true, beginning_raw_value, end_raw_value);
-}
-
-struct bt_stream *bt_message_discarded_events_borrow_stream(
-               struct bt_message *message)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
-       return borrow_discarded_items_message_stream(message);
-}
-
-void bt_message_discarded_events_set_count(struct bt_message *message,
-               uint64_t count)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
-       set_discarded_items_message_count(message, count);
-}
-
-const struct bt_clock_snapshot *
-bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
-       return borrow_discarded_items_message_beginning_default_clock_snapshot_const(
-               msg);
-}
-
-const struct bt_clock_snapshot *
-bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
-       return borrow_discarded_items_message_end_default_clock_snapshot_const(
-               msg);
-}
-
-const struct bt_stream *
-bt_message_discarded_events_borrow_stream_const(const struct bt_message *message)
-{
-       return (void *) bt_message_discarded_events_borrow_stream(
-               (void *) message);
-}
-
-enum bt_property_availability bt_message_discarded_events_get_count(
-               const struct bt_message *message, uint64_t *count)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
-       return get_discarded_items_message_count(message, count);
-}
-
-struct bt_message *bt_message_discarded_packets_create(
-               struct bt_self_message_iterator *message_iterator,
-               const struct bt_stream *stream)
-{
-       return create_discarded_items_message(message_iterator,
-               BT_MESSAGE_TYPE_DISCARDED_PACKETS, (void *) stream,
-               false, 0, 0);
-}
-
-struct bt_message *bt_message_discarded_packets_create_with_default_clock_snapshots(
-               struct bt_self_message_iterator *message_iterator,
-               const struct bt_stream *stream, uint64_t beginning_raw_value,
-               uint64_t end_raw_value)
-{
-       return create_discarded_items_message(message_iterator,
-               BT_MESSAGE_TYPE_DISCARDED_PACKETS, (void *) stream,
-               true, beginning_raw_value, end_raw_value);
-}
-
-struct bt_stream *bt_message_discarded_packets_borrow_stream(
-               struct bt_message *message)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
-       return borrow_discarded_items_message_stream(message);
-}
-
-void bt_message_discarded_packets_set_count(struct bt_message *message,
-               uint64_t count)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
-       set_discarded_items_message_count(message, count);
-}
-
-const struct bt_clock_snapshot *
-bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
-       return borrow_discarded_items_message_beginning_default_clock_snapshot_const(
-               msg);
-}
-
-const struct bt_clock_snapshot *
-bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
-       return borrow_discarded_items_message_end_default_clock_snapshot_const(
-               msg);
-}
-
-const struct bt_stream *
-bt_message_discarded_packets_borrow_stream_const(const struct bt_message *message)
-{
-       return (void *) bt_message_discarded_packets_borrow_stream(
-               (void *) message);
-}
-
-enum bt_property_availability bt_message_discarded_packets_get_count(
-               const struct bt_message *message, uint64_t *count)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
-       return get_discarded_items_message_count(message, count);
-}
-
-static inline
-const struct bt_clock_class *
-borrow_discarded_items_message_stream_class_default_clock_class(
-               const struct bt_message *msg)
-{
-       struct bt_message_discarded_items *disc_items_msg = (void *) msg;
-
-       BT_ASSERT(msg);
-       return disc_items_msg->stream->class->default_clock_class;
-}
-
-const struct bt_clock_class *
-bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
-       return borrow_discarded_items_message_stream_class_default_clock_class(
-               msg);
-}
-
-const struct bt_clock_class *
-bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
-       return borrow_discarded_items_message_stream_class_default_clock_class(
-               msg);
-}
diff --git a/lib/graph/message/event.c b/lib/graph/message/event.c
deleted file mode 100644 (file)
index 7544e33..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "MSG-EVENT"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/trace-ir/event.h>
-#include <babeltrace2/trace-ir/event-internal.h>
-#include <babeltrace2/trace-ir/event-class-internal.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/trace.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/graph/graph-internal.h>
-#include <babeltrace2/graph/message-event-const.h>
-#include <babeltrace2/graph/message-event.h>
-#include <babeltrace2/graph/message-event-internal.h>
-#include <babeltrace2/types.h>
-#include <stdbool.h>
-#include <inttypes.h>
-
-BT_ASSERT_PRE_FUNC
-static inline bool event_class_has_trace(struct bt_event_class *event_class)
-{
-       struct bt_stream_class *stream_class;
-
-       stream_class = bt_event_class_borrow_stream_class_inline(event_class);
-       BT_ASSERT(stream_class);
-       return bt_stream_class_borrow_trace_class(stream_class) != NULL;
-}
-
-BT_HIDDEN
-struct bt_message *bt_message_event_new(
-               struct bt_graph *graph)
-{
-       struct bt_message_event *message = NULL;
-
-       message = g_new0(struct bt_message_event, 1);
-       if (!message) {
-               BT_LOGE_STR("Failed to allocate one event message.");
-               goto error;
-       }
-
-       bt_message_init(&message->parent, BT_MESSAGE_TYPE_EVENT,
-               (bt_object_release_func) bt_message_event_recycle, graph);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(message);
-
-end:
-       return (void *) message;
-}
-
-static inline
-struct bt_message *create_event_message(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_event_class *c_event_class,
-               const struct bt_packet *c_packet, bool with_cs,
-               uint64_t raw_value)
-{
-       struct bt_self_component_port_input_message_iterator *msg_iter =
-               (void *) self_msg_iter;
-       struct bt_message_event *message = NULL;
-       struct bt_event_class *event_class = (void *) c_event_class;
-       struct bt_stream_class *stream_class;
-       struct bt_packet *packet = (void *) c_packet;
-       struct bt_event *event;
-
-       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE(event_class_has_trace(event_class),
-               "Event class is not part of a trace: %!+E", event_class);
-       stream_class = bt_event_class_borrow_stream_class_inline(event_class);
-       BT_ASSERT(stream_class);
-       BT_ASSERT_PRE((with_cs && stream_class->default_clock_class) ||
-               (!with_cs && !stream_class->default_clock_class),
-               "Creating an event message with a default clock snapshot, but without "
-               "a default clock class, or without a default clock snapshot, "
-               "but with a default clock class: ",
-               "%![ec-]+E, %![sc-]+S, with-cs=%d, "
-               "cs-val=%" PRIu64,
-               event_class, stream_class, with_cs, raw_value);
-       BT_LIB_LOGD("Creating event message object: %![ec-]+E", event_class);
-       event = bt_event_create(event_class, packet);
-       if (unlikely(!event)) {
-               BT_LIB_LOGE("Cannot create event from event class: "
-                       "%![ec-]+E", event_class);
-               goto error;
-       }
-
-       /*
-        * Create message from pool _after_ we have everything
-        * (in this case, a valid event object) so that we never have an
-        * error condition with a non-NULL message object.
-        * Otherwise:
-        *
-        * * We cannot recycle the message on error because
-        *   bt_message_event_recycle() expects a complete
-        *   message (and the event or clock class priority map
-        *   object could be unset).
-        *
-        * * We cannot destroy the message because we would need
-        *   to notify the graph (pool owner) so that it removes the
-        *   message from its message array.
-        */
-       message = (void *) bt_message_create_from_pool(
-               &msg_iter->graph->event_msg_pool, msg_iter->graph);
-       if (unlikely(!message)) {
-               /* bt_message_create_from_pool() logs errors */
-               goto error;
-       }
-
-       if (with_cs) {
-               BT_ASSERT(stream_class->default_clock_class);
-               message->default_cs = bt_clock_snapshot_create(
-                       stream_class->default_clock_class);
-               if (!message->default_cs) {
-                       goto error;
-               }
-
-               bt_clock_snapshot_set_raw_value(message->default_cs, raw_value);
-       }
-
-       BT_ASSERT(!message->event);
-       message->event = event;
-       bt_packet_set_is_frozen(packet, true);
-       bt_event_class_freeze(event_class);
-       BT_LIB_LOGD("Created event message object: "
-               "%![msg-]+n, %![event-]+e", message, event);
-       goto end;
-
-error:
-       BT_ASSERT(!message);
-       bt_event_destroy(event);
-
-end:
-       return (void *) message;
-}
-
-struct bt_message *bt_message_event_create(
-               struct bt_self_message_iterator *msg_iter,
-               const struct bt_event_class *event_class,
-               const struct bt_packet *packet)
-{
-       return create_event_message(msg_iter, event_class, packet, false, 0);
-}
-
-struct bt_message *bt_message_event_create_with_default_clock_snapshot(
-               struct bt_self_message_iterator *msg_iter,
-               const struct bt_event_class *event_class,
-               const struct bt_packet *packet,
-               uint64_t raw_value)
-{
-       return create_event_message(msg_iter, event_class, packet,
-               true, raw_value);
-}
-
-BT_HIDDEN
-void bt_message_event_destroy(struct bt_message *msg)
-{
-       struct bt_message_event *event_msg = (void *) msg;
-
-       BT_LIB_LOGD("Destroying event message: %!+n", msg);
-
-       if (event_msg->event) {
-               BT_LIB_LOGD("Recycling event: %!+e", event_msg->event);
-               bt_event_recycle(event_msg->event);
-               event_msg->event = NULL;
-       }
-
-       if (event_msg->default_cs) {
-               bt_clock_snapshot_recycle(event_msg->default_cs);
-               event_msg->default_cs = NULL;
-       }
-
-       g_free(msg);
-}
-
-BT_HIDDEN
-void bt_message_event_recycle(struct bt_message *msg)
-{
-       struct bt_message_event *event_msg = (void *) msg;
-       struct bt_graph *graph;
-
-       BT_ASSERT(event_msg);
-
-       if (unlikely(!msg->graph)) {
-               bt_message_event_destroy(msg);
-               return;
-       }
-
-       BT_LIB_LOGD("Recycling event message: %![msg-]+n, %![event-]+e",
-               msg, event_msg->event);
-       bt_message_reset(msg);
-       BT_ASSERT(event_msg->event);
-       bt_event_recycle(event_msg->event);
-       event_msg->event = NULL;
-
-       if (event_msg->default_cs) {
-               bt_clock_snapshot_recycle(event_msg->default_cs);
-               event_msg->default_cs = NULL;
-       }
-
-       graph = msg->graph;
-       msg->graph = NULL;
-       bt_object_pool_recycle_object(&graph->event_msg_pool, msg);
-}
-
-static inline
-struct bt_event *borrow_event(struct bt_message *message)
-{
-       struct bt_message_event *event_message;
-
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_EVENT);
-       event_message = container_of(message,
-                       struct bt_message_event, parent);
-       return event_message->event;
-}
-
-struct bt_event *bt_message_event_borrow_event(
-               struct bt_message *message)
-{
-       return borrow_event(message);
-}
-
-const struct bt_event *bt_message_event_borrow_event_const(
-               const struct bt_message *message)
-{
-       return borrow_event((void *) message);
-}
-
-const struct bt_clock_snapshot *
-bt_message_event_borrow_default_clock_snapshot_const(
-               const struct bt_message *msg)
-{
-       struct bt_message_event *event_msg = (void *) msg;
-       struct bt_stream_class *stream_class;
-
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_EVENT);
-       stream_class = bt_event_class_borrow_stream_class_inline(
-               event_msg->event->class);
-       BT_ASSERT(stream_class);
-       BT_ASSERT_PRE(stream_class->default_clock_class,
-               "Message's stream's class has no default clock class: "
-               "%![msg-]+n, %![sc-]+S", msg, stream_class);
-       return event_msg->default_cs;
-}
-
-const bt_clock_class *
-bt_message_event_borrow_stream_class_default_clock_class_const(
-               const bt_message *msg)
-{
-       struct bt_message_event *event_msg = (void *) msg;
-       struct bt_stream_class *stream_class;
-
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_EVENT);
-       stream_class = bt_event_class_borrow_stream_class_inline(
-               event_msg->event->class);
-       BT_ASSERT(stream_class);
-       return stream_class->default_clock_class;
-}
diff --git a/lib/graph/message/message-iterator-inactivity.c b/lib/graph/message/message-iterator-inactivity.c
deleted file mode 100644 (file)
index 4cb0a8e..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "MSG-MESSAGE-ITERATOR-INACTIVITY"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/clock-class.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/graph/message-message-iterator-inactivity-const.h>
-#include <babeltrace2/graph/message-message-iterator-inactivity.h>
-#include <babeltrace2/graph/message-message-iterator-inactivity-internal.h>
-
-static
-void bt_message_message_iterator_inactivity_destroy(struct bt_object *obj)
-{
-       struct bt_message_message_iterator_inactivity *message =
-                       (struct bt_message_message_iterator_inactivity *) obj;
-
-       BT_LIB_LOGD("Destroying message iterator inactivity message: %!+n",
-                       message);
-
-       if (message->default_cs) {
-               bt_clock_snapshot_recycle(message->default_cs);
-               message->default_cs = NULL;
-       }
-
-       g_free(message);
-}
-
-struct bt_message *bt_message_message_iterator_inactivity_create(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_clock_class *default_clock_class,
-               uint64_t value_cycles)
-{
-       struct bt_self_component_port_input_message_iterator *msg_iter =
-               (void *) self_msg_iter;
-       struct bt_message_message_iterator_inactivity *message;
-       struct bt_message *ret_msg = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
-       BT_ASSERT_PRE_NON_NULL(default_clock_class, "Default clock class");
-       BT_LIB_LOGD("Creating message iterator inactivity message object: "
-               "%![iter-]+i, %![default-cc-]+K, value=%" PRIu64, msg_iter,
-               default_clock_class, value_cycles);
-       message = g_new0(struct bt_message_message_iterator_inactivity, 1);
-       if (!message) {
-               BT_LOGE_STR("Failed to allocate one message iterator "
-                               "inactivity message.");
-               goto error;
-       }
-       bt_message_init(&message->parent,
-               BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY,
-               bt_message_message_iterator_inactivity_destroy, NULL);
-       ret_msg = &message->parent;
-       message->default_cs = bt_clock_snapshot_create(
-               (void *) default_clock_class);
-       if (!message->default_cs) {
-               goto error;
-       }
-       bt_clock_snapshot_set_raw_value(message->default_cs, value_cycles);
-
-       BT_LIB_LOGD("Created message iterator inactivity message object: %!+n",
-                       ret_msg);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(ret_msg);
-
-end:
-       return (void *) ret_msg;
-}
-
-extern const struct bt_clock_snapshot *
-bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
-               const bt_message *msg)
-{
-       struct bt_message_message_iterator_inactivity *inactivity = (void *) msg;
-
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY);
-       return inactivity->default_cs;
-}
diff --git a/lib/graph/message/message.c b/lib/graph/message/message.c
deleted file mode 100644 (file)
index 7cdd3d3..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "MSG"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/graph/message-const.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/graph/graph-internal.h>
-
-BT_HIDDEN
-void bt_message_init(struct bt_message *message,
-               enum bt_message_type type,
-               bt_object_release_func release,
-               struct bt_graph *graph)
-{
-       BT_ASSERT(type >= 0 && type <= BT_MESSAGE_TYPE_DISCARDED_PACKETS);
-       message->type = type;
-       bt_object_init_shared(&message->base, release);
-       message->graph = graph;
-
-       if (graph) {
-               bt_graph_add_message(graph, message);
-       }
-}
-
-enum bt_message_type bt_message_get_type(
-               const struct bt_message *message)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       return message->type;
-}
-
-BT_HIDDEN
-void bt_message_unlink_graph(struct bt_message *msg)
-{
-       BT_ASSERT(msg);
-       msg->graph = NULL;
-}
-
-void bt_message_get_ref(const struct bt_message *message)
-{
-       bt_object_get_ref(message);
-}
-
-void bt_message_put_ref(const struct bt_message *message)
-{
-       bt_object_put_ref(message);
-}
diff --git a/lib/graph/message/packet.c b/lib/graph/message/packet.c
deleted file mode 100644 (file)
index 9ed9a0c..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "MSG-PACKET"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/packet.h>
-#include <babeltrace2/trace-ir/packet-internal.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/trace-ir/stream.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/graph/graph-internal.h>
-#include <babeltrace2/graph/message-packet-beginning-const.h>
-#include <babeltrace2/graph/message-packet-end-const.h>
-#include <babeltrace2/graph/message-packet-beginning.h>
-#include <babeltrace2/graph/message-packet-end.h>
-#include <babeltrace2/graph/message-packet-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <inttypes.h>
-
-static inline
-struct bt_message *new_packet_message(struct bt_graph *graph,
-               enum bt_message_type type, bt_object_release_func recycle_func)
-{
-       struct bt_message_packet *message;
-
-       message = g_new0(struct bt_message_packet, 1);
-       if (!message) {
-               BT_LOGE_STR("Failed to allocate one packet message.");
-               goto error;
-       }
-
-       bt_message_init(&message->parent, type, recycle_func, graph);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(message);
-
-end:
-       return (void *) message;
-}
-
-BT_HIDDEN
-struct bt_message *bt_message_packet_beginning_new(struct bt_graph *graph)
-{
-       return new_packet_message(graph, BT_MESSAGE_TYPE_PACKET_BEGINNING,
-               (bt_object_release_func) bt_message_packet_beginning_recycle);
-}
-
-BT_HIDDEN
-struct bt_message *bt_message_packet_end_new(struct bt_graph *graph)
-{
-       return new_packet_message(graph, BT_MESSAGE_TYPE_PACKET_END,
-               (bt_object_release_func) bt_message_packet_end_recycle);
-}
-
-static inline
-struct bt_message *create_packet_message(
-               struct bt_self_component_port_input_message_iterator *msg_iter,
-               struct bt_packet *packet, struct bt_object_pool *pool,
-               bool with_cs, uint64_t raw_value)
-{
-       struct bt_message_packet *message = NULL;
-       struct bt_stream *stream;
-       struct bt_stream_class *stream_class;
-       bool need_cs;
-
-       BT_ASSERT(msg_iter);
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       stream = bt_packet_borrow_stream(packet);
-       BT_ASSERT(stream);
-       stream_class = bt_stream_borrow_class(stream);
-       BT_ASSERT(stream_class);
-
-       if (pool == &msg_iter->graph->packet_begin_msg_pool) {
-               need_cs = stream_class->packets_have_beginning_default_clock_snapshot;
-       } else {
-               need_cs = stream_class->packets_have_end_default_clock_snapshot;
-       }
-
-       /*
-        * `packet_has_default_clock_snapshot` implies that the stream
-        * class has a default clock class (precondition).
-        */
-       BT_ASSERT_PRE(need_cs ? with_cs : true,
-               "Unexpected stream class configuration when creating "
-               "a packet beginning or end message: "
-               "a default clock snapshot is needed, but none was provided: "
-               "%![stream-]+s, %![sc-]+S, with-cs=%d, "
-               "cs-val=%" PRIu64,
-               stream, stream_class, with_cs, raw_value);
-       BT_ASSERT_PRE(!need_cs ? !with_cs : true,
-               "Unexpected stream class configuration when creating "
-               "a packet beginning or end message: "
-               "no default clock snapshot is needed, but one was provided: "
-               "%![stream-]+s, %![sc-]+S, with-cs=%d, "
-               "cs-val=%" PRIu64,
-               stream, stream_class, with_cs, raw_value);
-       BT_LIB_LOGD("Creating packet message object: "
-               "%![packet-]+a, %![stream-]+s, %![sc-]+S",
-               packet, stream, stream_class);
-       message = (void *) bt_message_create_from_pool(pool, msg_iter->graph);
-       if (!message) {
-               /* bt_message_create_from_pool() logs errors */
-               goto end;
-       }
-
-       if (with_cs) {
-               BT_ASSERT(stream_class->default_clock_class);
-               message->default_cs = bt_clock_snapshot_create(
-                       stream_class->default_clock_class);
-               if (!message->default_cs) {
-                       bt_object_put_no_null_check(message);
-                       message = NULL;
-                       goto end;
-               }
-
-               bt_clock_snapshot_set_raw_value(message->default_cs, raw_value);
-       }
-
-       BT_ASSERT(!message->packet);
-       message->packet = packet;
-       bt_object_get_no_null_check_no_parent_check(
-               &message->packet->base);
-       bt_packet_set_is_frozen(packet, true);
-       BT_LIB_LOGD("Created packet message object: "
-               "%![msg-]+n, %![packet-]+a, %![stream-]+s, %![sc-]+S",
-               message, packet, stream, stream_class);
-       goto end;
-
-end:
-       return (void *) message;
-}
-
-struct bt_message *bt_message_packet_beginning_create(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_packet *packet)
-{
-       struct bt_self_component_port_input_message_iterator *msg_iter =
-               (void *) self_msg_iter;
-
-       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
-       return create_packet_message(msg_iter, (void *) packet,
-               &msg_iter->graph->packet_begin_msg_pool, false, 0);
-}
-
-struct bt_message *bt_message_packet_beginning_create_with_default_clock_snapshot(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_packet *packet, uint64_t raw_value)
-{
-       struct bt_self_component_port_input_message_iterator *msg_iter =
-               (void *) self_msg_iter;
-
-       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
-       return create_packet_message(msg_iter, (void *) packet,
-               &msg_iter->graph->packet_begin_msg_pool, true, raw_value);
-}
-
-struct bt_message *bt_message_packet_end_create(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_packet *packet)
-{
-       struct bt_self_component_port_input_message_iterator *msg_iter =
-               (void *) self_msg_iter;
-
-       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
-       return create_packet_message(msg_iter, (void *) packet,
-               &msg_iter->graph->packet_end_msg_pool, false, 0);
-}
-
-struct bt_message *bt_message_packet_end_create_with_default_clock_snapshot(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_packet *packet, uint64_t raw_value)
-{
-       struct bt_self_component_port_input_message_iterator *msg_iter =
-               (void *) self_msg_iter;
-
-       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
-       return create_packet_message(msg_iter, (void *) packet,
-               &msg_iter->graph->packet_end_msg_pool, true, raw_value);
-}
-
-BT_HIDDEN
-void bt_message_packet_destroy(struct bt_message *msg)
-{
-       struct bt_message_packet *packet_msg = (void *) msg;
-
-       BT_LIB_LOGD("Destroying packet message: %!+n", msg);
-       BT_LIB_LOGD("Putting packet: %!+a", packet_msg->packet);
-       BT_OBJECT_PUT_REF_AND_RESET(packet_msg->packet);
-
-       if (packet_msg->default_cs) {
-               bt_clock_snapshot_recycle(packet_msg->default_cs);
-               packet_msg->default_cs = NULL;
-       }
-
-       g_free(msg);
-}
-
-static inline
-void recycle_packet_message(struct bt_message *msg, struct bt_object_pool *pool)
-{
-       struct bt_message_packet *packet_msg = (void *) msg;
-
-       BT_LIB_LOGD("Recycling packet message: %!+n", msg);
-       bt_message_reset(msg);
-       bt_object_put_no_null_check(&packet_msg->packet->base);
-
-       if (packet_msg->default_cs) {
-               bt_clock_snapshot_recycle(packet_msg->default_cs);
-               packet_msg->default_cs = NULL;
-       }
-
-       packet_msg->packet = NULL;
-       msg->graph = NULL;
-       bt_object_pool_recycle_object(pool, msg);
-}
-
-BT_HIDDEN
-void bt_message_packet_beginning_recycle(struct bt_message *msg)
-{
-       BT_ASSERT(msg);
-
-       if (unlikely(!msg->graph)) {
-               bt_message_packet_destroy(msg);
-               return;
-       }
-
-       recycle_packet_message(msg, &msg->graph->packet_begin_msg_pool);
-}
-
-BT_HIDDEN
-void bt_message_packet_end_recycle(struct bt_message *msg)
-{
-       BT_ASSERT(msg);
-
-       if (unlikely(!msg->graph)) {
-               bt_message_packet_destroy(msg);
-               return;
-       }
-
-       recycle_packet_message(msg, &msg->graph->packet_end_msg_pool);
-}
-
-struct bt_packet *bt_message_packet_beginning_borrow_packet(
-               struct bt_message *message)
-{
-       struct bt_message_packet *packet_msg = (void *) message;
-
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message,
-               BT_MESSAGE_TYPE_PACKET_BEGINNING);
-       return packet_msg->packet;
-}
-
-const struct bt_packet *bt_message_packet_beginning_borrow_packet_const(
-               const struct bt_message *message)
-{
-       return bt_message_packet_beginning_borrow_packet(
-               (void *) message);
-}
-
-struct bt_packet *bt_message_packet_end_borrow_packet(
-               struct bt_message *message)
-{
-       struct bt_message_packet *packet_msg = (void *) message;
-
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message,
-               BT_MESSAGE_TYPE_PACKET_END);
-       return packet_msg->packet;
-}
-
-const struct bt_packet *bt_message_packet_end_borrow_packet_const(
-               const struct bt_message *message)
-{
-       return bt_message_packet_end_borrow_packet(
-               (void *) message);
-}
-
-static inline
-const struct bt_clock_snapshot *
-borrow_packet_message_default_clock_snapshot_const(
-               const struct bt_message *message)
-{
-       struct bt_message_packet *packet_msg = (void *) message;
-
-       BT_ASSERT(message);
-       BT_ASSERT_PRE(packet_msg->packet->stream->class->default_clock_class,
-               "Message's stream's class has no default clock class: "
-               "%![msg-]+n, %![sc-]+S",
-               message, packet_msg->packet->stream->class);
-       return packet_msg->default_cs;
-}
-
-const struct bt_clock_snapshot *
-bt_message_packet_beginning_borrow_default_clock_snapshot_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_PACKET_BEGINNING);
-       return borrow_packet_message_default_clock_snapshot_const(msg);
-}
-
-const struct bt_clock_snapshot *
-bt_message_packet_end_borrow_default_clock_snapshot_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_PACKET_END);
-       return borrow_packet_message_default_clock_snapshot_const(msg);
-}
-
-static inline
-const struct bt_clock_class *
-borrow_packet_message_stream_class_default_clock_class(
-               const struct bt_message *msg)
-{
-       struct bt_message_packet *packet_msg = (void *) msg;
-
-       BT_ASSERT(msg);
-       return packet_msg->packet->stream->class->default_clock_class;
-}
-
-const struct bt_clock_class *
-bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_PACKET_BEGINNING);
-       return borrow_packet_message_stream_class_default_clock_class(msg);
-}
-
-const struct bt_clock_class *
-bt_message_packet_end_borrow_stream_class_default_clock_class_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_PACKET_END);
-       return borrow_packet_message_stream_class_default_clock_class(msg);
-}
diff --git a/lib/graph/message/stream-activity.c b/lib/graph/message/stream-activity.c
deleted file mode 100644 (file)
index 7ecbd46..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "MSG-STREAM-ACTIVITY"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/clock-class.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/graph/message-stream-activity-beginning-const.h>
-#include <babeltrace2/graph/message-stream-activity-end-const.h>
-#include <babeltrace2/graph/message-stream-activity-beginning.h>
-#include <babeltrace2/graph/message-stream-activity-end.h>
-#include <babeltrace2/graph/message-stream-activity-internal.h>
-
-static
-void destroy_stream_activity_message(struct bt_object *obj)
-{
-       struct bt_message_stream_activity *message = (void *) obj;
-
-       BT_LIB_LOGD("Destroying stream activity message: %!+n", message);
-       BT_LIB_LOGD("Putting stream: %!+s", message->stream);
-       BT_OBJECT_PUT_REF_AND_RESET(message->stream);
-
-       if (message->default_cs) {
-               bt_clock_snapshot_recycle(message->default_cs);
-               message->default_cs = NULL;
-       }
-
-       g_free(message);
-}
-
-static inline
-struct bt_message *create_stream_activity_message(
-               struct bt_self_message_iterator *self_msg_iter,
-               struct bt_stream *stream, enum bt_message_type type)
-{
-       struct bt_message_stream_activity *message;
-       struct bt_stream_class *stream_class;
-
-       BT_ASSERT_PRE_NON_NULL(self_msg_iter, "Message iterator");
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       stream_class = bt_stream_borrow_class(stream);
-       BT_ASSERT(stream_class);
-       BT_LIB_LOGD("Creating stream activity message object: "
-               "type=%s, %![stream-]+s, %![sc-]+S",
-               bt_message_type_string(type), stream, stream_class);
-       message = g_new0(struct bt_message_stream_activity, 1);
-       if (!message) {
-               BT_LOGE_STR("Failed to allocate one stream activity message.");
-               goto error;
-       }
-
-       bt_message_init(&message->parent, type,
-               destroy_stream_activity_message, NULL);
-       message->stream = stream;
-       bt_object_get_no_null_check(message->stream);
-
-       if (stream_class->default_clock_class) {
-               message->default_cs = bt_clock_snapshot_create(
-                       stream_class->default_clock_class);
-               if (!message->default_cs) {
-                       goto error;
-               }
-       }
-
-       message->default_cs_state =
-               BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN;
-       BT_LIB_LOGD("Created stream activity message object: "
-               "%![msg-]+n, %![stream-]+s, %![sc-]+S", message,
-               stream, stream_class);
-
-       return (void *) &message->parent;
-
-error:
-       return NULL;
-}
-
-struct bt_message *bt_message_stream_activity_beginning_create(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_stream *stream)
-{
-       return create_stream_activity_message(self_msg_iter, (void *) stream,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
-}
-
-struct bt_message *bt_message_stream_activity_end_create(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_stream *stream)
-{
-       return create_stream_activity_message(self_msg_iter, (void *) stream,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
-}
-
-static inline
-struct bt_stream *borrow_stream_activity_message_stream(
-               struct bt_message *message)
-{
-       struct bt_message_stream_activity *stream_act_msg = (void *) message;
-
-       BT_ASSERT(message);
-       return stream_act_msg->stream;
-}
-
-struct bt_stream *bt_message_stream_activity_beginning_borrow_stream(
-               struct bt_message *message)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
-       return borrow_stream_activity_message_stream(message);
-}
-
-struct bt_stream *bt_message_stream_activity_end_borrow_stream(
-               struct bt_message *message)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
-       return borrow_stream_activity_message_stream(message);
-}
-
-const struct bt_stream *bt_message_stream_activity_beginning_borrow_stream_const(
-               const struct bt_message *message)
-{
-       return bt_message_stream_activity_beginning_borrow_stream(
-               (void *) message);
-}
-
-const struct bt_stream *bt_message_stream_activity_end_borrow_stream_const(
-               const struct bt_message *message)
-{
-       return bt_message_stream_activity_end_borrow_stream((void *) message);
-}
-
-static inline
-void set_stream_activity_message_default_clock_snapshot(
-               struct bt_message *msg, uint64_t value_cycles)
-{
-       struct bt_message_stream_activity *stream_act_msg = (void *) msg;
-       struct bt_stream_class *sc;
-
-       BT_ASSERT(msg);
-       BT_ASSERT_PRE_HOT(msg, "Message", ": %!+n", msg);
-       sc = stream_act_msg->stream->class;
-       BT_ASSERT(sc);
-       BT_ASSERT_PRE(sc->default_clock_class,
-               "Message's stream's class has no default clock class: "
-               "%![msg-]+n, %![sc-]+S", msg, sc);
-       bt_clock_snapshot_set_raw_value(stream_act_msg->default_cs,
-               value_cycles);
-       stream_act_msg->default_cs_state =
-               BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN;
-       BT_LIB_LOGV("Set stream activity message's default clock snapshot: "
-               "%![msg-]+n, value=%" PRIu64, msg, value_cycles);
-}
-
-void bt_message_stream_activity_beginning_set_default_clock_snapshot(
-               struct bt_message *msg, uint64_t raw_value)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
-       set_stream_activity_message_default_clock_snapshot(msg, raw_value);
-}
-
-void bt_message_stream_activity_end_set_default_clock_snapshot(
-               struct bt_message *msg, uint64_t raw_value)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
-       set_stream_activity_message_default_clock_snapshot(msg, raw_value);
-}
-
-static inline
-enum bt_message_stream_activity_clock_snapshot_state
-borrow_stream_activity_message_default_clock_snapshot_const(
-               const bt_message *msg, const bt_clock_snapshot **snapshot)
-{
-       const struct bt_message_stream_activity *stream_act_msg =
-               (const void *) msg;
-
-       BT_ASSERT_PRE_NON_NULL(snapshot, "Clock snapshot (output)");
-       *snapshot = stream_act_msg->default_cs;
-       return stream_act_msg->default_cs_state;
-}
-
-enum bt_message_stream_activity_clock_snapshot_state
-bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
-               const bt_message *msg, const bt_clock_snapshot **snapshot)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
-       return borrow_stream_activity_message_default_clock_snapshot_const(msg,
-               snapshot);
-}
-
-enum bt_message_stream_activity_clock_snapshot_state
-bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
-               const bt_message *msg, const bt_clock_snapshot **snapshot)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
-       return borrow_stream_activity_message_default_clock_snapshot_const(msg,
-               snapshot);
-}
-
-static inline
-void set_stream_activity_message_default_clock_snapshot_state(
-               struct bt_message *msg,
-               enum bt_message_stream_activity_clock_snapshot_state state)
-{
-       struct bt_message_stream_activity *stream_act_msg = (void *) msg;
-
-       BT_ASSERT(msg);
-       BT_ASSERT_PRE_HOT(msg, "Message", ": %!+n", msg);
-       BT_ASSERT_PRE(state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN,
-               "Invalid clock snapshot state: %![msg-]+n, state=%s",
-               msg,
-               bt_message_stream_activity_clock_snapshot_state_string(state));
-       stream_act_msg->default_cs_state = state;
-       BT_LIB_LOGV("Set stream activity message's default clock snapshot state: "
-               "%![msg-]+n, state=%s", msg,
-               bt_message_stream_activity_clock_snapshot_state_string(state));
-}
-
-void bt_message_stream_activity_beginning_set_default_clock_snapshot_state(
-               struct bt_message *msg,
-               enum bt_message_stream_activity_clock_snapshot_state state)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
-       set_stream_activity_message_default_clock_snapshot_state(msg, state);
-}
-
-void bt_message_stream_activity_end_set_default_clock_snapshot_state(
-               struct bt_message *msg,
-               enum bt_message_stream_activity_clock_snapshot_state state)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
-       set_stream_activity_message_default_clock_snapshot_state(msg, state);
-}
-
-static inline
-const struct bt_clock_class *
-borrow_stream_activity_message_stream_class_default_clock_class(
-               const struct bt_message *msg)
-{
-       struct bt_message_stream_activity *stream_act_msg = (void *) msg;
-
-       BT_ASSERT(msg);
-       return stream_act_msg->stream->class->default_clock_class;
-}
-
-const struct bt_clock_class *
-bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
-               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
-       return borrow_stream_activity_message_stream_class_default_clock_class(
-               msg);
-}
-
-const struct bt_clock_class *
-bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
-               const struct bt_message *msg)
-{
-       BT_ASSERT_PRE_NON_NULL(msg, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
-       return borrow_stream_activity_message_stream_class_default_clock_class(
-               msg);
-}
diff --git a/lib/graph/message/stream.c b/lib/graph/message/stream.c
deleted file mode 100644 (file)
index 935942a..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "MSG-STREAM"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-const.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/graph/message-stream-beginning.h>
-#include <babeltrace2/graph/message-stream-end.h>
-#include <babeltrace2/graph/message-stream-beginning-const.h>
-#include <babeltrace2/graph/message-stream-end-const.h>
-#include <babeltrace2/graph/message-stream-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <inttypes.h>
-
-static
-void destroy_stream_message(struct bt_object *obj)
-{
-       struct bt_message_stream *message = (void *) obj;
-
-       BT_LIB_LOGD("Destroying stream message: %!+n", message);
-       BT_LIB_LOGD("Putting stream: %!+s", message->stream);
-       BT_OBJECT_PUT_REF_AND_RESET(message->stream);
-       g_free(message);
-}
-
-static inline
-struct bt_message *create_stream_message(
-               struct bt_self_message_iterator *self_msg_iter,
-               struct bt_stream *stream, enum bt_message_type type)
-{
-       struct bt_message_stream *message;
-       struct bt_stream_class *stream_class;
-
-       BT_ASSERT_PRE_NON_NULL(self_msg_iter, "Message iterator");
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       stream_class = bt_stream_borrow_class(stream);
-       BT_ASSERT(stream_class);
-       BT_LIB_LOGD("Creating stream message object: "
-               "type=%s, %![stream-]+s, %![sc-]+S",
-               bt_message_type_string(type), stream, stream_class);
-       message = g_new0(struct bt_message_stream, 1);
-       if (!message) {
-               BT_LOGE_STR("Failed to allocate one stream message.");
-               goto error;
-       }
-
-       bt_message_init(&message->parent, type,
-               destroy_stream_message, NULL);
-       message->stream = stream;
-       bt_object_get_no_null_check(message->stream);
-       BT_LIB_LOGD("Created stream message object: "
-               "%![msg-]+n, %![stream-]+s, %![sc-]+S", message,
-               stream, stream_class);
-
-       return (void *) &message->parent;
-
-error:
-       return NULL;
-}
-
-struct bt_message *bt_message_stream_beginning_create(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_stream *stream)
-{
-       return create_stream_message(self_msg_iter, (void *) stream,
-               BT_MESSAGE_TYPE_STREAM_BEGINNING);
-}
-
-struct bt_message *bt_message_stream_end_create(
-               struct bt_self_message_iterator *self_msg_iter,
-               const struct bt_stream *stream)
-{
-       return create_stream_message(self_msg_iter, (void *) stream,
-               BT_MESSAGE_TYPE_STREAM_END);
-}
-
-static inline
-struct bt_stream *borrow_stream_message_stream(struct bt_message *message)
-{
-       struct bt_message_stream *stream_msg;
-
-       BT_ASSERT(message);
-       stream_msg = (void *) message;
-       return stream_msg->stream;
-}
-
-struct bt_stream *bt_message_stream_beginning_borrow_stream(
-               struct bt_message *message)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_STREAM_BEGINNING);
-       return borrow_stream_message_stream(message);
-}
-
-struct bt_stream *bt_message_stream_end_borrow_stream(
-               struct bt_message *message)
-{
-       BT_ASSERT_PRE_NON_NULL(message, "Message");
-       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_STREAM_END);
-       return borrow_stream_message_stream(message);
-}
-
-const struct bt_stream *bt_message_stream_beginning_borrow_stream_const(
-               const struct bt_message *message)
-{
-       return bt_message_stream_beginning_borrow_stream(
-               (void *) message);
-}
-
-const struct bt_stream *bt_message_stream_end_borrow_stream_const(
-               const struct bt_message *message)
-{
-       return bt_message_stream_end_borrow_stream(
-               (void *) message);
-}
diff --git a/lib/graph/port.c b/lib/graph/port.c
deleted file mode 100644 (file)
index f119d60..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PORT"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/graph/port-const.h>
-#include <babeltrace2/graph/port-input-const.h>
-#include <babeltrace2/graph/port-output-const.h>
-#include <babeltrace2/graph/self-component-port.h>
-#include <babeltrace2/graph/self-component-port-input.h>
-#include <babeltrace2/graph/self-component-port-output.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/port-internal.h>
-#include <babeltrace2/graph/connection-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-
-static
-void destroy_port(struct bt_object *obj)
-{
-       struct bt_port *port = (void *) obj;
-
-       BT_LIB_LOGD("Destroying port: %!+p", port);
-
-       if (port->name) {
-               g_string_free(port->name, TRUE);
-               port->name = NULL;
-       }
-
-       g_free(port);
-}
-
-BT_HIDDEN
-struct bt_port *bt_port_create(struct bt_component *parent_component,
-               enum bt_port_type type, const char *name, void *user_data)
-{
-       struct bt_port *port = NULL;
-
-       BT_ASSERT(name);
-       BT_ASSERT(parent_component);
-       BT_ASSERT(type == BT_PORT_TYPE_INPUT || type == BT_PORT_TYPE_OUTPUT);
-       BT_ASSERT(strlen(name) > 0);
-       port = g_new0(struct bt_port, 1);
-       if (!port) {
-               BT_LOGE_STR("Failed to allocate one port.");
-               goto end;
-       }
-
-       BT_LIB_LOGD("Creating port for component: %![comp-]+c, port-type=%s, "
-               "port-name=\"%s\"", parent_component, bt_port_type_string(type),
-               name);
-       bt_object_init_shared_with_parent(&port->base, destroy_port);
-       port->name = g_string_new(name);
-       if (!port->name) {
-               BT_LOGE_STR("Failed to allocate one GString.");
-               BT_OBJECT_PUT_REF_AND_RESET(port);
-               goto end;
-       }
-
-       port->type = type;
-       port->user_data = user_data;
-       bt_object_set_parent(&port->base, &parent_component->base);
-       BT_LIB_LOGD("Created port for component: "
-               "%![comp-]+c, %![port-]+p", parent_component, port);
-
-end:
-       return port;
-}
-
-const char *bt_port_get_name(const struct bt_port *port)
-{
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       return port->name->str;
-}
-
-enum bt_port_type bt_port_get_type(const struct bt_port *port)
-{
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       return port->type;
-}
-
-const struct bt_connection *bt_port_borrow_connection_const(
-               const struct bt_port *port)
-{
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       return port->connection;
-}
-
-const struct bt_component *bt_port_borrow_component_const(
-               const struct bt_port *port)
-{
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       return bt_port_borrow_component_inline(port);
-}
-
-struct bt_self_component *bt_self_component_port_borrow_component(
-               struct bt_self_component_port *port)
-{
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       return (void *) bt_object_borrow_parent((void *) port);
-}
-
-BT_HIDDEN
-void bt_port_set_connection(struct bt_port *port,
-               struct bt_connection *connection)
-{
-       /*
-        * Don't take a reference on connection as its existence is
-        * guaranteed by the existence of the graph in which the
-        * connection exists.
-        */
-       port->connection = connection;
-       BT_LIB_LOGV("Set port's connection: %![port-]+p, %![conn-]+x", port,
-               connection);
-}
-
-bt_bool bt_port_is_connected(const struct bt_port *port)
-{
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       return port->connection ? BT_TRUE : BT_FALSE;
-}
-
-void *bt_self_component_port_get_data(const struct bt_self_component_port *port)
-{
-       BT_ASSERT_PRE_NON_NULL(port, "Port");
-       return ((struct bt_port *) port)->user_data;
-}
-
-void bt_port_get_ref(const struct bt_port *port)
-{
-       bt_object_get_ref(port);
-}
-
-void bt_port_put_ref(const struct bt_port *port)
-{
-       bt_object_put_ref(port);
-}
-
-void bt_port_input_get_ref(const struct bt_port_input *port_input)
-{
-       bt_object_get_ref(port_input);
-}
-
-void bt_port_input_put_ref(const struct bt_port_input *port_input)
-{
-       bt_object_put_ref(port_input);
-}
-
-void bt_port_output_get_ref(const struct bt_port_output *port_output)
-{
-       bt_object_get_ref(port_output);
-}
-
-void bt_port_output_put_ref(const struct bt_port_output *port_output)
-{
-       bt_object_put_ref(port_output);
-}
diff --git a/lib/graph/query-executor.c b/lib/graph/query-executor.c
deleted file mode 100644 (file)
index 5c8e33e..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "QUERY-EXECUTOR"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/graph/query-executor-const.h>
-#include <babeltrace2/graph/query-executor.h>
-#include <babeltrace2/graph/query-executor-internal.h>
-#include <babeltrace2/graph/component-class.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/value-const.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-
-static
-void bt_query_executor_destroy(struct bt_object *obj)
-{
-       struct bt_query_executor *query_exec =
-               container_of(obj, struct bt_query_executor, base);
-
-       BT_LOGD("Destroying query executor: addr=%p", query_exec);
-       g_free(query_exec);
-}
-
-struct bt_query_executor *bt_query_executor_create(void)
-{
-       struct bt_query_executor *query_exec;
-
-       BT_LOGD_STR("Creating query executor.");
-       query_exec = g_new0(struct bt_query_executor, 1);
-       if (!query_exec) {
-               BT_LOGE_STR("Failed to allocate one query executor.");
-               goto end;
-       }
-
-       bt_object_init_shared(&query_exec->base,
-               bt_query_executor_destroy);
-       BT_LOGD("Created query executor: addr=%p", query_exec);
-
-end:
-       return (void *) query_exec;
-}
-
-enum bt_query_executor_status bt_query_executor_query(
-               struct bt_query_executor *query_exec,
-               const struct bt_component_class *comp_cls,
-               const char *object, const struct bt_value *params,
-               const struct bt_value **user_result)
-{
-       typedef enum bt_query_status (*method_t)(void *, const void *,
-               const void *, const void *, const void *);
-
-       enum bt_query_status status;
-       enum bt_query_executor_status exec_status;
-       method_t method = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(query_exec, "Query executor");
-       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
-       BT_ASSERT_PRE_NON_NULL(object, "Object");
-       BT_ASSERT_PRE_NON_NULL(user_result, "Result (output)");
-       BT_ASSERT_PRE(!query_exec->canceled, "Query executor is canceled.");
-
-       if (!params) {
-               params = bt_value_null;
-       }
-
-       switch (comp_cls->type) {
-       case BT_COMPONENT_CLASS_TYPE_SOURCE:
-       {
-               struct bt_component_class_source *src_cc = (void *) comp_cls;
-
-               method = (method_t) src_cc->methods.query;
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_FILTER:
-       {
-               struct bt_component_class_filter *flt_cc = (void *) comp_cls;
-
-               method = (method_t) flt_cc->methods.query;
-               break;
-       }
-       case BT_COMPONENT_CLASS_TYPE_SINK:
-       {
-               struct bt_component_class_sink *sink_cc = (void *) comp_cls;
-
-               method = (method_t) sink_cc->methods.query;
-               break;
-       }
-       default:
-               abort();
-       }
-
-       if (!method) {
-               /* Not an error: nothing to query */
-               BT_LIB_LOGD("Component class has no registered query method: "
-                       "%!+C", comp_cls);
-               exec_status = BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED;
-               goto end;
-       }
-
-       BT_LIB_LOGD("Calling user's query method: "
-               "query-exec-addr=%p, %![cc-]+C, object=\"%s\", %![params-]+v",
-               query_exec, comp_cls, object, params);
-       *user_result = NULL;
-       status = method((void *) comp_cls, query_exec, object, params,
-               user_result);
-       BT_LIB_LOGD("User method returned: status=%s, %![res-]+v",
-               bt_query_status_string(status), *user_result);
-       BT_ASSERT_PRE(status != BT_QUERY_STATUS_OK || *user_result,
-               "User method returned `BT_QUERY_STATUS_OK` without a result.");
-       exec_status = (int) status;
-       if (query_exec->canceled) {
-               BT_OBJECT_PUT_REF_AND_RESET(*user_result);
-               exec_status = BT_QUERY_EXECUTOR_STATUS_CANCELED;
-               goto end;
-       }
-
-end:
-       return exec_status;
-}
-
-enum bt_query_executor_status bt_query_executor_cancel(
-               struct bt_query_executor *query_exec)
-{
-       BT_ASSERT_PRE_NON_NULL(query_exec, "Query executor");
-       query_exec->canceled = BT_TRUE;
-       BT_LOGV("Canceled query executor: addr=%p", query_exec);
-       return BT_QUERY_EXECUTOR_STATUS_OK;
-}
-
-bt_bool bt_query_executor_is_canceled(const struct bt_query_executor *query_exec)
-{
-       BT_ASSERT_PRE_NON_NULL(query_exec, "Query executor");
-       return query_exec->canceled;
-}
-
-void bt_query_executor_get_ref(const struct bt_query_executor *query_executor)
-{
-       bt_object_get_ref(query_executor);
-}
-
-void bt_query_executor_put_ref(const struct bt_query_executor *query_executor)
-{
-       bt_object_put_ref(query_executor);
-}
diff --git a/lib/lib-logging.c b/lib/lib-logging.c
deleted file mode 100644 (file)
index 8b16a01..0000000
+++ /dev/null
@@ -1,1420 +0,0 @@
-/*
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "LIB-LOGGING"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <wchar.h>
-#include <glib.h>
-#include <babeltrace2/lib-logging-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/lib-logging-internal.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/event-class-internal.h>
-#include <babeltrace2/trace-ir/event-const.h>
-#include <babeltrace2/trace-ir/event-internal.h>
-#include <babeltrace2/trace-ir/packet-const.h>
-#include <babeltrace2/trace-ir/packet-internal.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/stream-const.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/trace-ir/trace-class-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/field-path-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/graph/component-class-sink-colander-internal.h>
-#include <babeltrace2/graph/component-filter-internal.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/component-sink-internal.h>
-#include <babeltrace2/graph/component-source-internal.h>
-#include <babeltrace2/graph/connection-internal.h>
-#include <babeltrace2/graph/graph-internal.h>
-#include <babeltrace2/graph/message-event-internal.h>
-#include <babeltrace2/graph/message-message-iterator-inactivity-internal.h>
-#include <babeltrace2/graph/message-internal.h>
-#include <babeltrace2/graph/message-iterator-internal.h>
-#include <babeltrace2/graph/message-packet-internal.h>
-#include <babeltrace2/graph/message-stream-internal.h>
-#include <babeltrace2/graph/message-stream-activity-internal.h>
-#include <babeltrace2/graph/message-discarded-items-internal.h>
-#include <babeltrace2/graph/port-internal.h>
-#include <babeltrace2/plugin/plugin-internal.h>
-#include <babeltrace2/plugin/plugin-so-internal.h>
-
-#define LIB_LOGGING_BUF_SIZE   (4096 * 4)
-
-static __thread char lib_logging_buf[LIB_LOGGING_BUF_SIZE];
-
-#define BUF_APPEND(_fmt, ...)                                          \
-       do {                                                            \
-               int _count;                                             \
-               size_t _size = LIB_LOGGING_BUF_SIZE -                   \
-                               (size_t) (*buf_ch - lib_logging_buf);   \
-               _count = snprintf(*buf_ch, _size, (_fmt), __VA_ARGS__); \
-               BT_ASSERT(_count >= 0);                                 \
-               *buf_ch += MIN(_count, _size);                          \
-               if (*buf_ch >= lib_logging_buf + LIB_LOGGING_BUF_SIZE - 1) { \
-                       return;                                         \
-               }                                                       \
-       } while (0)
-
-#define BUF_APPEND_UUID(_uuid)                                         \
-       do {                                                            \
-               BUF_APPEND(", %suuid=", prefix);                        \
-               format_uuid(buf_ch, (_uuid));                           \
-       } while (0)
-
-#define PRFIELD(_expr) prefix, (_expr)
-
-#define PRFIELD_GSTRING(_expr) PRFIELD((_expr) ? (_expr)->str : NULL)
-
-#define TMP_PREFIX_LEN 64
-#define SET_TMP_PREFIX(_prefix2)                                       \
-       do {                                                            \
-               snprintf(tmp_prefix, TMP_PREFIX_LEN - 1, "%s%s",        \
-                       prefix, (_prefix2));                            \
-               tmp_prefix[TMP_PREFIX_LEN - 1] = '\0';                  \
-       } while (0)
-
-static inline void format_component(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_component *component);
-
-static inline void format_port(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_port *port);
-
-static inline void format_connection(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_connection *connection);
-
-static inline void format_clock_snapshot(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_clock_snapshot *clock_snapshot);
-
-static inline void format_field_path(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_field_path *field_path);
-
-static inline void format_object(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_object *obj)
-{
-       BUF_APPEND(", %sref-count=%llu", prefix, obj->ref_count);
-}
-
-static inline void format_uuid(char **buf_ch, bt_uuid uuid)
-{
-       BUF_APPEND("\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-               (unsigned int) uuid[0],
-               (unsigned int) uuid[1],
-               (unsigned int) uuid[2],
-               (unsigned int) uuid[3],
-               (unsigned int) uuid[4],
-               (unsigned int) uuid[5],
-               (unsigned int) uuid[6],
-               (unsigned int) uuid[7],
-               (unsigned int) uuid[8],
-               (unsigned int) uuid[9],
-               (unsigned int) uuid[10],
-               (unsigned int) uuid[11],
-               (unsigned int) uuid[12],
-               (unsigned int) uuid[13],
-               (unsigned int) uuid[14],
-               (unsigned int) uuid[15]);
-}
-
-static inline void format_object_pool(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_object_pool *pool)
-{
-       BUF_APPEND(", %ssize=%zu", PRFIELD(pool->size));
-
-       if (pool->objects) {
-               BUF_APPEND(", %scap=%u", PRFIELD(pool->objects->len));
-       }
-}
-
-static inline void format_integer_field_class(char **buf_ch,
-               bool extended, const char *prefix,
-               const struct bt_field_class *field_class)
-{
-       const struct bt_field_class_integer *int_fc =
-               (const void *) field_class;
-
-       BUF_APPEND(", %srange-size=%" PRIu64 ", %sbase=%s",
-               PRFIELD(int_fc->range),
-               PRFIELD(bt_common_field_class_integer_preferred_display_base_string(int_fc->base)));
-}
-
-static inline void format_array_field_class(char **buf_ch,
-               bool extended, const char *prefix,
-               const struct bt_field_class *field_class)
-{
-       const struct bt_field_class_array *array_fc =
-               (const void *) field_class;
-
-       BUF_APPEND(", %selement-fc-addr=%p, %selement-fc-type=%s",
-               PRFIELD(array_fc->element_fc),
-               PRFIELD(bt_common_field_class_type_string(array_fc->element_fc->type)));
-}
-
-static inline void format_field_class(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_field_class *field_class)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %stype=%s",
-               PRFIELD(bt_common_field_class_type_string(field_class->type)));
-
-       if (extended) {
-               BUF_APPEND(", %sis-frozen=%d", PRFIELD(field_class->frozen));
-               BUF_APPEND(", %sis-part-of-trace-class=%d",
-                       PRFIELD(field_class->part_of_trace_class));
-       } else {
-               return;
-       }
-
-       switch (field_class->type) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
-       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
-       {
-               format_integer_field_class(buf_ch, extended, prefix, field_class);
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_REAL:
-       {
-               const struct bt_field_class_real *real_fc = (void *) field_class;
-
-               BUF_APPEND(", %sis-single-precision=%d",
-                       PRFIELD(real_fc->is_single_precision));
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-       {
-               const struct bt_field_class_enumeration *enum_fc =
-                       (const void *) field_class;
-
-               format_integer_field_class(buf_ch, extended, prefix, field_class);
-               BUF_APPEND(", %smapping-count=%u",
-                       PRFIELD(enum_fc->mappings->len));
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-       {
-               const struct bt_field_class_structure *struct_fc =
-                       (const void *) field_class;
-
-               if (struct_fc->common.named_fcs) {
-                       BUF_APPEND(", %smember-count=%u",
-                               PRFIELD(struct_fc->common.named_fcs->len));
-               }
-
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       {
-               const struct bt_field_class_static_array *array_fc =
-                       (const void *) field_class;
-
-               format_array_field_class(buf_ch, extended, prefix, field_class);
-               BUF_APPEND(", %slength=%" PRIu64, PRFIELD(array_fc->length));
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-       {
-               const struct bt_field_class_dynamic_array *array_fc =
-                       (const void *) field_class;
-
-               format_array_field_class(buf_ch, extended, prefix, field_class);
-
-               if (array_fc->length_fc) {
-                       SET_TMP_PREFIX("length-fc-");
-                       format_field_class(buf_ch, extended, tmp_prefix,
-                               array_fc->length_fc);
-               }
-
-               if (array_fc->length_field_path) {
-                       SET_TMP_PREFIX("length-field-path-");
-                       format_field_path(buf_ch, extended, tmp_prefix,
-                               array_fc->length_field_path);
-               }
-
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               const struct bt_field_class_variant *var_fc =
-                       (const void *) field_class;
-
-               if (var_fc->common.named_fcs) {
-                       BUF_APPEND(", %soption-count=%u",
-                               PRFIELD(var_fc->common.named_fcs->len));
-               }
-
-               if (var_fc->selector_fc) {
-                       SET_TMP_PREFIX("selector-fc-");
-                       format_field_class(buf_ch, extended, tmp_prefix,
-                               var_fc->selector_fc);
-               }
-
-               if (var_fc->selector_field_path) {
-                       SET_TMP_PREFIX("selector-field-path-");
-                       format_field_path(buf_ch, extended, tmp_prefix,
-                               var_fc->selector_field_path);
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-static inline void format_field_integer_extended(char **buf_ch,
-               const char *prefix, const struct bt_field *field)
-{
-       const struct bt_field_integer *integer = (void *) field;
-       const struct bt_field_class_integer *field_class =
-               (void *) field->class;
-       const char *fmt = NULL;
-
-       BT_ASSERT(field_class);
-
-       if (field_class->base == BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL) {
-               fmt = ", %svalue=%" PRIo64;
-       } else if (field_class->base == BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL) {
-               fmt = ", %svalue=%" PRIx64;
-       }
-
-       if (field_class->common.type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
-                       field_class->common.type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
-               if (!fmt) {
-                       fmt = ", %svalue=%" PRId64;
-               }
-
-               BUF_APPEND(fmt, PRFIELD(integer->value.i));
-       } else {
-               if (!fmt) {
-                       fmt = ", %svalue=%" PRIu64;
-               }
-
-               BUF_APPEND(fmt, PRFIELD(integer->value.u));
-       }
-}
-
-static inline void format_field(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_field *field)
-{
-       BUF_APPEND(", %sis-set=%d", PRFIELD(field->is_set));
-
-       if (extended) {
-               BUF_APPEND(", %sis-frozen=%d", PRFIELD(field->frozen));
-       }
-
-       BUF_APPEND(", %sclass-addr=%p", PRFIELD(field->class));
-
-       if (!field->class) {
-               return;
-       }
-
-       BUF_APPEND(", %sclass-type=%s",
-               PRFIELD(bt_common_field_class_type_string(field->class->type)));
-
-       if (!extended || !field->is_set) {
-               return;
-       }
-
-       switch (field->class->type) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
-       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-       {
-               format_field_integer_extended(buf_ch, prefix, field);
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_REAL:
-       {
-               const struct bt_field_real *real_field = (const void *) field;
-
-               BUF_APPEND(", %svalue=%f", PRFIELD(real_field->value));
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STRING:
-       {
-               const struct bt_field_string *str = (const void *) field;
-
-               if (str->buf) {
-                       BT_ASSERT(str->buf->data);
-                       BUF_APPEND(", %spartial-value=\"%.32s\"",
-                               PRFIELD(str->buf->data));
-               }
-
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-       {
-               const struct bt_field_array *array_field = (const void *) field;
-
-               BUF_APPEND(", %slength=%" PRIu64, PRFIELD(array_field->length));
-
-               if (array_field->fields) {
-                       BUF_APPEND(", %sallocated-length=%u",
-                               PRFIELD(array_field->fields->len));
-               }
-
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               const struct bt_field_variant *var_field = (const void *) field;
-
-               BUF_APPEND(", %sselected-field-index=%" PRIu64,
-                       PRFIELD(var_field->selected_index));
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-static inline void format_field_path(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_field_path *field_path)
-{
-       uint64_t i;
-
-       if (field_path->items) {
-               BT_ASSERT(field_path->items);
-               BUF_APPEND(", %sitem-count=%u",
-                       PRFIELD(field_path->items->len));
-       }
-
-       if (!extended || !field_path->items) {
-               return;
-       }
-
-       BUF_APPEND(", %spath=[%s",
-               PRFIELD(bt_common_scope_string(field_path->root)));
-
-       for (i = 0; i < bt_field_path_get_item_count(field_path); i++) {
-               const struct bt_field_path_item *fp_item =
-                       bt_field_path_borrow_item_by_index_const(field_path, i);
-
-               switch (bt_field_path_item_get_type(fp_item)) {
-               case BT_FIELD_PATH_ITEM_TYPE_INDEX:
-                       BUF_APPEND(", %" PRIu64,
-                               bt_field_path_item_index_get_index(fp_item));
-                       break;
-               case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
-                       BUF_APPEND("%s", ", <CUR>");
-                       break;
-               default:
-                       abort();
-               }
-       }
-
-       BUF_APPEND("%s", "]");
-}
-
-static inline void format_trace_class(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_trace_class *trace_class)
-{
-       if (trace_class->name.value) {
-               BUF_APPEND(", %sname=\"%s\"",
-                       PRFIELD(trace_class->name.value));
-       }
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-frozen=%d", PRFIELD(trace_class->frozen));
-
-       if (trace_class->uuid.value) {
-               BUF_APPEND_UUID(trace_class->uuid.value);
-       }
-
-       if (trace_class->stream_classes) {
-               BUF_APPEND(", %sstream-class-count=%u",
-                       PRFIELD(trace_class->stream_classes->len));
-       }
-
-       BUF_APPEND(", %sassigns-auto-sc-id=%d",
-               PRFIELD(trace_class->assigns_automatic_stream_class_id));
-}
-
-static inline void format_trace(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_trace *trace)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       if (trace->name.value) {
-               BUF_APPEND(", %sname=\"%s\"", PRFIELD(trace->name.value));
-       }
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-frozen=%d", PRFIELD(trace->frozen));
-
-       if (trace->streams) {
-               BUF_APPEND(", %sstream-count=%u",
-                       PRFIELD(trace->streams->len));
-       }
-
-       if (!trace->class) {
-               return;
-       }
-
-       BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace->class));
-       SET_TMP_PREFIX("trace-class-");
-       format_trace_class(buf_ch, false, tmp_prefix, trace->class);
-}
-
-static inline void format_stream_class(char **buf_ch, bool extended,
-               const char *prefix,
-               const struct bt_stream_class *stream_class)
-{
-       const struct bt_trace_class *trace_class;
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(stream_class->id));
-
-       if (stream_class->name.value) {
-               BUF_APPEND(", %sname=\"%s\"",
-                       PRFIELD(stream_class->name.value));
-       }
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-frozen=%d", PRFIELD(stream_class->frozen));
-
-       if (stream_class->event_classes) {
-               BUF_APPEND(", %sevent-class-count=%u",
-                       PRFIELD(stream_class->event_classes->len));
-       }
-
-       BUF_APPEND(", %spacket-context-fc-addr=%p, "
-               "%sevent-common-context-fc-addr=%p",
-               PRFIELD(stream_class->packet_context_fc),
-               PRFIELD(stream_class->event_common_context_fc));
-       trace_class = bt_stream_class_borrow_trace_class_inline(stream_class);
-       if (!trace_class) {
-               return;
-       }
-
-       BUF_APPEND(", %sassigns-auto-ec-id=%d, %sassigns-auto-stream-id=%d, "
-               "%spackets-have-default-beginning-cs=%d, "
-               "%spackets-have-default-end-cs=%d, "
-               "%ssupports-discarded-events=%d, "
-               "%sdiscarded-events-have-default-cs=%d, "
-               "%ssupports-discarded-packets=%d, "
-               "%sdiscarded-packets-have-default-cs=%d",
-               PRFIELD(stream_class->assigns_automatic_event_class_id),
-               PRFIELD(stream_class->assigns_automatic_stream_id),
-               PRFIELD(stream_class->packets_have_beginning_default_clock_snapshot),
-               PRFIELD(stream_class->packets_have_end_default_clock_snapshot),
-               PRFIELD(stream_class->supports_discarded_events),
-               PRFIELD(stream_class->discarded_events_have_default_clock_snapshots),
-               PRFIELD(stream_class->supports_discarded_packets),
-               PRFIELD(stream_class->discarded_packets_have_default_clock_snapshots));
-       BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace_class));
-       SET_TMP_PREFIX("trace-class-");
-       format_trace_class(buf_ch, false, tmp_prefix, trace_class);
-       SET_TMP_PREFIX("pcf-pool-");
-       format_object_pool(buf_ch, extended, tmp_prefix,
-               &stream_class->packet_context_field_pool);
-}
-
-static inline void format_event_class(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_event_class *event_class)
-{
-       const struct bt_stream_class *stream_class;
-       const struct bt_trace_class *trace_class;
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(event_class->id));
-
-       if (event_class->name.value) {
-               BUF_APPEND(", %sname=\"%s\"",
-                       PRFIELD(event_class->name.value));
-       }
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-frozen=%d", PRFIELD(event_class->frozen));
-
-       if (event_class->log_level.base.avail) {
-               BUF_APPEND(", %slog-level=%s",
-                       PRFIELD(bt_common_event_class_log_level_string(
-                               (int) event_class->log_level.value)));
-       }
-
-       if (event_class->emf_uri.value) {
-               BUF_APPEND(", %semf-uri=\"%s\"",
-                       PRFIELD(event_class->emf_uri.value));
-       }
-
-       BUF_APPEND(", %sspecific-context-fc-addr=%p, %spayload-fc-addr=%p",
-               PRFIELD(event_class->specific_context_fc),
-               PRFIELD(event_class->payload_fc));
-
-       stream_class = bt_event_class_borrow_stream_class_const(event_class);
-       if (!stream_class) {
-               return;
-       }
-
-       BUF_APPEND(", %sstream-class-addr=%p", PRFIELD(stream_class));
-       SET_TMP_PREFIX("stream-class-");
-       format_stream_class(buf_ch, false, tmp_prefix, stream_class);
-       trace_class = bt_stream_class_borrow_trace_class_inline(stream_class);
-       if (!trace_class) {
-               return;
-       }
-
-       BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace_class));
-       SET_TMP_PREFIX("trace-class-");
-       format_trace_class(buf_ch, false, tmp_prefix, trace_class);
-       SET_TMP_PREFIX("event-pool-");
-       format_object_pool(buf_ch, extended, tmp_prefix,
-               &event_class->event_pool);
-}
-
-static inline void format_stream(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_stream *stream)
-{
-       const struct bt_stream_class *stream_class;
-       const struct bt_trace_class *trace_class = NULL;
-       const struct bt_trace *trace = NULL;
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(stream->id));
-
-       if (stream->name.value) {
-               BUF_APPEND(", %sname=\"%s\"", PRFIELD(stream->name.value));
-       }
-
-       if (!extended) {
-               return;
-       }
-
-       stream_class = bt_stream_borrow_class_const(stream);
-       if (stream_class) {
-               BUF_APPEND(", %sstream-class-addr=%p", PRFIELD(stream_class));
-               SET_TMP_PREFIX("stream-class-");
-               format_stream_class(buf_ch, false, tmp_prefix, stream_class);
-               trace_class = bt_stream_class_borrow_trace_class_inline(stream_class);
-       }
-
-       if (trace_class) {
-               BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace_class));
-               SET_TMP_PREFIX("trace-class-");
-               format_trace_class(buf_ch, false, tmp_prefix, trace_class);
-       }
-
-       trace = bt_stream_borrow_trace_inline(stream);
-       if (trace) {
-               BUF_APPEND(", %strace-addr=%p", PRFIELD(trace));
-               SET_TMP_PREFIX("trace-");
-               format_trace(buf_ch, false, tmp_prefix, trace);
-       }
-
-       SET_TMP_PREFIX("packet-pool-");
-       format_object_pool(buf_ch, extended, tmp_prefix, &stream->packet_pool);
-}
-
-static inline void format_packet(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_packet *packet)
-{
-       const struct bt_stream *stream;
-       const struct bt_trace_class *trace_class;
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-frozen=%d, %scontext-field-addr=%p",
-               PRFIELD(packet->frozen),
-               PRFIELD(packet->context_field ? packet->context_field->field : NULL));
-       stream = bt_packet_borrow_stream_const(packet);
-       if (!stream) {
-               return;
-       }
-
-       BUF_APPEND(", %sstream-addr=%p", PRFIELD(stream));
-       SET_TMP_PREFIX("stream-");
-       format_stream(buf_ch, false, tmp_prefix, stream);
-       trace_class = (const struct bt_trace_class *) bt_object_borrow_parent(&stream->base);
-       if (!trace_class) {
-               return;
-       }
-
-       BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace_class));
-       SET_TMP_PREFIX("trace-class-");
-       format_trace_class(buf_ch, false, tmp_prefix, trace_class);
-}
-
-static inline void format_event(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_event *event)
-{
-       const struct bt_packet *packet;
-       const struct bt_stream *stream;
-       const struct bt_trace_class *trace_class;
-       const struct bt_stream_class *stream_class;
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-frozen=%d, "
-               "%scommon-context-field-addr=%p, "
-               "%sspecific-context-field-addr=%p, "
-               "%spayload-field-addr=%p, ",
-               PRFIELD(event->frozen),
-               PRFIELD(event->common_context_field),
-               PRFIELD(event->specific_context_field),
-               PRFIELD(event->payload_field));
-       BUF_APPEND(", %sevent-class-addr=%p", PRFIELD(event->class));
-
-       if (!event->class) {
-               return;
-       }
-
-       SET_TMP_PREFIX("event-class-");
-       format_event_class(buf_ch, false, tmp_prefix, event->class);
-       stream_class = bt_event_class_borrow_stream_class(event->class);
-       if (stream_class) {
-               BUF_APPEND(", %sstream-class-addr=%p", PRFIELD(stream_class));
-               SET_TMP_PREFIX("stream-class-");
-               format_stream_class(buf_ch, false, tmp_prefix,
-                       stream_class);
-
-               trace_class = bt_stream_class_borrow_trace_class_inline(
-                       stream_class);
-               if (trace_class) {
-                       BUF_APPEND(", %strace-class-addr=%p",
-                               PRFIELD(trace_class));
-                       SET_TMP_PREFIX("trace-class-");
-                       format_trace_class(buf_ch, false, tmp_prefix,
-                               trace_class);
-               }
-       }
-
-       packet = bt_event_borrow_packet_const(event);
-       if (!packet) {
-               return;
-       }
-
-       BUF_APPEND(", %spacket-addr=%p", PRFIELD(packet));
-       SET_TMP_PREFIX("packet-");
-       format_packet(buf_ch, false, tmp_prefix, packet);
-       stream = bt_packet_borrow_stream_const(packet);
-       if (!stream) {
-               return;
-       }
-
-       BUF_APPEND(", %sstream-addr=%p", PRFIELD(stream));
-       SET_TMP_PREFIX("stream-");
-       format_stream(buf_ch, false, tmp_prefix, stream);
-}
-
-static inline void format_clock_class(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_clock_class *clock_class)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       if (clock_class->name.value) {
-               BUF_APPEND(", %sname=\"%s\"", PRFIELD(clock_class->name.value));
-       }
-
-       BUF_APPEND(", %sfreq=%" PRIu64, PRFIELD(clock_class->frequency));
-
-       if (!extended) {
-               return;
-       }
-
-       if (clock_class->description.value) {
-               BUF_APPEND(", %spartial-descr=\"%.32s\"",
-                       PRFIELD(clock_class->description.value));
-       }
-
-       if (clock_class->uuid.value) {
-               BUF_APPEND_UUID(clock_class->uuid.value);
-       }
-
-       BUF_APPEND(", %sis-frozen=%d, %sprecision=%" PRIu64 ", "
-               "%soffset-s=%" PRId64 ", "
-               "%soffset-cycles=%" PRIu64 ", %sorigin-is-unix-epoch=%d, "
-               "%sbase-offset-ns=%" PRId64,
-               PRFIELD(clock_class->frozen), PRFIELD(clock_class->precision),
-               PRFIELD(clock_class->offset_seconds),
-               PRFIELD(clock_class->offset_cycles),
-               PRFIELD(clock_class->origin_is_unix_epoch),
-               PRFIELD(clock_class->base_offset.value_ns));
-
-       SET_TMP_PREFIX("cs-pool-");
-       format_object_pool(buf_ch, extended, tmp_prefix,
-               &clock_class->cs_pool);
-}
-
-static inline void format_clock_snapshot(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_clock_snapshot *clock_snapshot)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-       BUF_APPEND(", %svalue=%" PRIu64 ", %sns-from-origin=%" PRId64,
-               PRFIELD(clock_snapshot->value_cycles),
-               PRFIELD(clock_snapshot->ns_from_origin));
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-set=%d", PRFIELD(clock_snapshot->is_set));
-
-       if (clock_snapshot->clock_class) {
-               BUF_APPEND(", %sclock-class-addr=%p",
-                       PRFIELD(clock_snapshot->clock_class));
-               SET_TMP_PREFIX("clock-class-");
-               format_clock_class(buf_ch, false, tmp_prefix,
-                       clock_snapshot->clock_class);
-       }
-}
-
-static inline void format_value(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_value *value)
-{
-       BUF_APPEND(", %stype=%s",
-               PRFIELD(bt_common_value_type_string(bt_value_get_type(value))));
-
-       if (!extended) {
-               return;
-       }
-
-       switch (bt_value_get_type(value)) {
-       case BT_VALUE_TYPE_BOOL:
-       {
-               bt_bool val = bt_value_bool_get(value);
-
-               BUF_APPEND(", %svalue=%d", PRFIELD(val));
-               break;
-       }
-       case BT_VALUE_TYPE_UNSIGNED_INTEGER:
-       {
-               BUF_APPEND(", %svalue=%" PRIu64,
-                       PRFIELD(bt_value_unsigned_integer_get(value)));
-               break;
-       }
-       case BT_VALUE_TYPE_SIGNED_INTEGER:
-       {
-               BUF_APPEND(", %svalue=%" PRId64,
-                       PRFIELD(bt_value_signed_integer_get(value)));
-               break;
-       }
-       case BT_VALUE_TYPE_REAL:
-       {
-               double val = bt_value_real_get(value);
-
-               BUF_APPEND(", %svalue=%f", PRFIELD(val));
-               break;
-       }
-       case BT_VALUE_TYPE_STRING:
-       {
-               const char *val = bt_value_string_get(value);
-
-               BUF_APPEND(", %spartial-value=\"%.32s\"", PRFIELD(val));
-               break;
-       }
-       case BT_VALUE_TYPE_ARRAY:
-       {
-               int64_t count = bt_value_array_get_size(value);
-
-               BT_ASSERT(count >= 0);
-               BUF_APPEND(", %selement-count=%" PRId64, PRFIELD(count));
-               break;
-       }
-       case BT_VALUE_TYPE_MAP:
-       {
-               int64_t count = bt_value_map_get_size(value);
-
-               BT_ASSERT(count >= 0);
-               BUF_APPEND(", %selement-count=%" PRId64, PRFIELD(count));
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-static inline void format_message(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_message *msg)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %stype=%s",
-               PRFIELD(bt_message_type_string(msg->type)));
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-frozen=%d, %sgraph-addr=%p",
-               PRFIELD(msg->frozen), PRFIELD(msg->graph));
-
-       switch (msg->type) {
-       case BT_MESSAGE_TYPE_EVENT:
-       {
-               const struct bt_message_event *msg_event =
-                       (const void *) msg;
-
-               if (msg_event->event) {
-                       SET_TMP_PREFIX("event-");
-                       format_event(buf_ch, true, tmp_prefix,
-                               msg_event->event);
-               }
-
-               if (msg_event->default_cs) {
-                       SET_TMP_PREFIX("default-cs-");
-                       format_clock_snapshot(buf_ch, true, tmp_prefix,
-                               msg_event->default_cs);
-               }
-
-               break;
-       }
-       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
-       case BT_MESSAGE_TYPE_STREAM_END:
-       {
-               const struct bt_message_stream *msg_stream = (const void *) msg;
-
-               if (msg_stream->stream) {
-                       SET_TMP_PREFIX("stream-");
-                       format_stream(buf_ch, true, tmp_prefix,
-                               msg_stream->stream);
-               }
-
-               break;
-       }
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-       {
-               const struct bt_message_stream_activity *msg_stream_activity =
-                       (const void *) msg;
-
-               if (msg_stream_activity->stream) {
-                       SET_TMP_PREFIX("stream-");
-                       format_stream(buf_ch, true, tmp_prefix,
-                               msg_stream_activity->stream);
-               }
-
-               BUF_APPEND(", %sdefault-cs-state=%s",
-                       PRFIELD(bt_message_stream_activity_clock_snapshot_state_string(
-                               msg_stream_activity->default_cs_state)));
-
-               if (msg_stream_activity->default_cs) {
-                       SET_TMP_PREFIX("default-cs-");
-                       format_clock_snapshot(buf_ch, true, tmp_prefix,
-                               msg_stream_activity->default_cs);
-               }
-
-               break;
-       }
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-       case BT_MESSAGE_TYPE_PACKET_END:
-       {
-               const struct bt_message_packet *msg_packet = (const void *) msg;
-
-               if (msg_packet->packet) {
-                       SET_TMP_PREFIX("packet-");
-                       format_packet(buf_ch, true, tmp_prefix,
-                               msg_packet->packet);
-               }
-
-               if (msg_packet->default_cs) {
-                       SET_TMP_PREFIX("default-cs-");
-                       format_clock_snapshot(buf_ch, true, tmp_prefix,
-                               msg_packet->default_cs);
-               }
-
-               break;
-       }
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-       {
-               const struct bt_message_discarded_items *msg_disc_items =
-                       (const void *) msg;
-
-               if (msg_disc_items->stream) {
-                       SET_TMP_PREFIX("stream-");
-                       format_stream(buf_ch, true, tmp_prefix,
-                               msg_disc_items->stream);
-               }
-
-               if (msg_disc_items->default_begin_cs) {
-                       SET_TMP_PREFIX("default-begin-cs-");
-                       format_clock_snapshot(buf_ch, true, tmp_prefix,
-                               msg_disc_items->default_begin_cs);
-               }
-
-               if (msg_disc_items->default_end_cs) {
-                       SET_TMP_PREFIX("default-end-cs-");
-                       format_clock_snapshot(buf_ch, true, tmp_prefix,
-                               msg_disc_items->default_end_cs);
-               }
-
-               if (msg_disc_items->count.base.avail) {
-                       BUF_APPEND(", %scount=%" PRIu64,
-                               PRFIELD(msg_disc_items->count.value));
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-static inline void format_plugin_so_shared_lib_handle(char **buf_ch,
-               const char *prefix,
-               const struct bt_plugin_so_shared_lib_handle *handle)
-{
-       BUF_APPEND(", %saddr=%p", PRFIELD(handle));
-
-       if (handle->path) {
-               BUF_APPEND(", %spath=\"%s\"", PRFIELD_GSTRING(handle->path));
-       }
-}
-
-static inline void format_component_class(char **buf_ch, bool extended,
-               const char *prefix,
-               const struct bt_component_class *comp_class)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %stype=%s, %sname=\"%s\"",
-               PRFIELD(bt_component_class_type_string(comp_class->type)),
-               PRFIELD_GSTRING(comp_class->name));
-
-       if (comp_class->description) {
-               BUF_APPEND(", %spartial-descr=\"%.32s\"",
-                       PRFIELD_GSTRING(comp_class->description));
-       }
-
-       if (!extended) {
-               return;
-       }
-
-       BUF_APPEND(", %sis-frozen=%d", PRFIELD(comp_class->frozen));
-
-       if (comp_class->so_handle) {
-               SET_TMP_PREFIX("so-handle-");
-               format_plugin_so_shared_lib_handle(buf_ch, tmp_prefix,
-                       comp_class->so_handle);
-       }
-}
-
-static inline void format_component(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_component *component)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %sname=\"%s\"",
-               PRFIELD_GSTRING(component->name));
-
-       if (component->class) {
-               SET_TMP_PREFIX("class-");
-               format_component_class(buf_ch, extended, tmp_prefix,
-                       component->class);
-       }
-
-       if (!extended) {
-               return;
-       }
-
-       if (component->input_ports) {
-               BUF_APPEND(", %sinput-port-count=%u",
-                       PRFIELD(component->input_ports->len));
-       }
-
-       if (component->output_ports) {
-               BUF_APPEND(", %soutput-port-count=%u",
-                       PRFIELD(component->output_ports->len));
-       }
-}
-
-static inline void format_port(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_port *port)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %stype=%s, %sname=\"%s\"",
-               PRFIELD(bt_port_type_string(port->type)),
-               PRFIELD_GSTRING(port->name));
-
-       if (!extended) {
-               return;
-       }
-
-       if (port->connection) {
-               SET_TMP_PREFIX("conn-");
-               format_connection(buf_ch, false, tmp_prefix, port->connection);
-       }
-}
-
-static inline void format_connection(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_connection *connection)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       if (!extended) {
-               return;
-       }
-
-       if (connection->upstream_port) {
-               SET_TMP_PREFIX("upstream-port-");
-               format_port(buf_ch, false, tmp_prefix,
-                       connection->upstream_port);
-       }
-
-       if (connection->downstream_port) {
-               SET_TMP_PREFIX("downstream-port-");
-               format_port(buf_ch, false, tmp_prefix,
-                       connection->downstream_port);
-       }
-}
-
-static inline void format_graph(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_graph *graph)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %sis-canceled=%d, %scan-consume=%d, "
-               "%sconfig-state=%s",
-               PRFIELD(graph->canceled),
-               PRFIELD(graph->can_consume),
-               PRFIELD(bt_graph_configuration_state_string(graph->config_state)));
-
-       if (!extended) {
-               return;
-       }
-
-       if (graph->components) {
-               BUF_APPEND(", %scomp-count=%u",
-                       PRFIELD(graph->components->len));
-       }
-
-       if (graph->connections) {
-               BUF_APPEND(", %sconn-count=%u",
-                       PRFIELD(graph->connections->len));
-       }
-
-       SET_TMP_PREFIX("en-pool-");
-       format_object_pool(buf_ch, extended, tmp_prefix,
-               &graph->event_msg_pool);
-       SET_TMP_PREFIX("pbn-pool-");
-       format_object_pool(buf_ch, extended, tmp_prefix,
-               &graph->packet_begin_msg_pool);
-       SET_TMP_PREFIX("pen-pool-");
-       format_object_pool(buf_ch, extended, tmp_prefix,
-               &graph->packet_end_msg_pool);
-}
-
-static inline void format_message_iterator(char **buf_ch,
-               bool extended, const char *prefix,
-               const struct bt_message_iterator *iterator)
-{
-       const char *type;
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       if (iterator->type == BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT) {
-               type = "BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT";
-       } else if (iterator->type == BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT) {
-               type = "BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT";
-       } else {
-               type = "(unknown)";
-       }
-
-       BUF_APPEND(", %stype=%s", PRFIELD(type));
-
-       switch (iterator->type) {
-       case BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT:
-       {
-               const struct bt_self_component_port_input_message_iterator *
-                       port_in_iter = (const void *) iterator;
-
-               if (port_in_iter->upstream_component) {
-                       SET_TMP_PREFIX("upstream-comp-");
-                       format_component(buf_ch, false, tmp_prefix,
-                               port_in_iter->upstream_component);
-               }
-
-               if (port_in_iter->upstream_port) {
-                       SET_TMP_PREFIX("upstream-port-");
-                       format_port(buf_ch, false, tmp_prefix,
-                               port_in_iter->upstream_port);
-               }
-
-               if (port_in_iter->connection) {
-                       SET_TMP_PREFIX("upstream-conn-");
-                       format_connection(buf_ch, false, tmp_prefix,
-                               port_in_iter->connection);
-               }
-               break;
-       }
-       case BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT:
-       {
-               const struct bt_port_output_message_iterator *port_out_iter =
-                       (const void *) iterator;
-
-               if (port_out_iter->graph) {
-                       SET_TMP_PREFIX("graph-");
-                       format_graph(buf_ch, false, tmp_prefix,
-                               port_out_iter->graph);
-               }
-
-               if (port_out_iter->colander) {
-                       SET_TMP_PREFIX("colander-comp-");
-                       format_component(buf_ch, false, tmp_prefix,
-                               (void *) port_out_iter->colander);
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-static inline void format_plugin(char **buf_ch, bool extended,
-               const char *prefix, const struct bt_plugin *plugin)
-{
-       char tmp_prefix[TMP_PREFIX_LEN];
-
-       BUF_APPEND(", %stype=%s", PRFIELD(bt_plugin_type_string(plugin->type)));
-
-       if (plugin->info.path_set) {
-               BUF_APPEND(", %spath=\"%s\"",
-                       PRFIELD_GSTRING(plugin->info.path));
-       }
-
-       if (plugin->info.name_set) {
-               BUF_APPEND(", %sname=\"%s\"",
-                       PRFIELD_GSTRING(plugin->info.name));
-       }
-
-       if (!extended) {
-               return;
-       }
-
-       if (plugin->info.author_set) {
-               BUF_APPEND(", %sauthor=\"%s\"",
-                       PRFIELD_GSTRING(plugin->info.author));
-       }
-
-       if (plugin->info.license_set) {
-               BUF_APPEND(", %slicense=\"%s\"",
-                       PRFIELD_GSTRING(plugin->info.license));
-       }
-
-       if (plugin->info.version_set) {
-               BUF_APPEND(", %sversion=%u.%u.%u%s",
-                       PRFIELD(plugin->info.version.major),
-                       plugin->info.version.minor,
-                       plugin->info.version.patch,
-                       plugin->info.version.extra ?
-                               plugin->info.version.extra->str : "");
-       }
-
-       BUF_APPEND(", %ssrc-comp-class-count=%u, %sflt-comp-class-count=%u, "
-               "%ssink-comp-class-count=%u",
-               PRFIELD(plugin->src_comp_classes->len),
-               PRFIELD(plugin->flt_comp_classes->len),
-               PRFIELD(plugin->sink_comp_classes->len));
-
-       if (plugin->spec_data) {
-               const struct bt_plugin_so_spec_data *spec_data =
-                       (const void *) plugin->spec_data;
-
-               if (spec_data->shared_lib_handle) {
-                       SET_TMP_PREFIX("so-handle-");
-                       format_plugin_so_shared_lib_handle(buf_ch, tmp_prefix,
-                               spec_data->shared_lib_handle);
-               }
-       }
-}
-
-static inline void handle_conversion_specifier_bt(void *priv_data,
-               char **buf_ch, size_t avail_size,
-               const char **out_fmt_ch, va_list *args)
-{
-       const char *fmt_ch = *out_fmt_ch;
-       bool extended = false;
-       char prefix[64];
-       char *prefix_ch = prefix;
-       const void *obj;
-
-       /* skip "%!" */
-       fmt_ch += 2;
-
-       if (*fmt_ch == 'u') {
-               /* UUID */
-               obj = va_arg(*args, void *);
-               format_uuid(buf_ch, obj);
-               goto update_fmt;
-       }
-
-       if (*fmt_ch == '[') {
-               /* local prefix */
-               fmt_ch++;
-
-               while (true) {
-                       if (*fmt_ch == ']') {
-                               *prefix_ch = '\0';
-                               fmt_ch++;
-                               break;
-                       }
-
-                       *prefix_ch = *fmt_ch;
-                       prefix_ch++;
-                       fmt_ch++;
-               }
-       }
-
-       *prefix_ch = '\0';
-
-       if (*fmt_ch == '+') {
-               extended = true;
-               fmt_ch++;
-       }
-
-       obj = va_arg(*args, void *);
-       BUF_APPEND("%saddr=%p", prefix, obj);
-
-       if (!obj) {
-               goto update_fmt;
-       }
-
-       switch (*fmt_ch) {
-       case 'F':
-               format_field_class(buf_ch, extended, prefix, obj);
-               break;
-       case 'f':
-               format_field(buf_ch, extended, prefix, obj);
-               break;
-       case 'P':
-               format_field_path(buf_ch, extended, prefix, obj);
-               break;
-       case 'E':
-               format_event_class(buf_ch, extended, prefix, obj);
-               break;
-       case 'e':
-               format_event(buf_ch, extended, prefix, obj);
-               break;
-       case 'S':
-               format_stream_class(buf_ch, extended, prefix, obj);
-               break;
-       case 's':
-               format_stream(buf_ch, extended, prefix, obj);
-               break;
-       case 'a':
-               format_packet(buf_ch, extended, prefix, obj);
-               break;
-       case 't':
-               format_trace(buf_ch, extended, prefix, obj);
-               break;
-       case 'T':
-               format_trace_class(buf_ch, extended, prefix, obj);
-               break;
-       case 'K':
-               format_clock_class(buf_ch, extended, prefix, obj);
-               break;
-       case 'k':
-               format_clock_snapshot(buf_ch, extended, prefix, obj);
-               break;
-       case 'v':
-               format_value(buf_ch, extended, prefix, obj);
-               break;
-       case 'n':
-               format_message(buf_ch, extended, prefix, obj);
-               break;
-       case 'i':
-               format_message_iterator(buf_ch, extended, prefix, obj);
-               break;
-       case 'C':
-               format_component_class(buf_ch, extended, prefix, obj);
-               break;
-       case 'c':
-               format_component(buf_ch, extended, prefix, obj);
-               break;
-       case 'p':
-               format_port(buf_ch, extended, prefix, obj);
-               break;
-       case 'x':
-               format_connection(buf_ch, extended, prefix, obj);
-               break;
-       case 'l':
-               format_plugin(buf_ch, extended, prefix, obj);
-               break;
-       case 'g':
-               format_graph(buf_ch, extended, prefix, obj);
-               break;
-       case 'o':
-               format_object_pool(buf_ch, extended, prefix, obj);
-               break;
-       case 'O':
-               format_object(buf_ch, extended, prefix, obj);
-               break;
-       default:
-               abort();
-       }
-
-update_fmt:
-       fmt_ch++;
-       *out_fmt_ch = fmt_ch;
-}
-
-void bt_lib_log(const char *func, const char *file, unsigned line,
-               int lvl, const char *tag, const char *fmt, ...)
-{
-       va_list args;
-
-       BT_ASSERT(fmt);
-       va_start(args, fmt);
-       bt_common_custom_vsnprintf(lib_logging_buf, LIB_LOGGING_BUF_SIZE, '!',
-               handle_conversion_specifier_bt, NULL, fmt, &args);
-       va_end(args);
-       _bt_log_write_d(func, file, line, lvl, tag, "%s", lib_logging_buf);
-}
diff --git a/lib/logging.c b/lib/logging.c
deleted file mode 100644 (file)
index 7ebb52c..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <babeltrace2/logging.h>
-#include <babeltrace2/version.h>
-
-#define BT_LOG_TAG "LIB"
-#include <babeltrace2/lib-logging-internal.h>
-
-#ifdef BT_DEV_MODE
-/*
- * Default log level is FATAL in developer mode because fatal logging is
- * our way to communicate an unsatisfied precondition and the details.
- */
-# define DEFAULT_LOG_LEVEL     BT_LOG_FATAL
-#else
-/*
- * In non-developer mode, use NONE by default: we don't to print logging
- * statements for any executable which links with the library. The
- * executable should call bt_logging_set_global_level() or the
- * executable's user should set the BABELTRACE_LOGGING_GLOBAL_LEVEL
- * environment variable.
- */
-# define DEFAULT_LOG_LEVEL     BT_LOG_NONE
-#endif /* BT_DEV_MODE */
-
-int bt_lib_log_level = DEFAULT_LOG_LEVEL;
-
-enum bt_logging_level bt_logging_get_minimal_level(void)
-{
-       return BT_LOG_LEVEL;
-}
-
-enum bt_logging_level bt_logging_get_global_level(void)
-{
-       return bt_lib_log_level;
-}
-
-void bt_logging_set_global_level(enum bt_logging_level log_level)
-{
-#ifdef BT_DEV_MODE
-       /*
-        * Do not allow the library's log level to fall to NONE when in
-        * developer mode because fatal logging is our way to
-        * communicate an unsatisfied precondition and the details.
-        */
-       if (log_level == BT_LOG_NONE) {
-               log_level = BT_LOG_FATAL;
-       }
-#endif
-
-       bt_lib_log_level = log_level;
-}
-
-static
-void __attribute__((constructor)) bt_logging_ctor(void)
-{
-       const char *v_extra = bt_version_get_extra() ? bt_version_get_extra() :
-               "";
-
-       bt_logging_set_global_level(
-               bt_log_get_level_from_env("BABELTRACE_LOGGING_GLOBAL_LEVEL"));
-       BT_LOGI("Babeltrace %d.%d.%d%s library loaded: "
-               "major=%d, minor=%d, patch=%d, extra=\"%s\"",
-               bt_version_get_major(), bt_version_get_minor(),
-               bt_version_get_patch(), v_extra,
-               bt_version_get_major(), bt_version_get_minor(),
-               bt_version_get_patch(), v_extra);
-}
diff --git a/lib/object-pool.c b/lib/object-pool.c
deleted file mode 100644 (file)
index 8cdf98c..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "OBJECT-POOL"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <stdint.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-
-int bt_object_pool_initialize(struct bt_object_pool *pool,
-               bt_object_pool_new_object_func new_object_func,
-               bt_object_pool_destroy_object_func destroy_object_func,
-               void *data)
-{
-       int ret = 0;
-
-       BT_ASSERT(new_object_func);
-       BT_ASSERT(destroy_object_func);
-       BT_LOGD("Initializing object pool: addr=%p, data-addr=%p",
-               pool, data);
-       pool->objects = g_ptr_array_new();
-       if (!pool->objects) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       pool->funcs.new_object = new_object_func;
-       pool->funcs.destroy_object = destroy_object_func;
-       pool->data = data;
-       pool->size = 0;
-       BT_LIB_LOGD("Initialized object pool: %!+o", pool);
-       goto end;
-
-error:
-       if (pool) {
-               bt_object_pool_finalize(pool);
-       }
-
-       ret = -1;
-
-end:
-       return ret;
-}
-
-void bt_object_pool_finalize(struct bt_object_pool *pool)
-{
-       uint64_t i;
-
-       BT_ASSERT(pool);
-       BT_LIB_LOGD("Finalizing object pool: %!+o", pool);
-
-       if (pool->objects) {
-               for (i = 0; i < pool->size; i++) {
-                       void *obj = pool->objects->pdata[i];
-
-                       if (obj) {
-                               pool->funcs.destroy_object(obj, pool->data);
-                       }
-               }
-
-               g_ptr_array_free(pool->objects, TRUE);
-               pool->objects = NULL;
-       }
-}
diff --git a/lib/plugin/Makefile.am b/lib/plugin/Makefile.am
deleted file mode 100644 (file)
index bf8afa2..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LTLIBRARIES = libplugin.la
-
-# Plug-in system library
-libplugin_la_SOURCES = \
-       plugin.c \
-       plugin-so.c
diff --git a/lib/plugin/plugin-so.c b/lib/plugin/plugin-so.c
deleted file mode 100644 (file)
index ec69646..0000000
+++ /dev/null
@@ -1,1620 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-SO"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/plugin/plugin-internal.h>
-#include <babeltrace2/plugin/plugin-so-internal.h>
-#include <babeltrace2/plugin/plugin-dev.h>
-#include <babeltrace2/plugin/plugin-internal.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/graph/component-class.h>
-#include <babeltrace2/graph/component-class-source.h>
-#include <babeltrace2/graph/component-class-filter.h>
-#include <babeltrace2/graph/component-class-sink.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/list-internal.h>
-#include <string.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <gmodule.h>
-
-#define NATIVE_PLUGIN_SUFFIX           "." G_MODULE_SUFFIX
-#define NATIVE_PLUGIN_SUFFIX_LEN       sizeof(NATIVE_PLUGIN_SUFFIX)
-#define LIBTOOL_PLUGIN_SUFFIX          ".la"
-#define LIBTOOL_PLUGIN_SUFFIX_LEN      sizeof(LIBTOOL_PLUGIN_SUFFIX)
-
-#define PLUGIN_SUFFIX_LEN      max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
-                                       sizeof(LIBTOOL_PLUGIN_SUFFIX))
-
-BT_PLUGIN_MODULE();
-
-/*
- * This list, global to the library, keeps all component classes that
- * have a reference to their shared library handles. It allows iteration
- * on all component classes still present when the destructor executes
- * to release the shared library handle references they might still have.
- *
- * The list items are the component classes created with
- * bt_plugin_add_component_class(). They keep the shared library handle
- * object created by their plugin alive so that the plugin's code is
- * not discarded when it could still be in use by living components
- * created from those component classes:
- *
- *     [component] --ref-> [component class]-> [shlib handle]
- *
- * It allows this use-case:
- *
- *        my_plugins = bt_plugin_find_all_from_file("/path/to/my-plugin.so");
- *        // instantiate components from a plugin's component classes
- *        // put plugins and free my_plugins here
- *        // user code of instantiated components still exists
- *
- * An entry is removed from this list when a component class is
- * destroyed thanks to a custom destroy listener. When the entry is
- * removed, the entry is removed from the list, and we release the
- * reference on the shlib handle. Assuming the original plugin object
- * which contained some component classes is put first, when the last
- * component class is removed from this list, the shared library handle
- * object's reference count falls to zero and the shared library is
- * finally closed.
- */
-
-static
-BT_LIST_HEAD(component_class_list);
-
-__attribute__((destructor)) static
-void fini_comp_class_list(void)
-{
-       struct bt_component_class *comp_class, *tmp;
-
-       bt_list_for_each_entry_safe(comp_class, tmp, &component_class_list, node) {
-               bt_list_del(&comp_class->node);
-               BT_OBJECT_PUT_REF_AND_RESET(comp_class->so_handle);
-       }
-
-       BT_LOGD_STR("Released references from all component classes to shared library handles.");
-}
-
-static inline
-const char *bt_self_plugin_status_string(enum bt_self_plugin_status status)
-{
-       switch (status) {
-       case BT_SELF_PLUGIN_STATUS_OK:
-               return "BT_SELF_PLUGIN_STATUS_OK";
-       case BT_SELF_PLUGIN_STATUS_ERROR:
-               return "BT_SELF_PLUGIN_STATUS_ERROR";
-       case BT_SELF_PLUGIN_STATUS_NOMEM:
-               return "BT_SELF_PLUGIN_STATUS_NOMEM";
-       default:
-               return "(unknown)";
-       }
-}
-
-static
-void bt_plugin_so_shared_lib_handle_destroy(struct bt_object *obj)
-{
-       struct bt_plugin_so_shared_lib_handle *shared_lib_handle;
-
-       BT_ASSERT(obj);
-       shared_lib_handle = container_of(obj,
-               struct bt_plugin_so_shared_lib_handle, base);
-       const char *path = shared_lib_handle->path ?
-               shared_lib_handle->path->str : NULL;
-
-       BT_LOGD("Destroying shared library handle: addr=%p, path=\"%s\"",
-               shared_lib_handle, path);
-
-       if (shared_lib_handle->init_called && shared_lib_handle->exit) {
-               BT_LOGD_STR("Calling user's plugin exit function.");
-               shared_lib_handle->exit();
-               BT_LOGD_STR("User function returned.");
-       }
-
-       if (shared_lib_handle->module) {
-#ifndef NDEBUG
-               /*
-                * Valgrind shows incomplete stack traces when
-                * dynamically loaded libraries are closed before it
-                * finishes. Use the BABELTRACE_NO_DLCLOSE in a debug
-                * build to avoid this.
-                */
-               const char *var = getenv("BABELTRACE_NO_DLCLOSE");
-
-               if (!var || strcmp(var, "1") != 0) {
-#endif
-                       BT_LOGD("Closing GModule: path=\"%s\"", path);
-
-                       if (!g_module_close(shared_lib_handle->module)) {
-                               BT_LOGE("Cannot close GModule: %s: path=\"%s\"",
-                                       g_module_error(), path);
-                       }
-
-                       shared_lib_handle->module = NULL;
-#ifndef NDEBUG
-               } else {
-                       BT_LOGD("Not closing GModule because `BABELTRACE_NO_DLCLOSE=1`: "
-                               "path=\"%s\"", path);
-               }
-#endif
-       }
-
-       if (shared_lib_handle->path) {
-               g_string_free(shared_lib_handle->path, TRUE);
-               shared_lib_handle->path = NULL;
-       }
-
-       g_free(shared_lib_handle);
-}
-
-static
-struct bt_plugin_so_shared_lib_handle *bt_plugin_so_shared_lib_handle_create(
-               const char *path)
-{
-       struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL;
-
-       BT_LOGD("Creating shared library handle: path=\"%s\"", path);
-       shared_lib_handle = g_new0(struct bt_plugin_so_shared_lib_handle, 1);
-       if (!shared_lib_handle) {
-               BT_LOGE_STR("Failed to allocate one shared library handle.");
-               goto error;
-       }
-
-       bt_object_init_shared(&shared_lib_handle->base,
-               bt_plugin_so_shared_lib_handle_destroy);
-
-       if (!path) {
-               goto end;
-       }
-
-       shared_lib_handle->path = g_string_new(path);
-       if (!shared_lib_handle->path) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       shared_lib_handle->module = g_module_open(path, G_MODULE_BIND_LOCAL);
-       if (!shared_lib_handle->module) {
-               /*
-                * DEBUG-level logging because we're only _trying_ to
-                * open this file as a Babeltrace plugin: if it's not,
-                * it's not an error. And because this can be tried
-                * during bt_plugin_find_all_from_dir(), it's not even
-                * a warning.
-                */
-               BT_LOGD("Cannot open GModule: %s: path=\"%s\"",
-                       g_module_error(), path);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle);
-
-end:
-       if (shared_lib_handle) {
-               BT_LOGD("Created shared library handle: path=\"%s\", addr=%p",
-                       path, shared_lib_handle);
-       }
-
-       return shared_lib_handle;
-}
-
-static
-void bt_plugin_so_destroy_spec_data(struct bt_plugin *plugin)
-{
-       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
-
-       if (!plugin->spec_data) {
-               return;
-       }
-
-       BT_ASSERT(plugin->type == BT_PLUGIN_TYPE_SO);
-       BT_ASSERT(spec);
-       BT_OBJECT_PUT_REF_AND_RESET(spec->shared_lib_handle);
-       g_free(plugin->spec_data);
-       plugin->spec_data = NULL;
-}
-
-/*
- * This function does the following:
- *
- * 1. Iterate on the plugin descriptor attributes section and set the
- *    plugin's attributes depending on the attribute types. This
- *    includes the name of the plugin, its description, and its
- *    initialization function, for example.
- *
- * 2. Iterate on the component class descriptors section and create one
- *    "full descriptor" (temporary structure) for each one that is found
- *    and attached to our plugin descriptor.
- *
- * 3. Iterate on the component class descriptor attributes section and
- *    set the corresponding full descriptor's attributes depending on
- *    the attribute types. This includes the description of the
- *    component class, as well as its initialization and destroy
- *    methods.
- *
- * 4. Call the user's plugin initialization function, if any is
- *    defined.
- *
- * 5. For each full component class descriptor, create a component class
- *    object, set its optional attributes, and add it to the plugin
- *    object.
- *
- * 6. Freeze the plugin object.
- */
-static
-enum bt_plugin_status bt_plugin_so_init(
-               struct bt_plugin *plugin,
-               const struct __bt_plugin_descriptor *descriptor,
-               struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
-               struct __bt_plugin_descriptor_attribute const * const *attrs_end,
-               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
-               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
-               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
-               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
-{
-       /*
-        * This structure's members point to the plugin's memory
-        * (do NOT free).
-        */
-       struct comp_class_full_descriptor {
-               const struct __bt_plugin_component_class_descriptor *descriptor;
-               const char *description;
-               const char *help;
-
-               union {
-                       struct {
-                               bt_component_class_source_init_method init;
-                               bt_component_class_source_finalize_method finalize;
-                               bt_component_class_source_query_method query;
-                               bt_component_class_source_accept_output_port_connection_method accept_output_port_connection;
-                               bt_component_class_source_output_port_connected_method output_port_connected;
-                               bt_component_class_source_message_iterator_init_method msg_iter_init;
-                               bt_component_class_source_message_iterator_finalize_method msg_iter_finalize;
-                               bt_component_class_source_message_iterator_seek_ns_from_origin_method msg_iter_seek_ns_from_origin;
-                               bt_component_class_source_message_iterator_seek_beginning_method msg_iter_seek_beginning;
-                               bt_component_class_source_message_iterator_can_seek_ns_from_origin_method msg_iter_can_seek_ns_from_origin;
-                               bt_component_class_source_message_iterator_can_seek_beginning_method msg_iter_can_seek_beginning;
-                       } source;
-
-                       struct {
-                               bt_component_class_filter_init_method init;
-                               bt_component_class_filter_finalize_method finalize;
-                               bt_component_class_filter_query_method query;
-                               bt_component_class_filter_accept_input_port_connection_method accept_input_port_connection;
-                               bt_component_class_filter_accept_output_port_connection_method accept_output_port_connection;
-                               bt_component_class_filter_input_port_connected_method input_port_connected;
-                               bt_component_class_filter_output_port_connected_method output_port_connected;
-                               bt_component_class_filter_message_iterator_init_method msg_iter_init;
-                               bt_component_class_filter_message_iterator_finalize_method msg_iter_finalize;
-                               bt_component_class_filter_message_iterator_seek_ns_from_origin_method msg_iter_seek_ns_from_origin;
-                               bt_component_class_filter_message_iterator_seek_beginning_method msg_iter_seek_beginning;
-                               bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method msg_iter_can_seek_ns_from_origin;
-                               bt_component_class_filter_message_iterator_can_seek_beginning_method msg_iter_can_seek_beginning;
-                       } filter;
-
-                       struct {
-                               bt_component_class_sink_init_method init;
-                               bt_component_class_sink_finalize_method finalize;
-                               bt_component_class_sink_query_method query;
-                               bt_component_class_sink_accept_input_port_connection_method accept_input_port_connection;
-                               bt_component_class_sink_input_port_connected_method input_port_connected;
-                               bt_component_class_sink_graph_is_configured_method graph_is_configured;
-                       } sink;
-               } methods;
-       };
-
-       enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
-       struct __bt_plugin_descriptor_attribute const * const *cur_attr_ptr;
-       struct __bt_plugin_component_class_descriptor const * const *cur_cc_descr_ptr;
-       struct __bt_plugin_component_class_descriptor_attribute const * const *cur_cc_descr_attr_ptr;
-       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
-       GArray *comp_class_full_descriptors;
-       size_t i;
-       int ret;
-
-       BT_LOGD("Initializing plugin object from descriptors found in sections: "
-               "plugin-addr=%p, plugin-path=\"%s\", "
-               "attrs-begin-addr=%p, attrs-end-addr=%p, "
-               "cc-descr-begin-addr=%p, cc-descr-end-addr=%p, "
-               "cc-descr-attrs-begin-addr=%p, cc-descr-attrs-end-addr=%p",
-               plugin,
-               spec->shared_lib_handle->path ?
-                       spec->shared_lib_handle->path->str : NULL,
-               attrs_begin, attrs_end,
-               cc_descriptors_begin, cc_descriptors_end,
-               cc_descr_attrs_begin, cc_descr_attrs_end);
-       comp_class_full_descriptors = g_array_new(FALSE, TRUE,
-               sizeof(struct comp_class_full_descriptor));
-       if (!comp_class_full_descriptors) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               status = BT_PLUGIN_STATUS_ERROR;
-               goto end;
-       }
-
-       /* Set mandatory attributes */
-       spec->descriptor = descriptor;
-       bt_plugin_set_name(plugin, descriptor->name);
-
-       /*
-        * Find and set optional attributes attached to this plugin
-        * descriptor.
-        */
-       for (cur_attr_ptr = attrs_begin; cur_attr_ptr != attrs_end; cur_attr_ptr++) {
-               const struct __bt_plugin_descriptor_attribute *cur_attr =
-                       *cur_attr_ptr;
-
-               if (cur_attr == NULL) {
-                       continue;
-               }
-
-               if (cur_attr->plugin_descriptor != descriptor) {
-                       continue;
-               }
-
-               switch (cur_attr->type) {
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT:
-                       spec->init = cur_attr->value.init;
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT:
-                       spec->shared_lib_handle->exit = cur_attr->value.exit;
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR:
-                       bt_plugin_set_author(plugin, cur_attr->value.author);
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE:
-                       bt_plugin_set_license(plugin, cur_attr->value.license);
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
-                       bt_plugin_set_description(plugin, cur_attr->value.description);
-                       break;
-               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION:
-                       bt_plugin_set_version(plugin,
-                               (unsigned int) cur_attr->value.version.major,
-                               (unsigned int) cur_attr->value.version.minor,
-                               (unsigned int) cur_attr->value.version.patch,
-                               cur_attr->value.version.extra);
-                       break;
-               default:
-                       /*
-                        * WARN-level logging because this should not
-                        * happen with the appropriate ABI version. If
-                        * we're here, we know that for the reported
-                        * version of the ABI, this attribute is
-                        * unknown.
-                        */
-                       BT_LOGW("Ignoring unknown plugin descriptor attribute: "
-                               "plugin-path=\"%s\", plugin-name=\"%s\", "
-                               "attr-type-name=\"%s\", attr-type-id=%d",
-                               spec->shared_lib_handle->path ?
-                                       spec->shared_lib_handle->path->str :
-                                       NULL,
-                               descriptor->name, cur_attr->type_name,
-                               cur_attr->type);
-                       break;
-               }
-       }
-
-       /*
-        * Find component class descriptors attached to this plugin
-        * descriptor and initialize corresponding full component class
-        * descriptors in the array.
-        */
-       for (cur_cc_descr_ptr = cc_descriptors_begin; cur_cc_descr_ptr != cc_descriptors_end; cur_cc_descr_ptr++) {
-               const struct __bt_plugin_component_class_descriptor *cur_cc_descr =
-                       *cur_cc_descr_ptr;
-               struct comp_class_full_descriptor full_descriptor = {0};
-
-               if (cur_cc_descr == NULL) {
-                       continue;
-               }
-
-               if (cur_cc_descr->plugin_descriptor != descriptor) {
-                       continue;
-               }
-
-               full_descriptor.descriptor = cur_cc_descr;
-               g_array_append_val(comp_class_full_descriptors,
-                       full_descriptor);
-       }
-
-       /*
-        * Find component class descriptor attributes attached to this
-        * plugin descriptor and update corresponding full component
-        * class descriptors in the array.
-        */
-       for (cur_cc_descr_attr_ptr = cc_descr_attrs_begin; cur_cc_descr_attr_ptr != cc_descr_attrs_end; cur_cc_descr_attr_ptr++) {
-               const struct __bt_plugin_component_class_descriptor_attribute *cur_cc_descr_attr =
-                       *cur_cc_descr_attr_ptr;
-               enum bt_component_class_type cc_type;
-
-               if (cur_cc_descr_attr == NULL) {
-                       continue;
-               }
-
-               if (cur_cc_descr_attr->comp_class_descriptor->plugin_descriptor !=
-                               descriptor) {
-                       continue;
-               }
-
-               cc_type = cur_cc_descr_attr->comp_class_descriptor->type;
-
-               /* Find the corresponding component class descriptor entry */
-               for (i = 0; i < comp_class_full_descriptors->len; i++) {
-                       struct comp_class_full_descriptor *cc_full_descr =
-                               &g_array_index(comp_class_full_descriptors,
-                                       struct comp_class_full_descriptor, i);
-
-                       if (cur_cc_descr_attr->comp_class_descriptor !=
-                                       cc_full_descr->descriptor) {
-                               continue;
-                       }
-
-                       switch (cur_cc_descr_attr->type) {
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
-                               cc_full_descr->description =
-                                       cur_cc_descr_attr->value.description;
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_HELP:
-                               cc_full_descr->help =
-                                       cur_cc_descr_attr->value.help;
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.init =
-                                               cur_cc_descr_attr->value.source_init_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.init =
-                                               cur_cc_descr_attr->value.filter_init_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_SINK:
-                                       cc_full_descr->methods.sink.init =
-                                               cur_cc_descr_attr->value.sink_init_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FINALIZE_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.finalize =
-                                               cur_cc_descr_attr->value.source_finalize_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.finalize =
-                                               cur_cc_descr_attr->value.filter_finalize_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_SINK:
-                                       cc_full_descr->methods.sink.finalize =
-                                               cur_cc_descr_attr->value.sink_finalize_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_QUERY_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.query =
-                                               cur_cc_descr_attr->value.source_query_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.query =
-                                               cur_cc_descr_attr->value.filter_query_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_SINK:
-                                       cc_full_descr->methods.sink.query =
-                                               cur_cc_descr_attr->value.sink_query_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_ACCEPT_INPUT_PORT_CONNECTION_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.accept_input_port_connection =
-                                               cur_cc_descr_attr->value.filter_accept_input_port_connection_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_SINK:
-                                       cc_full_descr->methods.sink.accept_input_port_connection =
-                                               cur_cc_descr_attr->value.sink_accept_input_port_connection_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_ACCEPT_OUTPUT_PORT_CONNECTION_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.accept_output_port_connection =
-                                               cur_cc_descr_attr->value.source_accept_output_port_connection_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.accept_output_port_connection =
-                                               cur_cc_descr_attr->value.filter_accept_output_port_connection_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INPUT_PORT_CONNECTED_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.input_port_connected =
-                                               cur_cc_descr_attr->value.filter_input_port_connected_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_SINK:
-                                       cc_full_descr->methods.sink.input_port_connected =
-                                               cur_cc_descr_attr->value.sink_input_port_connected_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_OUTPUT_PORT_CONNECTED_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.output_port_connected =
-                                               cur_cc_descr_attr->value.source_output_port_connected_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.output_port_connected =
-                                               cur_cc_descr_attr->value.filter_output_port_connected_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_GRAPH_IS_CONFIGURED_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SINK:
-                                       cc_full_descr->methods.sink.graph_is_configured =
-                                               cur_cc_descr_attr->value.sink_graph_is_configured_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_INIT_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.msg_iter_init =
-                                               cur_cc_descr_attr->value.source_msg_iter_init_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.msg_iter_init =
-                                               cur_cc_descr_attr->value.filter_msg_iter_init_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_FINALIZE_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.msg_iter_finalize =
-                                               cur_cc_descr_attr->value.source_msg_iter_finalize_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.msg_iter_finalize =
-                                               cur_cc_descr_attr->value.filter_msg_iter_finalize_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_SEEK_NS_FROM_ORIGIN_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.msg_iter_seek_ns_from_origin =
-                                               cur_cc_descr_attr->value.source_msg_iter_seek_ns_from_origin_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.msg_iter_seek_ns_from_origin =
-                                               cur_cc_descr_attr->value.filter_msg_iter_seek_ns_from_origin_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_SEEK_BEGINNING_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.msg_iter_seek_beginning =
-                                               cur_cc_descr_attr->value.source_msg_iter_seek_beginning_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.msg_iter_seek_beginning =
-                                               cur_cc_descr_attr->value.filter_msg_iter_seek_beginning_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_CAN_SEEK_NS_FROM_ORIGIN_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.msg_iter_can_seek_ns_from_origin =
-                                               cur_cc_descr_attr->value.source_msg_iter_can_seek_ns_from_origin_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.msg_iter_can_seek_ns_from_origin =
-                                               cur_cc_descr_attr->value.filter_msg_iter_can_seek_ns_from_origin_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_CAN_SEEK_BEGINNING_METHOD:
-                               switch (cc_type) {
-                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                                       cc_full_descr->methods.source.msg_iter_can_seek_beginning =
-                                               cur_cc_descr_attr->value.source_msg_iter_can_seek_beginning_method;
-                                       break;
-                               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                                       cc_full_descr->methods.filter.msg_iter_can_seek_beginning =
-                                               cur_cc_descr_attr->value.filter_msg_iter_can_seek_beginning_method;
-                                       break;
-                               default:
-                                       abort();
-                               }
-                               break;
-                       default:
-                               /*
-                                * WARN-level logging because this
-                                * should not happen with the
-                                * appropriate ABI version. If we're
-                                * here, we know that for the reported
-                                * version of the ABI, this attribute is
-                                * unknown.
-                                */
-                               BT_LOGW("Ignoring unknown component class descriptor attribute: "
-                                       "plugin-path=\"%s\", "
-                                       "plugin-name=\"%s\", "
-                                       "comp-class-name=\"%s\", "
-                                       "comp-class-type=%s, "
-                                       "attr-type-name=\"%s\", "
-                                       "attr-type-id=%d",
-                                       spec->shared_lib_handle->path ?
-                                               spec->shared_lib_handle->path->str :
-                                               NULL,
-                                       descriptor->name,
-                                       cur_cc_descr_attr->comp_class_descriptor->name,
-                                       bt_component_class_type_string(
-                                               cur_cc_descr_attr->comp_class_descriptor->type),
-                                       cur_cc_descr_attr->type_name,
-                                       cur_cc_descr_attr->type);
-                               break;
-                       }
-               }
-       }
-
-       /* Initialize plugin */
-       if (spec->init) {
-               enum bt_self_plugin_status init_status;
-
-               BT_LOGD_STR("Calling user's plugin initialization function.");
-               init_status = spec->init((void *) plugin);
-               BT_LOGD("User function returned: %s",
-                       bt_self_plugin_status_string(init_status));
-
-               if (init_status < 0) {
-                       BT_LOGW_STR("User's plugin initialization function failed.");
-                       status = BT_PLUGIN_STATUS_ERROR;
-                       goto end;
-               }
-       }
-
-       spec->shared_lib_handle->init_called = BT_TRUE;
-
-       /* Add described component classes to plugin */
-       for (i = 0; i < comp_class_full_descriptors->len; i++) {
-               struct comp_class_full_descriptor *cc_full_descr =
-                       &g_array_index(comp_class_full_descriptors,
-                               struct comp_class_full_descriptor, i);
-               struct bt_component_class *comp_class = NULL;
-               struct bt_component_class_source *src_comp_class = NULL;
-               struct bt_component_class_filter *flt_comp_class = NULL;
-               struct bt_component_class_sink *sink_comp_class = NULL;
-
-               BT_LOGD("Creating and setting properties of plugin's component class: "
-                       "plugin-path=\"%s\", plugin-name=\"%s\", "
-                       "comp-class-name=\"%s\", comp-class-type=%s",
-                       spec->shared_lib_handle->path ?
-                               spec->shared_lib_handle->path->str :
-                               NULL,
-                       descriptor->name,
-                       cc_full_descr->descriptor->name,
-                       bt_component_class_type_string(
-                               cc_full_descr->descriptor->type));
-
-               switch (cc_full_descr->descriptor->type) {
-               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                       src_comp_class = bt_component_class_source_create(
-                               cc_full_descr->descriptor->name,
-                               cc_full_descr->descriptor->methods.source.msg_iter_next);
-                       comp_class = bt_component_class_source_as_component_class(
-                               src_comp_class);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       flt_comp_class = bt_component_class_filter_create(
-                               cc_full_descr->descriptor->name,
-                               cc_full_descr->descriptor->methods.source.msg_iter_next);
-                       comp_class = bt_component_class_filter_as_component_class(
-                               flt_comp_class);
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       sink_comp_class = bt_component_class_sink_create(
-                               cc_full_descr->descriptor->name,
-                               cc_full_descr->descriptor->methods.sink.consume);
-                       comp_class = bt_component_class_sink_as_component_class(
-                               sink_comp_class);
-                       break;
-               default:
-                       /*
-                        * WARN-level logging because this should not
-                        * happen with the appropriate ABI version. If
-                        * we're here, we know that for the reported
-                        * version of the ABI, this component class type
-                        * is unknown.
-                        */
-                       BT_LOGW("Ignoring unknown component class type: "
-                               "plugin-path=\"%s\", plugin-name=\"%s\", "
-                               "comp-class-name=\"%s\", comp-class-type=%d",
-                               spec->shared_lib_handle->path->str ?
-                                       spec->shared_lib_handle->path->str :
-                                       NULL,
-                               descriptor->name,
-                               cc_full_descr->descriptor->name,
-                               cc_full_descr->descriptor->type);
-                       continue;
-               }
-
-               if (!comp_class) {
-                       BT_LOGE_STR("Cannot create component class.");
-                       status = BT_PLUGIN_STATUS_ERROR;
-                       goto end;
-               }
-
-               if (cc_full_descr->description) {
-                       ret = bt_component_class_set_description(
-                               comp_class, cc_full_descr->description);
-                       if (ret) {
-                               BT_LOGE_STR("Cannot set component class's description.");
-                               status = BT_PLUGIN_STATUS_ERROR;
-                               BT_OBJECT_PUT_REF_AND_RESET(comp_class);
-                               goto end;
-                       }
-               }
-
-               if (cc_full_descr->help) {
-                       ret = bt_component_class_set_help(comp_class,
-                               cc_full_descr->help);
-                       if (ret) {
-                               BT_LOGE_STR("Cannot set component class's help string.");
-                               status = BT_PLUGIN_STATUS_ERROR;
-                               BT_OBJECT_PUT_REF_AND_RESET(comp_class);
-                               goto end;
-                       }
-               }
-
-               switch (cc_full_descr->descriptor->type) {
-               case BT_COMPONENT_CLASS_TYPE_SOURCE:
-                       if (cc_full_descr->methods.source.init) {
-                               ret = bt_component_class_source_set_init_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.init);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's initialization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.finalize) {
-                               ret = bt_component_class_source_set_finalize_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.finalize);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's finalization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.query) {
-                               ret = bt_component_class_source_set_query_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.query);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's query method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.accept_output_port_connection) {
-                               ret = bt_component_class_source_set_accept_output_port_connection_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.accept_output_port_connection);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's \"accept input output connection\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.output_port_connected) {
-                               ret = bt_component_class_source_set_output_port_connected_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.output_port_connected);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's \"output port connected\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.msg_iter_init) {
-                               ret = bt_component_class_source_set_message_iterator_init_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.msg_iter_init);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's message iterator initialization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.msg_iter_finalize) {
-                               ret = bt_component_class_source_set_message_iterator_finalize_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.msg_iter_finalize);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's message iterator finalization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.msg_iter_seek_ns_from_origin) {
-                               ret = bt_component_class_source_set_message_iterator_seek_ns_from_origin_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.msg_iter_seek_ns_from_origin);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's message iterator \"seek nanoseconds from origin\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.msg_iter_seek_beginning) {
-                               ret = bt_component_class_source_set_message_iterator_seek_beginning_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.msg_iter_seek_beginning);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's message iterator \"seek beginning\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.msg_iter_can_seek_ns_from_origin) {
-                               ret = bt_component_class_source_set_message_iterator_can_seek_ns_from_origin_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.msg_iter_can_seek_ns_from_origin);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's message iterator \"can seek nanoseconds from origin\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.source.msg_iter_can_seek_beginning) {
-                               ret = bt_component_class_source_set_message_iterator_can_seek_beginning_method(
-                                       src_comp_class,
-                                       cc_full_descr->methods.source.msg_iter_can_seek_beginning);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set source component class's message iterator \"can seek beginning\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_FILTER:
-                       if (cc_full_descr->methods.filter.init) {
-                               ret = bt_component_class_filter_set_init_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.init);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's initialization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.finalize) {
-                               ret = bt_component_class_filter_set_finalize_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.finalize);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's finalization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.query) {
-                               ret = bt_component_class_filter_set_query_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.query);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's query method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.accept_input_port_connection) {
-                               ret = bt_component_class_filter_set_accept_input_port_connection_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.accept_input_port_connection);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's \"accept input port connection\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.accept_output_port_connection) {
-                               ret = bt_component_class_filter_set_accept_output_port_connection_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.accept_output_port_connection);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's \"accept input output connection\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.input_port_connected) {
-                               ret = bt_component_class_filter_set_input_port_connected_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.input_port_connected);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's \"input port connected\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.output_port_connected) {
-                               ret = bt_component_class_filter_set_output_port_connected_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.output_port_connected);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's \"output port connected\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.msg_iter_init) {
-                               ret = bt_component_class_filter_set_message_iterator_init_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.msg_iter_init);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's message iterator initialization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.msg_iter_finalize) {
-                               ret = bt_component_class_filter_set_message_iterator_finalize_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.msg_iter_finalize);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's message iterator finalization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.msg_iter_seek_ns_from_origin) {
-                               ret = bt_component_class_filter_set_message_iterator_seek_ns_from_origin_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.msg_iter_seek_ns_from_origin);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's message iterator \"seek nanoseconds from origin\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.msg_iter_seek_beginning) {
-                               ret = bt_component_class_filter_set_message_iterator_seek_beginning_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.msg_iter_seek_beginning);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's message iterator \"seek beginning\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.msg_iter_can_seek_ns_from_origin) {
-                               ret = bt_component_class_filter_set_message_iterator_can_seek_ns_from_origin_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.msg_iter_can_seek_ns_from_origin);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's message iterator \"can seek nanoseconds from origin\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.filter.msg_iter_can_seek_beginning) {
-                               ret = bt_component_class_filter_set_message_iterator_can_seek_beginning_method(
-                                       flt_comp_class,
-                                       cc_full_descr->methods.filter.msg_iter_can_seek_beginning);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set filter component class's message iterator \"can seek beginning\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       break;
-               case BT_COMPONENT_CLASS_TYPE_SINK:
-                       if (cc_full_descr->methods.sink.init) {
-                               ret = bt_component_class_sink_set_init_method(
-                                       sink_comp_class,
-                                       cc_full_descr->methods.sink.init);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set sink component class's initialization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.sink.finalize) {
-                               ret = bt_component_class_sink_set_finalize_method(
-                                       sink_comp_class,
-                                       cc_full_descr->methods.sink.finalize);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set sink component class's finalization method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.sink.query) {
-                               ret = bt_component_class_sink_set_query_method(
-                                       sink_comp_class,
-                                       cc_full_descr->methods.sink.query);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set sink component class's query method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.sink.accept_input_port_connection) {
-                               ret = bt_component_class_sink_set_accept_input_port_connection_method(
-                                       sink_comp_class,
-                                       cc_full_descr->methods.sink.accept_input_port_connection);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set sink component class's \"accept input port connection\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.sink.input_port_connected) {
-                               ret = bt_component_class_sink_set_input_port_connected_method(
-                                       sink_comp_class,
-                                       cc_full_descr->methods.sink.input_port_connected);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set sink component class's \"input port connected\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       if (cc_full_descr->methods.sink.graph_is_configured) {
-                               ret = bt_component_class_sink_set_graph_is_configured_method(
-                                       sink_comp_class,
-                                       cc_full_descr->methods.sink.graph_is_configured);
-                               if (ret) {
-                                       BT_LOGE_STR("Cannot set sink component class's \"graph is configured\" method.");
-                                       status = BT_PLUGIN_STATUS_ERROR;
-                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
-                                       goto end;
-                               }
-                       }
-
-                       break;
-               default:
-                       abort();
-               }
-
-               /*
-                * Add component class to the plugin object.
-                *
-                * This will call back
-                * bt_plugin_so_on_add_component_class() so that we can
-                * add a mapping in the component class list when we
-                * know the component class is successfully added.
-                */
-               status = bt_plugin_add_component_class(plugin,
-                       (void *) comp_class);
-               BT_OBJECT_PUT_REF_AND_RESET(comp_class);
-               if (status < 0) {
-                       BT_LOGE("Cannot add component class to plugin.");
-                       goto end;
-               }
-       }
-
-end:
-       g_array_free(comp_class_full_descriptors, TRUE);
-       return status;
-}
-
-static
-struct bt_plugin *bt_plugin_so_create_empty(
-               struct bt_plugin_so_shared_lib_handle *shared_lib_handle)
-{
-       struct bt_plugin *plugin;
-       struct bt_plugin_so_spec_data *spec;
-
-       plugin = bt_plugin_create_empty(BT_PLUGIN_TYPE_SO);
-       if (!plugin) {
-               goto error;
-       }
-
-       plugin->destroy_spec_data = bt_plugin_so_destroy_spec_data;
-       plugin->spec_data = g_new0(struct bt_plugin_so_spec_data, 1);
-       if (!plugin->spec_data) {
-               BT_LOGE_STR("Failed to allocate one SO plugin specific data structure.");
-               goto error;
-       }
-
-       spec = plugin->spec_data;
-       spec->shared_lib_handle = shared_lib_handle;
-       bt_object_get_no_null_check(spec->shared_lib_handle);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(plugin);
-
-end:
-       return plugin;
-}
-
-static
-size_t count_non_null_items_in_section(const void *begin, const void *end)
-{
-       size_t count = 0;
-       const int * const *begin_int = (const int * const *) begin;
-       const int * const *end_int = (const int * const *) end;
-       const int * const *iter;
-
-       for (iter = begin_int; iter != end_int; iter++) {
-               if (*iter) {
-                       count++;
-               }
-       }
-
-       return count;
-}
-
-static
-struct bt_plugin_set *bt_plugin_so_create_all_from_sections(
-               struct bt_plugin_so_shared_lib_handle *shared_lib_handle,
-               struct __bt_plugin_descriptor const * const *descriptors_begin,
-               struct __bt_plugin_descriptor const * const *descriptors_end,
-               struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
-               struct __bt_plugin_descriptor_attribute const * const *attrs_end,
-               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
-               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
-               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
-               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
-{
-       size_t descriptor_count;
-       size_t attrs_count;
-       size_t cc_descriptors_count;
-       size_t cc_descr_attrs_count;
-       size_t i;
-       struct bt_plugin_set *plugin_set = NULL;
-
-       descriptor_count = count_non_null_items_in_section(descriptors_begin, descriptors_end);
-       attrs_count = count_non_null_items_in_section(attrs_begin, attrs_end);
-       cc_descriptors_count = count_non_null_items_in_section(cc_descriptors_begin, cc_descriptors_end);
-       cc_descr_attrs_count =  count_non_null_items_in_section(cc_descr_attrs_begin, cc_descr_attrs_end);
-
-       BT_LOGD("Creating all SO plugins from sections: "
-               "plugin-path=\"%s\", "
-               "descr-begin-addr=%p, descr-end-addr=%p, "
-               "attrs-begin-addr=%p, attrs-end-addr=%p, "
-               "cc-descr-begin-addr=%p, cc-descr-end-addr=%p, "
-               "cc-descr-attrs-begin-addr=%p, cc-descr-attrs-end-addr=%p, "
-               "descr-count=%zu, attrs-count=%zu, "
-               "cc-descr-count=%zu, cc-descr-attrs-count=%zu",
-               shared_lib_handle->path ? shared_lib_handle->path->str : NULL,
-               descriptors_begin, descriptors_end,
-               attrs_begin, attrs_end,
-               cc_descriptors_begin, cc_descriptors_end,
-               cc_descr_attrs_begin, cc_descr_attrs_end,
-               descriptor_count, attrs_count,
-               cc_descriptors_count, cc_descr_attrs_count);
-       plugin_set = bt_plugin_set_create();
-       if (!plugin_set) {
-               BT_LOGE_STR("Cannot create empty plugin set.");
-               goto error;
-       }
-
-       for (i = 0; i < descriptors_end - descriptors_begin; i++) {
-               enum bt_plugin_status status;
-               const struct __bt_plugin_descriptor *descriptor =
-                       descriptors_begin[i];
-               struct bt_plugin *plugin;
-
-               if (descriptor == NULL) {
-                       continue;
-               }
-
-               BT_LOGD("Creating plugin object for plugin: "
-                       "name=\"%s\", abi-major=%d, abi-minor=%d",
-                       descriptor->name, descriptor->major, descriptor->minor);
-
-               if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) {
-                       /*
-                        * DEBUG-level logging because we're only
-                        * _trying_ to open this file as a compatible
-                        * Babeltrace plugin: if it's not, it's not an
-                        * error. And because this can be tried during
-                        * bt_plugin_find_all_from_dir(), it's not
-                        * even a warning.
-                        */
-                       BT_LOGD("Unknown ABI major version: abi-major=%d",
-                               descriptor->major);
-                       goto error;
-               }
-
-               plugin = bt_plugin_so_create_empty(shared_lib_handle);
-               if (!plugin) {
-                       BT_LOGE_STR("Cannot create empty shared library handle.");
-                       goto error;
-               }
-
-               if (shared_lib_handle && shared_lib_handle->path) {
-                       bt_plugin_set_path(plugin, shared_lib_handle->path->str);
-               }
-
-               status = bt_plugin_so_init(plugin, descriptor, attrs_begin,
-                       attrs_end, cc_descriptors_begin, cc_descriptors_end,
-                       cc_descr_attrs_begin, cc_descr_attrs_end);
-               if (status < 0) {
-                       /*
-                        * DEBUG-level logging because we're only
-                        * _trying_ to open this file as a compatible
-                        * Babeltrace plugin: if it's not, it's not an
-                        * error. And because this can be tried during
-                        * bt_plugin_find_all_from_dir(), it's not
-                        * even a warning.
-                        */
-                       BT_LOGD_STR("Cannot initialize SO plugin object from sections.");
-                       BT_OBJECT_PUT_REF_AND_RESET(plugin);
-                       goto error;
-               }
-
-               /* Add to plugin set */
-               bt_plugin_set_add_plugin(plugin_set, plugin);
-               bt_object_put_ref(plugin);
-       }
-
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
-
-end:
-       return plugin_set;
-}
-
-BT_HIDDEN
-struct bt_plugin_set *bt_plugin_so_create_all_from_static(void)
-{
-       struct bt_plugin_set *plugin_set = NULL;
-       struct bt_plugin_so_shared_lib_handle *shared_lib_handle =
-               bt_plugin_so_shared_lib_handle_create(NULL);
-
-       if (!shared_lib_handle) {
-               goto end;
-       }
-
-       BT_LOGD_STR("Creating all SO plugins from built-in plugins.");
-       plugin_set = bt_plugin_so_create_all_from_sections(shared_lib_handle,
-               __bt_get_begin_section_plugin_descriptors(),
-               __bt_get_end_section_plugin_descriptors(),
-               __bt_get_begin_section_plugin_descriptor_attributes(),
-               __bt_get_end_section_plugin_descriptor_attributes(),
-               __bt_get_begin_section_component_class_descriptors(),
-               __bt_get_end_section_component_class_descriptors(),
-               __bt_get_begin_section_component_class_descriptor_attributes(),
-               __bt_get_end_section_component_class_descriptor_attributes());
-
-end:
-       BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle);
-
-       return plugin_set;
-}
-
-BT_HIDDEN
-struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path)
-{
-       size_t path_len;
-       struct bt_plugin_set *plugin_set = NULL;
-       struct __bt_plugin_descriptor const * const *descriptors_begin = NULL;
-       struct __bt_plugin_descriptor const * const *descriptors_end = NULL;
-       struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL;
-       struct __bt_plugin_descriptor_attribute const * const *attrs_end = NULL;
-       struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin = NULL;
-       struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end = NULL;
-       struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin = NULL;
-       struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end = NULL;
-       struct __bt_plugin_descriptor const * const *(*get_begin_section_plugin_descriptors)(void);
-       struct __bt_plugin_descriptor const * const *(*get_end_section_plugin_descriptors)(void);
-       struct __bt_plugin_descriptor_attribute const * const *(*get_begin_section_plugin_descriptor_attributes)(void);
-       struct __bt_plugin_descriptor_attribute const * const *(*get_end_section_plugin_descriptor_attributes)(void);
-       struct __bt_plugin_component_class_descriptor const * const *(*get_begin_section_component_class_descriptors)(void);
-       struct __bt_plugin_component_class_descriptor const * const *(*get_end_section_component_class_descriptors)(void);
-       struct __bt_plugin_component_class_descriptor_attribute const * const *(*get_begin_section_component_class_descriptor_attributes)(void);
-       struct __bt_plugin_component_class_descriptor_attribute const * const *(*get_end_section_component_class_descriptor_attributes)(void);
-       bt_bool is_libtool_wrapper = BT_FALSE, is_shared_object = BT_FALSE;
-       struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL;
-
-       if (!path) {
-               BT_LOGW_STR("Invalid parameter: path is NULL.");
-               goto end;
-       }
-
-       BT_LOGD("Creating all SO plugins from file: path=\"%s\"", path);
-       path_len = strlen(path);
-       if (path_len <= PLUGIN_SUFFIX_LEN) {
-               BT_LOGW("Invalid parameter: path length is too short: "
-                       "path-length=%zu", path_len);
-               goto end;
-       }
-
-       path_len++;
-       /*
-        * Check if the file ends with a known plugin file type suffix (i.e. .so
-        * or .la on Linux).
-        */
-       is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
-               path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
-               LIBTOOL_PLUGIN_SUFFIX_LEN);
-       is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
-               path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
-               NATIVE_PLUGIN_SUFFIX_LEN);
-       if (!is_shared_object && !is_libtool_wrapper) {
-               /* Name indicates this is not a plugin file; not an error */
-               BT_LOGV("File is not a SO plugin file: path=\"%s\"", path);
-               goto end;
-       }
-
-       shared_lib_handle = bt_plugin_so_shared_lib_handle_create(path);
-       if (!shared_lib_handle) {
-               BT_LOGD_STR("Cannot create shared library handle.");
-               goto end;
-       }
-
-       if (g_module_symbol(shared_lib_handle->module, "__bt_get_begin_section_plugin_descriptors",
-                       (gpointer *) &get_begin_section_plugin_descriptors)) {
-               descriptors_begin = get_begin_section_plugin_descriptors();
-       } else {
-               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
-                       "symbol=\"%s\"", path,
-                       "__bt_get_begin_section_plugin_descriptors");
-               goto end;
-       }
-
-       if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_plugin_descriptors",
-                       (gpointer *) &get_end_section_plugin_descriptors)) {
-               descriptors_end = get_end_section_plugin_descriptors();
-       } else {
-               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
-                       "symbol=\"%s\"", path,
-                       "__bt_get_end_section_plugin_descriptors");
-               goto end;
-       }
-
-       if (g_module_symbol(shared_lib_handle->module, "__bt_get_begin_section_plugin_descriptor_attributes",
-                       (gpointer *) &get_begin_section_plugin_descriptor_attributes)) {
-                attrs_begin = get_begin_section_plugin_descriptor_attributes();
-       } else {
-               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
-                       "symbol=\"%s\"", path,
-                       "__bt_get_begin_section_plugin_descriptor_attributes");
-       }
-
-       if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_plugin_descriptor_attributes",
-                       (gpointer *) &get_end_section_plugin_descriptor_attributes)) {
-               attrs_end = get_end_section_plugin_descriptor_attributes();
-       } else {
-               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
-                       "symbol=\"%s\"", path,
-                       "__bt_get_end_section_plugin_descriptor_attributes");
-       }
-
-       if ((!!attrs_begin - !!attrs_end) != 0) {
-               BT_LOGD("Found section start or end symbol, but not both: "
-                       "path=\"%s\", symbol-start=\"%s\", "
-                       "symbol-end=\"%s\", symbol-start-addr=%p, "
-                       "symbol-end-addr=%p",
-                       path, "__bt_get_begin_section_plugin_descriptor_attributes",
-                       "__bt_get_end_section_plugin_descriptor_attributes",
-                       attrs_begin, attrs_end);
-               goto end;
-       }
-
-       if (g_module_symbol(shared_lib_handle->module, "__bt_get_begin_section_component_class_descriptors",
-                       (gpointer *) &get_begin_section_component_class_descriptors)) {
-               cc_descriptors_begin = get_begin_section_component_class_descriptors();
-       } else {
-               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
-                       "symbol=\"%s\"", path,
-                       "__bt_get_begin_section_component_class_descriptors");
-       }
-
-       if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_component_class_descriptors",
-                       (gpointer *) &get_end_section_component_class_descriptors)) {
-               cc_descriptors_end = get_end_section_component_class_descriptors();
-       } else {
-               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
-                       "symbol=\"%s\"", path,
-                       "__bt_get_end_section_component_class_descriptors");
-       }
-
-       if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) {
-               BT_LOGD("Found section start or end symbol, but not both: "
-                       "path=\"%s\", symbol-start=\"%s\", "
-                       "symbol-end=\"%s\", symbol-start-addr=%p, "
-                       "symbol-end-addr=%p",
-                       path, "__bt_get_begin_section_component_class_descriptors",
-                       "__bt_get_end_section_component_class_descriptors",
-                       cc_descriptors_begin, cc_descriptors_end);
-               goto end;
-       }
-
-       if (g_module_symbol(shared_lib_handle->module, "__bt_get_begin_section_component_class_descriptor_attributes",
-                       (gpointer *) &get_begin_section_component_class_descriptor_attributes)) {
-               cc_descr_attrs_begin = get_begin_section_component_class_descriptor_attributes();
-       } else {
-               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
-                       "symbol=\"%s\"", path,
-                       "__bt_get_begin_section_component_class_descriptor_attributes");
-       }
-
-       if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_component_class_descriptor_attributes",
-                       (gpointer *) &get_end_section_component_class_descriptor_attributes)) {
-               cc_descr_attrs_end = get_end_section_component_class_descriptor_attributes();
-       } else {
-               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
-                       "symbol=\"%s\"", path,
-                       "__bt_get_end_section_component_class_descriptor_attributes");
-       }
-
-       if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) {
-               BT_LOGD("Found section start or end symbol, but not both: "
-                       "path=\"%s\", symbol-start=\"%s\", "
-                       "symbol-end=\"%s\", symbol-start-addr=%p, "
-                       "symbol-end-addr=%p",
-                       path, "__bt_get_begin_section_component_class_descriptor_attributes",
-                       "__bt_get_end_section_component_class_descriptor_attributes",
-                       cc_descr_attrs_begin, cc_descr_attrs_end);
-               goto end;
-       }
-
-       /* Initialize plugin */
-       BT_LOGD_STR("Initializing plugin object.");
-       plugin_set = bt_plugin_so_create_all_from_sections(shared_lib_handle,
-               descriptors_begin, descriptors_end, attrs_begin, attrs_end,
-               cc_descriptors_begin, cc_descriptors_end,
-               cc_descr_attrs_begin, cc_descr_attrs_end);
-
-end:
-       BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle);
-       return plugin_set;
-}
-
-static
-void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class,
-               void *data)
-{
-       bt_list_del(&comp_class->node);
-       BT_OBJECT_PUT_REF_AND_RESET(comp_class->so_handle);
-       BT_LOGV("Component class destroyed: removed entry from list: "
-               "comp-cls-addr=%p", comp_class);
-}
-
-void bt_plugin_so_on_add_component_class(struct bt_plugin *plugin,
-               struct bt_component_class *comp_class)
-{
-       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
-
-       BT_ASSERT(plugin->spec_data);
-       BT_ASSERT(plugin->type == BT_PLUGIN_TYPE_SO);
-
-       bt_list_add(&comp_class->node, &component_class_list);
-       comp_class->so_handle = spec->shared_lib_handle;
-       bt_object_get_no_null_check(comp_class->so_handle);
-
-       /* Add our custom destroy listener */
-       bt_component_class_add_destroy_listener(comp_class,
-               plugin_comp_class_destroy_listener, NULL);
-}
diff --git a/lib/plugin/plugin.c b/lib/plugin/plugin.c
deleted file mode 100644 (file)
index a6e9806..0000000
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/plugin/plugin-internal.h>
-#include <babeltrace2/plugin/plugin-so-internal.h>
-#include <babeltrace2/plugin/plugin-const.h>
-#include <babeltrace2/graph/component-class-const.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <babeltrace2/types.h>
-#include <glib.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/stat.h>
-#include <ftw.h>
-#include <pthread.h>
-
-#define PYTHON_PLUGIN_PROVIDER_FILENAME        "libbabeltrace2-python-plugin-provider." G_MODULE_SUFFIX
-#define PYTHON_PLUGIN_PROVIDER_SYM_NAME        bt_plugin_python_create_all_from_file
-#define PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR    TOSTRING(PYTHON_PLUGIN_PROVIDER_SYM_NAME)
-
-#define APPEND_ALL_FROM_DIR_NFDOPEN_MAX        8
-
-#ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT
-#include <babeltrace2/plugin/python-plugin-provider-internal.h>
-
-static
-struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path) =
-       bt_plugin_python_create_all_from_file;
-
-static
-void init_python_plugin_provider(void) {}
-#else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */
-static GModule *python_plugin_provider_module;
-static
-struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path);
-
-static
-void init_python_plugin_provider(void) {
-       if (bt_plugin_python_create_all_from_file_sym != NULL) {
-               return;
-       }
-
-       BT_LOGD_STR("Loading Python plugin provider module.");
-       python_plugin_provider_module =
-               g_module_open(PYTHON_PLUGIN_PROVIDER_FILENAME, 0);
-       if (!python_plugin_provider_module) {
-               BT_LOGI("Cannot open `%s`: %s: continuing without Python plugin support.",
-                       PYTHON_PLUGIN_PROVIDER_FILENAME, g_module_error());
-               return;
-       }
-
-       if (!g_module_symbol(python_plugin_provider_module,
-                       PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR,
-                       (gpointer) &bt_plugin_python_create_all_from_file_sym)) {
-               BT_LOGI("Cannot find the Python plugin provider loading symbol: continuing without Python plugin support: "
-                       "file=\"%s\", symbol=\"%s\"",
-                       PYTHON_PLUGIN_PROVIDER_FILENAME,
-                       PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR);
-               return;
-       }
-
-       BT_LOGI("Loaded Python plugin provider module: addr=%p",
-               python_plugin_provider_module);
-}
-
-__attribute__((destructor)) static
-void fini_python_plugin_provider(void) {
-       if (python_plugin_provider_module) {
-               BT_LOGD("Unloading Python plugin provider module.");
-
-               if (!g_module_close(python_plugin_provider_module)) {
-                       BT_LOGE("Failed to close the Python plugin provider module: %s.",
-                               g_module_error());
-               }
-
-               python_plugin_provider_module = NULL;
-       }
-}
-#endif
-
-uint64_t bt_plugin_set_get_plugin_count(struct bt_plugin_set *plugin_set)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin_set, "Plugin set");
-       return (uint64_t) plugin_set->plugins->len;
-}
-
-const struct bt_plugin *bt_plugin_set_borrow_plugin_by_index_const(
-               const struct bt_plugin_set *plugin_set, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin_set, "Plugin set");
-       BT_ASSERT_PRE_VALID_INDEX(index, plugin_set->plugins->len);
-       return g_ptr_array_index(plugin_set->plugins, index);
-}
-
-const struct bt_plugin_set *bt_plugin_find_all_from_static(void)
-{
-       /* bt_plugin_so_create_all_from_static() logs errors */
-       return bt_plugin_so_create_all_from_static();
-}
-
-const struct bt_plugin_set *bt_plugin_find_all_from_file(const char *path)
-{
-       struct bt_plugin_set *plugin_set = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(path, "Path");
-       BT_LOGD("Creating plugins from file: path=\"%s\"", path);
-
-       /* Try shared object plugins */
-       plugin_set = bt_plugin_so_create_all_from_file(path);
-       if (plugin_set) {
-               goto end;
-       }
-
-       /* Try Python plugins if support is available */
-       init_python_plugin_provider();
-       if (bt_plugin_python_create_all_from_file_sym) {
-               plugin_set = bt_plugin_python_create_all_from_file_sym(path);
-               if (plugin_set) {
-                       goto end;
-               }
-       }
-
-end:
-       if (plugin_set) {
-               BT_LOGD("Created %u plugins from file: "
-                       "path=\"%s\", count=%u, plugin-set-addr=%p",
-                       plugin_set->plugins->len, path,
-                       plugin_set->plugins->len, plugin_set);
-       } else {
-               BT_LOGD("Found no plugins in file: path=\"%s\"", path);
-       }
-
-       return plugin_set;
-}
-
-static void destroy_gstring(void *data)
-{
-       g_string_free(data, TRUE);
-}
-
-const struct bt_plugin *bt_plugin_find(const char *plugin_name)
-{
-       const char *system_plugin_dir;
-       char *home_plugin_dir = NULL;
-       const char *envvar;
-       const struct bt_plugin *plugin = NULL;
-       const struct bt_plugin_set *plugin_set = NULL;
-       GPtrArray *dirs = NULL;
-       int ret;
-       size_t i, j;
-
-       BT_ASSERT_PRE_NON_NULL(plugin_name, "Name");
-       BT_LOGD("Finding named plugin in standard directories and built-in plugins: "
-               "name=\"%s\"", plugin_name);
-       dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring);
-       if (!dirs) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto end;
-       }
-
-       /*
-        * Search order is:
-        *
-        * 1. BABELTRACE_PLUGIN_PATH environment variable
-        *    (colon-separated list of directories)
-        * 2. ~/.local/lib/babeltrace2/plugins
-        * 3. Default system directory for Babeltrace plugins, usually
-        *    /usr/lib/babeltrace2/plugins or
-        *    /usr/local/lib/babeltrace2/plugins if installed
-        *    locally
-        * 4. Built-in plugins (static)
-        *
-        * Directories are searched non-recursively.
-        */
-       envvar = getenv("BABELTRACE_PLUGIN_PATH");
-       if (envvar) {
-               ret = bt_common_append_plugin_path_dirs(envvar, dirs);
-               if (ret) {
-                       BT_LOGE_STR("Failed to append plugin path to array of directories.");
-                       goto end;
-               }
-       }
-
-       home_plugin_dir = bt_common_get_home_plugin_path();
-       if (home_plugin_dir) {
-               GString *home_plugin_dir_str =
-                       g_string_new(home_plugin_dir);
-
-               if (!home_plugin_dir_str) {
-                       BT_LOGE_STR("Failed to allocate a GString.");
-                       goto end;
-               }
-
-               g_ptr_array_add(dirs, home_plugin_dir_str);
-       }
-
-       system_plugin_dir = bt_common_get_system_plugin_path();
-       if (system_plugin_dir) {
-               GString *system_plugin_dir_str =
-                       g_string_new(system_plugin_dir);
-
-               if (!system_plugin_dir_str) {
-                       BT_LOGE_STR("Failed to allocate a GString.");
-                       goto end;
-               }
-
-               g_ptr_array_add(dirs, system_plugin_dir_str);
-       }
-
-       for (i = 0; i < dirs->len; i++) {
-               GString *dir = g_ptr_array_index(dirs, i);
-
-               BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
-
-               /*
-                * Skip this if the directory does not exist because
-                * bt_plugin_find_all_from_dir() would log a warning.
-                */
-               if (!g_file_test(dir->str, G_FILE_TEST_IS_DIR)) {
-                       BT_LOGV("Skipping nonexistent directory path: "
-                               "path=\"%s\"", dir->str);
-                       continue;
-               }
-
-               /* bt_plugin_find_all_from_dir() logs details/errors */
-               plugin_set = bt_plugin_find_all_from_dir(dir->str, BT_FALSE);
-               if (!plugin_set) {
-                       BT_LOGD("No plugins found in directory: path=\"%s\"",
-                               dir->str);
-                       continue;
-               }
-
-               for (j = 0; j < plugin_set->plugins->len; j++) {
-                       const struct bt_plugin *candidate_plugin =
-                               g_ptr_array_index(plugin_set->plugins, j);
-
-                       if (strcmp(bt_plugin_get_name(candidate_plugin),
-                                       plugin_name) == 0) {
-                               BT_LOGD("Plugin found in directory: name=\"%s\", path=\"%s\"",
-                                       plugin_name, dir->str);
-                               plugin = candidate_plugin;
-                               bt_object_get_no_null_check(plugin);
-                               goto end;
-                       }
-               }
-
-               BT_LOGD("Plugin not found in directory: name=\"%s\", path=\"%s\"",
-                       plugin_name, dir->str);
-       }
-
-       bt_object_put_ref(plugin_set);
-       plugin_set = bt_plugin_find_all_from_static();
-       if (plugin_set) {
-               for (j = 0; j < plugin_set->plugins->len; j++) {
-                       const struct bt_plugin *candidate_plugin =
-                               g_ptr_array_index(plugin_set->plugins, j);
-
-                       if (strcmp(bt_plugin_get_name(candidate_plugin),
-                                       plugin_name) == 0) {
-                               BT_LOGD("Plugin found in built-in plugins: "
-                                       "name=\"%s\"", plugin_name);
-                               plugin = candidate_plugin;
-                               bt_object_get_no_null_check(plugin);
-                               goto end;
-                       }
-               }
-       }
-
-end:
-       free(home_plugin_dir);
-       bt_object_put_ref(plugin_set);
-
-       if (dirs) {
-               g_ptr_array_free(dirs, TRUE);
-       }
-
-       if (plugin) {
-               BT_LIB_LOGD("Found plugin in standard directories and built-in plugins: "
-                       "%!+l", plugin);
-       } else {
-               BT_LOGD("No plugin found in standard directories and built-in plugins: "
-                       "name=\"%s\"", plugin_name);
-       }
-
-       return plugin;
-}
-
-static struct {
-       pthread_mutex_t lock;
-       struct bt_plugin_set *plugin_set;
-       bool recurse;
-} append_all_from_dir_info = {
-       .lock = PTHREAD_MUTEX_INITIALIZER
-};
-
-static
-int nftw_append_all_from_dir(const char *file, const struct stat *sb, int flag,
-               struct FTW *s)
-{
-       int ret = 0;
-       const char *name = file + s->base;
-
-       /* Check for recursion */
-       if (!append_all_from_dir_info.recurse && s->level > 1) {
-               goto end;
-       }
-
-       switch (flag) {
-       case FTW_F:
-       {
-               const struct bt_plugin_set *plugins_from_file;
-
-               if (name[0] == '.') {
-                       /* Skip hidden files */
-                       BT_LOGV("Skipping hidden file: path=\"%s\"", file);
-                       goto end;
-               }
-
-               plugins_from_file = bt_plugin_find_all_from_file(file);
-
-               if (plugins_from_file) {
-                       size_t j;
-
-                       for (j = 0; j < plugins_from_file->plugins->len; j++) {
-                               struct bt_plugin *plugin =
-                                       g_ptr_array_index(plugins_from_file->plugins, j);
-
-                               BT_LIB_LOGD("Adding plugin to plugin set: "
-                                       "plugin-path=\"%s\", %![plugin-]+l",
-                                       file, plugin);
-                               bt_plugin_set_add_plugin(
-                                       append_all_from_dir_info.plugin_set,
-                                       plugin);
-                       }
-
-                       bt_object_put_ref(plugins_from_file);
-               }
-               break;
-       }
-       case FTW_DNR:
-               /* Continue to next file / directory. */
-               BT_LOGW("Cannot enter directory: continuing: path=\"%s\"", file);
-               break;
-       case FTW_NS:
-               /* Continue to next file / directory. */
-               BT_LOGD("Cannot get file information: continuing: path=\"%s\"", file);
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static
-enum bt_plugin_status bt_plugin_create_append_all_from_dir(
-               struct bt_plugin_set *plugin_set, const char *path,
-               bt_bool recurse)
-{
-       int nftw_flags = FTW_PHYS;
-       enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK;
-
-       BT_ASSERT(plugin_set);
-       BT_ASSERT(path);
-       BT_ASSERT(strlen(path) < PATH_MAX);
-       pthread_mutex_lock(&append_all_from_dir_info.lock);
-       append_all_from_dir_info.plugin_set = plugin_set;
-       append_all_from_dir_info.recurse = recurse;
-       ret = nftw(path, nftw_append_all_from_dir,
-               APPEND_ALL_FROM_DIR_NFDOPEN_MAX, nftw_flags);
-       pthread_mutex_unlock(&append_all_from_dir_info.lock);
-       if (ret != 0) {
-               BT_LOGW_ERRNO("Cannot open directory", ": path=\"%s\"", path);
-               ret = BT_PLUGIN_STATUS_ERROR;
-       }
-
-       return ret;
-}
-
-const struct bt_plugin_set *bt_plugin_find_all_from_dir(const char *path,
-               bt_bool recurse)
-{
-       struct bt_plugin_set *plugin_set;
-       enum bt_plugin_status status;
-
-       BT_LOGD("Creating all plugins in directory: path=\"%s\", recurse=%d",
-               path, recurse);
-       plugin_set = bt_plugin_set_create();
-       if (!plugin_set) {
-               BT_LOGE_STR("Cannot create empty plugin set.");
-               goto error;
-       }
-
-       /* Append found plugins to array */
-       status = bt_plugin_create_append_all_from_dir(plugin_set, path,
-               recurse);
-       if (status < 0) {
-               BT_LOGW("Cannot append plugins found in directory: "
-                       "path=\"%s\", status=%s",
-                       path, bt_plugin_status_string(status));
-               goto error;
-       }
-
-       BT_LOGD("Created %u plugins from directory: count=%u, path=\"%s\"",
-               plugin_set->plugins->len, plugin_set->plugins->len, path);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
-
-end:
-       return plugin_set;
-}
-
-const char *bt_plugin_get_name(const struct bt_plugin *plugin)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       return plugin->info.name_set ? plugin->info.name->str : NULL;
-}
-
-const char *bt_plugin_get_author(const struct bt_plugin *plugin)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       return plugin->info.author_set ? plugin->info.author->str : NULL;
-}
-
-const char *bt_plugin_get_license(const struct bt_plugin *plugin)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       return plugin->info.license_set ? plugin->info.license->str : NULL;
-}
-
-const char *bt_plugin_get_path(const struct bt_plugin *plugin)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       return plugin->info.path_set ? plugin->info.path->str : NULL;
-}
-
-const char *bt_plugin_get_description(const struct bt_plugin *plugin)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       return plugin->info.description_set ?
-               plugin->info.description->str : NULL;
-}
-
-enum bt_property_availability bt_plugin_get_version(const struct bt_plugin *plugin,
-               unsigned int *major, unsigned int *minor, unsigned int *patch,
-               const char **extra)
-{
-       enum bt_property_availability avail =
-               BT_PROPERTY_AVAILABILITY_AVAILABLE;
-
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-
-       if (!plugin->info.version_set) {
-               BT_LIB_LOGV("Plugin's version is not set: %!+l", plugin);
-               avail = BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
-               goto end;
-       }
-
-       if (major) {
-               *major = plugin->info.version.major;
-       }
-
-       if (minor) {
-               *minor = plugin->info.version.minor;
-       }
-
-       if (patch) {
-               *patch = plugin->info.version.patch;
-       }
-
-       if (extra) {
-               *extra = plugin->info.version.extra->str;
-       }
-
-end:
-       return avail;
-}
-
-uint64_t bt_plugin_get_source_component_class_count(const struct bt_plugin *plugin)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       return (uint64_t) plugin->src_comp_classes->len;
-}
-
-uint64_t bt_plugin_get_filter_component_class_count(const struct bt_plugin *plugin)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       return (uint64_t) plugin->flt_comp_classes->len;
-}
-
-uint64_t bt_plugin_get_sink_component_class_count(const struct bt_plugin *plugin)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       return (uint64_t) plugin->sink_comp_classes->len;
-}
-
-static inline
-struct bt_component_class *borrow_component_class_by_index(
-               const struct bt_plugin *plugin, GPtrArray *comp_classes,
-               uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       BT_ASSERT_PRE_VALID_INDEX(index, comp_classes->len);
-       return g_ptr_array_index(comp_classes, index);
-}
-
-const struct bt_component_class_source *
-bt_plugin_borrow_source_component_class_by_index_const(
-               const struct bt_plugin *plugin, uint64_t index)
-{
-       return (const void *) borrow_component_class_by_index(plugin,
-               plugin->src_comp_classes, index);
-}
-
-const struct bt_component_class_filter *
-bt_plugin_borrow_filter_component_class_by_index_const(
-               const struct bt_plugin *plugin, uint64_t index)
-{
-       return (const void *) borrow_component_class_by_index(plugin,
-               plugin->flt_comp_classes, index);
-}
-
-const struct bt_component_class_sink *
-bt_plugin_borrow_sink_component_class_by_index_const(
-               const struct bt_plugin *plugin, uint64_t index)
-{
-       return (const void *) borrow_component_class_by_index(plugin,
-               plugin->sink_comp_classes, index);
-}
-
-static inline
-struct bt_component_class *borrow_component_class_by_name(
-               const struct bt_plugin *plugin, GPtrArray *comp_classes,
-               const char *name)
-{
-       struct bt_component_class *comp_class = NULL;
-       size_t i;
-
-       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-
-       for (i = 0; i < comp_classes->len; i++) {
-               struct bt_component_class *comp_class_candidate =
-                       g_ptr_array_index(comp_classes, i);
-               const char *comp_class_cand_name =
-                       bt_component_class_get_name(comp_class_candidate);
-
-               BT_ASSERT(comp_class_cand_name);
-
-               if (strcmp(name, comp_class_cand_name) == 0) {
-                       comp_class = comp_class_candidate;
-                       break;
-               }
-       }
-
-       return comp_class;
-}
-
-const struct bt_component_class_source *
-bt_plugin_borrow_source_component_class_by_name_const(
-               const struct bt_plugin *plugin, const char *name)
-{
-       return (const void *) borrow_component_class_by_name(plugin,
-               plugin->src_comp_classes, name);
-}
-
-const struct bt_component_class_filter *
-bt_plugin_borrow_filter_component_class_by_name_const(
-               const struct bt_plugin *plugin, const char *name)
-{
-       return (const void *) borrow_component_class_by_name(plugin,
-               plugin->flt_comp_classes, name);
-}
-
-const struct bt_component_class_sink *
-bt_plugin_borrow_sink_component_class_by_name_const(
-               const struct bt_plugin *plugin, const char *name)
-{
-       return (const void *) borrow_component_class_by_name(plugin,
-               plugin->sink_comp_classes, name);
-}
-
-void bt_plugin_get_ref(const struct bt_plugin *plugin)
-{
-       bt_object_get_ref(plugin);
-}
-
-void bt_plugin_put_ref(const struct bt_plugin *plugin)
-{
-       bt_object_put_ref(plugin);
-}
-
-void bt_plugin_set_get_ref(const struct bt_plugin_set *plugin_set)
-{
-       bt_object_get_ref(plugin_set);
-}
-
-void bt_plugin_set_put_ref(const struct bt_plugin_set *plugin_set)
-{
-       bt_object_put_ref(plugin_set);
-}
diff --git a/lib/prio_heap/Makefile.am b/lib/prio_heap/Makefile.am
deleted file mode 100644 (file)
index d1e23b0..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-noinst_LTLIBRARIES = libprio_heap.la
-
-libprio_heap_la_SOURCES = prio_heap.c
diff --git a/lib/prio_heap/prio_heap.c b/lib/prio_heap/prio_heap.c
deleted file mode 100644 (file)
index 97a69ac..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Static-sized priority heap containing pointers. Based on CLRS,
- * chapter 6.
- *
- * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/prio-heap-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef DEBUG_HEAP
-void check_heap(const struct ptr_heap *heap)
-{
-       size_t i;
-
-       if (!heap->len)
-               return;
-
-       for (i = 1; i < heap->len; i++)
-               BT_ASSERT(!heap->gt(heap->ptrs[i], heap->ptrs[0]));
-}
-#endif
-
-static
-size_t parent(size_t i)
-{
-       return (i - 1) >> 1;
-}
-
-static
-size_t left(size_t i)
-{
-       return (i << 1) + 1;
-}
-
-static
-size_t right(size_t i)
-{
-       return (i << 1) + 2;
-}
-
-/*
- * Copy of heap->ptrs pointer is invalid after heap_grow.
- */
-static
-int heap_grow(struct ptr_heap *heap, size_t new_len)
-{
-       void **new_ptrs;
-
-       if (likely(heap->alloc_len >= new_len))
-               return 0;
-
-       heap->alloc_len = max_t(size_t, new_len, heap->alloc_len << 1);
-       new_ptrs = calloc(heap->alloc_len, sizeof(void *));
-       if (unlikely(!new_ptrs))
-               return -ENOMEM;
-       if (likely(heap->ptrs))
-               memcpy(new_ptrs, heap->ptrs, heap->len * sizeof(void *));
-       free(heap->ptrs);
-       heap->ptrs = new_ptrs;
-       return 0;
-}
-
-static
-int heap_set_len(struct ptr_heap *heap, size_t new_len)
-{
-       int ret;
-
-       ret = heap_grow(heap, new_len);
-       if (unlikely(ret))
-               return ret;
-       heap->len = new_len;
-       return 0;
-}
-
-int bt_heap_init(struct ptr_heap *heap, size_t alloc_len,
-             int gt(void *a, void *b))
-{
-       heap->ptrs = NULL;
-       heap->len = 0;
-       heap->alloc_len = 0;
-       heap->gt = gt;
-       /*
-        * Minimum size allocated is 1 entry to ensure memory allocation
-        * never fails within bt_heap_replace_max.
-        */
-       return heap_grow(heap, max_t(size_t, 1, alloc_len));
-}
-
-void bt_heap_free(struct ptr_heap *heap)
-{
-       free(heap->ptrs);
-}
-
-static void heapify(struct ptr_heap *heap, size_t i)
-{
-       void **ptrs = heap->ptrs;
-       size_t l, r, largest;
-
-       for (;;) {
-               void *tmp;
-
-               l = left(i);
-               r = right(i);
-               if (l < heap->len && heap->gt(ptrs[l], ptrs[i]))
-                       largest = l;
-               else
-                       largest = i;
-               if (r < heap->len && heap->gt(ptrs[r], ptrs[largest]))
-                       largest = r;
-               if (unlikely(largest == i))
-                       break;
-               tmp = ptrs[i];
-               ptrs[i] = ptrs[largest];
-               ptrs[largest] = tmp;
-               i = largest;
-       }
-       check_heap(heap);
-}
-
-void *bt_heap_replace_max(struct ptr_heap *heap, void *p)
-{
-       void *res;
-
-       if (unlikely(!heap->len)) {
-               (void) heap_set_len(heap, 1);
-               heap->ptrs[0] = p;
-               check_heap(heap);
-               return NULL;
-       }
-
-       /* Replace the current max and heapify */
-       res = heap->ptrs[0];
-       heap->ptrs[0] = p;
-       heapify(heap, 0);
-       return res;
-}
-
-int bt_heap_insert(struct ptr_heap *heap, void *p)
-{
-       void **ptrs;
-       size_t pos;
-       int ret;
-
-       ret = heap_set_len(heap, heap->len + 1);
-       if (unlikely(ret))
-               return ret;
-       ptrs = heap->ptrs;
-       pos = heap->len - 1;
-       while (pos > 0 && heap->gt(p, ptrs[parent(pos)])) {
-               /* Move parent down until we find the right spot */
-               ptrs[pos] = ptrs[parent(pos)];
-               pos = parent(pos);
-       }
-       ptrs[pos] = p;
-       check_heap(heap);
-       return 0;
-}
-
-void *bt_heap_remove(struct ptr_heap *heap)
-{
-       switch (heap->len) {
-       case 0:
-               return NULL;
-       case 1:
-               (void) heap_set_len(heap, 0);
-               return heap->ptrs[0];
-       }
-       /* Shrink, replace the current max by previous last entry and heapify */
-       heap_set_len(heap, heap->len - 1);
-       /* len changed. previous last entry is at heap->len */
-       return bt_heap_replace_max(heap, heap->ptrs[heap->len]);
-}
-
-void *bt_heap_cherrypick(struct ptr_heap *heap, void *p)
-{
-       size_t pos, len = heap->len;
-
-       for (pos = 0; pos < len; pos++)
-               if (unlikely(heap->ptrs[pos] == p))
-                       goto found;
-       return NULL;
-found:
-       if (unlikely(heap->len == 1)) {
-               (void) heap_set_len(heap, 0);
-               check_heap(heap);
-               return heap->ptrs[0];
-       }
-       /* Replace p with previous last entry and heapify. */
-       heap_set_len(heap, heap->len - 1);
-       /* len changed. previous last entry is at heap->len */
-       heap->ptrs[pos] = heap->ptrs[heap->len];
-       heapify(heap, pos);
-       return p;
-}
-
-int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src)
-{
-       int ret;
-
-       ret = bt_heap_init(dst, src->alloc_len, src->gt);
-       if (ret < 0)
-               goto end;
-
-       ret = heap_set_len(dst, src->len);
-       if (ret < 0)
-               goto end;
-
-       memcpy(dst->ptrs, src->ptrs, src->len * sizeof(void *));
-
-end:
-       return ret;
-}
diff --git a/lib/trace-ir/Makefile.am b/lib/trace-ir/Makefile.am
deleted file mode 100644 (file)
index 0b2107e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-noinst_LTLIBRARIES = libtrace-ir.la
-
-libtrace_ir_la_SOURCES = \
-       attributes.c \
-       clock-class.c \
-       clock-snapshot.c \
-       event.c \
-       event-class.c \
-       field-wrapper.c \
-       field.c \
-       field-class.c \
-       field-path.c \
-       packet.c \
-       packet-context-field.c \
-       resolve-field-path.c \
-       stream.c \
-       stream-class.c \
-       trace.c \
-       trace-class.c \
-       utils.c
-
-libtrace_ir_la_LIBADD = $(UUID_LIBS)
diff --git a/lib/trace-ir/attributes.c b/lib/trace-ir/attributes.c
deleted file mode 100644 (file)
index 8e85af5..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "ATTRS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/value-const.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/trace-ir/attributes-internal.h>
-#include <inttypes.h>
-#include <babeltrace2/compat/string-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-#define BT_ATTR_NAME_INDEX             0
-#define BT_ATTR_VALUE_INDEX            1
-
-BT_HIDDEN
-struct bt_value *bt_attributes_create(void)
-{
-       struct bt_value *attr_obj;
-
-       /*
-        * Attributes: array value object of array value objects, each one
-        * containing two entries: a string value object (attributes
-        * field name), and a value object (attributes field value).
-        *
-        * Example (JSON representation):
-        *
-        *     [
-        *         ["hostname", "eeppdesk"],
-        *         ["sysname", "Linux"],
-        *         ["tracer_major", 2],
-        *         ["tracer_minor", 5]
-        *     ]
-        */
-       BT_LOGD_STR("Creating attributes object.");
-       attr_obj = bt_value_array_create();
-       if (!attr_obj) {
-               BT_LOGE_STR("Failed to create array value.");
-       } else {
-               BT_LOGD("Created attributes object: addr=%p",
-                       attr_obj);
-       }
-
-       return attr_obj;
-}
-
-BT_HIDDEN
-void bt_attributes_destroy(struct bt_value *attr_obj)
-{
-       BT_LOGD("Destroying attributes object: addr=%p", attr_obj);
-       BT_OBJECT_PUT_REF_AND_RESET(attr_obj);
-}
-
-BT_HIDDEN
-int64_t bt_attributes_get_count(const struct bt_value *attr_obj)
-{
-       return bt_value_array_get_size(attr_obj);
-}
-
-BT_HIDDEN
-const char *bt_attributes_get_field_name(const struct bt_value *attr_obj,
-               uint64_t index)
-{
-       const char *ret = NULL;
-       const struct bt_value *attr_field_obj = NULL;
-       const struct bt_value *attr_field_name_obj = NULL;
-
-       if (!attr_obj) {
-               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
-               goto end;
-       }
-
-       if (index >= bt_value_array_get_size(attr_obj)) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "index=%" PRIu64 ", count=%" PRId64,
-                       index, bt_value_array_get_size(attr_obj));
-               goto end;
-       }
-
-       attr_field_obj = bt_value_array_borrow_element_by_index_const(
-               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_borrow_element_by_index_const(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;
-       }
-
-       ret = bt_value_string_get(attr_field_name_obj);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_value *bt_attributes_borrow_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;
-       }
-
-       if (index >= bt_value_array_get_size(attr_obj)) {
-               BT_LOGW("Invalid parameter: index is out of bounds: "
-                       "index=%" PRIu64 ", count=%" PRId64,
-                       index, bt_value_array_get_size(attr_obj));
-               goto end;
-       }
-
-       attr_field_obj =
-               bt_value_array_borrow_element_by_index(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_borrow_element_by_index(
-               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:
-       return value_obj;
-}
-
-static
-struct bt_value *bt_attributes_borrow_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_get_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) {
-               const char *field_name;
-
-               value_obj = bt_value_array_borrow_element_by_index(
-                       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_borrow_element_by_index(
-                               value_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,
-                               value_obj, (int64_t) BT_ATTR_NAME_INDEX);
-                       goto error;
-               }
-
-               field_name = bt_value_string_get(attr_field_name_obj);
-
-               if (!strcmp(field_name, name)) {
-                       break;
-               }
-
-               value_obj = NULL;
-       }
-
-       return value_obj;
-
-error:
-       value_obj = NULL;
-       return value_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_borrow_field_by_name(attr_obj, name);
-       if (attr_field_obj) {
-               ret = bt_value_array_set_element_by_index(
-                       attr_field_obj, BT_ATTR_VALUE_INDEX,
-                       value_obj);
-               attr_field_obj = NULL;
-               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_element(attr_field_obj,
-               name);
-       ret |= bt_value_array_append_element(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_element(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_object_put_ref(attr_field_obj);
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_value *bt_attributes_borrow_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_borrow_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_borrow_element_by_index(
-               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:
-       return value_obj;
-}
-
-BT_HIDDEN
-int bt_attributes_freeze(const 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_get_size(attr_obj);
-       BT_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_borrow_field_value(
-                       (void *) 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);
-       }
-
-end:
-       return ret;
-}
diff --git a/lib/trace-ir/clock-class.c b/lib/trace-ir/clock-class.c
deleted file mode 100644 (file)
index 515cdb4..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CLOCK-CLASS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/trace-ir/clock-class-const.h>
-#include <babeltrace2/trace-ir/clock-class.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/compat/string-internal.h>
-#include <inttypes.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-#define BT_ASSERT_PRE_CLOCK_CLASS_HOT(_cc) \
-       BT_ASSERT_PRE_HOT((_cc), "Clock class", ": %!+K", (_cc))
-
-static
-void destroy_clock_class(struct bt_object *obj)
-{
-       struct bt_clock_class *clock_class = (void *) obj;
-
-       BT_LIB_LOGD("Destroying clock class: %!+K", clock_class);
-
-       if (clock_class->name.str) {
-               g_string_free(clock_class->name.str, TRUE);
-               clock_class->name.str = NULL;
-               clock_class->name.value = NULL;
-       }
-
-       if (clock_class->description.str) {
-               g_string_free(clock_class->description.str, TRUE);
-               clock_class->description.str = NULL;
-               clock_class->description.value = NULL;
-       }
-
-       bt_object_pool_finalize(&clock_class->cs_pool);
-       g_free(clock_class);
-}
-
-static
-void free_clock_snapshot(struct bt_clock_snapshot *clock_snapshot,
-               struct bt_clock_class *clock_class)
-{
-       bt_clock_snapshot_destroy(clock_snapshot);
-}
-
-static inline
-void set_base_offset(struct bt_clock_class *clock_class)
-{
-       clock_class->base_offset.overflows = bt_util_get_base_offset_ns(
-               clock_class->offset_seconds, clock_class->offset_cycles,
-               clock_class->frequency, &clock_class->base_offset.value_ns);
-}
-
-struct bt_clock_class *bt_clock_class_create(bt_self_component *self_comp)
-{
-       int ret;
-       struct bt_clock_class *clock_class = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(self_comp, "Self component");
-       BT_LOGD_STR("Creating default clock class object");
-
-       clock_class = g_new0(struct bt_clock_class, 1);
-       if (!clock_class) {
-               BT_LOGE_STR("Failed to allocate one clock class.");
-               goto error;
-       }
-
-       bt_object_init_shared(&clock_class->base, destroy_clock_class);
-       clock_class->name.str = g_string_new(NULL);
-       if (!clock_class->name.str) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       clock_class->description.str = g_string_new(NULL);
-       if (!clock_class->description.str) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       clock_class->frequency = UINT64_C(1000000000);
-       clock_class->origin_is_unix_epoch = BT_TRUE;
-       set_base_offset(clock_class);
-       ret = bt_object_pool_initialize(&clock_class->cs_pool,
-               (bt_object_pool_new_object_func) bt_clock_snapshot_new,
-               (bt_object_pool_destroy_object_func)
-                       free_clock_snapshot,
-               clock_class);
-       if (ret) {
-               BT_LOGE("Failed to initialize clock snapshot pool: ret=%d",
-                       ret);
-               goto error;
-       }
-
-       BT_LIB_LOGD("Created clock class object: %!+K", clock_class);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(clock_class);
-
-end:
-       return clock_class;
-}
-
-const char *bt_clock_class_get_name(const struct bt_clock_class *clock_class)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       return clock_class->name.value;
-}
-
-enum bt_clock_class_status bt_clock_class_set_name(
-               struct bt_clock_class *clock_class, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
-       g_string_assign(clock_class->name.str, name);
-       clock_class->name.value = clock_class->name.str->str;
-       BT_LIB_LOGV("Set clock class's name: %!+K", clock_class);
-       return BT_CLOCK_CLASS_STATUS_OK;
-}
-
-const char *bt_clock_class_get_description(
-               const struct bt_clock_class *clock_class)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       return clock_class->description.value;
-}
-
-enum bt_clock_class_status bt_clock_class_set_description(
-               struct bt_clock_class *clock_class, const char *descr)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_NON_NULL(descr, "Description");
-       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
-       g_string_assign(clock_class->description.str, descr);
-       clock_class->description.value = clock_class->description.str->str;
-       BT_LIB_LOGV("Set clock class's description: %!+K",
-               clock_class);
-       return BT_CLOCK_CLASS_STATUS_OK;
-}
-
-uint64_t bt_clock_class_get_frequency(const struct bt_clock_class *clock_class)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       return clock_class->frequency;
-}
-
-void bt_clock_class_set_frequency(struct bt_clock_class *clock_class,
-               uint64_t frequency)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
-       BT_ASSERT_PRE(frequency != UINT64_C(-1) && frequency != 0,
-               "Invalid frequency: %![cc-]+K, new-freq=%" PRIu64,
-               clock_class, frequency);
-       BT_ASSERT_PRE(clock_class->offset_cycles < frequency,
-               "Offset (cycles) is greater than clock class's frequency: "
-               "%![cc-]+K, new-freq=%" PRIu64, clock_class, frequency);
-       clock_class->frequency = frequency;
-       set_base_offset(clock_class);
-       BT_LIB_LOGV("Set clock class's frequency: %!+K", clock_class);
-}
-
-uint64_t bt_clock_class_get_precision(const struct bt_clock_class *clock_class)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       return clock_class->precision;
-}
-
-void bt_clock_class_set_precision(struct bt_clock_class *clock_class,
-               uint64_t precision)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
-       BT_ASSERT_PRE(precision != UINT64_C(-1),
-               "Invalid precision: %![cc-]+K, new-precision=%" PRIu64,
-               clock_class, precision);
-       clock_class->precision = precision;
-       BT_LIB_LOGV("Set clock class's precision: %!+K", clock_class);
-}
-
-void bt_clock_class_get_offset(const struct bt_clock_class *clock_class,
-               int64_t *seconds, uint64_t *cycles)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_NON_NULL(seconds, "Seconds (output)");
-       BT_ASSERT_PRE_NON_NULL(cycles, "Cycles (output)");
-       *seconds = clock_class->offset_seconds;
-       *cycles = clock_class->offset_cycles;
-}
-
-void bt_clock_class_set_offset(struct bt_clock_class *clock_class,
-               int64_t seconds, uint64_t cycles)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
-       BT_ASSERT_PRE(cycles < clock_class->frequency,
-               "Offset (cycles) is greater than clock class's frequency: "
-               "%![cc-]+K, new-offset-cycles=%" PRIu64, clock_class, cycles);
-       clock_class->offset_seconds = seconds;
-       clock_class->offset_cycles = cycles;
-       set_base_offset(clock_class);
-       BT_LIB_LOGV("Set clock class's offset: %!+K", clock_class);
-}
-
-bt_bool bt_clock_class_origin_is_unix_epoch(const struct bt_clock_class *clock_class)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       return (bool) clock_class->origin_is_unix_epoch;
-}
-
-void bt_clock_class_set_origin_is_unix_epoch(struct bt_clock_class *clock_class,
-               bt_bool origin_is_unix_epoch)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
-       clock_class->origin_is_unix_epoch = (bool) origin_is_unix_epoch;
-       BT_LIB_LOGV("Set clock class's origin is Unix epoch property: %!+K",
-               clock_class);
-}
-
-bt_uuid bt_clock_class_get_uuid(const struct bt_clock_class *clock_class)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       return clock_class->uuid.value;
-}
-
-void bt_clock_class_set_uuid(struct bt_clock_class *clock_class,
-               bt_uuid uuid)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_NON_NULL(uuid, "UUID");
-       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
-       memcpy(clock_class->uuid.uuid, uuid, BABELTRACE_UUID_LEN);
-       clock_class->uuid.value = clock_class->uuid.uuid;
-       BT_LIB_LOGV("Set clock class's UUID: %!+K", clock_class);
-}
-
-BT_HIDDEN
-void _bt_clock_class_freeze(const struct bt_clock_class *clock_class)
-{
-       BT_ASSERT(clock_class);
-
-       if (clock_class->frozen) {
-               return;
-       }
-
-       BT_LIB_LOGD("Freezing clock class: %!+K", clock_class);
-       ((struct bt_clock_class *) clock_class)->frozen = 1;
-}
-
-enum bt_clock_class_status bt_clock_class_cycles_to_ns_from_origin(
-               const struct bt_clock_class *clock_class,
-               uint64_t cycles, int64_t *ns)
-{
-       int ret;
-
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds (output)");
-       ret = bt_util_ns_from_origin_clock_class(clock_class, cycles, ns);
-       if (ret) {
-               ret = BT_CLOCK_CLASS_STATUS_OVERFLOW;
-               BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
-                       "from origin for given clock class: "
-                       "value overflows the signed 64-bit integer range: "
-                       "%![cc-]+K, cycles=%" PRIu64,
-                       clock_class, cycles);
-       }
-
-       return ret;
-}
-
-void bt_clock_class_get_ref(const struct bt_clock_class *clock_class)
-{
-       bt_object_get_ref(clock_class);
-}
-
-void bt_clock_class_put_ref(const struct bt_clock_class *clock_class)
-{
-       bt_object_put_ref(clock_class);
-}
diff --git a/lib/trace-ir/clock-snapshot.c b/lib/trace-ir/clock-snapshot.c
deleted file mode 100644 (file)
index 050f82a..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "CLOCK-SNAPSHOT"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-const.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/compat/string-internal.h>
-#include <inttypes.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-BT_HIDDEN
-void bt_clock_snapshot_destroy(struct bt_clock_snapshot *clock_snapshot)
-{
-       BT_LIB_LOGD("Destroying clock snapshot: %!+k", clock_snapshot);
-       BT_OBJECT_PUT_REF_AND_RESET(clock_snapshot->clock_class);
-       g_free(clock_snapshot);
-}
-
-BT_HIDDEN
-struct bt_clock_snapshot *bt_clock_snapshot_new(
-               struct bt_clock_class *clock_class)
-{
-       struct bt_clock_snapshot *ret = NULL;
-
-       BT_ASSERT(clock_class);
-       BT_LIB_LOGD("Creating clock snapshot object: %![cc-]+K=",
-               clock_class);
-       ret = g_new0(struct bt_clock_snapshot, 1);
-       if (!ret) {
-               BT_LOGE_STR("Failed to allocate one clock snapshot.");
-               goto end;
-       }
-
-       bt_object_init_unique(&ret->base);
-       ret->clock_class = clock_class;
-       bt_object_get_no_null_check(clock_class);
-       bt_clock_class_freeze(clock_class);
-       BT_LIB_LOGD("Created clock snapshot object: %!+k", ret);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_clock_snapshot *bt_clock_snapshot_create(
-               struct bt_clock_class *clock_class)
-{
-       struct bt_clock_snapshot *clock_snapshot = NULL;
-
-       BT_ASSERT(clock_class);
-       clock_snapshot = bt_object_pool_create_object(&clock_class->cs_pool);
-       if (!clock_snapshot) {
-               BT_LIB_LOGE("Cannot allocate one clock snapshot from clock class's clock snapshot pool: "
-                       "%![cc-]+K", clock_class);
-               goto error;
-       }
-
-       if (likely(!clock_snapshot->clock_class)) {
-               clock_snapshot->clock_class = clock_class;
-               bt_object_get_no_null_check(clock_class);
-       }
-
-       goto end;
-
-error:
-       if (clock_snapshot) {
-               bt_clock_snapshot_recycle(clock_snapshot);
-               clock_snapshot = NULL;
-       }
-
-end:
-       return clock_snapshot;
-}
-
-BT_HIDDEN
-void bt_clock_snapshot_recycle(struct bt_clock_snapshot *clock_snapshot)
-{
-       struct bt_clock_class *clock_class;
-
-       BT_ASSERT(clock_snapshot);
-       BT_LIB_LOGD("Recycling clock snapshot: %!+k", clock_snapshot);
-
-       /*
-        * Those are the important ordered steps:
-        *
-        * 1. Reset the clock snapshot object, but do NOT put its clock
-        *    class's reference. This clock class contains the pool to
-        *    which we're about to recycle this clock snapshot object,
-        *    so we must guarantee its existence thanks to this existing
-        *    reference.
-        *
-        * 2. Move the clock class reference to our `clock_class`
-        *    variable so that we can set the clock snapshot's clock
-        *    class member to NULL before recycling it. We CANNOT do
-        *    this after we put the clock class reference because this
-        *    bt_object_put_ref() could destroy the clock class, also
-        *    destroying its clock snapshot pool, thus also destroying
-        *    our clock snapshot object (this would result in an invalid
-        *    write access).
-        *
-        * 3. Recycle the clock snapshot object.
-        *
-        * 4. Put our clock class reference.
-        */
-       bt_clock_snapshot_reset(clock_snapshot);
-       clock_class = clock_snapshot->clock_class;
-       BT_ASSERT(clock_class);
-       clock_snapshot->clock_class = NULL;
-       bt_object_pool_recycle_object(&clock_class->cs_pool, clock_snapshot);
-       bt_object_put_ref(clock_class);
-}
-
-uint64_t bt_clock_snapshot_get_value(
-               const struct bt_clock_snapshot *clock_snapshot)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_snapshot, "Clock snapshot");
-       BT_ASSERT_PRE(clock_snapshot->is_set,
-               "Clock snapshot is not set: %!+k", clock_snapshot);
-       return clock_snapshot->value_cycles;
-}
-
-enum bt_clock_snapshot_status bt_clock_snapshot_get_ns_from_origin(
-               const struct bt_clock_snapshot *clock_snapshot,
-               int64_t *ret_value_ns)
-{
-       int ret = BT_CLOCK_SNAPSHOT_STATUS_OK;
-
-       BT_ASSERT_PRE_NON_NULL(clock_snapshot, "Clock snapshot");
-       BT_ASSERT_PRE_NON_NULL(ret_value_ns, "Value (ns) (output)");
-       BT_ASSERT_PRE(clock_snapshot->is_set,
-               "Clock snapshot is not set: %!+k", clock_snapshot);
-
-       if (clock_snapshot->ns_from_origin_overflows) {
-               BT_LIB_LOGD("Clock snapshot, once converted to nanoseconds from origin, "
-                       "overflows the signed 64-bit integer range: "
-                       "%![cs-]+k", clock_snapshot);
-               ret = BT_CLOCK_SNAPSHOT_STATUS_OVERFLOW;
-               goto end;
-       }
-
-       *ret_value_ns = clock_snapshot->ns_from_origin;
-
-end:
-       return ret;
-}
-
-const struct bt_clock_class *bt_clock_snapshot_borrow_clock_class_const(
-               const struct bt_clock_snapshot *clock_snapshot)
-{
-       BT_ASSERT_PRE_NON_NULL(clock_snapshot, "Clock snapshot");
-       return clock_snapshot->clock_class;
-}
diff --git a/lib/trace-ir/event-class.c b/lib/trace-ir/event-class.c
deleted file mode 100644 (file)
index db3911a..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "EVENT-CLASS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/clock-snapshot-internal.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/field-class.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/event-class.h>
-#include <babeltrace2/trace-ir/event-class-const.h>
-#include <babeltrace2/trace-ir/event-class-internal.h>
-#include <babeltrace2/trace-ir/event-internal.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/trace-ir/resolve-field-path-internal.h>
-#include <babeltrace2/trace-ir/attributes-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-#define BT_ASSERT_PRE_EVENT_CLASS_HOT(_ec) \
-       BT_ASSERT_PRE_HOT(((const struct bt_event_class *) (_ec)),      \
-               "Event class", ": %!+E", (_ec))
-
-static
-void destroy_event_class(struct bt_object *obj)
-{
-       struct bt_event_class *event_class = (void *) obj;
-
-       BT_LIB_LOGD("Destroying event class: %!+E", event_class);
-
-       if (event_class->name.str) {
-               g_string_free(event_class->name.str, TRUE);
-               event_class->name.str = NULL;
-       }
-
-       if (event_class->emf_uri.str) {
-               g_string_free(event_class->emf_uri.str, TRUE);
-               event_class->emf_uri.str = NULL;
-       }
-
-       BT_LOGD_STR("Putting context field class.");
-       BT_OBJECT_PUT_REF_AND_RESET(event_class->specific_context_fc);
-       BT_LOGD_STR("Putting payload field class.");
-       BT_OBJECT_PUT_REF_AND_RESET(event_class->payload_fc);
-       bt_object_pool_finalize(&event_class->event_pool);
-       g_free(obj);
-}
-
-static
-void free_event(struct bt_event *event,
-               struct bt_event_class *event_class)
-{
-       bt_event_destroy(event);
-}
-
-BT_ASSERT_PRE_FUNC
-static
-bool event_class_id_is_unique(const struct bt_stream_class *stream_class,
-               uint64_t id)
-{
-       uint64_t i;
-       bool is_unique = true;
-
-       for (i = 0; i < stream_class->event_classes->len; i++) {
-               const struct bt_event_class *ec =
-                       stream_class->event_classes->pdata[i];
-
-               if (ec->id == id) {
-                       is_unique = false;
-                       goto end;
-               }
-       }
-
-end:
-       return is_unique;
-}
-
-static
-struct bt_event_class *create_event_class_with_id(
-               struct bt_stream_class *stream_class, uint64_t id)
-{
-       int ret;
-       struct bt_event_class *event_class;
-
-       BT_ASSERT(stream_class);
-       BT_ASSERT_PRE(event_class_id_is_unique(stream_class, id),
-               "Duplicate event class ID: %![sc-]+S, id=%" PRIu64,
-               stream_class, id);
-       BT_LIB_LOGD("Creating event class object: %![sc-]+S, id=%" PRIu64,
-               stream_class, id);
-       event_class = g_new0(struct bt_event_class, 1);
-       if (!event_class) {
-               BT_LOGE_STR("Failed to allocate one event class.");
-               goto error;
-       }
-
-       bt_object_init_shared_with_parent(&event_class->base,
-               destroy_event_class);
-       event_class->id = id;
-       bt_property_uint_init(&event_class->log_level,
-                       BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE, 0);
-       event_class->name.str = g_string_new(NULL);
-       if (!event_class->name.str) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               ret = -1;
-               goto end;
-       }
-
-       event_class->emf_uri.str = g_string_new(NULL);
-       if (!event_class->emf_uri.str) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               ret = -1;
-               goto end;
-       }
-
-       ret = bt_object_pool_initialize(&event_class->event_pool,
-               (bt_object_pool_new_object_func) bt_event_new,
-               (bt_object_pool_destroy_object_func) free_event,
-               event_class);
-       if (ret) {
-               BT_LOGE("Failed to initialize event pool: ret=%d",
-                       ret);
-               goto error;
-       }
-
-       bt_object_set_parent(&event_class->base, &stream_class->base);
-       g_ptr_array_add(stream_class->event_classes, event_class);
-       bt_stream_class_freeze(stream_class);
-       BT_LIB_LOGD("Created event class object: %!+E", event_class);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(event_class);
-
-end:
-       return event_class;
-}
-
-struct bt_event_class *bt_event_class_create(
-               struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE(stream_class->assigns_automatic_event_class_id,
-               "Stream class does not automatically assigns event class IDs: "
-               "%![sc-]+S", stream_class);
-       return create_event_class_with_id(stream_class,
-               (uint64_t) stream_class->event_classes->len);
-}
-
-struct bt_event_class *bt_event_class_create_with_id(
-               struct bt_stream_class *stream_class, uint64_t id)
-{
-       BT_ASSERT_PRE(!stream_class->assigns_automatic_event_class_id,
-               "Stream class automatically assigns event class IDs: "
-               "%![sc-]+S", stream_class);
-       return create_event_class_with_id(stream_class, id);
-}
-
-const char *bt_event_class_get_name(const struct bt_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->name.value;
-}
-
-enum bt_event_class_status bt_event_class_set_name(
-               struct bt_event_class *event_class, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
-       g_string_assign(event_class->name.str, name);
-       event_class->name.value = event_class->name.str->str;
-       BT_LIB_LOGV("Set event class's name: %!+E", event_class);
-       return BT_EVENT_CLASS_STATUS_OK;
-}
-
-uint64_t bt_event_class_get_id(const struct bt_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->id;
-}
-
-enum bt_property_availability bt_event_class_get_log_level(
-               const struct bt_event_class *event_class,
-               enum bt_event_class_log_level *log_level)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT_PRE_NON_NULL(log_level, "Log level (output)");
-       *log_level = (enum bt_event_class_log_level)
-               event_class->log_level.value;
-       return event_class->log_level.base.avail;
-}
-
-void bt_event_class_set_log_level(
-               struct bt_event_class *event_class,
-               enum bt_event_class_log_level log_level)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
-       bt_property_uint_set(&event_class->log_level,
-               (uint64_t) log_level);
-       BT_LIB_LOGV("Set event class's log level: %!+E", event_class);
-}
-
-const char *bt_event_class_get_emf_uri(const struct bt_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->emf_uri.value;
-}
-
-enum bt_event_class_status bt_event_class_set_emf_uri(
-               struct bt_event_class *event_class,
-               const char *emf_uri)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT_PRE_NON_NULL(emf_uri, "EMF URI");
-       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
-       g_string_assign(event_class->emf_uri.str, emf_uri);
-       event_class->emf_uri.value = event_class->emf_uri.str->str;
-       BT_LIB_LOGV("Set event class's EMF URI: %!+E", event_class);
-       return BT_EVENT_CLASS_STATUS_OK;
-}
-
-struct bt_stream_class *bt_event_class_borrow_stream_class(
-               struct bt_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return bt_event_class_borrow_stream_class_inline(event_class);
-}
-
-const struct bt_stream_class *
-bt_event_class_borrow_stream_class_const(
-               const struct bt_event_class *event_class)
-{
-       return bt_event_class_borrow_stream_class((void *) event_class);
-}
-
-const struct bt_field_class *
-bt_event_class_borrow_specific_context_field_class_const(
-               const struct bt_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->specific_context_fc;
-}
-
-struct bt_field_class *
-bt_event_class_borrow_specific_context_field_class(
-               struct bt_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->specific_context_fc;
-}
-
-enum bt_event_class_status bt_event_class_set_specific_context_field_class(
-               struct bt_event_class *event_class,
-               struct bt_field_class *field_class)
-{
-       int ret;
-       struct bt_stream_class *stream_class;
-       struct bt_resolve_field_path_context resolve_ctx = {
-               .packet_context = NULL,
-               .event_common_context = NULL,
-               .event_specific_context = field_class,
-               .event_payload = NULL,
-       };
-
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
-       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
-       BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
-               BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Specific context field class is not a structure field class: "
-               "%!+F", field_class);
-       stream_class = bt_event_class_borrow_stream_class_inline(
-               event_class);
-       resolve_ctx.packet_context = stream_class->packet_context_fc;
-       resolve_ctx.event_common_context =
-               stream_class->event_common_context_fc;
-
-       ret = bt_resolve_field_paths(field_class, &resolve_ctx);
-       if (ret) {
-               /*
-                * This is the only reason for which
-                * bt_resolve_field_paths() can fail: anything else
-                * would be because a precondition is not satisfied.
-                */
-               ret = BT_EVENT_CLASS_STATUS_NOMEM;
-               goto end;
-       }
-
-       bt_field_class_make_part_of_trace_class(field_class);
-       bt_object_put_ref(event_class->specific_context_fc);
-       event_class->specific_context_fc = field_class;
-       bt_object_get_no_null_check(event_class->specific_context_fc);
-       bt_field_class_freeze(field_class);
-       BT_LIB_LOGV("Set event class's specific context field class: %!+E",
-               event_class);
-
-end:
-       return ret;
-}
-
-const struct bt_field_class *bt_event_class_borrow_payload_field_class_const(
-               const struct bt_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->payload_fc;
-}
-
-struct bt_field_class *bt_event_class_borrow_payload_field_class(
-               struct bt_event_class *event_class)
-{
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       return event_class->payload_fc;
-}
-
-enum bt_event_class_status bt_event_class_set_payload_field_class(
-               struct bt_event_class *event_class,
-               struct bt_field_class *field_class)
-{
-       int ret;
-       struct bt_stream_class *stream_class;
-       struct bt_resolve_field_path_context resolve_ctx = {
-               .packet_context = NULL,
-               .event_common_context = NULL,
-               .event_specific_context = NULL,
-               .event_payload = field_class,
-       };
-
-       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
-       BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
-       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
-       BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
-               BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Payload field class is not a structure field class: %!+F",
-               field_class);
-       stream_class = bt_event_class_borrow_stream_class_inline(
-               event_class);
-       resolve_ctx.packet_context = stream_class->packet_context_fc;
-       resolve_ctx.event_common_context =
-               stream_class->event_common_context_fc;
-       resolve_ctx.event_specific_context = event_class->specific_context_fc;
-
-       ret = bt_resolve_field_paths(field_class, &resolve_ctx);
-       if (ret) {
-               /*
-                * This is the only reason for which
-                * bt_resolve_field_paths() can fail: anything else
-                * would be because a precondition is not satisfied.
-                */
-               ret = BT_EVENT_CLASS_STATUS_NOMEM;
-               goto end;
-       }
-
-       bt_field_class_make_part_of_trace_class(field_class);
-       bt_object_put_ref(event_class->payload_fc);
-       event_class->payload_fc = field_class;
-       bt_object_get_no_null_check(event_class->payload_fc);
-       bt_field_class_freeze(field_class);
-       BT_LIB_LOGV("Set event class's payload field class: %!+E", event_class);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void _bt_event_class_freeze(const struct bt_event_class *event_class)
-{
-       /* The field classes are already frozen */
-       BT_ASSERT(event_class);
-       BT_LIB_LOGD("Freezing event class: %!+E", event_class);
-       ((struct bt_event_class *) event_class)->frozen = true;
-}
-
-void bt_event_class_get_ref(const struct bt_event_class *event_class)
-{
-       bt_object_get_ref(event_class);
-}
-
-void bt_event_class_put_ref(const struct bt_event_class *event_class)
-{
-       bt_object_put_ref(event_class);
-}
diff --git a/lib/trace-ir/event.c b/lib/trace-ir/event.c
deleted file mode 100644 (file)
index 5f09485..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "EVENT"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/event-const.h>
-#include <babeltrace2/trace-ir/event-internal.h>
-#include <babeltrace2/trace-ir/event-class.h>
-#include <babeltrace2/trace-ir/event-class-internal.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/trace-ir/stream-class-const.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/packet.h>
-#include <babeltrace2/trace-ir/packet-internal.h>
-#include <babeltrace2/trace-ir/trace.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/trace-ir/packet-internal.h>
-#include <babeltrace2/trace-ir/attributes-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <inttypes.h>
-
-BT_HIDDEN
-void _bt_event_set_is_frozen(const struct bt_event *event, bool is_frozen)
-{
-       BT_ASSERT(event);
-       BT_LIB_LOGD("Setting event's frozen state: %!+e, is-frozen=%d",
-               event, is_frozen);
-
-       if (event->common_context_field) {
-               BT_LOGD_STR("Setting event's common context field's frozen state.");
-               bt_field_set_is_frozen(
-                       event->common_context_field, is_frozen);
-       }
-
-       if (event->specific_context_field) {
-               BT_LOGD_STR("Setting event's specific context field's frozen state.");
-               bt_field_set_is_frozen(event->specific_context_field,
-                       is_frozen);
-       }
-
-       if (event->payload_field) {
-               BT_LOGD_STR("Setting event's payload field's frozen state.");
-               bt_field_set_is_frozen(event->payload_field,
-                       is_frozen);
-       }
-
-       ((struct bt_event *) event)->frozen = is_frozen;
-       BT_LOGD_STR("Setting event's packet's frozen state.");
-       bt_packet_set_is_frozen(event->packet, is_frozen);
-}
-
-BT_HIDDEN
-struct bt_event *bt_event_new(struct bt_event_class *event_class)
-{
-       struct bt_event *event = NULL;
-       struct bt_stream_class *stream_class;
-       struct bt_field_class *fc;
-
-       BT_ASSERT(event_class);
-       event = g_new0(struct bt_event, 1);
-       if (!event) {
-               BT_LOGE_STR("Failed to allocate one event.");
-               goto error;
-       }
-
-       bt_object_init_unique(&event->base);
-       stream_class = bt_event_class_borrow_stream_class(event_class);
-       BT_ASSERT(stream_class);
-       fc = stream_class->event_common_context_fc;
-       if (fc) {
-               event->common_context_field = bt_field_create(fc);
-               if (!event->common_context_field) {
-                       /* bt_field_create() logs errors */
-                       goto error;
-               }
-       }
-
-       fc = event_class->specific_context_fc;
-       if (fc) {
-               event->specific_context_field = bt_field_create(fc);
-               if (!event->specific_context_field) {
-                       /* bt_field_create() logs errors */
-                       goto error;
-               }
-       }
-
-       fc = event_class->payload_fc;
-       if (fc) {
-               event->payload_field = bt_field_create(fc);
-               if (!event->payload_field) {
-                       /* bt_field_create() logs errors */
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       if (event) {
-               bt_event_destroy(event);
-               event = NULL;
-       }
-
-end:
-       return event;
-}
-
-struct bt_event_class *bt_event_borrow_class(struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->class;
-}
-
-const struct bt_event_class *bt_event_borrow_class_const(
-               const struct bt_event *event)
-{
-       return bt_event_borrow_class((void *) event);
-}
-
-struct bt_stream *bt_event_borrow_stream(struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->packet ? event->packet->stream : NULL;
-}
-
-const struct bt_stream *bt_event_borrow_stream_const(
-               const struct bt_event *event)
-{
-       return bt_event_borrow_stream((void *) event);
-}
-
-struct bt_field *bt_event_borrow_common_context_field(struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->common_context_field;
-}
-
-const struct bt_field *bt_event_borrow_common_context_field_const(
-               const struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->common_context_field;
-}
-
-struct bt_field *bt_event_borrow_specific_context_field(struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->specific_context_field;
-}
-
-const struct bt_field *bt_event_borrow_specific_context_field_const(
-               const struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->specific_context_field;
-}
-
-struct bt_field *bt_event_borrow_payload_field(struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->payload_field;
-}
-
-const struct bt_field *bt_event_borrow_payload_field_const(
-               const struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->payload_field;
-}
-
-BT_HIDDEN
-void bt_event_destroy(struct bt_event *event)
-{
-       BT_ASSERT(event);
-       BT_LIB_LOGD("Destroying event: %!+e", event);
-
-       if (event->common_context_field) {
-               BT_LOGD_STR("Destroying event's stream event context field.");
-               bt_field_destroy(event->common_context_field);
-               event->common_context_field = NULL;
-       }
-
-       if (event->specific_context_field) {
-               BT_LOGD_STR("Destroying event's context field.");
-               bt_field_destroy(event->specific_context_field);
-               event->specific_context_field = NULL;
-       }
-
-       if (event->payload_field) {
-               BT_LOGD_STR("Destroying event's payload field.");
-               bt_field_destroy(event->payload_field);
-               event->payload_field = NULL;
-       }
-
-       BT_LOGD_STR("Putting event's class.");
-       bt_object_put_ref(event->class);
-       BT_LOGD_STR("Putting event's packet.");
-       BT_OBJECT_PUT_REF_AND_RESET(event->packet);
-       g_free(event);
-}
-
-struct bt_packet *bt_event_borrow_packet(struct bt_event *event)
-{
-       BT_ASSERT_PRE_NON_NULL(event, "Event");
-       return event->packet;
-}
-
-const struct bt_packet *bt_event_borrow_packet_const(
-               const struct bt_event *event)
-{
-       return bt_event_borrow_packet((void *) event);
-}
diff --git a/lib/trace-ir/field-class.c b/lib/trace-ir/field-class.c
deleted file mode 100644 (file)
index c1f1805..0000000
+++ /dev/null
@@ -1,1355 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "FIELD-CLASSES"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/field-class.h>
-#include <babeltrace2/trace-ir/field-class-const.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/field-path-internal.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/field-const.h>
-#include <babeltrace2/trace-ir/field.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/trace-ir/clock-class.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/glib-internal.h>
-#include <float.h>
-#include <inttypes.h>
-#include <stdlib.h>
-
-enum bt_field_class_type bt_field_class_get_type(
-               const struct bt_field_class *fc)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       return fc->type;
-}
-
-static
-void init_field_class(struct bt_field_class *fc, enum bt_field_class_type type,
-               bt_object_release_func release_func)
-{
-       BT_ASSERT(fc);
-       BT_ASSERT(bt_field_class_has_known_type(fc));
-       BT_ASSERT(release_func);
-       bt_object_init_shared(&fc->base, release_func);
-       fc->type = type;
-}
-
-static
-void init_integer_field_class(struct bt_field_class_integer *fc,
-               enum bt_field_class_type type,
-               bt_object_release_func release_func)
-{
-       init_field_class((void *) fc, type, release_func);
-       fc->range = 64;
-       fc->base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
-}
-
-static
-void destroy_integer_field_class(struct bt_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_LIB_LOGD("Destroying integer field class object: %!+F", obj);
-       g_free(obj);
-}
-
-static inline
-struct bt_field_class *create_integer_field_class(bt_trace_class *trace_class,
-               enum bt_field_class_type type)
-{
-       struct bt_field_class_integer *int_fc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
-       BT_LOGD("Creating default integer field class object: type=%s",
-               bt_common_field_class_type_string(type));
-       int_fc = g_new0(struct bt_field_class_integer, 1);
-       if (!int_fc) {
-               BT_LOGE_STR("Failed to allocate one integer field class.");
-               goto error;
-       }
-
-       init_integer_field_class(int_fc, type, destroy_integer_field_class);
-       BT_LIB_LOGD("Created integer field class object: %!+F", int_fc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(int_fc);
-
-end:
-       return (void *) int_fc;
-}
-
-struct bt_field_class *bt_field_class_unsigned_integer_create(
-               bt_trace_class *trace_class)
-{
-       return create_integer_field_class(trace_class,
-               BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER);
-}
-
-struct bt_field_class *bt_field_class_signed_integer_create(
-               bt_trace_class *trace_class)
-{
-       return create_integer_field_class(trace_class,
-               BT_FIELD_CLASS_TYPE_SIGNED_INTEGER);
-}
-
-uint64_t bt_field_class_integer_get_field_value_range(
-               const struct bt_field_class *fc)
-{
-       const struct bt_field_class_integer *int_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_IS_INT(fc, "Field class");
-       return int_fc->range;
-}
-
-BT_ASSERT_PRE_FUNC
-static
-bool size_is_valid_for_enumeration_field_class(struct bt_field_class *fc,
-               uint64_t size)
-{
-       // TODO
-       return true;
-}
-
-void bt_field_class_integer_set_field_value_range(
-               struct bt_field_class *fc, uint64_t size)
-{
-       struct bt_field_class_integer *int_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_IS_INT(fc, "Field class");
-       BT_ASSERT_PRE_FC_HOT(fc, "Field class");
-       BT_ASSERT_PRE(size <= 64,
-               "Unsupported size for integer field class's field value range "
-               "(maximum is 64): size=%" PRIu64, size);
-       BT_ASSERT_PRE(
-               int_fc->common.type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
-               int_fc->common.type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
-               size_is_valid_for_enumeration_field_class(fc, size),
-               "Invalid field value range for enumeration field class: "
-               "at least one of the current mapping ranges contains values "
-               "which are outside this range: %!+F, size=%" PRIu64, fc, size);
-       int_fc->range = size;
-       BT_LIB_LOGV("Set integer field class's field value range: %!+F", fc);
-}
-
-enum bt_field_class_integer_preferred_display_base
-bt_field_class_integer_get_preferred_display_base(const struct bt_field_class *fc)
-{
-       const struct bt_field_class_integer *int_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_IS_INT(fc, "Field class");
-       return int_fc->base;
-}
-
-void bt_field_class_integer_set_preferred_display_base(
-               struct bt_field_class *fc,
-               enum bt_field_class_integer_preferred_display_base base)
-{
-       struct bt_field_class_integer *int_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_IS_INT(fc, "Field class");
-       BT_ASSERT_PRE_FC_HOT(fc, "Field class");
-       int_fc->base = base;
-       BT_LIB_LOGV("Set integer field class's preferred display base: %!+F", fc);
-}
-
-static
-void finalize_enumeration_field_class_mapping(
-               struct bt_field_class_enumeration_mapping *mapping)
-{
-       BT_ASSERT(mapping);
-
-       if (mapping->label) {
-               g_string_free(mapping->label, TRUE);
-       }
-
-       if (mapping->ranges) {
-               g_array_free(mapping->ranges, TRUE);
-       }
-}
-
-static
-void destroy_enumeration_field_class(struct bt_object *obj)
-{
-       struct bt_field_class_enumeration *fc = (void *) obj;
-
-       BT_ASSERT(fc);
-       BT_LIB_LOGD("Destroying enumeration field class object: %!+F", fc);
-
-       if (fc->mappings) {
-               uint64_t i;
-
-               for (i = 0; i < fc->mappings->len; i++) {
-                       finalize_enumeration_field_class_mapping(
-                               BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(fc, i));
-               }
-
-               g_array_free(fc->mappings, TRUE);
-               fc->mappings = NULL;
-       }
-
-       if (fc->label_buf) {
-               g_ptr_array_free(fc->label_buf, TRUE);
-               fc->label_buf = NULL;
-       }
-
-       g_free(fc);
-}
-
-static
-struct bt_field_class *create_enumeration_field_class(
-               bt_trace_class *trace_class, enum bt_field_class_type type)
-{
-       struct bt_field_class_enumeration *enum_fc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
-       BT_LOGD("Creating default enumeration field class object: type=%s",
-               bt_common_field_class_type_string(type));
-       enum_fc = g_new0(struct bt_field_class_enumeration, 1);
-       if (!enum_fc) {
-               BT_LOGE_STR("Failed to allocate one enumeration field class.");
-               goto error;
-       }
-
-       init_integer_field_class((void *) enum_fc, type,
-               destroy_enumeration_field_class);
-       enum_fc->mappings = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_field_class_enumeration_mapping));
-       if (!enum_fc->mappings) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               goto error;
-       }
-
-       enum_fc->label_buf = g_ptr_array_new();
-       if (!enum_fc->label_buf) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               goto error;
-       }
-
-       BT_LIB_LOGD("Created enumeration field class object: %!+F", enum_fc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(enum_fc);
-
-end:
-       return (void *) enum_fc;
-}
-
-struct bt_field_class *bt_field_class_unsigned_enumeration_create(
-               bt_trace_class *trace_class)
-{
-       return create_enumeration_field_class(trace_class,
-               BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION);
-}
-
-struct bt_field_class *bt_field_class_signed_enumeration_create(
-               bt_trace_class *trace_class)
-{
-       return create_enumeration_field_class(trace_class,
-               BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION);
-}
-
-uint64_t bt_field_class_enumeration_get_mapping_count(
-               const struct bt_field_class *fc)
-{
-       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_IS_ENUM(fc, "Field class");
-       return (uint64_t) enum_fc->mappings->len;
-}
-
-const struct bt_field_class_unsigned_enumeration_mapping *
-bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
-               const struct bt_field_class *fc, uint64_t index)
-{
-       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_VALID_INDEX(index, enum_fc->mappings->len);
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
-               "Field class");
-       return (const void *) BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(fc, index);
-}
-
-const struct bt_field_class_signed_enumeration_mapping *
-bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
-               const struct bt_field_class *fc, uint64_t index)
-{
-       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_VALID_INDEX(index, enum_fc->mappings->len);
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
-               "Field class");
-       return (const void *) BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(fc, index);
-}
-
-const char *bt_field_class_enumeration_mapping_get_label(
-               const struct bt_field_class_enumeration_mapping *mapping)
-{
-       BT_ASSERT_PRE_NON_NULL(mapping, "Enumeration field class mapping");
-       return mapping->label->str;
-}
-
-uint64_t bt_field_class_enumeration_mapping_get_range_count(
-               const struct bt_field_class_enumeration_mapping *mapping)
-{
-       BT_ASSERT_PRE_NON_NULL(mapping, "Enumeration field class mapping");
-       return (uint64_t) mapping->ranges->len;
-}
-
-static inline
-void get_enumeration_field_class_mapping_range_at_index(
-               const struct bt_field_class_enumeration_mapping *mapping,
-               uint64_t index, uint64_t *lower, uint64_t *upper)
-{
-       const struct bt_field_class_enumeration_mapping_range *range;
-
-       BT_ASSERT_PRE_NON_NULL(mapping, "Ranges");
-       BT_ASSERT_PRE_NON_NULL(lower, "Range's lower (output)");
-       BT_ASSERT_PRE_NON_NULL(upper, "Range's upper (output)");
-       BT_ASSERT_PRE_VALID_INDEX(index, mapping->ranges->len);
-       range = BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(mapping, index);
-       *lower = range->lower.u;
-       *upper = range->upper.u;
-}
-
-void bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
-               const struct bt_field_class_unsigned_enumeration_mapping *ranges,
-               uint64_t index, uint64_t *lower, uint64_t *upper)
-{
-       get_enumeration_field_class_mapping_range_at_index(
-               (const void *) ranges, index, lower, upper);
-}
-
-void bt_field_class_signed_enumeration_mapping_get_range_by_index(
-               const struct bt_field_class_signed_enumeration_mapping *ranges,
-               uint64_t index, int64_t *lower, int64_t *upper)
-{
-       get_enumeration_field_class_mapping_range_at_index(
-               (const void *) ranges, index,
-               (uint64_t *) lower, (uint64_t *) upper);
-}
-
-enum bt_field_class_status
-bt_field_class_unsigned_enumeration_get_mapping_labels_by_value(
-               const struct bt_field_class *fc, uint64_t value,
-               bt_field_class_enumeration_mapping_label_array *label_array,
-               uint64_t *count)
-{
-       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
-       uint64_t i;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
-       BT_ASSERT_PRE_NON_NULL(count, "Count (output)");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
-               "Field class");
-       g_ptr_array_set_size(enum_fc->label_buf, 0);
-
-       for (i = 0; i < enum_fc->mappings->len; i++) {
-               uint64_t j;
-               const struct bt_field_class_enumeration_mapping *mapping =
-                       BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i);
-
-               for (j = 0; j < mapping->ranges->len; j++) {
-                       const struct bt_field_class_enumeration_mapping_range *range =
-                               BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(
-                                       mapping, j);
-
-                       if (value >= range->lower.u &&
-                                       value <= range->upper.u) {
-                               g_ptr_array_add(enum_fc->label_buf,
-                                       mapping->label->str);
-                               break;
-                       }
-               }
-       }
-
-       *label_array = (void *) enum_fc->label_buf->pdata;
-       *count = (uint64_t) enum_fc->label_buf->len;
-       return BT_FIELD_CLASS_STATUS_OK;
-}
-
-enum bt_field_class_status
-bt_field_class_signed_enumeration_get_mapping_labels_by_value(
-               const struct bt_field_class *fc, int64_t value,
-               bt_field_class_enumeration_mapping_label_array *label_array,
-               uint64_t *count)
-{
-       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
-       uint64_t i;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
-       BT_ASSERT_PRE_NON_NULL(count, "Count (output)");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
-               "Field class");
-       g_ptr_array_set_size(enum_fc->label_buf, 0);
-
-       for (i = 0; i < enum_fc->mappings->len; i++) {
-               uint64_t j;
-               const struct bt_field_class_enumeration_mapping *mapping =
-                       BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i);
-
-               for (j = 0; j < mapping->ranges->len; j++) {
-                       const struct bt_field_class_enumeration_mapping_range *range =
-                               BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(
-                                       mapping, j);
-
-                       if (value >= range->lower.i &&
-                                       value <= range->upper.i) {
-                               g_ptr_array_add(enum_fc->label_buf,
-                                       mapping->label->str);
-                               break;
-                       }
-               }
-       }
-
-       *label_array = (void *) enum_fc->label_buf->pdata;
-       *count = (uint64_t) enum_fc->label_buf->len;
-       return BT_FIELD_CLASS_STATUS_OK;
-}
-
-static inline
-enum bt_field_class_status add_mapping_to_enumeration_field_class(
-               struct bt_field_class *fc,
-               const char *label, uint64_t lower, uint64_t upper)
-{
-       int ret = BT_FIELD_CLASS_STATUS_OK;
-       uint64_t i;
-       struct bt_field_class_enumeration *enum_fc = (void *) fc;
-       struct bt_field_class_enumeration_mapping *mapping = NULL;
-       struct bt_field_class_enumeration_mapping_range *range;
-
-       BT_ASSERT(fc);
-       BT_ASSERT_PRE_NON_NULL(label, "Label");
-
-       /* Find existing mapping identified by this label */
-       for (i = 0; i < enum_fc->mappings->len; i++) {
-               struct bt_field_class_enumeration_mapping *mapping_candidate =
-                       BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i);
-
-               if (strcmp(mapping_candidate->label->str, label) == 0) {
-                       mapping = mapping_candidate;
-                       break;
-               }
-       }
-
-       if (!mapping) {
-               /* Create new mapping for this label */
-               g_array_set_size(enum_fc->mappings, enum_fc->mappings->len + 1);
-               mapping = BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc,
-                       enum_fc->mappings->len - 1);
-               mapping->ranges = g_array_new(FALSE, TRUE,
-                       sizeof(struct bt_field_class_enumeration_mapping_range));
-               if (!mapping->ranges) {
-                       finalize_enumeration_field_class_mapping(mapping);
-                       g_array_set_size(enum_fc->mappings,
-                               enum_fc->mappings->len - 1);
-                       ret = BT_FIELD_CLASS_STATUS_NOMEM;
-                       goto end;
-               }
-
-               mapping->label = g_string_new(label);
-               if (!mapping->label) {
-                       finalize_enumeration_field_class_mapping(mapping);
-                       g_array_set_size(enum_fc->mappings,
-                               enum_fc->mappings->len - 1);
-                       ret = BT_FIELD_CLASS_STATUS_NOMEM;
-                       goto end;
-               }
-       }
-
-       /* Add range */
-       BT_ASSERT(mapping);
-       g_array_set_size(mapping->ranges, mapping->ranges->len + 1);
-       range = BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(mapping,
-               mapping->ranges->len - 1);
-       range->lower.u = lower;
-       range->upper.u = upper;
-       BT_LIB_LOGV("Added mapping to enumeration field class: "
-               "%![fc-]+F, label=\"%s\", lower-unsigned=%" PRIu64 ", "
-               "upper-unsigned=%" PRIu64, fc, label, lower, upper);
-
-end:
-       return ret;
-}
-
-enum bt_field_class_status bt_field_class_unsigned_enumeration_map_range(
-               struct bt_field_class *fc, const char *label,
-               uint64_t range_lower, uint64_t range_upper)
-{
-       struct bt_field_class_enumeration *enum_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
-               "Field class");
-       BT_ASSERT_PRE(range_lower <= range_upper,
-               "Range's upper bound is less than lower bound: "
-               "upper=%" PRIu64 ", lower=%" PRIu64,
-               range_lower, range_upper);
-       BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(enum_fc->common.range,
-               range_lower),
-               "Range's lower bound is outside the enumeration field class's value range: "
-               "%![fc-]+F, lower=%" PRIu64, fc, range_lower);
-       BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(enum_fc->common.range,
-               range_upper),
-               "Range's upper bound is outside the enumeration field class's value range: "
-               "%![fc-]+F, upper=%" PRIu64, fc, range_upper);
-       return add_mapping_to_enumeration_field_class(fc, label, range_lower,
-               range_upper);
-}
-
-enum bt_field_class_status bt_field_class_signed_enumeration_map_range(
-               struct bt_field_class *fc, const char *label,
-               int64_t range_lower, int64_t range_upper)
-{
-       struct bt_field_class_enumeration *enum_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
-               "Field class");
-       BT_ASSERT_PRE(range_lower <= range_upper,
-               "Range's upper bound is less than lower bound: "
-               "upper=%" PRId64 ", lower=%" PRId64,
-               range_lower, range_upper);
-       BT_ASSERT_PRE(bt_util_value_is_in_range_signed(enum_fc->common.range,
-               range_lower),
-               "Range's lower bound is outside the enumeration field class's value range: "
-               "%![fc-]+F, lower=%" PRId64, fc, range_lower);
-       BT_ASSERT_PRE(bt_util_value_is_in_range_signed(enum_fc->common.range,
-               range_upper),
-               "Range's upper bound is outside the enumeration field class's value range: "
-               "%![fc-]+F, upper=%" PRId64, fc, range_upper);
-       return add_mapping_to_enumeration_field_class(fc, label, range_lower,
-               range_upper);
-}
-
-static
-void destroy_real_field_class(struct bt_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_LIB_LOGD("Destroying real field class object: %!+F", obj);
-       g_free(obj);
-}
-
-struct bt_field_class *bt_field_class_real_create(bt_trace_class *trace_class)
-{
-       struct bt_field_class_real *real_fc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
-       BT_LOGD_STR("Creating default real field class object.");
-       real_fc = g_new0(struct bt_field_class_real, 1);
-       if (!real_fc) {
-               BT_LOGE_STR("Failed to allocate one real field class.");
-               goto error;
-       }
-
-       init_field_class((void *) real_fc, BT_FIELD_CLASS_TYPE_REAL,
-               destroy_real_field_class);
-       BT_LIB_LOGD("Created real field class object: %!+F", real_fc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(real_fc);
-
-end:
-       return (void *) real_fc;
-}
-
-bt_bool bt_field_class_real_is_single_precision(const struct bt_field_class *fc)
-{
-       const struct bt_field_class_real *real_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_REAL, "Field class");
-       return real_fc->is_single_precision;
-}
-
-void bt_field_class_real_set_is_single_precision(struct bt_field_class *fc,
-               bt_bool is_single_precision)
-{
-       struct bt_field_class_real *real_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_REAL, "Field class");
-       BT_ASSERT_PRE_FC_HOT(fc, "Field class");
-       real_fc->is_single_precision = (bool) is_single_precision;
-       BT_LIB_LOGV("Set real field class's \"is single precision\" property: "
-               "%!+F", fc);
-}
-
-static
-int init_named_field_classes_container(
-               struct bt_field_class_named_field_class_container *fc,
-               enum bt_field_class_type type,
-               bt_object_release_func release_func)
-{
-       int ret = 0;
-
-       init_field_class((void *) fc, type, release_func);
-       fc->named_fcs = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_named_field_class));
-       if (!fc->named_fcs) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               ret = -1;
-               goto end;
-       }
-
-       fc->name_to_index = g_hash_table_new(g_str_hash, g_str_equal);
-       if (!fc->name_to_index) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-void finalize_named_field_class(struct bt_named_field_class *named_fc)
-{
-       BT_ASSERT(named_fc);
-       BT_LIB_LOGD("Finalizing named field class: "
-               "addr=%p, name=\"%s\", %![fc-]+F",
-               named_fc, named_fc->name ? named_fc->name->str : NULL,
-               named_fc->fc);
-
-       if (named_fc->name) {
-               g_string_free(named_fc->name, TRUE);
-       }
-
-       BT_LOGD_STR("Putting named field class's field class.");
-       BT_OBJECT_PUT_REF_AND_RESET(named_fc->fc);
-}
-
-static
-void finalize_named_field_classes_container(
-               struct bt_field_class_named_field_class_container *fc)
-{
-       uint64_t i;
-
-       BT_ASSERT(fc);
-
-       if (fc->named_fcs) {
-               for (i = 0; i < fc->named_fcs->len; i++) {
-                       finalize_named_field_class(
-                               &g_array_index(fc->named_fcs,
-                                       struct bt_named_field_class, i));
-               }
-
-               g_array_free(fc->named_fcs, TRUE);
-       }
-
-       if (fc->name_to_index) {
-               g_hash_table_destroy(fc->name_to_index);
-       }
-}
-
-static
-void destroy_structure_field_class(struct bt_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_LIB_LOGD("Destroying structure field class object: %!+F", obj);
-       finalize_named_field_classes_container((void *) obj);
-       g_free(obj);
-}
-
-struct bt_field_class *bt_field_class_structure_create(
-               bt_trace_class *trace_class)
-{
-       int ret;
-       struct bt_field_class_structure *struct_fc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
-       BT_LOGD_STR("Creating default structure field class object.");
-       struct_fc = g_new0(struct bt_field_class_structure, 1);
-       if (!struct_fc) {
-               BT_LOGE_STR("Failed to allocate one structure field class.");
-               goto error;
-       }
-
-       ret = init_named_field_classes_container((void *) struct_fc,
-               BT_FIELD_CLASS_TYPE_STRUCTURE, destroy_structure_field_class);
-       if (ret) {
-               goto error;
-       }
-
-       BT_LIB_LOGD("Created structure field class object: %!+F", struct_fc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(struct_fc);
-
-end:
-       return (void *) struct_fc;
-}
-
-static
-enum bt_field_class_status append_named_field_class_to_container_field_class(
-               struct bt_field_class_named_field_class_container *container_fc,
-               const char *name, struct bt_field_class *fc)
-{
-       int ret = BT_FIELD_CLASS_STATUS_OK;
-       struct bt_named_field_class *named_fc;
-       GString *name_str;
-
-       BT_ASSERT(container_fc);
-       BT_ASSERT_PRE_FC_HOT(container_fc, "Field class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE(!bt_g_hash_table_contains(container_fc->name_to_index,
-               name),
-               "Duplicate member/option name in structure/variant field class: "
-               "%![container-fc-]+F, name=\"%s\"", container_fc, name);
-       name_str = g_string_new(name);
-       if (!name_str) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               ret = BT_FIELD_CLASS_STATUS_NOMEM;
-               goto end;
-       }
-
-       g_array_set_size(container_fc->named_fcs,
-               container_fc->named_fcs->len + 1);
-       named_fc = &g_array_index(container_fc->named_fcs,
-               struct bt_named_field_class, container_fc->named_fcs->len - 1);
-       named_fc->name = name_str;
-       named_fc->fc = fc;
-       bt_object_get_no_null_check(fc);
-       g_hash_table_insert(container_fc->name_to_index, named_fc->name->str,
-               GUINT_TO_POINTER(container_fc->named_fcs->len - 1));
-
-       /*
-        * Freeze the field class, but not the named field class (the
-        * user can still modify it, if possible, until the container
-        * itself is frozen).
-        */
-       bt_field_class_freeze(fc);
-
-end:
-       return ret;
-}
-
-enum bt_field_class_status bt_field_class_structure_append_member(
-               struct bt_field_class *fc, const char *name,
-               struct bt_field_class *member_fc)
-{
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Field class");
-       return append_named_field_class_to_container_field_class((void *) fc,
-               name, member_fc);
-}
-
-uint64_t bt_field_class_structure_get_member_count(
-               const struct bt_field_class *fc)
-{
-       struct bt_field_class_structure *struct_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Field class");
-       return (uint64_t) struct_fc->common.named_fcs->len;
-}
-
-static
-struct bt_named_field_class *
-borrow_named_field_class_from_container_field_class_at_index(
-               struct bt_field_class_named_field_class_container *fc,
-               uint64_t index)
-{
-       BT_ASSERT(fc);
-       BT_ASSERT_PRE_VALID_INDEX(index, fc->named_fcs->len);
-       return BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc, index);
-}
-
-const struct bt_field_class_structure_member *
-bt_field_class_structure_borrow_member_by_index_const(
-               const struct bt_field_class *fc, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Field class");
-       return (const void *)
-               borrow_named_field_class_from_container_field_class_at_index(
-                       (void *) fc, index);
-}
-
-struct bt_field_class_structure_member *
-bt_field_class_structure_borrow_member_by_index(
-               struct bt_field_class *fc, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Field class");
-       return (void *)
-               borrow_named_field_class_from_container_field_class_at_index(
-                       (void *) fc, index);
-}
-
-static
-struct bt_named_field_class *
-borrow_named_field_class_from_container_field_class_by_name(
-               struct bt_field_class_named_field_class_container *fc,
-               const char *name)
-{
-       struct bt_named_field_class *named_fc = NULL;
-       gpointer orig_key;
-       gpointer value;
-
-       BT_ASSERT(fc);
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       if (!g_hash_table_lookup_extended(fc->name_to_index, name, &orig_key,
-                       &value)) {
-               goto end;
-       }
-
-       named_fc = BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc,
-               GPOINTER_TO_UINT(value));
-
-end:
-       return named_fc;
-}
-
-const struct bt_field_class_structure_member *
-bt_field_class_structure_borrow_member_by_name_const(
-               const struct bt_field_class *fc, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Field class");
-       return (const void *)
-               borrow_named_field_class_from_container_field_class_by_name(
-                       (void *) fc, name);
-}
-
-struct bt_field_class_structure_member *
-bt_field_class_structure_borrow_member_by_name(
-               struct bt_field_class *fc, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Field class");
-       return (void *)
-               borrow_named_field_class_from_container_field_class_by_name(
-                       (void *) fc, name);
-}
-
-const char *bt_field_class_structure_member_get_name(
-               const struct bt_field_class_structure_member *member)
-{
-       const struct bt_named_field_class *named_fc = (const void *) member;
-
-       BT_ASSERT_PRE_NON_NULL(member, "Structure field class member");
-       return named_fc->name->str;
-}
-
-const struct bt_field_class *
-bt_field_class_structure_member_borrow_field_class_const(
-               const struct bt_field_class_structure_member *member)
-{
-       const struct bt_named_field_class *named_fc = (const void *) member;
-
-       BT_ASSERT_PRE_NON_NULL(member, "Structure field class member");
-       return named_fc->fc;
-}
-
-struct bt_field_class *
-bt_field_class_structure_member_borrow_field_class(
-               struct bt_field_class_structure_member *member)
-{
-       struct bt_named_field_class *named_fc = (void *) member;
-
-       BT_ASSERT_PRE_NON_NULL(member, "Structure field class member");
-       return named_fc->fc;
-}
-
-static
-void destroy_variant_field_class(struct bt_object *obj)
-{
-       struct bt_field_class_variant *fc = (void *) obj;
-
-       BT_ASSERT(fc);
-       BT_LIB_LOGD("Destroying variant field class object: %!+F", fc);
-       finalize_named_field_classes_container((void *) fc);
-       BT_LOGD_STR("Putting selector field path.");
-       BT_OBJECT_PUT_REF_AND_RESET(fc->selector_field_path);
-       BT_LOGD_STR("Putting selector field class.");
-       BT_OBJECT_PUT_REF_AND_RESET(fc->selector_fc);
-       g_free(fc);
-}
-
-struct bt_field_class *bt_field_class_variant_create(
-               bt_trace_class *trace_class)
-{
-       int ret;
-       struct bt_field_class_variant *var_fc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
-       BT_LOGD_STR("Creating default variant field class object.");
-       var_fc = g_new0(struct bt_field_class_variant, 1);
-       if (!var_fc) {
-               BT_LOGE_STR("Failed to allocate one variant field class.");
-               goto error;
-       }
-
-       ret = init_named_field_classes_container((void *) var_fc,
-               BT_FIELD_CLASS_TYPE_VARIANT, destroy_variant_field_class);
-       if (ret) {
-               goto error;
-       }
-
-       BT_LIB_LOGD("Created variant field class object: %!+F", var_fc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(var_fc);
-
-end:
-       return (void *) var_fc;
-}
-
-enum bt_field_class_status bt_field_class_variant_set_selector_field_class(
-               struct bt_field_class *fc,
-               struct bt_field_class *selector_fc)
-{
-       struct bt_field_class_variant *var_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Variant field class");
-       BT_ASSERT_PRE_NON_NULL(selector_fc, "Selector field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
-       BT_ASSERT_PRE_FC_IS_ENUM(selector_fc, "Selector field class");
-       BT_ASSERT_PRE_FC_HOT(fc, "Variant field class");
-       var_fc->selector_fc = selector_fc;
-       bt_object_get_no_null_check(selector_fc);
-       bt_field_class_freeze(selector_fc);
-       return BT_FIELD_CLASS_STATUS_OK;
-}
-
-enum bt_field_class_status bt_field_class_variant_append_option(
-               struct bt_field_class *fc,
-               const char *name, struct bt_field_class *option_fc)
-{
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
-       return append_named_field_class_to_container_field_class((void *) fc,
-               name, option_fc);
-}
-
-const struct bt_field_class_variant_option *
-bt_field_class_variant_borrow_option_by_name_const(
-               const struct bt_field_class *fc, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
-       return (const void *)
-               borrow_named_field_class_from_container_field_class_by_name(
-                       (void *) fc, name);
-}
-
-struct bt_field_class_variant_option *
-bt_field_class_variant_borrow_option_by_name(
-               struct bt_field_class *fc, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
-       return (void *)
-               borrow_named_field_class_from_container_field_class_by_name(
-                       (void *) fc, name);
-}
-
-uint64_t bt_field_class_variant_get_option_count(const struct bt_field_class *fc)
-{
-       const struct bt_field_class_variant *var_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
-       return (uint64_t) var_fc->common.named_fcs->len;
-}
-
-const struct bt_field_class_variant_option *
-bt_field_class_variant_borrow_option_by_index_const(
-               const struct bt_field_class *fc, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
-       return (const void *)
-               borrow_named_field_class_from_container_field_class_at_index(
-                       (void *) fc, index);
-}
-
-struct bt_field_class_variant_option *
-bt_field_class_variant_borrow_option_by_index(
-               struct bt_field_class *fc, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
-       return (void *)
-               borrow_named_field_class_from_container_field_class_at_index(
-                       (void *) fc, index);
-}
-
-const char *bt_field_class_variant_option_get_name(
-               const struct bt_field_class_variant_option *option)
-{
-       const struct bt_named_field_class *named_fc = (const void *) option;
-
-       BT_ASSERT_PRE_NON_NULL(option, "Variant field class option");
-       return named_fc->name->str;
-}
-
-const struct bt_field_class *
-bt_field_class_variant_option_borrow_field_class_const(
-               const struct bt_field_class_variant_option *option)
-{
-       const struct bt_named_field_class *named_fc = (const void *) option;
-
-       BT_ASSERT_PRE_NON_NULL(option, "Variant field class option");
-       return named_fc->fc;
-}
-
-struct bt_field_class *
-bt_field_class_variant_option_borrow_field_class(
-               struct bt_field_class_variant_option *option)
-{
-       struct bt_named_field_class *named_fc = (void *) option;
-
-       BT_ASSERT_PRE_NON_NULL(option, "Variant field class option");
-       return named_fc->fc;
-}
-
-const struct bt_field_path *
-bt_field_class_variant_borrow_selector_field_path_const(
-               const struct bt_field_class *fc)
-{
-       const struct bt_field_class_variant *var_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT,
-               "Field class");
-       return var_fc->selector_field_path;
-}
-
-static
-void init_array_field_class(struct bt_field_class_array *fc,
-               enum bt_field_class_type type, bt_object_release_func release_func,
-               struct bt_field_class *element_fc)
-{
-       BT_ASSERT(element_fc);
-       init_field_class((void *) fc, type, release_func);
-       fc->element_fc = element_fc;
-       bt_object_get_no_null_check(element_fc);
-       bt_field_class_freeze(element_fc);
-}
-
-static
-void finalize_array_field_class(struct bt_field_class_array *array_fc)
-{
-       BT_ASSERT(array_fc);
-       BT_LOGD_STR("Putting element field class.");
-       BT_OBJECT_PUT_REF_AND_RESET(array_fc->element_fc);
-}
-
-static
-void destroy_static_array_field_class(struct bt_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_LIB_LOGD("Destroying static array field class object: %!+F", obj);
-       finalize_array_field_class((void *) obj);
-       g_free(obj);
-}
-
-struct bt_field_class *
-bt_field_class_static_array_create(bt_trace_class *trace_class,
-               struct bt_field_class *element_fc, uint64_t length)
-{
-       struct bt_field_class_static_array *array_fc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(element_fc, "Element field class");
-       BT_LOGD_STR("Creating default static array field class object.");
-       array_fc = g_new0(struct bt_field_class_static_array, 1);
-       if (!array_fc) {
-               BT_LOGE_STR("Failed to allocate one static array field class.");
-               goto error;
-       }
-
-       init_array_field_class((void *) array_fc, BT_FIELD_CLASS_TYPE_STATIC_ARRAY,
-               destroy_static_array_field_class, element_fc);
-       array_fc->length = length;
-       BT_LIB_LOGD("Created static array field class object: %!+F", array_fc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(array_fc);
-
-end:
-       return (void *) array_fc;
-}
-
-const struct bt_field_class *
-bt_field_class_array_borrow_element_field_class_const(
-               const struct bt_field_class *fc)
-{
-       const struct bt_field_class_array *array_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_IS_ARRAY(fc, "Field class");
-       return array_fc->element_fc;
-}
-
-struct bt_field_class *
-bt_field_class_array_borrow_element_field_class(struct bt_field_class *fc)
-{
-       struct bt_field_class_array *array_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_IS_ARRAY(fc, "Field class");
-       return array_fc->element_fc;
-}
-
-uint64_t bt_field_class_static_array_get_length(const struct bt_field_class *fc)
-{
-       const struct bt_field_class_static_array *array_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STATIC_ARRAY,
-               "Field class");
-       return (uint64_t) array_fc->length;
-}
-
-static
-void destroy_dynamic_array_field_class(struct bt_object *obj)
-{
-       struct bt_field_class_dynamic_array *fc = (void *) obj;
-
-       BT_ASSERT(fc);
-       BT_LIB_LOGD("Destroying dynamic array field class object: %!+F", fc);
-       finalize_array_field_class((void *) fc);
-       BT_LOGD_STR("Putting length field path.");
-       BT_OBJECT_PUT_REF_AND_RESET(fc->length_field_path);
-       BT_LOGD_STR("Putting length field class.");
-       BT_OBJECT_PUT_REF_AND_RESET(fc->length_fc);
-       g_free(fc);
-}
-
-struct bt_field_class *bt_field_class_dynamic_array_create(
-               bt_trace_class *trace_class,
-               struct bt_field_class *element_fc)
-{
-       struct bt_field_class_dynamic_array *array_fc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(element_fc, "Element field class");
-       BT_LOGD_STR("Creating default dynamic array field class object.");
-       array_fc = g_new0(struct bt_field_class_dynamic_array, 1);
-       if (!array_fc) {
-               BT_LOGE_STR("Failed to allocate one dynamic array field class.");
-               goto error;
-       }
-
-       init_array_field_class((void *) array_fc,
-               BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY,
-               destroy_dynamic_array_field_class, element_fc);
-       BT_LIB_LOGD("Created dynamic array field class object: %!+F", array_fc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(array_fc);
-
-end:
-       return (void *) array_fc;
-}
-
-enum bt_field_class_status bt_field_class_dynamic_array_set_length_field_class(
-               struct bt_field_class *fc,
-               struct bt_field_class *length_fc)
-{
-       struct bt_field_class_dynamic_array *array_fc = (void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Dynamic array field class");
-       BT_ASSERT_PRE_NON_NULL(length_fc, "Length field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY,
-               "Field class");
-       BT_ASSERT_PRE_FC_IS_UNSIGNED_INT(length_fc, "Length field class");
-       BT_ASSERT_PRE_FC_HOT(fc, "Dynamic array field class");
-       array_fc->length_fc = length_fc;
-       bt_object_get_no_null_check(length_fc);
-       bt_field_class_freeze(length_fc);
-       return BT_FIELD_CLASS_STATUS_OK;
-}
-
-const struct bt_field_path *
-bt_field_class_dynamic_array_borrow_length_field_path_const(
-               const struct bt_field_class *fc)
-{
-       const struct bt_field_class_dynamic_array *seq_fc = (const void *) fc;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY,
-               "Field class");
-       return seq_fc->length_field_path;
-}
-
-static
-void destroy_string_field_class(struct bt_object *obj)
-{
-       BT_ASSERT(obj);
-       BT_LIB_LOGD("Destroying string field class object: %!+F", obj);
-       g_free(obj);
-}
-
-struct bt_field_class *bt_field_class_string_create(bt_trace_class *trace_class)
-{
-       struct bt_field_class_string *string_fc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
-       BT_LOGD_STR("Creating default string field class object.");
-       string_fc = g_new0(struct bt_field_class_string, 1);
-       if (!string_fc) {
-               BT_LOGE_STR("Failed to allocate one string field class.");
-               goto error;
-       }
-
-       init_field_class((void *) string_fc, BT_FIELD_CLASS_TYPE_STRING,
-               destroy_string_field_class);
-       BT_LIB_LOGD("Created string field class object: %!+F", string_fc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(string_fc);
-
-end:
-       return (void *) string_fc;
-}
-
-BT_HIDDEN
-void _bt_field_class_freeze(const struct bt_field_class *c_fc)
-{
-       struct bt_field_class *fc = (void *) c_fc;
-
-       /*
-        * Element/member/option field classes are frozen when added to
-        * their owner.
-        */
-       BT_ASSERT(fc);
-       fc->frozen = true;
-
-       switch (fc->type) {
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct bt_field_class_named_field_class_container *container_fc =
-                       (void *) fc;
-               uint64_t i;
-
-               for (i = 0; i < container_fc->named_fcs->len; i++) {
-                       struct bt_named_field_class *named_fc =
-                               BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
-                                       container_fc, i);
-
-                       bt_named_field_class_freeze(named_fc);
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-BT_HIDDEN
-void _bt_named_field_class_freeze(const struct bt_named_field_class *named_fc)
-{
-       BT_ASSERT(named_fc);
-       ((struct bt_named_field_class *) named_fc)->frozen = true;
-       bt_field_class_freeze(named_fc->fc);
-}
-
-BT_HIDDEN
-void _bt_field_class_make_part_of_trace_class(const struct bt_field_class *c_fc)
-{
-       struct bt_field_class *fc = (void *) c_fc;
-
-       BT_ASSERT(fc);
-       BT_ASSERT_PRE(!fc->part_of_trace_class,
-               "Field class is already part of a trace: %!+F", fc);
-       fc->part_of_trace_class = true;
-
-       switch (fc->type) {
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct bt_field_class_named_field_class_container *container_fc =
-                       (void *) fc;
-               uint64_t i;
-
-               for (i = 0; i < container_fc->named_fcs->len; i++) {
-                       struct bt_named_field_class *named_fc =
-                               BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
-                                       container_fc, i);
-
-                       bt_field_class_make_part_of_trace_class(named_fc->fc);
-               }
-
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-       {
-               struct bt_field_class_array *array_fc = (void *) fc;
-
-               bt_field_class_make_part_of_trace_class(array_fc->element_fc);
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-void bt_field_class_get_ref(const struct bt_field_class *field_class)
-{
-       bt_object_get_ref(field_class);
-}
-
-void bt_field_class_put_ref(const struct bt_field_class *field_class)
-{
-       bt_object_put_ref(field_class);
-}
diff --git a/lib/trace-ir/field-path.c b/lib/trace-ir/field-path.c
deleted file mode 100644 (file)
index 23b65a7..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "FIELD-PATH"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/field-class.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/field-path-internal.h>
-#include <babeltrace2/trace-ir/field-path-const.h>
-#include <limits.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-
-static
-void destroy_field_path(struct bt_object *obj)
-{
-       struct bt_field_path *field_path = (struct bt_field_path *) obj;
-
-       BT_ASSERT(field_path);
-       BT_LIB_LOGD("Destroying field path: %!+P", field_path);
-       g_array_free(field_path->items, TRUE);
-       field_path->items = NULL;
-       g_free(field_path);
-}
-
-BT_HIDDEN
-struct bt_field_path *bt_field_path_create(void)
-{
-       struct bt_field_path *field_path = NULL;
-
-       BT_LOGD_STR("Creating empty field path object.");
-
-       field_path = g_new0(struct bt_field_path, 1);
-       if (!field_path) {
-               BT_LOGE_STR("Failed to allocate one field path.");
-               goto error;
-       }
-
-       bt_object_init_shared(&field_path->base, destroy_field_path);
-       field_path->items = g_array_new(FALSE, FALSE,
-               sizeof(struct bt_field_path_item));
-       if (!field_path->items) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               goto error;
-       }
-
-       BT_LIB_LOGD("Created empty field path object: %!+P", field_path);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(field_path);
-
-end:
-       return field_path;
-}
-
-enum bt_scope bt_field_path_get_root_scope(
-               const struct bt_field_path *field_path)
-{
-       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
-       return field_path->root;
-}
-
-uint64_t bt_field_path_get_item_count(const struct bt_field_path *field_path)
-{
-       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
-       return (uint64_t) field_path->items->len;
-}
-
-const struct bt_field_path_item *bt_field_path_borrow_item_by_index_const(
-               const struct bt_field_path *field_path, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
-       BT_ASSERT_PRE_VALID_INDEX(index, field_path->items->len);
-       return bt_field_path_borrow_item_by_index_inline(field_path, index);
-}
-
-enum bt_field_path_item_type bt_field_path_item_get_type(
-               const struct bt_field_path_item *field_path_item)
-{
-       BT_ASSERT_PRE_NON_NULL(field_path_item, "Field path item");
-       return field_path_item->type;
-}
-
-uint64_t bt_field_path_item_index_get_index(
-               const struct bt_field_path_item *field_path_item)
-{
-       BT_ASSERT_PRE_NON_NULL(field_path_item, "Field path item");
-       BT_ASSERT_PRE(field_path_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX,
-               "Field path item is not an index field path item: "
-               "addr=%p, type=%s", field_path_item,
-               bt_field_path_item_type_string(field_path_item->type));
-       return  field_path_item->index;
-}
-
-void bt_field_path_get_ref(const struct bt_field_path *field_path)
-{
-       bt_object_get_ref(field_path);
-}
-
-void bt_field_path_put_ref(const struct bt_field_path *field_path)
-{
-       bt_object_put_ref(field_path);
-}
diff --git a/lib/trace-ir/field-wrapper.c b/lib/trace-ir/field-wrapper.c
deleted file mode 100644 (file)
index 8d0fdc7..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "FIELD-WRAPPER"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/trace-ir/field-wrapper-internal.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/object-pool-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <glib.h>
-
-BT_HIDDEN
-struct bt_field_wrapper *bt_field_wrapper_new(void *data)
-{
-       struct bt_field_wrapper *field_wrapper =
-               g_new0(struct bt_field_wrapper, 1);
-
-       BT_LOGD_STR("Creating empty field wrapper object.");
-
-       if (!field_wrapper) {
-               BT_LOGE("Failed to allocate one field wrapper.");
-               goto end;
-       }
-
-       bt_object_init_unique(&field_wrapper->base);
-       BT_LOGD("Created empty field wrapper object: addr=%p",
-               field_wrapper);
-
-end:
-       return field_wrapper;
-}
-
-BT_HIDDEN
-void bt_field_wrapper_destroy(struct bt_field_wrapper *field_wrapper)
-{
-       BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper);
-
-       if (field_wrapper->field) {
-               BT_LOGD_STR("Destroying field.");
-               bt_field_destroy((void *) field_wrapper->field);
-               field_wrapper->field = NULL;
-       }
-
-       BT_LOGD_STR("Putting stream class.");
-       g_free(field_wrapper);
-}
-
-BT_HIDDEN
-struct bt_field_wrapper *bt_field_wrapper_create(
-               struct bt_object_pool *pool, struct bt_field_class *fc)
-{
-       struct bt_field_wrapper *field_wrapper = NULL;
-
-       BT_ASSERT(pool);
-       BT_ASSERT(fc);
-       field_wrapper = bt_object_pool_create_object(pool);
-       if (!field_wrapper) {
-               BT_LIB_LOGE("Cannot allocate one field wrapper from field wrapper pool: "
-                       "%![pool-]+o", pool);
-               goto error;
-       }
-
-       if (!field_wrapper->field) {
-               field_wrapper->field = (void *) bt_field_create(fc);
-               if (!field_wrapper->field) {
-                       BT_LIB_LOGE("Cannot create field wrapper from field class: "
-                               "%![fc-]+F", fc);
-                       goto error;
-               }
-
-               BT_LIB_LOGD("Created initial field wrapper object: "
-                       "wrapper-addr=%p, %![field-]+f", field_wrapper,
-                       field_wrapper->field);
-       }
-
-       goto end;
-
-error:
-       if (field_wrapper) {
-               bt_field_wrapper_destroy(field_wrapper);
-               field_wrapper = NULL;
-       }
-
-end:
-       return field_wrapper;
-}
diff --git a/lib/trace-ir/field.c b/lib/trace-ir/field.c
deleted file mode 100644 (file)
index 4cf1542..0000000
+++ /dev/null
@@ -1,1179 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "FIELDS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/field.h>
-#include <babeltrace2/trace-ir/field-const.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/compat/fcntl-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <inttypes.h>
-
-static
-void reset_single_field(struct bt_field *field);
-
-static
-void reset_array_field(struct bt_field *field);
-
-static
-void reset_structure_field(struct bt_field *field);
-
-static
-void reset_variant_field(struct bt_field *field);
-
-static
-void set_single_field_is_frozen(struct bt_field *field, bool is_frozen);
-
-static
-void set_array_field_is_frozen(struct bt_field *field, bool is_frozen);
-
-static
-void set_structure_field_is_frozen(struct bt_field *field, bool is_frozen);
-
-static
-void set_variant_field_is_frozen(struct bt_field *field, bool is_frozen);
-
-static
-bool single_field_is_set(const struct bt_field *field);
-
-static
-bool array_field_is_set(const struct bt_field *field);
-
-static
-bool structure_field_is_set(const struct bt_field *field);
-
-static
-bool variant_field_is_set(const struct bt_field *field);
-
-static
-struct bt_field_methods integer_field_methods = {
-       .set_is_frozen = set_single_field_is_frozen,
-       .is_set = single_field_is_set,
-       .reset = reset_single_field,
-};
-
-static
-struct bt_field_methods real_field_methods = {
-       .set_is_frozen = set_single_field_is_frozen,
-       .is_set = single_field_is_set,
-       .reset = reset_single_field,
-};
-
-static
-struct bt_field_methods string_field_methods = {
-       .set_is_frozen = set_single_field_is_frozen,
-       .is_set = single_field_is_set,
-       .reset = reset_single_field,
-};
-
-static
-struct bt_field_methods structure_field_methods = {
-       .set_is_frozen = set_structure_field_is_frozen,
-       .is_set = structure_field_is_set,
-       .reset = reset_structure_field,
-};
-
-static
-struct bt_field_methods array_field_methods = {
-       .set_is_frozen = set_array_field_is_frozen,
-       .is_set = array_field_is_set,
-       .reset = reset_array_field,
-};
-
-static
-struct bt_field_methods variant_field_methods = {
-       .set_is_frozen = set_variant_field_is_frozen,
-       .is_set = variant_field_is_set,
-       .reset = reset_variant_field,
-};
-
-static
-struct bt_field *create_integer_field(struct bt_field_class *);
-
-static
-struct bt_field *create_real_field(struct bt_field_class *);
-
-static
-struct bt_field *create_string_field(struct bt_field_class *);
-
-static
-struct bt_field *create_structure_field(struct bt_field_class *);
-
-static
-struct bt_field *create_static_array_field(struct bt_field_class *);
-
-static
-struct bt_field *create_dynamic_array_field(struct bt_field_class *);
-
-static
-struct bt_field *create_variant_field(struct bt_field_class *);
-
-static
-struct bt_field *(* const field_create_funcs[])(struct bt_field_class *) = {
-       [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER]  = create_integer_field,
-       [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER]    = create_integer_field,
-       [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = create_integer_field,
-       [BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION]        = create_integer_field,
-       [BT_FIELD_CLASS_TYPE_REAL]                      = create_real_field,
-       [BT_FIELD_CLASS_TYPE_STRING]            = create_string_field,
-       [BT_FIELD_CLASS_TYPE_STRUCTURE]         = create_structure_field,
-       [BT_FIELD_CLASS_TYPE_STATIC_ARRAY]              = create_static_array_field,
-       [BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY]     = create_dynamic_array_field,
-       [BT_FIELD_CLASS_TYPE_VARIANT]           = create_variant_field,
-};
-
-static
-void destroy_integer_field(struct bt_field *field);
-
-static
-void destroy_real_field(struct bt_field *field);
-
-static
-void destroy_string_field(struct bt_field *field);
-
-static
-void destroy_structure_field(struct bt_field *field);
-
-static
-void destroy_array_field(struct bt_field *field);
-
-static
-void destroy_variant_field(struct bt_field *field);
-
-static
-void (* const field_destroy_funcs[])(struct bt_field *) = {
-       [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER]  = destroy_integer_field,
-       [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER]    = destroy_integer_field,
-       [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = destroy_integer_field,
-       [BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION]        = destroy_integer_field,
-       [BT_FIELD_CLASS_TYPE_REAL]                      = destroy_real_field,
-       [BT_FIELD_CLASS_TYPE_STRING]            = destroy_string_field,
-       [BT_FIELD_CLASS_TYPE_STRUCTURE]         = destroy_structure_field,
-       [BT_FIELD_CLASS_TYPE_STATIC_ARRAY]              = destroy_array_field,
-       [BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY]     = destroy_array_field,
-       [BT_FIELD_CLASS_TYPE_VARIANT]           = destroy_variant_field,
-};
-
-struct bt_field_class *bt_field_borrow_class(const struct bt_field *field)
-{
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       return field->class;
-}
-
-const struct bt_field_class *bt_field_borrow_class_const(
-               const struct bt_field *field)
-{
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       return field->class;
-}
-
-enum bt_field_class_type bt_field_get_class_type(const struct bt_field *field)
-{
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       return field->class->type;
-}
-
-BT_HIDDEN
-struct bt_field *bt_field_create(struct bt_field_class *fc)
-{
-       struct bt_field *field = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
-       BT_ASSERT(bt_field_class_has_known_type(fc));
-       field = field_create_funcs[fc->type](fc);
-       if (!field) {
-               BT_LIB_LOGE("Cannot create field object from field class: "
-                       "%![fc-]+F", fc);
-               goto end;
-       }
-
-end:
-       return field;
-}
-
-static inline
-void init_field(struct bt_field *field, struct bt_field_class *fc,
-               struct bt_field_methods *methods)
-{
-       BT_ASSERT(field);
-       BT_ASSERT(fc);
-       bt_object_init_unique(&field->base);
-       field->methods = methods;
-       field->class = fc;
-       bt_object_get_no_null_check(fc);
-}
-
-static
-struct bt_field *create_integer_field(struct bt_field_class *fc)
-{
-       struct bt_field_integer *int_field;
-
-       BT_LIB_LOGD("Creating integer field object: %![fc-]+F", fc);
-       int_field = g_new0(struct bt_field_integer, 1);
-       if (!int_field) {
-               BT_LOGE_STR("Failed to allocate one integer field.");
-               goto end;
-       }
-
-       init_field((void *) int_field, fc, &integer_field_methods);
-       BT_LIB_LOGD("Created integer field object: %!+f", int_field);
-
-end:
-       return (void *) int_field;
-}
-
-static
-struct bt_field *create_real_field(struct bt_field_class *fc)
-{
-       struct bt_field_real *real_field;
-
-       BT_LIB_LOGD("Creating real field object: %![fc-]+F", fc);
-       real_field = g_new0(struct bt_field_real, 1);
-       if (!real_field) {
-               BT_LOGE_STR("Failed to allocate one real field.");
-               goto end;
-       }
-
-       init_field((void *) real_field, fc, &real_field_methods);
-       BT_LIB_LOGD("Created real field object: %!+f", real_field);
-
-end:
-       return (void *) real_field;
-}
-
-static
-struct bt_field *create_string_field(struct bt_field_class *fc)
-{
-       struct bt_field_string *string_field;
-
-       BT_LIB_LOGD("Creating string field object: %![fc-]+F", fc);
-       string_field = g_new0(struct bt_field_string, 1);
-       if (!string_field) {
-               BT_LOGE_STR("Failed to allocate one string field.");
-               goto end;
-       }
-
-       init_field((void *) string_field, fc, &string_field_methods);
-       string_field->buf = g_array_sized_new(FALSE, FALSE,
-               sizeof(char), 1);
-       if (!string_field->buf) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               BT_OBJECT_PUT_REF_AND_RESET(string_field);
-               goto end;
-       }
-
-       g_array_index(string_field->buf, char, 0) = '\0';
-       BT_LIB_LOGD("Created string field object: %!+f", string_field);
-
-end:
-       return (void *) string_field;
-}
-
-static inline
-int create_fields_from_named_field_classes(
-               struct bt_field_class_named_field_class_container *fc,
-               GPtrArray **fields)
-{
-       int ret = 0;
-       uint64_t i;
-
-       *fields = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_field_destroy);
-       if (!*fields) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_set_size(*fields, fc->named_fcs->len);
-
-       for (i = 0; i < fc->named_fcs->len; i++) {
-               struct bt_field *field;
-               struct bt_named_field_class *named_fc =
-                       BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc, i);
-
-               field = bt_field_create(named_fc->fc);
-               if (!field) {
-                       BT_LIB_LOGE("Failed to create structure member or variant option field: "
-                               "name=\"%s\", %![fc-]+F",
-                               named_fc->name->str, named_fc->fc);
-                       ret = -1;
-                       goto end;
-               }
-
-               g_ptr_array_index(*fields, i) = field;
-       }
-
-end:
-       return ret;
-}
-
-static
-struct bt_field *create_structure_field(struct bt_field_class *fc)
-{
-       struct bt_field_structure *struct_field;
-
-       BT_LIB_LOGD("Creating structure field object: %![fc-]+F", fc);
-       struct_field = g_new0(struct bt_field_structure, 1);
-       if (!struct_field) {
-               BT_LOGE_STR("Failed to allocate one structure field.");
-               goto end;
-       }
-
-       init_field((void *) struct_field, fc, &structure_field_methods);
-
-       if (create_fields_from_named_field_classes((void *) fc,
-                       &struct_field->fields)) {
-               BT_LIB_LOGE("Cannot create structure member fields: "
-                       "%![fc-]+F", fc);
-               BT_OBJECT_PUT_REF_AND_RESET(struct_field);
-               goto end;
-       }
-
-       BT_LIB_LOGD("Created structure field object: %!+f", struct_field);
-
-end:
-       return (void *) struct_field;
-}
-
-static
-struct bt_field *create_variant_field(struct bt_field_class *fc)
-{
-       struct bt_field_variant *var_field;
-
-       BT_LIB_LOGD("Creating variant field object: %![fc-]+F", fc);
-       var_field = g_new0(struct bt_field_variant, 1);
-       if (!var_field) {
-               BT_LOGE_STR("Failed to allocate one variant field.");
-               goto end;
-       }
-
-       init_field((void *) var_field, fc, &variant_field_methods);
-
-       if (create_fields_from_named_field_classes((void *) fc,
-                       &var_field->fields)) {
-               BT_LIB_LOGE("Cannot create variant member fields: "
-                       "%![fc-]+F", fc);
-               BT_OBJECT_PUT_REF_AND_RESET(var_field);
-               goto end;
-       }
-
-       BT_LIB_LOGD("Created variant field object: %!+f", var_field);
-
-end:
-       return (void *) var_field;
-}
-
-static inline
-int init_array_field_fields(struct bt_field_array *array_field)
-{
-       int ret = 0;
-       uint64_t i;
-       struct bt_field_class_array *array_fc;
-
-       BT_ASSERT(array_field);
-       array_fc = (void *) array_field->common.class;
-       array_field->fields = g_ptr_array_sized_new(array_field->length);
-       if (!array_field->fields) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               ret = -1;
-               goto end;
-       }
-
-       g_ptr_array_set_free_func(array_field->fields,
-               (GDestroyNotify) bt_field_destroy);
-       g_ptr_array_set_size(array_field->fields, array_field->length);
-
-       for (i = 0; i < array_field->length; i++) {
-               array_field->fields->pdata[i] = bt_field_create(
-                       array_fc->element_fc);
-               if (!array_field->fields->pdata[i]) {
-                       BT_LIB_LOGE("Cannot create array field's element field: "
-                               "index=%" PRIu64 ", %![fc-]+F", i, array_fc);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-struct bt_field *create_static_array_field(struct bt_field_class *fc)
-{
-       struct bt_field_class_static_array *array_fc = (void *) fc;
-       struct bt_field_array *array_field;
-
-       BT_LIB_LOGD("Creating static array field object: %![fc-]+F", fc);
-       array_field = g_new0(struct bt_field_array, 1);
-       if (!array_field) {
-               BT_LOGE_STR("Failed to allocate one static array field.");
-               goto end;
-       }
-
-       init_field((void *) array_field, fc, &array_field_methods);
-       array_field->length = array_fc->length;
-
-       if (init_array_field_fields(array_field)) {
-               BT_LIB_LOGE("Cannot create static array fields: "
-                       "%![fc-]+F", fc);
-               BT_OBJECT_PUT_REF_AND_RESET(array_field);
-               goto end;
-       }
-
-       BT_LIB_LOGD("Created static array field object: %!+f", array_field);
-
-end:
-       return (void *) array_field;
-}
-
-static
-struct bt_field *create_dynamic_array_field(struct bt_field_class *fc)
-{
-       struct bt_field_array *array_field;
-
-       BT_LIB_LOGD("Creating dynamic array field object: %![fc-]+F", fc);
-       array_field = g_new0(struct bt_field_array, 1);
-       if (!array_field) {
-               BT_LOGE_STR("Failed to allocate one dynamic array field.");
-               goto end;
-       }
-
-       init_field((void *) array_field, fc, &array_field_methods);
-
-       if (init_array_field_fields(array_field)) {
-               BT_LIB_LOGE("Cannot create dynamic array fields: "
-                       "%![fc-]+F", fc);
-               BT_OBJECT_PUT_REF_AND_RESET(array_field);
-               goto end;
-       }
-
-       BT_LIB_LOGD("Created dynamic array field object: %!+f", array_field);
-
-end:
-       return (void *) array_field;
-}
-
-int64_t bt_field_signed_integer_get_value(const struct bt_field *field)
-{
-       const struct bt_field_integer *int_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(field, "Field");
-       return int_field->value.i;
-}
-
-void bt_field_signed_integer_set_value(struct bt_field *field, int64_t value)
-{
-       struct bt_field_integer *int_field = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(field, "Field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
-       BT_ASSERT_PRE(bt_util_value_is_in_range_signed(
-               ((struct bt_field_class_integer *) field->class)->range, value),
-               "Value is out of bounds: value=%" PRId64 ", %![field-]+f, "
-               "%![fc-]+F", value, field, field->class);
-       int_field->value.i = value;
-       bt_field_set_single(field, true);
-}
-
-uint64_t bt_field_unsigned_integer_get_value(const struct bt_field *field)
-{
-       const struct bt_field_integer *int_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(field, "Field");
-       return int_field->value.u;
-}
-
-void bt_field_unsigned_integer_set_value(struct bt_field *field, uint64_t value)
-{
-       struct bt_field_integer *int_field = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(field, "Field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
-       BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(
-               ((struct bt_field_class_integer *) field->class)->range, value),
-               "Value is out of bounds: value=%" PRIu64 ", %![field-]+f, "
-               "%![fc-]+F", value, field, field->class);
-       int_field->value.u = value;
-       bt_field_set_single(field, true);
-}
-
-double bt_field_real_get_value(const struct bt_field *field)
-{
-       const struct bt_field_real *real_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_REAL, "Field");
-       return real_field->value;
-}
-
-void bt_field_real_set_value(struct bt_field *field, double value)
-{
-       struct bt_field_real *real_field = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_REAL, "Field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
-       BT_ASSERT_PRE(
-               !((struct bt_field_class_real *) field->class)->is_single_precision ||
-               (double) (float) value == value,
-               "Invalid value for a single-precision real number: value=%f, "
-               "%![fc-]+F", value, field->class);
-       real_field->value = value;
-       bt_field_set_single(field, true);
-}
-
-enum bt_field_status bt_field_unsigned_enumeration_get_mapping_labels(
-               const struct bt_field *field,
-               bt_field_class_enumeration_mapping_label_array *label_array,
-               uint64_t *count)
-{
-       const struct bt_field_integer *int_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
-       BT_ASSERT_PRE_NON_NULL(label_array, "Count (output)");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, "Field");
-       return (int)
-               bt_field_class_unsigned_enumeration_get_mapping_labels_by_value(
-                       field->class, int_field->value.u, label_array, count);
-}
-
-enum bt_field_status bt_field_signed_enumeration_get_mapping_labels(
-               const struct bt_field *field,
-               bt_field_class_enumeration_mapping_label_array *label_array,
-               uint64_t *count)
-{
-       const struct bt_field_integer *int_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
-       BT_ASSERT_PRE_NON_NULL(label_array, "Count (output)");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, "Field");
-       return (int)
-               bt_field_class_signed_enumeration_get_mapping_labels_by_value(
-                       field->class, int_field->value.i, label_array, count);
-}
-
-const char *bt_field_string_get_value(const struct bt_field *field)
-{
-       const struct bt_field_string *string_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_STRING,
-               "Field");
-       return (const char *) string_field->buf->data;
-}
-
-uint64_t bt_field_string_get_length(const struct bt_field *field)
-{
-       const struct bt_field_string *string_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_STRING,
-               "Field");
-       return string_field->length;
-}
-
-static inline
-void clear_string_field(struct bt_field *field)
-{
-       struct bt_field_string *string_field = (void *) field;
-
-       BT_ASSERT(field);
-       string_field->length = 0;
-       bt_field_set_single(field, true);
-}
-
-enum bt_field_status bt_field_string_set_value(struct bt_field *field,
-               const char *value)
-{
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_STRING,
-               "Field");
-       clear_string_field(field);
-       return bt_field_string_append_with_length(field, value,
-               (uint64_t) strlen(value));
-}
-
-enum bt_field_status bt_field_string_append(struct bt_field *field, const char *value)
-{
-       return bt_field_string_append_with_length(field,
-               value, (uint64_t) strlen(value));
-}
-
-enum bt_field_status bt_field_string_append_with_length(struct bt_field *field,
-               const char *value, uint64_t length)
-{
-       struct bt_field_string *string_field = (void *) field;
-       char *data;
-       uint64_t new_length;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_STRING, "Field");
-
-       /* Make sure no null bytes are appended */
-       BT_ASSERT_PRE(memchr(value, '\0', length) == NULL,
-               "String value to append contains a null character: "
-               "partial-value=\"%.32s\", length=%" PRIu64, value, length);
-
-       new_length = length + string_field->length;
-
-       if (unlikely(new_length + 1 > string_field->buf->len)) {
-               g_array_set_size(string_field->buf, new_length + 1);
-       }
-
-       data = string_field->buf->data;
-       memcpy(data + string_field->length, value, length);
-       ((char *) string_field->buf->data)[new_length] = '\0';
-       string_field->length = new_length;
-       bt_field_set_single(field, true);
-       return BT_FIELD_STATUS_OK;
-}
-
-enum bt_field_status bt_field_string_clear(struct bt_field *field)
-{
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_STRING, "Field");
-       clear_string_field(field);
-       return BT_FIELD_STATUS_OK;
-}
-
-uint64_t bt_field_array_get_length(const struct bt_field *field)
-{
-       const struct bt_field_array *array_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_ARRAY(field, "Field");
-       return array_field->length;
-}
-
-enum bt_field_status bt_field_dynamic_array_set_length(struct bt_field *field,
-               uint64_t length)
-{
-       int ret = BT_FIELD_STATUS_OK;
-       struct bt_field_array *array_field = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, "Field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
-
-       if (unlikely(length > array_field->fields->len)) {
-               /* Make more room */
-               struct bt_field_class_array *array_fc;
-               uint64_t cur_len = array_field->fields->len;
-               uint64_t i;
-
-               g_ptr_array_set_size(array_field->fields, length);
-               array_fc = (void *) field->class;
-
-               for (i = cur_len; i < array_field->fields->len; i++) {
-                       struct bt_field *elem_field = bt_field_create(
-                               array_fc->element_fc);
-
-                       if (!elem_field) {
-                               BT_LIB_LOGE("Cannot create element field for "
-                                       "dynamic array field: "
-                                       "index=%" PRIu64 ", "
-                                       "%![array-field-]+f", i, field);
-                               ret = BT_FIELD_STATUS_NOMEM;
-                               goto end;
-                       }
-
-                       BT_ASSERT(!array_field->fields->pdata[i]);
-                       array_field->fields->pdata[i] = elem_field;
-               }
-       }
-
-       array_field->length = length;
-
-end:
-       return ret;
-}
-
-static inline
-struct bt_field *borrow_array_field_element_field_by_index(
-               struct bt_field *field, uint64_t index)
-{
-       struct bt_field_array *array_field = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_IS_ARRAY(field, "Field");
-       BT_ASSERT_PRE_VALID_INDEX(index, array_field->length);
-       return array_field->fields->pdata[index];
-}
-
-struct bt_field *bt_field_array_borrow_element_field_by_index(
-               struct bt_field *field, uint64_t index)
-{
-       return borrow_array_field_element_field_by_index(field, index);
-}
-
-const struct bt_field *
-bt_field_array_borrow_element_field_by_index_const(
-               const struct bt_field *field, uint64_t index)
-{
-       return borrow_array_field_element_field_by_index((void *) field, index);
-}
-
-static inline
-struct bt_field *borrow_structure_field_member_field_by_index(
-               struct bt_field *field, uint64_t index)
-{
-       struct bt_field_structure *struct_field = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_STRUCTURE, "Field");
-       BT_ASSERT_PRE_VALID_INDEX(index, struct_field->fields->len);
-       return struct_field->fields->pdata[index];
-}
-
-struct bt_field *bt_field_structure_borrow_member_field_by_index(
-               struct bt_field *field, uint64_t index)
-{
-       return borrow_structure_field_member_field_by_index(field,
-               index);
-}
-
-const struct bt_field *
-bt_field_structure_borrow_member_field_by_index_const(
-               const struct bt_field *field, uint64_t index)
-{
-       return borrow_structure_field_member_field_by_index(
-               (void *) field, index);
-}
-
-static inline
-struct bt_field *borrow_structure_field_member_field_by_name(
-               struct bt_field *field, const char *name)
-{
-       struct bt_field *ret_field = NULL;
-       struct bt_field_class_structure *struct_fc;
-       struct bt_field_structure *struct_field = (void *) field;
-       gpointer orig_key;
-       gpointer index;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_NON_NULL(name, "Field name");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_STRUCTURE, "Field");
-       struct_fc = (void *) field->class;
-
-       if (!g_hash_table_lookup_extended(struct_fc->common.name_to_index, name,
-                       &orig_key, &index)) {
-               goto end;
-       }
-
-       ret_field = struct_field->fields->pdata[GPOINTER_TO_UINT(index)];
-       BT_ASSERT(ret_field);
-
-end:
-       return ret_field;
-}
-
-struct bt_field *bt_field_structure_borrow_member_field_by_name(
-               struct bt_field *field, const char *name)
-{
-       return borrow_structure_field_member_field_by_name(field, name);
-}
-
-const struct bt_field *bt_field_structure_borrow_member_field_by_name_const(
-               const struct bt_field *field, const char *name)
-{
-       return borrow_structure_field_member_field_by_name(
-               (void *) field, name);
-}
-
-static inline
-struct bt_field *borrow_variant_field_selected_option_field(
-               struct bt_field *field)
-{
-       struct bt_field_variant *var_field = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_VARIANT, "Field");
-       BT_ASSERT_PRE(var_field->selected_field,
-               "Variant field has no selected field: %!+f", field);
-       return var_field->selected_field;
-}
-
-struct bt_field *bt_field_variant_borrow_selected_option_field(
-               struct bt_field *field)
-{
-       return borrow_variant_field_selected_option_field(field);
-}
-
-const struct bt_field *bt_field_variant_borrow_selected_option_field_const(
-               const struct bt_field *field)
-{
-       return borrow_variant_field_selected_option_field((void *) field);
-}
-
-enum bt_field_status bt_field_variant_select_option_field(
-               struct bt_field *field, uint64_t index)
-{
-       struct bt_field_variant *var_field = (void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_VARIANT, "Field");
-       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
-       BT_ASSERT_PRE_VALID_INDEX(index, var_field->fields->len);
-       var_field->selected_field = var_field->fields->pdata[index];
-       var_field->selected_index = index;
-       return BT_FIELD_STATUS_OK;
-}
-
-uint64_t bt_field_variant_get_selected_option_field_index(
-               const struct bt_field *field)
-{
-       const struct bt_field_variant *var_field = (const void *) field;
-
-       BT_ASSERT_PRE_NON_NULL(field, "Field");
-       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
-               BT_FIELD_CLASS_TYPE_VARIANT, "Field");
-       BT_ASSERT_PRE(var_field->selected_field,
-               "Variant field has no selected field: %!+f", field);
-       return var_field->selected_index;
-}
-
-static inline
-void bt_field_finalize(struct bt_field *field)
-{
-       BT_ASSERT(field);
-       BT_LOGD_STR("Putting field's class.");
-       BT_OBJECT_PUT_REF_AND_RESET(field->class);
-}
-
-static
-void destroy_integer_field(struct bt_field *field)
-{
-       BT_ASSERT(field);
-       BT_LIB_LOGD("Destroying integer field object: %!+f", field);
-       bt_field_finalize(field);
-       g_free(field);
-}
-
-static
-void destroy_real_field(struct bt_field *field)
-{
-       BT_ASSERT(field);
-       BT_LIB_LOGD("Destroying real field object: %!+f", field);
-       bt_field_finalize(field);
-       g_free(field);
-}
-
-static
-void destroy_structure_field(struct bt_field *field)
-{
-       struct bt_field_structure *struct_field = (void *) field;
-
-       BT_ASSERT(field);
-       BT_LIB_LOGD("Destroying structure field object: %!+f", field);
-       bt_field_finalize(field);
-
-       if (struct_field->fields) {
-               g_ptr_array_free(struct_field->fields, TRUE);
-               struct_field->fields = NULL;
-       }
-
-       g_free(field);
-}
-
-static
-void destroy_variant_field(struct bt_field *field)
-{
-       struct bt_field_variant *var_field = (void *) field;
-
-       BT_ASSERT(field);
-       BT_LIB_LOGD("Destroying variant field object: %!+f", field);
-       bt_field_finalize(field);
-
-       if (var_field->fields) {
-               g_ptr_array_free(var_field->fields, TRUE);
-               var_field->fields = NULL;
-       }
-
-       g_free(field);
-}
-
-static
-void destroy_array_field(struct bt_field *field)
-{
-       struct bt_field_array *array_field = (void *) field;
-
-       BT_ASSERT(field);
-       BT_LIB_LOGD("Destroying array field object: %!+f", field);
-       bt_field_finalize(field);
-
-       if (array_field->fields) {
-               g_ptr_array_free(array_field->fields, TRUE);
-               array_field->fields = NULL;
-       }
-
-       g_free(field);
-}
-
-static
-void destroy_string_field(struct bt_field *field)
-{
-       struct bt_field_string *string_field = (void *) field;
-
-       BT_ASSERT(field);
-       BT_LIB_LOGD("Destroying string field object: %!+f", field);
-       bt_field_finalize(field);
-
-       if (string_field->buf) {
-               g_array_free(string_field->buf, TRUE);
-               string_field->buf = NULL;
-       }
-
-       g_free(field);
-}
-
-BT_HIDDEN
-void bt_field_destroy(struct bt_field *field)
-{
-       BT_ASSERT(field);
-       BT_ASSERT(bt_field_class_has_known_type(field->class));
-       field_destroy_funcs[field->class->type](field);
-}
-
-static
-void reset_single_field(struct bt_field *field)
-{
-       BT_ASSERT(field);
-       field->is_set = false;
-}
-
-static
-void reset_structure_field(struct bt_field *field)
-{
-       uint64_t i;
-       struct bt_field_structure *struct_field = (void *) field;
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < struct_field->fields->len; i++) {
-               bt_field_reset(struct_field->fields->pdata[i]);
-       }
-}
-
-static
-void reset_variant_field(struct bt_field *field)
-{
-       uint64_t i;
-       struct bt_field_variant *var_field = (void *) field;
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < var_field->fields->len; i++) {
-               bt_field_reset(var_field->fields->pdata[i]);
-       }
-}
-
-static
-void reset_array_field(struct bt_field *field)
-{
-       uint64_t i;
-       struct bt_field_array *array_field = (void *) field;
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < array_field->fields->len; i++) {
-               bt_field_reset(array_field->fields->pdata[i]);
-       }
-}
-
-static
-void set_single_field_is_frozen(struct bt_field *field, bool is_frozen)
-{
-       field->frozen = is_frozen;
-}
-
-static
-void set_structure_field_is_frozen(struct bt_field *field, bool is_frozen)
-{
-       uint64_t i;
-       struct bt_field_structure *struct_field = (void *) field;
-
-       BT_LIB_LOGD("Setting structure field's frozen state: "
-               "%![field-]+f, is-frozen=%d", field, is_frozen);
-
-       for (i = 0; i < struct_field->fields->len; i++) {
-               struct bt_field *member_field = struct_field->fields->pdata[i];
-
-               BT_LIB_LOGD("Setting structure field's member field's "
-                       "frozen state: %![field-]+f, index=%" PRIu64,
-                       member_field, i);
-               bt_field_set_is_frozen(member_field, is_frozen);
-       }
-
-       set_single_field_is_frozen(field, is_frozen);
-}
-
-static
-void set_variant_field_is_frozen(struct bt_field *field, bool is_frozen)
-{
-       uint64_t i;
-       struct bt_field_variant *var_field = (void *) field;
-
-       BT_LIB_LOGD("Setting variant field's frozen state: "
-               "%![field-]+f, is-frozen=%d", field, is_frozen);
-
-       for (i = 0; i < var_field->fields->len; i++) {
-               struct bt_field *option_field = var_field->fields->pdata[i];
-
-               BT_LIB_LOGD("Setting variant field's option field's "
-                       "frozen state: %![field-]+f, index=%" PRIu64,
-                       option_field, i);
-               bt_field_set_is_frozen(option_field, is_frozen);
-       }
-
-       set_single_field_is_frozen(field, is_frozen);
-}
-
-static
-void set_array_field_is_frozen(struct bt_field *field, bool is_frozen)
-{
-       uint64_t i;
-       struct bt_field_array *array_field = (void *) field;
-
-       BT_LIB_LOGD("Setting array field's frozen state: "
-               "%![field-]+f, is-frozen=%d", field, is_frozen);
-
-       for (i = 0; i < array_field->fields->len; i++) {
-               struct bt_field *elem_field = array_field->fields->pdata[i];
-
-               BT_LIB_LOGD("Setting array field's element field's "
-                       "frozen state: %![field-]+f, index=%" PRIu64,
-                       elem_field, i);
-               bt_field_set_is_frozen(elem_field, is_frozen);
-       }
-
-       set_single_field_is_frozen(field, is_frozen);
-}
-
-BT_HIDDEN
-void _bt_field_set_is_frozen(const struct bt_field *field,
-               bool is_frozen)
-{
-       BT_ASSERT(field);
-       BT_LIB_LOGD("Setting field object's frozen state: %!+f, is-frozen=%d",
-               field, is_frozen);
-       BT_ASSERT(field->methods->set_is_frozen);
-       field->methods->set_is_frozen((void *) field, is_frozen);
-}
-
-static
-bool single_field_is_set(const struct bt_field *field)
-{
-       BT_ASSERT(field);
-       return field->is_set;
-}
-
-static
-bool structure_field_is_set(const struct bt_field *field)
-{
-       bool is_set = true;
-       uint64_t i;
-       const struct bt_field_structure *struct_field = (const void *) field;
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < struct_field->fields->len; i++) {
-               is_set = bt_field_is_set(struct_field->fields->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
-       }
-
-end:
-       return is_set;
-}
-
-static
-bool variant_field_is_set(const struct bt_field *field)
-{
-       const struct bt_field_variant *var_field = (const void *) field;
-       bool is_set = false;
-
-       BT_ASSERT(field);
-
-       if (var_field->selected_field) {
-               is_set = bt_field_is_set(var_field->selected_field);
-       }
-
-       return is_set;
-}
-
-static
-bool array_field_is_set(const struct bt_field *field)
-{
-       bool is_set = true;
-       uint64_t i;
-       const struct bt_field_array *array_field = (const void *) field;
-
-       BT_ASSERT(field);
-
-       for (i = 0; i < array_field->length; i++) {
-               is_set = bt_field_is_set(array_field->fields->pdata[i]);
-               if (!is_set) {
-                       goto end;
-               }
-       }
-
-end:
-       return is_set;
-}
diff --git a/lib/trace-ir/packet-context-field.c b/lib/trace-ir/packet-context-field.c
deleted file mode 100644 (file)
index dbebab8..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PACKET-CONTEXT-FIELD"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/packet-context-field.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/field-wrapper-internal.h>
-#include <glib.h>
-
-struct bt_field *bt_packet_context_field_borrow_field(
-               struct bt_packet_context_field *context_field)
-{
-       struct bt_field_wrapper *field_wrapper = (void *) context_field;
-
-       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet context field");
-       return (void *) field_wrapper->field;
-}
-
-void bt_packet_context_field_release(
-               struct bt_packet_context_field *context_field)
-{
-       struct bt_field_wrapper *field_wrapper = (void *) context_field;
-
-       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet context field");
-
-       /*
-        * Do not recycle because the pool could be destroyed at this
-        * point. This function is only called when there's an error
-        * anyway because the goal of a packet context field wrapper is
-        * to eventually move it to a packet with
-        * bt_packet_move_context() after creating it.
-        */
-       bt_field_wrapper_destroy(field_wrapper);
-}
-
-struct bt_packet_context_field *bt_packet_context_field_create(
-               struct bt_stream_class *stream_class)
-{
-       struct bt_field_wrapper *field_wrapper;
-
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE(stream_class->frozen,
-               "Stream class is not part of a trace class: %!+S",
-               stream_class);
-       BT_ASSERT_PRE(stream_class->packet_context_fc,
-               "Stream class has no packet context field class: %!+S",
-               stream_class);
-       field_wrapper = bt_field_wrapper_create(
-               &stream_class->packet_context_field_pool,
-               (void *) stream_class->packet_context_fc);
-       if (!field_wrapper) {
-               BT_LIB_LOGE("Cannot allocate one packet context field from stream class: "
-                       "%![sc-]+S", stream_class);
-               goto error;
-       }
-
-       BT_ASSERT(field_wrapper->field);
-       bt_stream_class_freeze(stream_class);
-       goto end;
-
-error:
-       if (field_wrapper) {
-               bt_field_wrapper_destroy(field_wrapper);
-               field_wrapper = NULL;
-       }
-
-end:
-       return (void *) field_wrapper;
-}
diff --git a/lib/trace-ir/packet.c b/lib/trace-ir/packet.c
deleted file mode 100644 (file)
index e005cea..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PACKET"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/packet-const.h>
-#include <babeltrace2/trace-ir/packet.h>
-#include <babeltrace2/trace-ir/packet-internal.h>
-#include <babeltrace2/trace-ir/field-wrapper-internal.h>
-#include <babeltrace2/trace-ir/trace.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/trace-ir/stream.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <inttypes.h>
-
-#define BT_ASSERT_PRE_PACKET_HOT(_packet) \
-       BT_ASSERT_PRE_HOT((_packet), "Packet", ": %!+a", (_packet))
-
-struct bt_stream *bt_packet_borrow_stream(struct bt_packet *packet)
-{
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       return packet->stream;
-}
-
-const struct bt_stream *bt_packet_borrow_stream_const(
-               const struct bt_packet *packet)
-{
-       return bt_packet_borrow_stream((void *) packet);
-}
-
-struct bt_field *bt_packet_borrow_context_field(struct bt_packet *packet)
-{
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       return packet->context_field ? packet->context_field->field : NULL;
-}
-
-const struct bt_field *bt_packet_borrow_context_field_const(
-               const struct bt_packet *packet)
-{
-       return bt_packet_borrow_context_field((void *) packet);
-}
-
-BT_HIDDEN
-void _bt_packet_set_is_frozen(const struct bt_packet *packet, bool is_frozen)
-{
-       if (!packet) {
-               return;
-       }
-
-       BT_LIB_LOGD("Setting packet's frozen state: %![packet-]+a, "
-               "is-frozen=%d", packet, is_frozen);
-
-       if (packet->context_field) {
-               BT_LOGD_STR("Setting packet's context field's frozen state.");
-               bt_field_set_is_frozen(packet->context_field->field,
-                       is_frozen);
-       }
-
-       ((struct bt_packet *) packet)->frozen = is_frozen;
-}
-
-static inline
-void reset_packet(struct bt_packet *packet)
-{
-       BT_ASSERT(packet);
-       BT_LIB_LOGD("Resetting packet: %!+a", packet);
-       bt_packet_set_is_frozen(packet, false);
-
-       if (packet->context_field) {
-               bt_field_set_is_frozen(packet->context_field->field, false);
-               bt_field_reset(packet->context_field->field);
-       }
-}
-
-static
-void recycle_context_field(struct bt_field_wrapper *context_field,
-               struct bt_stream_class *stream_class)
-{
-       BT_ASSERT(context_field);
-       BT_LIB_LOGD("Recycling packet context field: "
-               "addr=%p, %![sc-]+S, %![field-]+f", context_field,
-               stream_class, context_field->field);
-       bt_object_pool_recycle_object(&stream_class->packet_context_field_pool,
-               context_field);
-}
-
-BT_HIDDEN
-void bt_packet_recycle(struct bt_packet *packet)
-{
-       struct bt_stream *stream;
-
-       BT_ASSERT(packet);
-       BT_LIB_LOGD("Recycling packet: %!+a", packet);
-
-       /*
-        * Those are the important ordered steps:
-        *
-        * 1. Reset the packet object (put any permanent reference it
-        *    has, unfreeze it and its fields in developer mode, etc.),
-        *    but do NOT put its stream's reference. This stream
-        *    contains the pool to which we're about to recycle this
-        *    packet object, so we must guarantee its existence thanks
-        *    to this existing reference.
-        *
-        * 2. Move the stream reference to our `stream`
-        *    variable so that we can set the packet's stream member
-        *    to NULL before recycling it. We CANNOT do this after
-        *    we put the stream reference because this bt_object_put_ref()
-        *    could destroy the stream, also destroying its
-        *    packet pool, thus also destroying our packet object (this
-        *    would result in an invalid write access).
-        *
-        * 3. Recycle the packet object.
-        *
-        * 4. Put our stream reference.
-        */
-       reset_packet(packet);
-       stream = packet->stream;
-       BT_ASSERT(stream);
-       packet->stream = NULL;
-       bt_object_pool_recycle_object(&stream->packet_pool, packet);
-       bt_object_put_no_null_check(&stream->base);
-}
-
-BT_HIDDEN
-void bt_packet_destroy(struct bt_packet *packet)
-{
-       BT_LIB_LOGD("Destroying packet: %!+a", packet);
-
-       if (packet->context_field) {
-               if (packet->stream) {
-                       BT_LOGD_STR("Recycling packet's context field.");
-                       recycle_context_field(packet->context_field,
-                               packet->stream->class);
-               } else {
-                       bt_field_wrapper_destroy(packet->context_field);
-               }
-
-               packet->context_field = NULL;
-       }
-
-       BT_LOGD_STR("Putting packet's stream.");
-       BT_OBJECT_PUT_REF_AND_RESET(packet->stream);
-       g_free(packet);
-}
-
-BT_HIDDEN
-struct bt_packet *bt_packet_new(struct bt_stream *stream)
-{
-       struct bt_packet *packet = NULL;
-       struct bt_trace_class *trace_class = NULL;
-
-       BT_ASSERT(stream);
-       BT_LIB_LOGD("Creating packet object: %![stream-]+s", stream);
-       packet = g_new0(struct bt_packet, 1);
-       if (!packet) {
-               BT_LOGE_STR("Failed to allocate one packet object.");
-               goto error;
-       }
-
-       bt_object_init_shared(&packet->base,
-               (bt_object_release_func) bt_packet_recycle);
-       packet->stream = stream;
-       bt_object_get_no_null_check(stream);
-       trace_class = bt_stream_class_borrow_trace_class_inline(stream->class);
-       BT_ASSERT(trace_class);
-
-       if (stream->class->packet_context_fc) {
-               BT_LOGD_STR("Creating initial packet context field.");
-               packet->context_field = bt_field_wrapper_create(
-                       &stream->class->packet_context_field_pool,
-                       stream->class->packet_context_fc);
-               if (!packet->context_field) {
-                       BT_LOGE_STR("Cannot create packet context field wrapper.");
-                       goto error;
-               }
-       }
-
-       BT_LIB_LOGD("Created packet object: %!+a", packet);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(packet);
-
-end:
-       return packet;
-}
-
-struct bt_packet *bt_packet_create(const struct bt_stream *c_stream)
-{
-       struct bt_packet *packet = NULL;
-       struct bt_stream *stream = (void *) c_stream;
-
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       packet = bt_object_pool_create_object(&stream->packet_pool);
-       if (unlikely(!packet)) {
-               BT_LIB_LOGE("Cannot allocate one packet from stream's packet pool: "
-                       "%![stream-]+s", stream);
-               goto end;
-       }
-
-       if (likely(!packet->stream)) {
-               packet->stream = stream;
-               bt_object_get_no_null_check_no_parent_check(
-                       &packet->stream->base);
-       }
-
-end:
-       return (void *) packet;
-}
-
-enum bt_packet_status bt_packet_move_context_field(struct bt_packet *packet,
-               struct bt_packet_context_field *context_field)
-{
-       struct bt_stream_class *stream_class;
-       struct bt_field_wrapper *field_wrapper = (void *) context_field;
-
-       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
-       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Context field");
-       BT_ASSERT_PRE_HOT(packet, "Packet", ": %!+a", packet);
-       stream_class = packet->stream->class;
-       BT_ASSERT_PRE(stream_class->packet_context_fc,
-               "Stream class has no packet context field class: %!+S",
-               stream_class);
-       BT_ASSERT_PRE(field_wrapper->field->class ==
-               stream_class->packet_context_fc,
-               "Unexpected packet context field's class: "
-               "%![fc-]+F, %![expected-fc-]+F", field_wrapper->field->class,
-               stream_class->packet_context_fc);
-
-       /* Recycle current context field: always exists */
-       BT_ASSERT(packet->context_field);
-       recycle_context_field(packet->context_field, stream_class);
-
-       /* Move new field */
-       packet->context_field = field_wrapper;
-       return BT_PACKET_STATUS_OK;
-}
-
-void bt_packet_get_ref(const struct bt_packet *packet)
-{
-       bt_object_get_ref(packet);
-}
-
-void bt_packet_put_ref(const struct bt_packet *packet)
-{
-       bt_object_put_ref(packet);
-}
diff --git a/lib/trace-ir/resolve-field-path.c b/lib/trace-ir/resolve-field-path.c
deleted file mode 100644 (file)
index 1f7b5cd..0000000
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "RESOLVE-FIELD-PATH"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/field-path-internal.h>
-#include <babeltrace2/trace-ir/field-path-const.h>
-#include <babeltrace2/trace-ir/resolve-field-path-internal.h>
-#include <limits.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <glib.h>
-
-static
-bool find_field_class_recursive(struct bt_field_class *fc,
-               struct bt_field_class *tgt_fc, struct bt_field_path *field_path)
-{
-       bool found = false;
-
-       if (tgt_fc == fc) {
-               found = true;
-               goto end;
-       }
-
-       switch (fc->type) {
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct bt_field_class_named_field_class_container *container_fc =
-                       (void *) fc;
-               uint64_t i;
-
-               for (i = 0; i < container_fc->named_fcs->len; i++) {
-                       struct bt_named_field_class *named_fc =
-                               BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
-                                       container_fc, i);
-                       struct bt_field_path_item item = {
-                               .type = BT_FIELD_PATH_ITEM_TYPE_INDEX,
-                               .index = i,
-                       };
-
-                       bt_field_path_append_item(field_path, &item);
-                       found = find_field_class_recursive(named_fc->fc,
-                               tgt_fc, field_path);
-                       if (found) {
-                               goto end;
-                       }
-
-                       bt_field_path_remove_last_item(field_path);
-               }
-
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-       {
-               struct bt_field_class_array *array_fc = (void *) fc;
-               struct bt_field_path_item item = {
-                       .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT,
-                       .index = UINT64_C(-1),
-               };
-
-               bt_field_path_append_item(field_path, &item);
-               found = find_field_class_recursive(array_fc->element_fc,
-                       tgt_fc, field_path);
-               if (found) {
-                       goto end;
-               }
-
-               bt_field_path_remove_last_item(field_path);
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return found;
-}
-
-static
-int find_field_class(struct bt_field_class *root_fc,
-               enum bt_scope root_scope, struct bt_field_class *tgt_fc,
-               struct bt_field_path **ret_field_path)
-{
-       int ret = 0;
-       struct bt_field_path *field_path = NULL;
-
-       if (!root_fc) {
-               goto end;
-       }
-
-       field_path = bt_field_path_create();
-       if (!field_path) {
-               ret = -1;
-               goto end;
-       }
-
-       field_path->root = root_scope;
-       if (!find_field_class_recursive(root_fc, tgt_fc, field_path)) {
-               /* Not found here */
-               BT_OBJECT_PUT_REF_AND_RESET(field_path);
-       }
-
-end:
-       *ret_field_path = field_path;
-       return ret;
-}
-
-static
-struct bt_field_path *find_field_class_in_ctx(struct bt_field_class *fc,
-               struct bt_resolve_field_path_context *ctx)
-{
-       struct bt_field_path *field_path = NULL;
-       int ret;
-
-       ret = find_field_class(ctx->packet_context, BT_SCOPE_PACKET_CONTEXT,
-               fc, &field_path);
-       if (ret || field_path) {
-               goto end;
-       }
-
-       ret = find_field_class(ctx->event_common_context,
-               BT_SCOPE_EVENT_COMMON_CONTEXT, fc, &field_path);
-       if (ret || field_path) {
-               goto end;
-       }
-
-       ret = find_field_class(ctx->event_specific_context,
-               BT_SCOPE_EVENT_SPECIFIC_CONTEXT, fc, &field_path);
-       if (ret || field_path) {
-               goto end;
-       }
-
-       ret = find_field_class(ctx->event_payload, BT_SCOPE_EVENT_PAYLOAD,
-               fc, &field_path);
-       if (ret || field_path) {
-               goto end;
-       }
-
-end:
-       return field_path;
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-bool target_is_before_source(struct bt_field_path *src_field_path,
-               struct bt_field_path *tgt_field_path)
-{
-       bool is_valid = true;
-       uint64_t src_i = 0, tgt_i = 0;
-
-       if (tgt_field_path->root < src_field_path->root) {
-               goto end;
-       }
-
-       if (tgt_field_path->root > src_field_path->root) {
-               is_valid = false;
-               goto end;
-       }
-
-       BT_ASSERT(tgt_field_path->root == src_field_path->root);
-
-       for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
-                       tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
-               struct bt_field_path_item *src_fp_item =
-                       bt_field_path_borrow_item_by_index_inline(
-                               src_field_path, src_i);
-               struct bt_field_path_item *tgt_fp_item =
-                       bt_field_path_borrow_item_by_index_inline(
-                               tgt_field_path, tgt_i);
-
-               if (src_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX &&
-                               tgt_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX) {
-                       if (tgt_fp_item->index > src_fp_item->index) {
-                               is_valid = false;
-                               goto end;
-                       }
-               }
-
-               src_i++;
-               tgt_i++;
-       }
-
-end:
-       return is_valid;
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-struct bt_field_class *borrow_root_field_class(
-               struct bt_resolve_field_path_context *ctx, enum bt_scope scope)
-{
-       switch (scope) {
-       case BT_SCOPE_PACKET_CONTEXT:
-               return ctx->packet_context;
-       case BT_SCOPE_EVENT_COMMON_CONTEXT:
-               return ctx->event_common_context;
-       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               return ctx->event_specific_context;
-       case BT_SCOPE_EVENT_PAYLOAD:
-               return ctx->event_payload;
-       default:
-               abort();
-       }
-
-       return NULL;
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-struct bt_field_class *borrow_child_field_class(
-               struct bt_field_class *parent_fc,
-               struct bt_field_path_item *fp_item)
-{
-       struct bt_field_class *child_fc = NULL;
-
-       switch (parent_fc->type) {
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct bt_named_field_class *named_fc;
-
-               BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX);
-               named_fc = BT_FIELD_CLASS_NAMED_FC_AT_INDEX(parent_fc,
-                       fp_item->index);
-               child_fc = named_fc->fc;
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-       {
-               struct bt_field_class_array *array_fc = (void *) parent_fc;
-
-               BT_ASSERT(fp_item->type ==
-                       BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
-               child_fc = array_fc->element_fc;
-               break;
-       }
-       default:
-               break;
-       }
-
-       return child_fc;
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-bool target_field_path_in_different_scope_has_struct_fc_only(
-               struct bt_field_path *src_field_path,
-               struct bt_field_path *tgt_field_path,
-               struct bt_resolve_field_path_context *ctx)
-{
-       bool is_valid = true;
-       uint64_t i = 0;
-       struct bt_field_class *fc;
-
-       if (src_field_path->root == tgt_field_path->root) {
-               goto end;
-       }
-
-       fc = borrow_root_field_class(ctx, tgt_field_path->root);
-
-       for (i = 0; i < tgt_field_path->items->len; i++) {
-               struct bt_field_path_item *fp_item =
-                       bt_field_path_borrow_item_by_index_inline(
-                               tgt_field_path, i);
-
-               if (fc->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY ||
-                               fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY ||
-                               fc->type == BT_FIELD_CLASS_TYPE_VARIANT) {
-                       is_valid = false;
-                       goto end;
-               }
-
-               BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX);
-               fc = borrow_child_field_class(fc, fp_item);
-       }
-
-end:
-       return is_valid;
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-bool lca_is_structure_field_class(struct bt_field_path *src_field_path,
-               struct bt_field_path *tgt_field_path,
-               struct bt_resolve_field_path_context *ctx)
-{
-       bool is_valid = true;
-       struct bt_field_class *src_fc;
-       struct bt_field_class *tgt_fc;
-       struct bt_field_class *prev_fc = NULL;
-       uint64_t src_i = 0, tgt_i = 0;
-
-       if (src_field_path->root != tgt_field_path->root) {
-               goto end;
-       }
-
-       src_fc = borrow_root_field_class(ctx, src_field_path->root);
-       tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
-       BT_ASSERT(src_fc);
-       BT_ASSERT(tgt_fc);
-
-       for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
-                       tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
-               struct bt_field_path_item *src_fp_item =
-                       bt_field_path_borrow_item_by_index_inline(
-                               src_field_path, src_i);
-               struct bt_field_path_item *tgt_fp_item =
-                       bt_field_path_borrow_item_by_index_inline(
-                               tgt_field_path, tgt_i);
-
-               if (src_fc != tgt_fc) {
-                       if (!prev_fc) {
-                               /*
-                                * This is correct: the LCA is the root
-                                * scope field class, which must be a
-                                * structure field class.
-                                */
-                               break;
-                       }
-
-                       if (prev_fc->type != BT_FIELD_CLASS_TYPE_STRUCTURE) {
-                               is_valid = false;
-                       }
-
-                       break;
-               }
-
-               prev_fc = src_fc;
-               src_fc = borrow_child_field_class(src_fc, src_fp_item);
-               tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
-       }
-
-end:
-       return is_valid;
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-bool lca_to_target_has_struct_fc_only(struct bt_field_path *src_field_path,
-               struct bt_field_path *tgt_field_path,
-               struct bt_resolve_field_path_context *ctx)
-{
-       bool is_valid = true;
-       struct bt_field_class *src_fc;
-       struct bt_field_class *tgt_fc;
-       uint64_t src_i = 0, tgt_i = 0;
-
-       if (src_field_path->root != tgt_field_path->root) {
-               goto end;
-       }
-
-       src_fc = borrow_root_field_class(ctx, src_field_path->root);
-       tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
-       BT_ASSERT(src_fc);
-       BT_ASSERT(tgt_fc);
-       BT_ASSERT(src_fc == tgt_fc);
-
-       /* Find LCA */
-       for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
-                       tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
-               struct bt_field_path_item *src_fp_item =
-                       bt_field_path_borrow_item_by_index_inline(
-                               src_field_path, src_i);
-               struct bt_field_path_item *tgt_fp_item =
-                       bt_field_path_borrow_item_by_index_inline(
-                               tgt_field_path, tgt_i);
-
-               if (src_i != tgt_i) {
-                       /* Next field class is different: LCA is `tgt_fc` */
-                       break;
-               }
-
-               src_fc = borrow_child_field_class(src_fc, src_fp_item);
-               tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
-       }
-
-       /* Only structure field classes to the target */
-       for (; tgt_i < tgt_field_path->items->len; tgt_i++) {
-               struct bt_field_path_item *tgt_fp_item =
-                       bt_field_path_borrow_item_by_index_inline(
-                               tgt_field_path, tgt_i);
-
-               if (tgt_fc->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY ||
-                               tgt_fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY ||
-                               tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT) {
-                       is_valid = false;
-                       goto end;
-               }
-
-               tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
-       }
-
-end:
-       return is_valid;
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-bool field_path_is_valid(struct bt_field_class *src_fc,
-               struct bt_field_class *tgt_fc,
-               struct bt_resolve_field_path_context *ctx)
-{
-       bool is_valid = true;
-       struct bt_field_path *src_field_path = find_field_class_in_ctx(
-               src_fc, ctx);
-       struct bt_field_path *tgt_field_path = find_field_class_in_ctx(
-               tgt_fc, ctx);
-
-       if (!src_field_path) {
-               BT_ASSERT_PRE_MSG("Cannot find requesting field class in "
-                       "resolving context: %!+F", src_fc);
-               is_valid = false;
-               goto end;
-       }
-
-       if (!tgt_field_path) {
-               BT_ASSERT_PRE_MSG("Cannot find target field class in "
-                       "resolving context: %!+F", tgt_fc);
-               is_valid = false;
-               goto end;
-       }
-
-       /* Target must be before source */
-       if (!target_is_before_source(src_field_path, tgt_field_path)) {
-               BT_ASSERT_PRE_MSG("Target field class is located after "
-                       "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
-                       src_fc, tgt_fc);
-               is_valid = false;
-               goto end;
-       }
-
-       /*
-        * If target is in a different scope than source, there are no
-        * array or variant field classes on the way to the target.
-        */
-       if (!target_field_path_in_different_scope_has_struct_fc_only(
-                       src_field_path, tgt_field_path, ctx)) {
-               BT_ASSERT_PRE_MSG("Target field class is located in a "
-                       "different scope than requesting field class, "
-                       "but within an array or a variant field class: "
-                       "%![req-fc-]+F, %![tgt-fc-]+F",
-                       src_fc, tgt_fc);
-               is_valid = false;
-               goto end;
-       }
-
-       /* Same scope: LCA must be a structure field class */
-       if (!lca_is_structure_field_class(src_field_path, tgt_field_path, ctx)) {
-               BT_ASSERT_PRE_MSG("Lowest common ancestor of target and "
-                       "requesting field classes is not a structure field class: "
-                       "%![req-fc-]+F, %![tgt-fc-]+F",
-                       src_fc, tgt_fc);
-               is_valid = false;
-               goto end;
-       }
-
-       /* Same scope: path from LCA to target has no array/variant FTs */
-       if (!lca_to_target_has_struct_fc_only(src_field_path, tgt_field_path,
-                       ctx)) {
-               BT_ASSERT_PRE_MSG("Path from lowest common ancestor of target "
-                       "and requesting field classes to target field class "
-                       "contains an array or a variant field class: "
-                       "%![req-fc-]+F, %![tgt-fc-]+F", src_fc, tgt_fc);
-               is_valid = false;
-               goto end;
-       }
-
-end:
-       bt_object_put_ref(src_field_path);
-       bt_object_put_ref(tgt_field_path);
-       return is_valid;
-}
-
-static
-struct bt_field_path *resolve_field_path(struct bt_field_class *src_fc,
-               struct bt_field_class *tgt_fc,
-               struct bt_resolve_field_path_context *ctx)
-{
-       BT_ASSERT_PRE(field_path_is_valid(src_fc, tgt_fc, ctx),
-               "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
-               src_fc, tgt_fc);
-       return find_field_class_in_ctx(tgt_fc, ctx);
-}
-
-BT_HIDDEN
-int bt_resolve_field_paths(struct bt_field_class *fc,
-               struct bt_resolve_field_path_context *ctx)
-{
-       int ret = 0;
-
-       BT_ASSERT(fc);
-
-       /* Resolving part for dynamic array and variant field classes */
-       switch (fc->type) {
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-       {
-               struct bt_field_class_dynamic_array *dyn_array_fc = (void *) fc;
-
-               if (dyn_array_fc->length_fc) {
-                       BT_ASSERT(!dyn_array_fc->length_field_path);
-                       dyn_array_fc->length_field_path = resolve_field_path(
-                               fc, dyn_array_fc->length_fc, ctx);
-                       if (!dyn_array_fc->length_field_path) {
-                               ret = -1;
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct bt_field_class_variant *var_fc = (void *) fc;
-
-               if (var_fc->selector_fc) {
-                       BT_ASSERT(!var_fc->selector_field_path);
-                       var_fc->selector_field_path =
-                               resolve_field_path(fc,
-                                       var_fc->selector_fc, ctx);
-                       if (!var_fc->selector_field_path) {
-                               ret = -1;
-                               goto end;
-                       }
-               }
-       }
-       default:
-               break;
-       }
-
-       /* Recursive part */
-       switch (fc->type) {
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct bt_field_class_named_field_class_container *container_fc =
-                       (void *) fc;
-               uint64_t i;
-
-               for (i = 0; i < container_fc->named_fcs->len; i++) {
-                       struct bt_named_field_class *named_fc =
-                               BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
-                                       container_fc, i);
-
-                       ret = bt_resolve_field_paths(named_fc->fc, ctx);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-       {
-               struct bt_field_class_array *array_fc = (void *) fc;
-
-               ret = bt_resolve_field_paths(array_fc->element_fc, ctx);
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
diff --git a/lib/trace-ir/stream-class.c b/lib/trace-ir/stream-class.c
deleted file mode 100644 (file)
index 1f6732d..0000000
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "STREAM-CLASS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/trace-ir/event-class-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/field-internal.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/trace-const.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/trace-ir/field-wrapper-internal.h>
-#include <babeltrace2/trace-ir/resolve-field-path-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/property-internal.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-#define BT_ASSERT_PRE_STREAM_CLASS_HOT(_sc) \
-       BT_ASSERT_PRE_HOT((_sc), "Stream class", ": %!+S", (_sc))
-
-static
-void destroy_stream_class(struct bt_object *obj)
-{
-       struct bt_stream_class *stream_class = (void *) obj;
-
-       BT_LIB_LOGD("Destroying stream class: %!+S", stream_class);
-       BT_LOGD_STR("Putting default clock class.");
-       BT_OBJECT_PUT_REF_AND_RESET(stream_class->default_clock_class);
-
-       if (stream_class->event_classes) {
-               BT_LOGD_STR("Destroying event classes.");
-               g_ptr_array_free(stream_class->event_classes, TRUE);
-               stream_class->event_classes = NULL;
-       }
-
-       if (stream_class->name.str) {
-               g_string_free(stream_class->name.str, TRUE);
-               stream_class->name.str = NULL;
-               stream_class->name.value = NULL;
-       }
-
-       BT_LOGD_STR("Putting packet context field class.");
-       BT_OBJECT_PUT_REF_AND_RESET(stream_class->packet_context_fc);
-       BT_LOGD_STR("Putting event common context field class.");
-       BT_OBJECT_PUT_REF_AND_RESET(stream_class->event_common_context_fc);
-       bt_object_pool_finalize(&stream_class->packet_context_field_pool);
-       g_free(stream_class);
-}
-
-static
-void free_field_wrapper(struct bt_field_wrapper *field_wrapper,
-               struct bt_stream_class *stream_class)
-{
-       bt_field_wrapper_destroy((void *) field_wrapper);
-}
-
-BT_ASSERT_PRE_FUNC
-static
-bool stream_class_id_is_unique(const struct bt_trace_class *tc, uint64_t id)
-{
-       uint64_t i;
-       bool is_unique = true;
-
-       for (i = 0; i < tc->stream_classes->len; i++) {
-               const struct bt_stream_class *sc =
-                       tc->stream_classes->pdata[i];
-
-               if (sc->id == id) {
-                       is_unique = false;
-                       goto end;
-               }
-       }
-
-end:
-       return is_unique;
-}
-
-static
-struct bt_stream_class *create_stream_class_with_id(
-               struct bt_trace_class *tc, uint64_t id)
-{
-       struct bt_stream_class *stream_class = NULL;
-       int ret;
-
-       BT_ASSERT(tc);
-       BT_ASSERT_PRE(stream_class_id_is_unique(tc, id),
-               "Duplicate stream class ID: %![tc-]+T, id=%" PRIu64, tc, id);
-       BT_LIB_LOGD("Creating stream class object: %![tc-]+T, id=%" PRIu64,
-               tc, id);
-       stream_class = g_new0(struct bt_stream_class, 1);
-       if (!stream_class) {
-               BT_LOGE_STR("Failed to allocate one stream class.");
-               goto error;
-       }
-
-       bt_object_init_shared_with_parent(&stream_class->base,
-               destroy_stream_class);
-
-       stream_class->name.str = g_string_new(NULL);
-       if (!stream_class->name.str) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               ret = -1;
-               goto end;
-       }
-
-       stream_class->id = id;
-       stream_class->assigns_automatic_event_class_id = true;
-       stream_class->assigns_automatic_stream_id = true;
-       stream_class->event_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!stream_class->event_classes) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       ret = bt_object_pool_initialize(&stream_class->packet_context_field_pool,
-               (bt_object_pool_new_object_func) bt_field_wrapper_new,
-               (bt_object_pool_destroy_object_func) free_field_wrapper,
-               stream_class);
-       if (ret) {
-               BT_LOGE("Failed to initialize packet context field pool: ret=%d",
-                       ret);
-               goto error;
-       }
-
-       bt_object_set_parent(&stream_class->base, &tc->base);
-       g_ptr_array_add(tc->stream_classes, stream_class);
-       bt_trace_class_freeze(tc);
-       BT_LIB_LOGD("Created stream class object: %!+S", stream_class);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(stream_class);
-
-end:
-       return stream_class;
-}
-
-struct bt_stream_class *bt_stream_class_create(struct bt_trace_class *tc)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE(tc->assigns_automatic_stream_class_id,
-               "Trace class does not automatically assigns stream class IDs: "
-               "%![sc-]+T", tc);
-       return create_stream_class_with_id(tc,
-               (uint64_t) tc->stream_classes->len);
-}
-
-struct bt_stream_class *bt_stream_class_create_with_id(
-               struct bt_trace_class *tc, uint64_t id)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE(!tc->assigns_automatic_stream_class_id,
-               "Trace class automatically assigns stream class IDs: "
-               "%![sc-]+T", tc);
-       return create_stream_class_with_id(tc, id);
-}
-
-struct bt_trace_class *bt_stream_class_borrow_trace_class(
-               struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return bt_stream_class_borrow_trace_class_inline(stream_class);
-}
-
-const struct bt_trace_class *bt_stream_class_borrow_trace_class_const(
-               const struct bt_stream_class *stream_class)
-{
-       return bt_stream_class_borrow_trace_class((void *) stream_class);
-}
-
-const char *bt_stream_class_get_name(const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->name.value;
-}
-
-enum bt_stream_class_status bt_stream_class_set_name(
-               struct bt_stream_class *stream_class,
-               const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       g_string_assign(stream_class->name.str, name);
-       stream_class->name.value = stream_class->name.str->str;
-       BT_LIB_LOGV("Set stream class's name: %!+S", stream_class);
-       return BT_STREAM_CLASS_STATUS_OK;
-}
-
-uint64_t bt_stream_class_get_id(const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->id;
-}
-
-uint64_t bt_stream_class_get_event_class_count(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (uint64_t) stream_class->event_classes->len;
-}
-
-struct bt_event_class *bt_stream_class_borrow_event_class_by_index(
-               struct bt_stream_class *stream_class, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_VALID_INDEX(index, stream_class->event_classes->len);
-       return g_ptr_array_index(stream_class->event_classes, index);
-}
-
-const struct bt_event_class *
-bt_stream_class_borrow_event_class_by_index_const(
-               const struct bt_stream_class *stream_class, uint64_t index)
-{
-       return bt_stream_class_borrow_event_class_by_index(
-               (void *) stream_class, index);
-}
-
-struct bt_event_class *bt_stream_class_borrow_event_class_by_id(
-               struct bt_stream_class *stream_class, uint64_t id)
-{
-       struct bt_event_class *event_class = NULL;
-       uint64_t i;
-
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-
-       for (i = 0; i < stream_class->event_classes->len; i++) {
-               struct bt_event_class *event_class_candidate =
-                       g_ptr_array_index(stream_class->event_classes, i);
-
-               if (event_class_candidate->id == id) {
-                       event_class = event_class_candidate;
-                       goto end;
-               }
-       }
-
-end:
-       return event_class;
-}
-
-const struct bt_event_class *
-bt_stream_class_borrow_event_class_by_id_const(
-               const struct bt_stream_class *stream_class, uint64_t id)
-{
-       return bt_stream_class_borrow_event_class_by_id(
-               (void *) stream_class, id);
-}
-
-const struct bt_field_class *
-bt_stream_class_borrow_packet_context_field_class_const(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->packet_context_fc;
-}
-
-struct bt_field_class *
-bt_stream_class_borrow_packet_context_field_class(
-               struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->packet_context_fc;
-}
-
-enum bt_stream_class_status bt_stream_class_set_packet_context_field_class(
-               struct bt_stream_class *stream_class,
-               struct bt_field_class *field_class)
-{
-       int ret;
-       struct bt_resolve_field_path_context resolve_ctx = {
-               .packet_context = field_class,
-               .event_common_context = NULL,
-               .event_specific_context = NULL,
-               .event_payload = NULL,
-       };
-
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
-               BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Packet context field class is not a structure field class: %!+F",
-               field_class);
-       ret = bt_resolve_field_paths(field_class, &resolve_ctx);
-       if (ret) {
-               /*
-                * This is the only reason for which
-                * bt_resolve_field_paths() can fail: anything else
-                * would be because a precondition is not satisfied.
-                */
-               ret = BT_STREAM_CLASS_STATUS_NOMEM;
-               goto end;
-       }
-
-       bt_field_class_make_part_of_trace_class(field_class);
-       bt_object_put_ref(stream_class->packet_context_fc);
-       stream_class->packet_context_fc = field_class;
-       bt_object_get_no_null_check(stream_class->packet_context_fc);
-       bt_field_class_freeze(field_class);
-       BT_LIB_LOGV("Set stream class's packet context field class: %!+S",
-               stream_class);
-
-end:
-       return ret;
-}
-
-const struct bt_field_class *
-bt_stream_class_borrow_event_common_context_field_class_const(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->event_common_context_fc;
-}
-
-struct bt_field_class *
-bt_stream_class_borrow_event_common_context_field_class(
-               struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->event_common_context_fc;
-}
-
-enum bt_stream_class_status
-bt_stream_class_set_event_common_context_field_class(
-               struct bt_stream_class *stream_class,
-               struct bt_field_class *field_class)
-{
-       int ret;
-       struct bt_resolve_field_path_context resolve_ctx = {
-               .packet_context = NULL,
-               .event_common_context = field_class,
-               .event_specific_context = NULL,
-               .event_payload = NULL,
-       };
-
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
-               BT_FIELD_CLASS_TYPE_STRUCTURE,
-               "Event common context field class is not a structure field class: %!+F",
-               field_class);
-       resolve_ctx.packet_context = stream_class->packet_context_fc;
-       ret = bt_resolve_field_paths(field_class, &resolve_ctx);
-       if (ret) {
-               /*
-                * This is the only reason for which
-                * bt_resolve_field_paths() can fail: anything else
-                * would be because a precondition is not satisfied.
-                */
-               ret = BT_STREAM_CLASS_STATUS_NOMEM;
-               goto end;
-       }
-
-       bt_field_class_make_part_of_trace_class(field_class);
-       bt_object_put_ref(stream_class->event_common_context_fc);
-       stream_class->event_common_context_fc = field_class;
-       bt_object_get_no_null_check(stream_class->event_common_context_fc);
-       bt_field_class_freeze(field_class);
-       BT_LIB_LOGV("Set stream class's event common context field class: %!+S",
-               stream_class);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void _bt_stream_class_freeze(const struct bt_stream_class *stream_class)
-{
-       /* The field classes and default clock class are already frozen */
-       BT_ASSERT(stream_class);
-       BT_LIB_LOGD("Freezing stream class: %!+S", stream_class);
-       ((struct bt_stream_class *) stream_class)->frozen = true;
-}
-
-enum bt_stream_class_status bt_stream_class_set_default_clock_class(
-               struct bt_stream_class *stream_class,
-               struct bt_clock_class *clock_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       bt_object_put_ref(stream_class->default_clock_class);
-       stream_class->default_clock_class = clock_class;
-       bt_object_get_no_null_check(stream_class->default_clock_class);
-       bt_clock_class_freeze(clock_class);
-       BT_LIB_LOGV("Set stream class's default clock class: %!+S",
-               stream_class);
-       return BT_STREAM_CLASS_STATUS_OK;
-}
-
-struct bt_clock_class *bt_stream_class_borrow_default_clock_class(
-               struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->default_clock_class;
-}
-
-const struct bt_clock_class *bt_stream_class_borrow_default_clock_class_const(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return stream_class->default_clock_class;
-}
-
-bt_bool bt_stream_class_assigns_automatic_event_class_id(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (bt_bool) stream_class->assigns_automatic_event_class_id;
-}
-
-void bt_stream_class_set_assigns_automatic_event_class_id(
-               struct bt_stream_class *stream_class,
-               bt_bool value)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       stream_class->assigns_automatic_event_class_id = (bool) value;
-       BT_LIB_LOGV("Set stream class's automatic event class ID "
-               "assignment property: %!+S", stream_class);
-}
-
-bt_bool bt_stream_class_packets_have_beginning_default_clock_snapshot(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (bt_bool) stream_class->packets_have_beginning_default_clock_snapshot;
-}
-
-void bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
-               struct bt_stream_class *stream_class, bt_bool value)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       BT_ASSERT_PRE(!value || stream_class->default_clock_class,
-               "Stream class has no default clock class: %!+S", stream_class);
-       stream_class->packets_have_beginning_default_clock_snapshot =
-               (bool) value;
-       BT_LIB_LOGV("Set stream class's \"packets have default beginning "
-               "clock snapshot\" property: %!+S", stream_class);
-}
-
-bt_bool bt_stream_class_packets_have_end_default_clock_snapshot(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (bt_bool) stream_class->packets_have_end_default_clock_snapshot;
-}
-
-void bt_stream_class_set_packets_have_end_default_clock_snapshot(
-               struct bt_stream_class *stream_class, bt_bool value)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       BT_ASSERT_PRE(!value || stream_class->default_clock_class,
-               "Stream class has no default clock class: %!+S", stream_class);
-       stream_class->packets_have_end_default_clock_snapshot =
-               (bool) value;
-       BT_LIB_LOGV("Set stream class's \"packets have default end "
-               "clock snapshot\" property: %!+S", stream_class);
-}
-
-bt_bool bt_stream_class_assigns_automatic_stream_id(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (bt_bool) stream_class->assigns_automatic_stream_id;
-}
-
-void bt_stream_class_set_supports_discarded_events(
-               struct bt_stream_class *stream_class,
-               bt_bool supports_discarded_events,
-               bt_bool with_default_clock_snapshots)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       BT_ASSERT_PRE(supports_discarded_events ||
-               !with_default_clock_snapshots,
-               "Discarded events cannot have default clock snapshots when "
-               "not supported: %!+S", stream_class);
-       BT_ASSERT_PRE(!with_default_clock_snapshots ||
-               stream_class->default_clock_class,
-               "Stream class has no default clock class: %!+S", stream_class);
-       stream_class->supports_discarded_events =
-               (bool) supports_discarded_events;
-       stream_class->discarded_events_have_default_clock_snapshots =
-               (bool) with_default_clock_snapshots;
-       BT_LIB_LOGV("Set stream class's discarded events support property: "
-               "%!+S", stream_class);
-}
-
-bt_bool bt_stream_class_supports_discarded_events(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (bt_bool) stream_class->supports_discarded_events;
-}
-
-bt_bool bt_stream_class_discarded_events_have_default_clock_snapshots(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (bt_bool) stream_class->discarded_events_have_default_clock_snapshots;
-}
-
-void bt_stream_class_set_supports_discarded_packets(
-               struct bt_stream_class *stream_class,
-               bt_bool supports_discarded_packets,
-               bt_bool with_default_clock_snapshots)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       BT_ASSERT_PRE(supports_discarded_packets ||
-               !with_default_clock_snapshots,
-               "Discarded packets cannot have default clock snapshots when "
-               "not supported: %!+S", stream_class);
-       BT_ASSERT_PRE(!with_default_clock_snapshots ||
-               stream_class->default_clock_class,
-               "Stream class has no default clock class: %!+S", stream_class);
-       stream_class->supports_discarded_packets =
-               (bool) supports_discarded_packets;
-       stream_class->discarded_packets_have_default_clock_snapshots =
-               (bool) with_default_clock_snapshots;
-       BT_LIB_LOGV("Set stream class's discarded packets support property: "
-               "%!+S", stream_class);
-}
-
-bt_bool bt_stream_class_supports_discarded_packets(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (bt_bool) stream_class->supports_discarded_packets;
-}
-
-bt_bool bt_stream_class_discarded_packets_have_default_clock_snapshots(
-               const struct bt_stream_class *stream_class)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       return (bt_bool) stream_class->discarded_packets_have_default_clock_snapshots;
-}
-
-void bt_stream_class_set_assigns_automatic_stream_id(
-               struct bt_stream_class *stream_class,
-               bt_bool value)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
-       stream_class->assigns_automatic_stream_id = (bool) value;
-       BT_LIB_LOGV("Set stream class's automatic stream ID "
-               "assignment property: %!+S", stream_class);
-}
-
-void bt_stream_class_get_ref(const struct bt_stream_class *stream_class)
-{
-       bt_object_get_ref(stream_class);
-}
-
-void bt_stream_class_put_ref(const struct bt_stream_class *stream_class)
-{
-       bt_object_put_ref(stream_class);
-}
diff --git a/lib/trace-ir/stream.c b/lib/trace-ir/stream.c
deleted file mode 100644 (file)
index 3af38f3..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "STREAM"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/stream-const.h>
-#include <babeltrace2/trace-ir/stream.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/stream-class.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/trace.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/trace-ir/packet-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/align-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/property-internal.h>
-#include <inttypes.h>
-#include <unistd.h>
-
-#define BT_ASSERT_PRE_STREAM_HOT(_stream) \
-       BT_ASSERT_PRE_HOT((_stream), "Stream", ": %!+s", (_stream))
-
-static
-void destroy_stream(struct bt_object *obj)
-{
-       struct bt_stream *stream = (void *) obj;
-
-       BT_LIB_LOGD("Destroying stream object: %!+s", stream);
-
-       if (stream->name.str) {
-               g_string_free(stream->name.str, TRUE);
-               stream->name.str = NULL;
-               stream->name.value = NULL;
-       }
-
-       BT_LOGD_STR("Putting stream's class.");
-       bt_object_put_ref(stream->class);
-       bt_object_pool_finalize(&stream->packet_pool);
-       g_free(stream);
-}
-
-static
-void bt_stream_free_packet(struct bt_packet *packet, struct bt_stream *stream)
-{
-       bt_packet_destroy(packet);
-}
-
-BT_ASSERT_PRE_FUNC
-static inline
-bool stream_id_is_unique(struct bt_trace *trace,
-               struct bt_stream_class *stream_class, uint64_t id)
-{
-       uint64_t i;
-       bool is_unique = true;
-
-       for (i = 0; i < trace->streams->len; i++) {
-               struct bt_stream *stream = trace->streams->pdata[i];
-
-               if (stream->class != stream_class) {
-                       continue;
-               }
-
-               if (stream->id == id) {
-                       is_unique = false;
-                       goto end;
-               }
-       }
-
-end:
-       return is_unique;
-}
-
-static
-struct bt_stream *create_stream_with_id(struct bt_stream_class *stream_class,
-               struct bt_trace *trace, uint64_t id)
-{
-       int ret;
-       struct bt_stream *stream;
-
-       BT_ASSERT(stream_class);
-       BT_ASSERT(trace);
-       BT_ASSERT_PRE(trace->class ==
-               bt_stream_class_borrow_trace_class_inline(stream_class),
-               "Trace's class is different from stream class's parent trace class: "
-               "%![sc-]+S, %![trace-]+t", stream_class, trace);
-       BT_ASSERT_PRE(stream_id_is_unique(trace, stream_class, id),
-               "Duplicate stream ID: %![trace-]+t, id=%" PRIu64, trace, id);
-       BT_LIB_LOGD("Creating stream object: %![trace-]+t, id=%" PRIu64,
-               trace, id);
-       stream = g_new0(struct bt_stream, 1);
-       if (!stream) {
-               BT_LOGE_STR("Failed to allocate one stream.");
-               goto error;
-       }
-
-       bt_object_init_shared_with_parent(&stream->base, destroy_stream);
-       stream->name.str = g_string_new(NULL);
-       if (!stream->name.str) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       stream->id = id;
-       ret = bt_object_pool_initialize(&stream->packet_pool,
-               (bt_object_pool_new_object_func) bt_packet_new,
-               (bt_object_pool_destroy_object_func) bt_stream_free_packet,
-               stream);
-       if (ret) {
-               BT_LOGE("Failed to initialize packet pool: ret=%d", ret);
-               goto error;
-       }
-
-       stream->class = stream_class;
-       bt_object_get_no_null_check(stream_class);
-
-       /* bt_trace_add_stream() sets the parent trace, and freezes the trace */
-       bt_trace_add_stream(trace, stream);
-
-       bt_stream_class_freeze(stream_class);
-       BT_LIB_LOGD("Created stream object: %!+s", stream);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(stream);
-
-end:
-       return stream;
-}
-
-struct bt_stream *bt_stream_create(struct bt_stream_class *stream_class,
-               struct bt_trace *trace)
-{
-       uint64_t id;
-
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(stream_class->assigns_automatic_stream_id,
-               "Stream class does not automatically assigns stream IDs: "
-               "%![sc-]+S", stream_class);
-       id = bt_trace_get_automatic_stream_id(trace, stream_class);
-       return create_stream_with_id(stream_class, trace, id);
-}
-
-struct bt_stream *bt_stream_create_with_id(struct bt_stream_class *stream_class,
-               struct bt_trace *trace, uint64_t id)
-{
-       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(!stream_class->assigns_automatic_stream_id,
-               "Stream class automatically assigns stream IDs: "
-               "%![sc-]+S", stream_class);
-       return create_stream_with_id(stream_class, trace, id);
-}
-
-struct bt_stream_class *bt_stream_borrow_class(struct bt_stream *stream)
-{
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       return stream->class;
-}
-
-const struct bt_stream_class *bt_stream_borrow_class_const(
-               const struct bt_stream *stream)
-{
-       return bt_stream_borrow_class((void *) stream);
-}
-
-struct bt_trace *bt_stream_borrow_trace(struct bt_stream *stream)
-{
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       return bt_stream_borrow_trace_inline(stream);
-}
-
-const struct bt_trace *bt_stream_borrow_trace_const(
-               const struct bt_stream *stream)
-{
-       return bt_stream_borrow_trace((void *) stream);
-}
-
-const char *bt_stream_get_name(const struct bt_stream *stream)
-{
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       return stream->name.value;
-}
-
-enum bt_stream_status bt_stream_set_name(struct bt_stream *stream,
-               const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_STREAM_HOT(stream);
-       g_string_assign(stream->name.str, name);
-       stream->name.value = stream->name.str->str;
-       BT_LIB_LOGV("Set stream's name: %!+s", stream);
-       return BT_STREAM_STATUS_OK;
-}
-
-uint64_t bt_stream_get_id(const struct bt_stream *stream)
-{
-       BT_ASSERT_PRE_NON_NULL(stream, "Stream class");
-       return stream->id;
-}
-
-BT_HIDDEN
-void _bt_stream_freeze(const struct bt_stream *stream)
-{
-       BT_ASSERT(stream);
-       BT_LIB_LOGD("Freezing stream: %!+s", stream);
-       ((struct bt_stream *) stream)->frozen = true;
-}
-
-void bt_stream_get_ref(const struct bt_stream *stream)
-{
-       bt_object_get_ref(stream);
-}
-
-void bt_stream_put_ref(const struct bt_stream *stream)
-{
-       bt_object_put_ref(stream);
-}
diff --git a/lib/trace-ir/trace-class.c b/lib/trace-ir/trace-class.c
deleted file mode 100644 (file)
index 51cc669..0000000
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "TRACE"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/trace-class.h>
-#include <babeltrace2/trace-ir/trace-class-const.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/event-internal.h>
-#include <babeltrace2/trace-ir/event-class.h>
-#include <babeltrace2/trace-ir/event-class-internal.h>
-#include <babeltrace2/ctf-writer/functor-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/trace-ir/field-wrapper-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/attributes-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/trace-ir/resolve-field-path-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/value-const.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/glib-internal.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-
-struct bt_trace_class_destruction_listener_elem {
-       bt_trace_class_destruction_listener_func func;
-       void *data;
-};
-
-#define BT_ASSERT_PRE_TRACE_CLASS_HOT(_tc)                             \
-       BT_ASSERT_PRE_HOT((_tc), "Trace class", ": %!+T", (_tc))
-
-static
-void destroy_trace_class(struct bt_object *obj)
-{
-       struct bt_trace_class *tc = (void *) obj;
-
-       BT_LIB_LOGD("Destroying trace class object: %!+T", tc);
-       /*
-        * Call destruction listener functions so that everything else
-        * still exists in the trace class.
-        */
-       if (tc->destruction_listeners) {
-               uint64_t i;
-               BT_LIB_LOGV("Calling trace class destruction listener(s): %!+T", tc);
-
-               /*
-               * The trace class' reference count is 0 if we're here. Increment
-               * it to avoid a double-destroy (possibly infinitely recursive).
-               * This could happen for example if a destruction listener did
-               * bt_object_get_ref() (or anything that causes
-               * bt_object_get_ref() to be called) on the trace class (ref.
-               * count goes from 0 to 1), and then bt_object_put_ref(): the
-               * reference count would go from 1 to 0 again and this function
-               * would be called again.
-               */
-               tc->base.ref_count++;
-
-               /* Call all the trace class destruction listeners */
-               for (i = 0; i < tc->destruction_listeners->len; i++) {
-                       struct bt_trace_class_destruction_listener_elem elem =
-                               g_array_index(tc->destruction_listeners,
-                                               struct bt_trace_class_destruction_listener_elem, i);
-
-                       if (elem.func) {
-                               elem.func(tc, elem.data);
-                       }
-
-                       /*
-                        * The destruction listener should not have kept a
-                        * reference to the trace class.
-                        */
-                       BT_ASSERT_PRE(tc->base.ref_count == 1, "Destruction listener kept a reference to the trace class being destroyed: %![tc-]+T", tc);
-               }
-               g_array_free(tc->destruction_listeners, TRUE);
-               tc->destruction_listeners = NULL;
-       }
-
-       if (tc->environment) {
-               BT_LOGD_STR("Destroying environment attributes.");
-               bt_attributes_destroy(tc->environment);
-               tc->environment = NULL;
-       }
-
-       if (tc->name.str) {
-               g_string_free(tc->name.str, TRUE);
-               tc->name.str = NULL;
-               tc->name.value = NULL;
-       }
-
-       if (tc->stream_classes) {
-               BT_LOGD_STR("Destroying stream classes.");
-               g_ptr_array_free(tc->stream_classes, TRUE);
-               tc->stream_classes = NULL;
-       }
-
-       g_free(tc);
-}
-
-struct bt_trace_class *bt_trace_class_create(bt_self_component *self_comp)
-{
-       struct bt_trace_class *tc = NULL;
-
-       BT_ASSERT_PRE_NON_NULL(self_comp, "Self component");
-       BT_LOGD_STR("Creating default trace class object.");
-       tc = g_new0(struct bt_trace_class, 1);
-       if (!tc) {
-               BT_LOGE_STR("Failed to allocate one trace class.");
-               goto error;
-       }
-
-       bt_object_init_shared_with_parent(&tc->base, destroy_trace_class);
-
-       tc->stream_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!tc->stream_classes) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-
-       tc->name.str = g_string_new(NULL);
-       if (!tc->name.str) {
-               BT_LOGE_STR("Failed to allocate one GString.");
-               goto error;
-       }
-
-       tc->environment = bt_attributes_create();
-       if (!tc->environment) {
-               BT_LOGE_STR("Cannot create empty attributes object.");
-               goto error;
-       }
-
-       tc->destruction_listeners = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_trace_class_destruction_listener_elem));
-       if (!tc->destruction_listeners) {
-               BT_LOGE_STR("Failed to allocate one GArray.");
-               goto error;
-       }
-
-       tc->assigns_automatic_stream_class_id = true;
-       BT_LIB_LOGD("Created trace class object: %!+T", tc);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(tc);
-
-end:
-       return tc;
-}
-
-const char *bt_trace_class_get_name(const struct bt_trace_class *tc)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       return tc->name.value;
-}
-
-enum bt_trace_class_status bt_trace_class_set_name(
-               struct bt_trace_class *tc, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_TRACE_CLASS_HOT(tc);
-       g_string_assign(tc->name.str, name);
-       tc->name.value = tc->name.str->str;
-       BT_LIB_LOGV("Set trace class's name: %!+T", tc);
-       return BT_TRACE_CLASS_STATUS_OK;
-}
-
-bt_uuid bt_trace_class_get_uuid(const struct bt_trace_class *tc)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       return tc->uuid.value;
-}
-
-void bt_trace_class_set_uuid(struct bt_trace_class *tc, bt_uuid uuid)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(uuid, "UUID");
-       BT_ASSERT_PRE_TRACE_CLASS_HOT(tc);
-       memcpy(tc->uuid.uuid, uuid, BABELTRACE_UUID_LEN);
-       tc->uuid.value = tc->uuid.uuid;
-       BT_LIB_LOGV("Set trace class's UUID: %!+T", tc);
-}
-
-enum bt_trace_class_status bt_trace_class_add_destruction_listener(
-               const struct bt_trace_class *_tc,
-               bt_trace_class_destruction_listener_func listener,
-               void *data, uint64_t *listener_id)
-{
-       struct bt_trace_class *tc = (void *) _tc;
-       uint64_t i;
-       struct bt_trace_class_destruction_listener_elem new_elem = {
-               .func = listener,
-               .data = data,
-       };
-
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(listener, "Listener");
-
-       /* Find the next available spot */
-       for (i = 0; i < tc->destruction_listeners->len; i++) {
-               struct bt_trace_class_destruction_listener_elem elem =
-                       g_array_index(tc->destruction_listeners,
-                               struct bt_trace_class_destruction_listener_elem, i);
-
-               if (!elem.func) {
-                       break;
-               }
-       }
-
-       if (i == tc->destruction_listeners->len) {
-               g_array_append_val(tc->destruction_listeners, new_elem);
-       } else {
-               g_array_insert_val(tc->destruction_listeners, i, new_elem);
-       }
-
-       if (listener_id) {
-               *listener_id = i;
-       }
-
-       BT_LIB_LOGV("Added trace class destruction listener: %![tc-]+T, "
-                       "listener-id=%" PRIu64, tc, i);
-       return BT_TRACE_CLASS_STATUS_OK;
-}
-
-BT_ASSERT_PRE_FUNC
-static
-bool has_listener_id(const struct bt_trace_class *tc, uint64_t listener_id)
-{
-       BT_ASSERT(listener_id < tc->destruction_listeners->len);
-       return (&g_array_index(tc->destruction_listeners,
-                       struct bt_trace_class_destruction_listener_elem,
-                       listener_id))->func != NULL;
-}
-
-enum bt_trace_class_status bt_trace_class_remove_destruction_listener(
-               const struct bt_trace_class *_tc, uint64_t listener_id)
-{
-       struct bt_trace_class *tc = (void *) _tc;
-       struct bt_trace_class_destruction_listener_elem *elem;
-
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE(has_listener_id(tc, listener_id),
-               "Trace class has no such trace class destruction listener ID: "
-               "%![tc-]+T, %" PRIu64, tc, listener_id);
-       elem = &g_array_index(tc->destruction_listeners,
-                       struct bt_trace_class_destruction_listener_elem,
-                       listener_id);
-       BT_ASSERT(elem->func);
-
-       elem->func = NULL;
-       elem->data = NULL;
-       BT_LIB_LOGV("Removed trace class destruction listener: "
-               "%![tc-]+T, listener-id=%" PRIu64,
-               tc, listener_id);
-       return BT_TRACE_CLASS_STATUS_OK;
-}
-
-BT_ASSERT_FUNC
-static
-bool trace_has_environment_entry(const struct bt_trace_class *tc, const char *name)
-{
-       BT_ASSERT(tc);
-
-       return bt_attributes_borrow_field_value_by_name(
-               tc->environment, name) != NULL;
-}
-
-static
-enum bt_trace_class_status set_environment_entry(struct bt_trace_class *tc,
-               const char *name, struct bt_value *value)
-{
-       int ret;
-
-       BT_ASSERT(tc);
-       BT_ASSERT(name);
-       BT_ASSERT(value);
-       BT_ASSERT_PRE(!tc->frozen ||
-               !trace_has_environment_entry(tc, name),
-               "Trace class is frozen: cannot replace environment entry: "
-               "%![tc-]+T, entry-name=\"%s\"", tc, name);
-       ret = bt_attributes_set_field_value(tc->environment, name,
-               value);
-       if (ret) {
-               ret = BT_TRACE_CLASS_STATUS_NOMEM;
-               BT_LIB_LOGE("Cannot set trace class's environment entry: "
-                       "%![tc-]+T, entry-name=\"%s\"", tc, name);
-       } else {
-               bt_value_freeze(value);
-               BT_LIB_LOGV("Set trace class's environment entry: "
-                       "%![tc-]+T, entry-name=\"%s\"", tc, name);
-       }
-
-       return ret;
-}
-
-enum bt_trace_class_status bt_trace_class_set_environment_entry_string(
-               struct bt_trace_class *tc, const char *name, const char *value)
-{
-       int ret;
-       struct bt_value *value_obj;
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       value_obj = bt_value_string_create_init(value);
-       if (!value_obj) {
-               BT_LOGE_STR("Cannot create a string value object.");
-               ret = -1;
-               goto end;
-       }
-
-       /* set_environment_entry() logs errors */
-       ret = set_environment_entry(tc, name, value_obj);
-
-end:
-       bt_object_put_ref(value_obj);
-       return ret;
-}
-
-enum bt_trace_class_status bt_trace_class_set_environment_entry_integer(
-               struct bt_trace_class *tc, const char *name, int64_t value)
-{
-       int ret;
-       struct bt_value *value_obj;
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       value_obj = bt_value_signed_integer_create_init(value);
-       if (!value_obj) {
-               BT_LOGE_STR("Cannot create an integer value object.");
-               ret = BT_TRACE_CLASS_STATUS_NOMEM;
-               goto end;
-       }
-
-       /* set_environment_entry() logs errors */
-       ret = set_environment_entry(tc, name, value_obj);
-
-end:
-       bt_object_put_ref(value_obj);
-       return ret;
-}
-
-uint64_t bt_trace_class_get_environment_entry_count(const struct bt_trace_class *tc)
-{
-       int64_t ret;
-
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       ret = bt_attributes_get_count(tc->environment);
-       BT_ASSERT(ret >= 0);
-       return (uint64_t) ret;
-}
-
-void bt_trace_class_borrow_environment_entry_by_index_const(
-               const struct bt_trace_class *tc, uint64_t index,
-               const char **name, const struct bt_value **value)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_NON_NULL(value, "Value");
-       BT_ASSERT_PRE_VALID_INDEX(index,
-               bt_attributes_get_count(tc->environment));
-       *value = bt_attributes_borrow_field_value(tc->environment, index);
-       BT_ASSERT(*value);
-       *name = bt_attributes_get_field_name(tc->environment, index);
-       BT_ASSERT(*name);
-}
-
-const struct bt_value *bt_trace_class_borrow_environment_entry_value_by_name_const(
-               const struct bt_trace_class *tc, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       return bt_attributes_borrow_field_value_by_name(tc->environment,
-               name);
-}
-
-uint64_t bt_trace_class_get_stream_class_count(const struct bt_trace_class *tc)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       return (uint64_t) tc->stream_classes->len;
-}
-
-struct bt_stream_class *bt_trace_class_borrow_stream_class_by_index(
-               struct bt_trace_class *tc, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_VALID_INDEX(index, tc->stream_classes->len);
-       return g_ptr_array_index(tc->stream_classes, index);
-}
-
-const struct bt_stream_class *
-bt_trace_class_borrow_stream_class_by_index_const(
-               const struct bt_trace_class *tc, uint64_t index)
-{
-       return bt_trace_class_borrow_stream_class_by_index(
-               (void *) tc, index);
-}
-
-struct bt_stream_class *bt_trace_class_borrow_stream_class_by_id(
-               struct bt_trace_class *tc, uint64_t id)
-{
-       struct bt_stream_class *stream_class = NULL;
-       uint64_t i;
-
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-
-       for (i = 0; i < tc->stream_classes->len; i++) {
-               struct bt_stream_class *stream_class_candidate =
-                       g_ptr_array_index(tc->stream_classes, i);
-
-               if (stream_class_candidate->id == id) {
-                       stream_class = stream_class_candidate;
-                       goto end;
-               }
-       }
-
-end:
-       return stream_class;
-}
-
-const struct bt_stream_class *
-bt_trace_class_borrow_stream_class_by_id_const(
-               const struct bt_trace_class *tc, uint64_t id)
-{
-       return bt_trace_class_borrow_stream_class_by_id((void *) tc, id);
-}
-
-BT_HIDDEN
-void _bt_trace_class_freeze(const struct bt_trace_class *tc)
-{
-       BT_ASSERT(tc);
-       BT_LIB_LOGD("Freezing trace class: %!+T", tc);
-       ((struct bt_trace_class *) tc)->frozen = true;
-}
-
-bt_bool bt_trace_class_assigns_automatic_stream_class_id(const struct bt_trace_class *tc)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       return (bt_bool) tc->assigns_automatic_stream_class_id;
-}
-
-void bt_trace_class_set_assigns_automatic_stream_class_id(struct bt_trace_class *tc,
-               bt_bool value)
-{
-       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
-       BT_ASSERT_PRE_TRACE_CLASS_HOT(tc);
-       tc->assigns_automatic_stream_class_id = (bool) value;
-       BT_LIB_LOGV("Set trace class's automatic stream class ID "
-               "assignment property: %!+T", tc);
-}
-
-void bt_trace_class_get_ref(const struct bt_trace_class *trace_class)
-{
-       bt_object_get_ref(trace_class);
-}
-
-void bt_trace_class_put_ref(const struct bt_trace_class *trace_class)
-{
-       bt_object_put_ref(trace_class);
-}
diff --git a/lib/trace-ir/trace.c b/lib/trace-ir/trace.c
deleted file mode 100644 (file)
index da8d7d7..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "TRACE"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/trace-ir/trace.h>
-#include <babeltrace2/trace-ir/trace-class-internal.h>
-#include <babeltrace2/trace-ir/trace-const.h>
-#include <babeltrace2/trace-ir/trace-internal.h>
-#include <babeltrace2/trace-ir/clock-class-internal.h>
-#include <babeltrace2/trace-ir/stream-internal.h>
-#include <babeltrace2/trace-ir/stream-class-internal.h>
-#include <babeltrace2/trace-ir/event-internal.h>
-#include <babeltrace2/trace-ir/event-class.h>
-#include <babeltrace2/trace-ir/event-class-internal.h>
-#include <babeltrace2/ctf-writer/functor-internal.h>
-#include <babeltrace2/ctf-writer/clock-internal.h>
-#include <babeltrace2/trace-ir/field-wrapper-internal.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/attributes-internal.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-#include <babeltrace2/trace-ir/resolve-field-path-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/value-const.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/glib-internal.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-
-struct bt_trace_destruction_listener_elem {
-       bt_trace_destruction_listener_func func;
-       void *data;
-};
-
-#define BT_ASSERT_PRE_TRACE_HOT(_trace) \
-       BT_ASSERT_PRE_HOT((_trace), "Trace", ": %!+t", (_trace))
-
-static
-void destroy_trace(struct bt_object *obj)
-{
-       struct bt_trace *trace = (void *) obj;
-
-       BT_LIB_LOGD("Destroying trace object: %!+t", trace);
-
-       /*
-        * Call destruction listener functions so that everything else
-        * still exists in the trace.
-        */
-       if (trace->destruction_listeners) {
-               uint64_t i;
-               BT_LIB_LOGV("Calling trace destruction listener(s): %!+t", trace);
-
-               /*
-               * The trace's reference count is 0 if we're here. Increment
-               * it to avoid a double-destroy (possibly infinitely recursive).
-               * This could happen for example if a destruction listener did
-               * bt_object_get_ref() (or anything that causes
-               * bt_object_get_ref() to be called) on the trace (ref.
-               * count goes from 0 to 1), and then bt_object_put_ref(): the
-               * reference count would go from 1 to 0 again and this function
-               * would be called again.
-               */
-               trace->base.ref_count++;
-
-               /* Call all the trace destruction listeners */
-               for (i = 0; i < trace->destruction_listeners->len; i++) {
-                       struct bt_trace_destruction_listener_elem elem =
-                               g_array_index(trace->destruction_listeners,
-                                               struct bt_trace_destruction_listener_elem, i);
-
-                       if (elem.func) {
-                               elem.func(trace, elem.data);
-                       }
-
-                       /*
-                        * The destruction listener should not have kept a
-                        * reference to the trace.
-                        */
-                       BT_ASSERT_PRE(trace->base.ref_count == 1, "Destruction listener kept a reference to the trace being destroyed: %![trace-]+t", trace);
-               }
-               g_array_free(trace->destruction_listeners, TRUE);
-               trace->destruction_listeners = NULL;
-       }
-
-       if (trace->name.str) {
-               g_string_free(trace->name.str, TRUE);
-               trace->name.str = NULL;
-               trace->name.value = NULL;
-       }
-
-       if (trace->streams) {
-               BT_LOGD_STR("Destroying streams.");
-               g_ptr_array_free(trace->streams, TRUE);
-               trace->streams = NULL;
-       }
-
-       if (trace->stream_classes_stream_count) {
-               g_hash_table_destroy(trace->stream_classes_stream_count);
-               trace->stream_classes_stream_count = NULL;
-       }
-
-       BT_LOGD_STR("Putting trace's class.");
-       bt_object_put_ref(trace->class);
-       trace->class = NULL;
-       g_free(trace);
-}
-
-struct bt_trace *bt_trace_create(struct bt_trace_class *tc)
-{
-       struct bt_trace *trace = NULL;
-
-       BT_LIB_LOGD("Creating trace object: %![tc-]+T", tc);
-       trace = g_new0(struct bt_trace, 1);
-       if (!trace) {
-               BT_LOGE_STR("Failed to allocate one trace.");
-               goto error;
-       }
-
-       bt_object_init_shared(&trace->base, destroy_trace);
-       trace->streams = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) bt_object_try_spec_release);
-       if (!trace->streams) {
-               BT_LOGE_STR("Failed to allocate one GPtrArray.");
-               goto error;
-       }
-
-       trace->stream_classes_stream_count = g_hash_table_new(g_direct_hash,
-               g_direct_equal);
-       if (!trace->stream_classes_stream_count) {
-               BT_LOGE_STR("Failed to allocate one GHashTable.");
-               goto error;
-       }
-
-       trace->name.str = g_string_new(NULL);
-       if (!trace->name.str) {
-               BT_LOGE_STR("Failed to allocate one GString.");
-               goto error;
-       }
-
-       trace->destruction_listeners = g_array_new(FALSE, TRUE,
-               sizeof(struct bt_trace_destruction_listener_elem));
-       if (!trace->destruction_listeners) {
-               BT_LOGE_STR("Failed to allocate one GArray.");
-               goto error;
-       }
-
-       trace->class = tc;
-       bt_object_get_no_null_check(trace->class);
-       BT_LIB_LOGD("Created trace object: %!+t", trace);
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(trace);
-
-end:
-       return trace;
-}
-
-const char *bt_trace_get_name(const struct bt_trace *trace)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->name.value;
-}
-
-enum bt_trace_status bt_trace_set_name(struct bt_trace *trace, const char *name)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE_NON_NULL(name, "Name");
-       BT_ASSERT_PRE_TRACE_HOT(trace);
-       g_string_assign(trace->name.str, name);
-       trace->name.value = trace->name.str->str;
-       BT_LIB_LOGV("Set trace's name: %!+t", trace);
-       return BT_TRACE_STATUS_OK;
-}
-
-uint64_t bt_trace_get_stream_count(const struct bt_trace *trace)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return (uint64_t) trace->streams->len;
-}
-
-struct bt_stream *bt_trace_borrow_stream_by_index(
-               struct bt_trace *trace, uint64_t index)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE_VALID_INDEX(index, trace->streams->len);
-       return g_ptr_array_index(trace->streams, index);
-}
-
-const struct bt_stream *bt_trace_borrow_stream_by_index_const(
-               const struct bt_trace *trace, uint64_t index)
-{
-       return bt_trace_borrow_stream_by_index((void *) trace, index);
-}
-
-struct bt_stream *bt_trace_borrow_stream_by_id(struct bt_trace *trace,
-               uint64_t id)
-{
-       struct bt_stream *stream = NULL;
-       uint64_t i;
-
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-
-       for (i = 0; i < trace->streams->len; i++) {
-               struct bt_stream *stream_candidate =
-                       g_ptr_array_index(trace->streams, i);
-
-               if (stream_candidate->id == id) {
-                       stream = stream_candidate;
-                       goto end;
-               }
-       }
-
-end:
-       return stream;
-}
-
-const struct bt_stream *bt_trace_borrow_stream_by_id_const(
-               const struct bt_trace *trace, uint64_t id)
-{
-       return bt_trace_borrow_stream_by_id((void *) trace, id);
-}
-
-enum bt_trace_status bt_trace_add_destruction_listener(
-               const struct bt_trace *c_trace,
-               bt_trace_destruction_listener_func listener,
-               void *data, uint64_t *listener_id)
-{
-       struct bt_trace *trace = (void *) c_trace;
-       uint64_t i;
-       struct bt_trace_destruction_listener_elem new_elem = {
-               .func = listener,
-               .data = data,
-       };
-
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE_NON_NULL(listener, "Listener");
-
-       /* Find the next available spot */
-       for (i = 0; i < trace->destruction_listeners->len; i++) {
-               struct bt_trace_destruction_listener_elem elem =
-                       g_array_index(trace->destruction_listeners,
-                               struct bt_trace_destruction_listener_elem, i);
-
-               if (!elem.func) {
-                       break;
-               }
-       }
-
-       if (i == trace->destruction_listeners->len) {
-               g_array_append_val(trace->destruction_listeners, new_elem);
-       } else {
-               g_array_insert_val(trace->destruction_listeners, i, new_elem);
-       }
-
-       if (listener_id) {
-               *listener_id = i;
-       }
-
-       BT_LIB_LOGV("Added destruction listener: " "%![trace-]+t, "
-                       "listener-id=%" PRIu64, trace, i);
-       return BT_TRACE_STATUS_OK;
-}
-
-BT_ASSERT_PRE_FUNC
-static
-bool has_listener_id(const struct bt_trace *trace, uint64_t listener_id)
-{
-       BT_ASSERT(listener_id < trace->destruction_listeners->len);
-       return (&g_array_index(trace->destruction_listeners,
-                       struct bt_trace_destruction_listener_elem,
-                       listener_id))->func != NULL;
-}
-
-enum bt_trace_status bt_trace_remove_destruction_listener(
-               const struct bt_trace *c_trace, uint64_t listener_id)
-{
-       struct bt_trace *trace = (void *) c_trace;
-       struct bt_trace_destruction_listener_elem *elem;
-
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       BT_ASSERT_PRE(has_listener_id(trace, listener_id),
-               "Trace has no such trace destruction listener ID: "
-               "%![trace-]+t, %" PRIu64, trace, listener_id);
-       elem = &g_array_index(trace->destruction_listeners,
-                       struct bt_trace_destruction_listener_elem,
-                       listener_id);
-       BT_ASSERT(elem->func);
-
-       elem->func = NULL;
-       elem->data = NULL;
-       BT_LIB_LOGV("Removed \"trace destruction listener: "
-               "%![trace-]+t, listener-id=%" PRIu64,
-               trace, listener_id);
-       return BT_TRACE_STATUS_OK;
-}
-
-BT_HIDDEN
-void _bt_trace_freeze(const struct bt_trace *trace)
-{
-       BT_ASSERT(trace);
-       BT_LIB_LOGD("Freezing trace's class: %!+T", trace->class);
-       bt_trace_class_freeze(trace->class);
-       BT_LIB_LOGD("Freezing trace: %!+t", trace);
-       ((struct bt_trace *) trace)->frozen = true;
-}
-
-BT_HIDDEN
-void bt_trace_add_stream(struct bt_trace *trace, struct bt_stream *stream)
-{
-       guint count = 0;
-
-       bt_object_set_parent(&stream->base, &trace->base);
-       g_ptr_array_add(trace->streams, stream);
-       bt_trace_freeze(trace);
-
-       if (bt_g_hash_table_contains(trace->stream_classes_stream_count,
-                       stream->class)) {
-               count = GPOINTER_TO_UINT(g_hash_table_lookup(
-                       trace->stream_classes_stream_count, stream->class));
-       }
-
-       g_hash_table_insert(trace->stream_classes_stream_count,
-               stream->class, GUINT_TO_POINTER(count + 1));
-}
-
-BT_HIDDEN
-uint64_t bt_trace_get_automatic_stream_id(const struct bt_trace *trace,
-               const struct bt_stream_class *stream_class)
-{
-       gpointer orig_key;
-       gpointer value;
-       uint64_t id = 0;
-
-       BT_ASSERT(stream_class);
-       BT_ASSERT(trace);
-       if (g_hash_table_lookup_extended(trace->stream_classes_stream_count,
-                       stream_class, &orig_key, &value)) {
-               id = (uint64_t) GPOINTER_TO_UINT(value);
-       }
-
-       return id;
-}
-
-struct bt_trace_class *bt_trace_borrow_class(struct bt_trace *trace)
-{
-       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
-       return trace->class;
-}
-
-const struct bt_trace_class *bt_trace_borrow_class_const(
-               const struct bt_trace *trace)
-{
-       return bt_trace_borrow_class((void *) trace);
-}
-
-void bt_trace_get_ref(const struct bt_trace *trace)
-{
-       bt_object_get_ref(trace);
-}
-
-void bt_trace_put_ref(const struct bt_trace *trace)
-{
-       bt_object_put_ref(trace);
-}
diff --git a/lib/trace-ir/utils.c b/lib/trace-ir/utils.c
deleted file mode 100644 (file)
index 355cb77..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "TRACE-IR-UTILS"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <stdlib.h>
-#include <glib.h>
-#include <babeltrace2/trace-ir/field-class-internal.h>
-#include <babeltrace2/trace-ir/clock-class.h>
-#include <babeltrace2/assert-internal.h>
diff --git a/lib/util.c b/lib/util.c
deleted file mode 100644 (file)
index 82456dc..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "UTIL"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <babeltrace2/assert-pre-internal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <string.h>
-#include <inttypes.h>
-#include <babeltrace2/util.h>
-#include <babeltrace2/trace-ir/utils-internal.h>
-
-bt_util_status bt_util_clock_cycles_to_ns_from_origin(uint64_t cycles,
-               uint64_t frequency, int64_t offset_seconds,
-               uint64_t offset_cycles, int64_t *ns)
-{
-       bool overflows;
-       int64_t base_offset_ns;
-       bt_util_status status = BT_UTIL_STATUS_OK;
-       int ret;
-
-       BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds (output)");
-       BT_ASSERT_PRE(frequency != UINT64_C(-1) && frequency != 0,
-               "Invalid frequency: freq=%" PRIu64, frequency);
-       BT_ASSERT_PRE(offset_cycles < frequency,
-               "Offset (cycles) is greater than frequency: "
-               "offset-cycles=%" PRIu64 ", freq=%" PRIu64,
-               offset_cycles, frequency);
-
-       overflows = bt_util_get_base_offset_ns(offset_seconds, offset_cycles,
-               frequency, &base_offset_ns);
-       if (overflows) {
-               status = BT_UTIL_STATUS_OVERFLOW;
-               goto end;
-       }
-
-       ret = bt_util_ns_from_origin_inline(base_offset_ns,
-               offset_seconds, offset_cycles,
-               frequency, cycles, ns);
-       if (ret) {
-               status = BT_UTIL_STATUS_OVERFLOW;
-       }
-
-end:
-       return status;
-}
diff --git a/lib/value.c b/lib/value.c
deleted file mode 100644 (file)
index 6ec7497..0000000
+++ /dev/null
@@ -1,1369 +0,0 @@
-/*
- * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "VALUES"
-#include <babeltrace2/lib-logging-internal.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <string.h>
-#include <inttypes.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/value-const.h>
-#include <babeltrace2/value.h>
-#include <babeltrace2/compat/glib-internal.h>
-#include <babeltrace2/types.h>
-#include <babeltrace2/assert-pre-internal.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/assert-internal.h>
-
-#define BT_VALUE_TO_BOOL(_base) ((struct bt_value_bool *) (_base))
-#define BT_VALUE_TO_INTEGER(_base) ((struct bt_value_integer *) (_base))
-#define BT_VALUE_TO_REAL(_base) ((struct bt_value_real *) (_base))
-#define BT_VALUE_TO_STRING(_base) ((struct bt_value_string *) (_base))
-#define BT_VALUE_TO_ARRAY(_base) ((struct bt_value_array *) (_base))
-#define BT_VALUE_TO_MAP(_base) ((struct bt_value_map *) (_base))
-
-#define BT_ASSERT_PRE_VALUE_IS_TYPE(_value, _type)                     \
-       BT_ASSERT_PRE(((struct bt_value *) (_value))->type == (_type),  \
-               "Value has the wrong type ID: expected-type=%s, "       \
-               "%![value-]+v", bt_common_value_type_string(_type),     \
-               (_value))
-
-#define BT_ASSERT_PRE_VALUE_HOT(_value, _name)                         \
-       BT_ASSERT_PRE_HOT(((struct bt_value *) (_value)), (_name),      \
-               ": %!+v", (_value))
-
-#define BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count)            \
-       BT_ASSERT_PRE((_index) < (_count),                              \
-               "Index is out of bound: "                               \
-               "index=%" PRIu64 ", count=%u", (_index), (_count));
-
-static
-void bt_value_null_instance_release_func(struct bt_object *obj)
-{
-       BT_LOGW("Releasing the null value singleton: addr=%p", obj);
-}
-
-static
-struct bt_value bt_value_null_instance = {
-       .base = {
-               .is_shared = true,
-               .ref_count = 1,
-               .release_func = bt_value_null_instance_release_func,
-               .spec_release_func = NULL,
-               .parent_is_owner_listener_func = NULL,
-               .parent = NULL,
-       },
-       .type = BT_VALUE_TYPE_NULL,
-       .frozen = BT_TRUE,
-};
-
-struct bt_value *const bt_value_null = &bt_value_null_instance;
-
-static
-void bt_value_destroy(struct bt_object *obj);
-
-static
-void bt_value_string_destroy(struct bt_value *object)
-{
-       g_string_free(BT_VALUE_TO_STRING(object)->gstr, TRUE);
-       BT_VALUE_TO_STRING(object)->gstr = NULL;
-}
-
-static
-void bt_value_array_destroy(struct bt_value *object)
-{
-       /*
-        * Pointer array's registered value destructor will take care
-        * of putting each contained object.
-        */
-       g_ptr_array_free(BT_VALUE_TO_ARRAY(object)->garray, TRUE);
-       BT_VALUE_TO_ARRAY(object)->garray = NULL;
-}
-
-static
-void bt_value_map_destroy(struct bt_value *object)
-{
-       /*
-        * Hash table's registered value destructor will take care of
-        * putting each contained object. Keys are GQuarks and cannot
-        * be destroyed anyway.
-        */
-       g_hash_table_destroy(BT_VALUE_TO_MAP(object)->ght);
-       BT_VALUE_TO_MAP(object)->ght = NULL;
-}
-
-static
-void (* const destroy_funcs[])(struct bt_value *) = {
-       [BT_VALUE_TYPE_NULL] =                  NULL,
-       [BT_VALUE_TYPE_BOOL] =                  NULL,
-       [BT_VALUE_TYPE_UNSIGNED_INTEGER] =      NULL,
-       [BT_VALUE_TYPE_SIGNED_INTEGER] =        NULL,
-       [BT_VALUE_TYPE_REAL] =                  NULL,
-       [BT_VALUE_TYPE_STRING] =                bt_value_string_destroy,
-       [BT_VALUE_TYPE_ARRAY] =                 bt_value_array_destroy,
-       [BT_VALUE_TYPE_MAP] =                   bt_value_map_destroy,
-};
-
-static
-struct bt_value *bt_value_null_copy(const struct bt_value *null_obj)
-{
-       return (void *) bt_value_null;
-}
-
-static
-struct bt_value *bt_value_bool_copy(const struct bt_value *bool_obj)
-{
-       return bt_value_bool_create_init(
-               BT_VALUE_TO_BOOL(bool_obj)->value);
-}
-
-static inline
-struct bt_value *bt_value_integer_create_init(enum bt_value_type type,
-               uint64_t uval);
-
-static
-struct bt_value *bt_value_integer_copy(
-               const struct bt_value *integer_obj)
-{
-       return bt_value_integer_create_init(integer_obj->type,
-               BT_VALUE_TO_INTEGER(integer_obj)->value.u);
-}
-
-static
-struct bt_value *bt_value_real_copy(const struct bt_value *real_obj)
-{
-       return bt_value_real_create_init(
-               BT_VALUE_TO_REAL(real_obj)->value);
-}
-
-static
-struct bt_value *bt_value_string_copy(const struct bt_value *string_obj)
-{
-       return bt_value_string_create_init(
-               BT_VALUE_TO_STRING(string_obj)->gstr->str);
-}
-
-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;
-}
-
-static
-struct bt_value *(* const copy_funcs[])(const struct bt_value *) = {
-       [BT_VALUE_TYPE_NULL] =                  bt_value_null_copy,
-       [BT_VALUE_TYPE_BOOL] =                  bt_value_bool_copy,
-       [BT_VALUE_TYPE_UNSIGNED_INTEGER] =      bt_value_integer_copy,
-       [BT_VALUE_TYPE_SIGNED_INTEGER] =        bt_value_integer_copy,
-       [BT_VALUE_TYPE_REAL] =                  bt_value_real_copy,
-       [BT_VALUE_TYPE_STRING] =                bt_value_string_copy,
-       [BT_VALUE_TYPE_ARRAY] =                 bt_value_array_copy,
-       [BT_VALUE_TYPE_MAP] =                   bt_value_map_copy,
-};
-
-static
-bt_bool bt_value_null_compare(const struct bt_value *object_a,
-               const struct bt_value *object_b)
-{
-       /*
-        * Always BT_TRUE since bt_value_compare() already checks if both
-        * object_a and object_b have the same type, and in the case of
-        * null value objects, they're always the same if it is so.
-        */
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_value_bool_compare(const struct bt_value *object_a,
-               const struct bt_value *object_b)
-{
-       if (BT_VALUE_TO_BOOL(object_a)->value !=
-                       BT_VALUE_TO_BOOL(object_b)->value) {
-               BT_LOGV("Boolean value objects are different: "
-                       "bool-a-val=%d, bool-b-val=%d",
-                       BT_VALUE_TO_BOOL(object_a)->value,
-                       BT_VALUE_TO_BOOL(object_b)->value);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_value_integer_compare(const struct bt_value *object_a,
-               const struct bt_value *object_b)
-{
-       if (BT_VALUE_TO_INTEGER(object_a)->value.u !=
-                       BT_VALUE_TO_INTEGER(object_b)->value.u) {
-               if (object_a->type == BT_VALUE_TYPE_UNSIGNED_INTEGER) {
-                       BT_LOGV("Unsigned integer value objects are different: "
-                               "int-a-val=%" PRIu64 ", int-b-val=%" PRIu64,
-                               BT_VALUE_TO_INTEGER(object_a)->value.u,
-                               BT_VALUE_TO_INTEGER(object_b)->value.u);
-               } else {
-                       BT_LOGV("Signed integer value objects are different: "
-                               "int-a-val=%" PRId64 ", int-b-val=%" PRId64,
-                               BT_VALUE_TO_INTEGER(object_a)->value.i,
-                               BT_VALUE_TO_INTEGER(object_b)->value.i);
-               }
-
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_value_real_compare(const struct bt_value *object_a,
-               const struct bt_value *object_b)
-{
-       if (BT_VALUE_TO_REAL(object_a)->value !=
-                       BT_VALUE_TO_REAL(object_b)->value) {
-               BT_LOGV("Real number value objects are different: "
-                       "real-a-val=%f, real-b-val=%f",
-                       BT_VALUE_TO_REAL(object_a)->value,
-                       BT_VALUE_TO_REAL(object_b)->value);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_value_string_compare(const struct bt_value *object_a,
-               const struct bt_value *object_b)
-{
-       if (strcmp(BT_VALUE_TO_STRING(object_a)->gstr->str,
-                       BT_VALUE_TO_STRING(object_b)->gstr->str) != 0) {
-               BT_LOGV("String value objects are different: "
-                       "string-a-val=\"%s\", string-b-val=\"%s\"",
-                       BT_VALUE_TO_STRING(object_a)->gstr->str,
-                       BT_VALUE_TO_STRING(object_b)->gstr->str);
-               return BT_FALSE;
-       }
-
-       return BT_TRUE;
-}
-
-static
-bt_bool bt_value_array_compare(const struct bt_value *object_a,
-               const struct bt_value *object_b)
-{
-       int i;
-       bt_bool ret = BT_TRUE;
-       const struct bt_value_array *array_obj_a =
-               BT_VALUE_TO_ARRAY(object_a);
-
-       if (bt_value_array_get_size(object_a) !=
-                       bt_value_array_get_size(object_b)) {
-               BT_LOGV("Array values are different: size mismatch "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
-                       object_a, object_b,
-                       bt_value_array_get_size(object_a),
-                       bt_value_array_get_size(object_b));
-               ret = BT_FALSE;
-               goto end;
-       }
-
-       for (i = 0; i < array_obj_a->garray->len; ++i) {
-               const struct bt_value *element_obj_a;
-               const struct bt_value *element_obj_b;
-
-               element_obj_a = bt_value_array_borrow_element_by_index_const(
-                       object_a, i);
-               element_obj_b = bt_value_array_borrow_element_by_index_const(
-                       object_b, i);
-
-               if (!bt_value_compare(element_obj_a, element_obj_b)) {
-                       BT_LOGV("Array values's elements are different: "
-                               "value-a-addr=%p, value-b-addr=%p, index=%d",
-                               element_obj_a, element_obj_b, i);
-                       ret = BT_FALSE;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_bool bt_value_map_compare(const struct bt_value *object_a,
-               const struct bt_value *object_b)
-{
-       bt_bool ret = BT_TRUE;
-       GHashTableIter iter;
-       gpointer key, element_obj_a;
-       const struct bt_value_map *map_obj_a = BT_VALUE_TO_MAP(object_a);
-
-       if (bt_value_map_get_size(object_a) !=
-                       bt_value_map_get_size(object_b)) {
-               BT_LOGV("Map values are different: size mismatch "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
-                       object_a, object_b,
-                       bt_value_map_get_size(object_a),
-                       bt_value_map_get_size(object_b));
-               ret = BT_FALSE;
-               goto end;
-       }
-
-       g_hash_table_iter_init(&iter, map_obj_a->ght);
-
-       while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) {
-               const struct bt_value *element_obj_b;
-               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
-
-               element_obj_b = bt_value_map_borrow_entry_value_const(object_b,
-                       key_str);
-
-               if (!bt_value_compare(element_obj_a, element_obj_b)) {
-                       BT_LOGV("Map values's elements are different: "
-                               "value-a-addr=%p, value-b-addr=%p, key=\"%s\"",
-                               element_obj_a, element_obj_b, key_str);
-                       ret = BT_FALSE;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-bt_bool (* const compare_funcs[])(const struct bt_value *,
-               const struct bt_value *) = {
-       [BT_VALUE_TYPE_NULL] =                  bt_value_null_compare,
-       [BT_VALUE_TYPE_BOOL] =                  bt_value_bool_compare,
-       [BT_VALUE_TYPE_UNSIGNED_INTEGER] =      bt_value_integer_compare,
-       [BT_VALUE_TYPE_SIGNED_INTEGER] =        bt_value_integer_compare,
-       [BT_VALUE_TYPE_REAL] =                  bt_value_real_compare,
-       [BT_VALUE_TYPE_STRING] =                bt_value_string_compare,
-       [BT_VALUE_TYPE_ARRAY] =                 bt_value_array_compare,
-       [BT_VALUE_TYPE_MAP] =                   bt_value_map_compare,
-};
-
-static
-void bt_value_null_freeze(struct bt_value *object)
-{
-}
-
-static
-void bt_value_generic_freeze(struct bt_value *object)
-{
-       object->frozen = BT_TRUE;
-}
-
-static
-void bt_value_array_freeze(struct bt_value *object)
-{
-       int i;
-       struct bt_value_array *typed_array_obj =
-               BT_VALUE_TO_ARRAY(object);
-
-       for (i = 0; i < typed_array_obj->garray->len; ++i) {
-               bt_value_freeze(g_ptr_array_index(typed_array_obj->garray, i));
-       }
-
-       bt_value_generic_freeze(object);
-}
-
-static
-void bt_value_map_freeze(struct bt_value *object)
-{
-       GHashTableIter iter;
-       gpointer key, element_obj;
-       const struct bt_value_map *map_obj = BT_VALUE_TO_MAP(object);
-
-       g_hash_table_iter_init(&iter, map_obj->ght);
-
-       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
-               bt_value_freeze(element_obj);
-       }
-
-       bt_value_generic_freeze(object);
-}
-
-static
-void (* const freeze_funcs[])(struct bt_value *) = {
-       [BT_VALUE_TYPE_NULL] =                  bt_value_null_freeze,
-       [BT_VALUE_TYPE_BOOL] =                  bt_value_generic_freeze,
-       [BT_VALUE_TYPE_UNSIGNED_INTEGER] =      bt_value_generic_freeze,
-       [BT_VALUE_TYPE_SIGNED_INTEGER] =        bt_value_generic_freeze,
-       [BT_VALUE_TYPE_REAL] =                  bt_value_generic_freeze,
-       [BT_VALUE_TYPE_STRING] =                bt_value_generic_freeze,
-       [BT_VALUE_TYPE_ARRAY] =                 bt_value_array_freeze,
-       [BT_VALUE_TYPE_MAP] =                   bt_value_map_freeze,
-};
-
-static
-void bt_value_destroy(struct bt_object *obj)
-{
-       struct bt_value *value;
-
-       value = container_of(obj, struct bt_value, base);
-       BT_LOGD("Destroying value: addr=%p", value);
-
-       if (bt_value_is_null(value)) {
-               BT_LOGD_STR("Not destroying the null value singleton.");
-               return;
-       }
-
-       if (destroy_funcs[value->type]) {
-               destroy_funcs[value->type](value);
-       }
-
-       g_free(value);
-}
-
-BT_HIDDEN
-enum bt_value_status _bt_value_freeze(const struct bt_value *c_object)
-{
-       const struct bt_value *object = (void *) c_object;
-       enum bt_value_status ret = BT_VALUE_STATUS_OK;
-
-       BT_ASSERT(object);
-
-       if (object->frozen) {
-               goto end;
-       }
-
-       BT_LOGD("Freezing value: addr=%p", object);
-       freeze_funcs[object->type]((void *) object);
-
-end:
-       return ret;
-}
-
-enum bt_value_type bt_value_get_type(const struct bt_value *object)
-{
-       BT_ASSERT_PRE_NON_NULL(object, "Value object");
-       return object->type;
-}
-
-static
-struct bt_value bt_value_create_base(enum bt_value_type type)
-{
-       struct bt_value value;
-
-       value.type = type;
-       value.frozen = BT_FALSE;
-       bt_object_init_shared(&value.base, bt_value_destroy);
-       return value;
-}
-
-struct bt_value *bt_value_bool_create_init(bt_bool val)
-{
-       struct bt_value_bool *bool_obj;
-
-       BT_LOGD("Creating boolean value object: val=%d", val);
-       bool_obj = g_new0(struct bt_value_bool, 1);
-       if (!bool_obj) {
-               BT_LOGE_STR("Failed to allocate one boolean value object.");
-               goto end;
-       }
-
-       bool_obj->base = bt_value_create_base(BT_VALUE_TYPE_BOOL);
-       bool_obj->value = val;
-       BT_LOGD("Created boolean value object: addr=%p", bool_obj);
-
-end:
-       return (void *) bool_obj;
-}
-
-struct bt_value *bt_value_bool_create(void)
-{
-       return bt_value_bool_create_init(BT_FALSE);
-}
-
-static inline
-struct bt_value *bt_value_integer_create_init(enum bt_value_type type,
-               uint64_t uval)
-{
-       struct bt_value_integer *integer_obj;
-
-       BT_ASSERT(type == BT_VALUE_TYPE_UNSIGNED_INTEGER ||
-               type == BT_VALUE_TYPE_SIGNED_INTEGER);
-
-       if (type == BT_VALUE_TYPE_UNSIGNED_INTEGER) {
-               BT_LOGD("Creating unsigned integer value object: val=%" PRIu64,
-                       uval);
-       } else {
-               BT_LOGD("Creating signed integer value object: val=%" PRId64,
-                       (int64_t) uval);
-       }
-
-       integer_obj = g_new0(struct bt_value_integer, 1);
-       if (!integer_obj) {
-               BT_LOGE_STR("Failed to allocate one integer value object.");
-               goto end;
-       }
-
-       integer_obj->base = bt_value_create_base(type);
-       integer_obj->value.u = uval;
-       BT_LOGD("Created %ssigned integer value object: addr=%p",
-               type == BT_VALUE_TYPE_UNSIGNED_INTEGER ? "un" : "",
-               integer_obj);
-
-end:
-       return (void *) integer_obj;
-}
-
-struct bt_value *bt_value_unsigned_integer_create_init(uint64_t val)
-{
-       return bt_value_integer_create_init(BT_VALUE_TYPE_UNSIGNED_INTEGER,
-               val);
-}
-
-struct bt_value *bt_value_unsigned_integer_create(void)
-{
-       return bt_value_unsigned_integer_create_init(0);
-}
-
-struct bt_value *bt_value_signed_integer_create_init(int64_t val)
-{
-       return bt_value_integer_create_init(BT_VALUE_TYPE_SIGNED_INTEGER,
-               (uint64_t) val);
-}
-
-struct bt_value *bt_value_signed_integer_create(void)
-{
-       return bt_value_signed_integer_create_init(0);
-}
-
-struct bt_value *bt_value_real_create_init(double val)
-{
-       struct bt_value_real *real_obj;
-
-       BT_LOGD("Creating real number value object: val=%f", val);
-       real_obj = g_new0(struct bt_value_real, 1);
-       if (!real_obj) {
-               BT_LOGE_STR("Failed to allocate one real number value object.");
-               goto end;
-       }
-
-       real_obj->base = bt_value_create_base(BT_VALUE_TYPE_REAL);
-       real_obj->value = val;
-       BT_LOGD("Created real number value object: addr=%p",
-               real_obj);
-
-end:
-       return (void *) real_obj;
-}
-
-struct bt_value *bt_value_real_create(void)
-{
-       return bt_value_real_create_init(0.);
-}
-
-struct bt_value *bt_value_string_create_init(const char *val)
-{
-       struct bt_value_string *string_obj = NULL;
-
-       if (!val) {
-               BT_LOGW_STR("Invalid parameter: value is NULL.");
-               goto end;
-       }
-
-       BT_LOGD("Creating string value object: val-len=%zu", strlen(val));
-       string_obj = g_new0(struct bt_value_string, 1);
-       if (!string_obj) {
-               BT_LOGE_STR("Failed to allocate one string object.");
-               goto end;
-       }
-
-       string_obj->base = bt_value_create_base(BT_VALUE_TYPE_STRING);
-       string_obj->gstr = g_string_new(val);
-       if (!string_obj->gstr) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               g_free(string_obj);
-               string_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created string value object: addr=%p",
-               string_obj);
-
-end:
-       return (void *) string_obj;
-}
-
-struct bt_value *bt_value_string_create(void)
-{
-       return bt_value_string_create_init("");
-}
-
-struct bt_value *bt_value_array_create(void)
-{
-       struct bt_value_array *array_obj;
-
-       BT_LOGD_STR("Creating empty array value object.");
-       array_obj = g_new0(struct bt_value_array, 1);
-       if (!array_obj) {
-               BT_LOGE_STR("Failed to allocate one array object.");
-               goto end;
-       }
-
-       array_obj->base = bt_value_create_base(BT_VALUE_TYPE_ARRAY);
-       array_obj->garray = bt_g_ptr_array_new_full(0,
-               (GDestroyNotify) bt_object_put_ref);
-       if (!array_obj->garray) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               g_free(array_obj);
-               array_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created array value object: addr=%p",
-               array_obj);
-
-end:
-       return (void *) array_obj;
-}
-
-struct bt_value *bt_value_map_create(void)
-{
-       struct bt_value_map *map_obj;
-
-       BT_LOGD_STR("Creating empty map value object.");
-       map_obj = g_new0(struct bt_value_map, 1);
-       if (!map_obj) {
-               BT_LOGE_STR("Failed to allocate one map object.");
-               goto end;
-       }
-
-       map_obj->base = bt_value_create_base(BT_VALUE_TYPE_MAP);
-       map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-               NULL, (GDestroyNotify) bt_object_put_ref);
-       if (!map_obj->ght) {
-               BT_LOGE_STR("Failed to allocate a GHashTable.");
-               g_free(map_obj);
-               map_obj = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created map value object: addr=%p",
-               map_obj);
-
-end:
-       return (void *) map_obj;
-}
-
-bt_bool bt_value_bool_get(const struct bt_value *bool_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_VALUE_TYPE_BOOL);
-       return BT_VALUE_TO_BOOL(bool_obj)->value;
-}
-
-void bt_value_bool_set(struct bt_value *bool_obj, bt_bool val)
-{
-       BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_VALUE_TYPE_BOOL);
-       BT_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object");
-       BT_VALUE_TO_BOOL(bool_obj)->value = val;
-       BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d",
-               bool_obj, val);
-}
-
-uint64_t bt_value_unsigned_integer_get(const struct bt_value *integer_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj,
-               BT_VALUE_TYPE_UNSIGNED_INTEGER);
-       return BT_VALUE_TO_INTEGER(integer_obj)->value.u;
-}
-
-int64_t bt_value_signed_integer_get(const struct bt_value *integer_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj,
-               BT_VALUE_TYPE_SIGNED_INTEGER);
-       return BT_VALUE_TO_INTEGER(integer_obj)->value.i;
-}
-
-static inline
-void bt_value_integer_set(struct bt_value *integer_obj,
-               enum bt_value_type expected_type, uint64_t uval)
-{
-       BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, expected_type);
-       BT_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object");
-       BT_VALUE_TO_INTEGER(integer_obj)->value.u = uval;
-}
-
-void bt_value_unsigned_integer_set(struct bt_value *integer_obj,
-               uint64_t val)
-{
-       bt_value_integer_set(integer_obj, BT_VALUE_TYPE_UNSIGNED_INTEGER, val);
-       BT_LOGV("Set unsigned integer value's raw value: "
-               "value-addr=%p, value=%" PRIu64, integer_obj, val);
-}
-
-void bt_value_signed_integer_set(struct bt_value *integer_obj,
-               int64_t val)
-{
-       bt_value_integer_set(integer_obj, BT_VALUE_TYPE_SIGNED_INTEGER,
-               (uint64_t) val);
-       BT_LOGV("Set signed integer value's raw value: "
-               "value-addr=%p, value=%" PRId64, integer_obj, val);
-}
-
-double bt_value_real_get(const struct bt_value *real_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(real_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_VALUE_TYPE_REAL);
-       return BT_VALUE_TO_REAL(real_obj)->value;
-}
-
-void bt_value_real_set(struct bt_value *real_obj, double val)
-{
-       BT_ASSERT_PRE_NON_NULL(real_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_VALUE_TYPE_REAL);
-       BT_ASSERT_PRE_VALUE_HOT(real_obj, "Value object");
-       BT_VALUE_TO_REAL(real_obj)->value = val;
-       BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f",
-               real_obj, val);
-}
-
-const char *bt_value_string_get(const struct bt_value *string_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(string_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_VALUE_TYPE_STRING);
-       return BT_VALUE_TO_STRING(string_obj)->gstr->str;
-}
-
-enum bt_value_status bt_value_string_set(
-               struct bt_value *string_obj, const char *val)
-{
-       BT_ASSERT_PRE_NON_NULL(string_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_VALUE_TYPE_STRING);
-       BT_ASSERT_PRE_VALUE_HOT(string_obj, "Value object");
-       g_string_assign(BT_VALUE_TO_STRING(string_obj)->gstr, val);
-       BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p",
-               string_obj, val);
-       return BT_VALUE_STATUS_OK;
-}
-
-uint64_t bt_value_array_get_size(const struct bt_value *array_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(array_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
-       return (uint64_t) BT_VALUE_TO_ARRAY(array_obj)->garray->len;
-}
-
-struct bt_value *bt_value_array_borrow_element_by_index(
-               struct bt_value *array_obj, uint64_t index)
-{
-       struct bt_value_array *typed_array_obj =
-               BT_VALUE_TO_ARRAY(array_obj);
-
-       BT_ASSERT_PRE_NON_NULL(array_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
-       BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
-               typed_array_obj->garray->len);
-       return g_ptr_array_index(typed_array_obj->garray, index);
-}
-
-const struct bt_value *bt_value_array_borrow_element_by_index_const(
-               const struct bt_value *array_obj,
-               uint64_t index)
-{
-       return bt_value_array_borrow_element_by_index(
-               (void *) array_obj, index);
-}
-
-enum bt_value_status bt_value_array_append_element(
-               struct bt_value *array_obj,
-               struct bt_value *element_obj)
-{
-       struct bt_value_array *typed_array_obj =
-               BT_VALUE_TO_ARRAY(array_obj);
-
-       BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
-       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
-       BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
-       g_ptr_array_add(typed_array_obj->garray, element_obj);
-       bt_object_get_ref(element_obj);
-       BT_LOGV("Appended element to array value: array-value-addr=%p, "
-               "element-value-addr=%p, new-size=%u",
-               array_obj, element_obj, typed_array_obj->garray->len);
-       return BT_VALUE_STATUS_OK;
-}
-
-enum bt_value_status bt_value_array_append_bool_element(
-               struct bt_value *array_obj, bt_bool val)
-{
-       enum bt_value_status ret;
-       struct bt_value *bool_obj = NULL;
-
-       bool_obj = bt_value_bool_create_init(val);
-       ret = bt_value_array_append_element(array_obj,
-               (void *) bool_obj);
-       bt_object_put_ref(bool_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_array_append_unsigned_integer_element(
-               struct bt_value *array_obj, uint64_t val)
-{
-       enum bt_value_status ret;
-       struct bt_value *integer_obj = NULL;
-
-       integer_obj = bt_value_unsigned_integer_create_init(val);
-       ret = bt_value_array_append_element(array_obj,
-               (void *) integer_obj);
-       bt_object_put_ref(integer_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_array_append_signed_integer_element(
-               struct bt_value *array_obj, int64_t val)
-{
-       enum bt_value_status ret;
-       struct bt_value *integer_obj = NULL;
-
-       integer_obj = bt_value_signed_integer_create_init(val);
-       ret = bt_value_array_append_element(array_obj,
-               (void *) integer_obj);
-       bt_object_put_ref(integer_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_array_append_real_element(
-               struct bt_value *array_obj, double val)
-{
-       enum bt_value_status ret;
-       struct bt_value *real_obj = NULL;
-
-       real_obj = bt_value_real_create_init(val);
-       ret = bt_value_array_append_element(array_obj,
-               (void *) real_obj);
-       bt_object_put_ref(real_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_array_append_string_element(
-               struct bt_value *array_obj, const char *val)
-{
-       enum bt_value_status ret;
-       struct bt_value *string_obj = NULL;
-
-       string_obj = bt_value_string_create_init(val);
-       ret = bt_value_array_append_element(array_obj,
-               (void *) string_obj);
-       bt_object_put_ref(string_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_array_append_empty_array_element(
-               struct bt_value *array_obj)
-{
-       enum bt_value_status ret;
-       struct bt_value *empty_array_obj = NULL;
-
-       empty_array_obj = bt_value_array_create();
-       ret = bt_value_array_append_element(array_obj,
-               (void *) empty_array_obj);
-       bt_object_put_ref(empty_array_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_array_append_empty_map_element(
-               struct bt_value *array_obj)
-{
-       enum bt_value_status ret;
-       struct bt_value *map_obj = NULL;
-
-       map_obj = bt_value_map_create();
-       ret = bt_value_array_append_element(array_obj,
-               (void *) map_obj);
-       bt_object_put_ref(map_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_array_set_element_by_index(
-               struct bt_value *array_obj, uint64_t index,
-               struct bt_value *element_obj)
-{
-       struct bt_value_array *typed_array_obj =
-               BT_VALUE_TO_ARRAY(array_obj);
-
-       BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
-       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
-       BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
-       BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
-               typed_array_obj->garray->len);
-       bt_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index));
-       g_ptr_array_index(typed_array_obj->garray, index) = element_obj;
-       bt_object_get_ref(element_obj);
-       BT_LOGV("Set array value's element: array-value-addr=%p, "
-               "index=%" PRIu64 ", element-value-addr=%p",
-               array_obj, index, element_obj);
-       return BT_VALUE_STATUS_OK;
-}
-
-uint64_t bt_value_map_get_size(const struct bt_value *map_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
-       return (uint64_t) g_hash_table_size(BT_VALUE_TO_MAP(map_obj)->ght);
-}
-
-struct bt_value *bt_value_map_borrow_entry_value(struct bt_value *map_obj,
-               const char *key)
-{
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
-       return g_hash_table_lookup(BT_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)));
-}
-
-const struct bt_value *bt_value_map_borrow_entry_value_const(
-               const struct bt_value *map_obj, const char *key)
-{
-       return bt_value_map_borrow_entry_value((void *) map_obj, key);
-}
-
-bt_bool bt_value_map_has_entry(const struct bt_value *map_obj, const char *key)
-{
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
-       return bt_g_hash_table_contains(BT_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)));
-}
-
-enum bt_value_status bt_value_map_insert_entry(
-               struct bt_value *map_obj,
-               const char *key, struct bt_value *element_obj)
-{
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Map value object");
-       BT_ASSERT_PRE_NON_NULL(key, "Key");
-       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
-       BT_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object");
-       g_hash_table_insert(BT_VALUE_TO_MAP(map_obj)->ght,
-               GUINT_TO_POINTER(g_quark_from_string(key)), element_obj);
-       bt_object_get_ref(element_obj);
-       BT_LOGV("Inserted value into map value: map-value-addr=%p, "
-               "key=\"%s\", element-value-addr=%p",
-               map_obj, key, element_obj);
-       return BT_VALUE_STATUS_OK;
-}
-
-enum bt_value_status bt_value_map_insert_bool_entry(
-               struct bt_value *map_obj, const char *key, bt_bool val)
-{
-       enum bt_value_status ret;
-       struct bt_value *bool_obj = NULL;
-
-       bool_obj = bt_value_bool_create_init(val);
-       ret = bt_value_map_insert_entry(map_obj, key,
-               (void *) bool_obj);
-       bt_object_put_ref(bool_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_map_insert_unsigned_integer_entry(
-               struct bt_value *map_obj, const char *key, uint64_t val)
-{
-       enum bt_value_status ret;
-       struct bt_value *integer_obj = NULL;
-
-       integer_obj = bt_value_unsigned_integer_create_init(val);
-       ret = bt_value_map_insert_entry(map_obj, key,
-               (void *) integer_obj);
-       bt_object_put_ref(integer_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_map_insert_signed_integer_entry(
-               struct bt_value *map_obj, const char *key, int64_t val)
-{
-       enum bt_value_status ret;
-       struct bt_value *integer_obj = NULL;
-
-       integer_obj = bt_value_signed_integer_create_init(val);
-       ret = bt_value_map_insert_entry(map_obj, key,
-               (void *) integer_obj);
-       bt_object_put_ref(integer_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_map_insert_real_entry(
-               struct bt_value *map_obj, const char *key, double val)
-{
-       enum bt_value_status ret;
-       struct bt_value *real_obj = NULL;
-
-       real_obj = bt_value_real_create_init(val);
-       ret = bt_value_map_insert_entry(map_obj, key,
-               (void *) real_obj);
-       bt_object_put_ref(real_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_map_insert_string_entry(
-               struct bt_value *map_obj, const char *key,
-               const char *val)
-{
-       enum bt_value_status ret;
-       struct bt_value *string_obj = NULL;
-
-       string_obj = bt_value_string_create_init(val);
-       ret = bt_value_map_insert_entry(map_obj, key,
-               (void *) string_obj);
-       bt_object_put_ref(string_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_map_insert_empty_array_entry(
-               struct bt_value *map_obj, const char *key)
-{
-       enum bt_value_status ret;
-       struct bt_value *array_obj = NULL;
-
-       array_obj = bt_value_array_create();
-       ret = bt_value_map_insert_entry(map_obj, key,
-               (void *) array_obj);
-       bt_object_put_ref(array_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_map_insert_empty_map_entry(
-               struct bt_value *map_obj, const char *key)
-{
-       enum bt_value_status ret;
-       struct bt_value *empty_map_obj = NULL;
-
-       empty_map_obj = bt_value_map_create();
-       ret = bt_value_map_insert_entry(map_obj, key,
-               (void *) empty_map_obj);
-       bt_object_put_ref(empty_map_obj);
-       return ret;
-}
-
-enum bt_value_status bt_value_map_foreach_entry(struct bt_value *map_obj,
-               bt_value_map_foreach_entry_func func, void *data)
-{
-       enum bt_value_status ret = BT_VALUE_STATUS_OK;
-       gpointer key, element_obj;
-       GHashTableIter iter;
-       struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj);
-
-       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
-       BT_ASSERT_PRE_NON_NULL(func, "Callback");
-       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
-       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));
-
-               if (!func(key_str, element_obj, data)) {
-                       BT_LOGV("User canceled the loop: key=\"%s\", "
-                               "value-addr=%p, data=%p",
-                               key_str, element_obj, data);
-                       ret = BT_VALUE_STATUS_CANCELED;
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-enum bt_value_status bt_value_map_foreach_entry_const(
-               const struct bt_value *map_obj,
-               bt_value_map_foreach_entry_const_func func, void *data)
-{
-       return bt_value_map_foreach_entry((void *) map_obj,
-               (bt_value_map_foreach_entry_func) func, data);
-}
-
-struct extend_map_element_data {
-       struct bt_value *extended_obj;
-       enum bt_value_status status;
-};
-
-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;
-}
-
-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;
-}
-
-enum bt_value_status bt_value_copy(const struct bt_value *object,
-               struct bt_value **copy_obj)
-{
-       enum bt_value_status status = BT_VALUE_STATUS_OK;
-
-       BT_ASSERT_PRE_NON_NULL(object, "Value object");
-       BT_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)");
-       BT_LOGD("Copying value object: addr=%p", object);
-       *copy_obj = copy_funcs[object->type](object);
-       if (*copy_obj) {
-               BT_LOGD("Copied value object: copy-value-addr=%p",
-                       copy_obj);
-       } else {
-               status = BT_VALUE_STATUS_NOMEM;
-               *copy_obj = NULL;
-               BT_LOGE_STR("Failed to copy value object.");
-       }
-
-       return status;
-}
-
-bt_bool bt_value_compare(const struct bt_value *object_a,
-       const struct bt_value *object_b)
-{
-       bt_bool ret = BT_FALSE;
-
-       BT_ASSERT_PRE_NON_NULL(object_a, "Value object A");
-       BT_ASSERT_PRE_NON_NULL(object_b, "Value object B");
-
-       if (object_a->type != object_b->type) {
-               BT_LOGV("Values are different: type mismatch: "
-                       "value-a-addr=%p, value-b-addr=%p, "
-                       "value-a-type=%s, value-b-type=%s",
-                       object_a, object_b,
-                       bt_common_value_type_string(object_a->type),
-                       bt_common_value_type_string(object_b->type));
-               goto end;
-       }
-
-       ret = compare_funcs[object_a->type](object_a, object_b);
-
-end:
-       return ret;
-}
-
-void bt_value_get_ref(const struct bt_value *value)
-{
-       bt_object_get_ref(value);
-}
-
-void bt_value_put_ref(const struct bt_value *value)
-{
-       bt_object_put_ref(value);
-}
diff --git a/logging/LICENSE b/logging/LICENSE
deleted file mode 100644 (file)
index 5569c1d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 wonder-mice
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/logging/Makefile.am b/logging/Makefile.am
deleted file mode 100644 (file)
index 559ea22..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-noinst_LTLIBRARIES = libbabeltrace2-logging.la
-
-libbabeltrace2_logging_la_SOURCES = log.c
diff --git a/logging/log.c b/logging/log.c
deleted file mode 100644 (file)
index a7946ca..0000000
+++ /dev/null
@@ -1,1419 +0,0 @@
-/*
- * This is zf_log.c, modified with Babeltrace prefixes.
- * See <https://github.com/wonder-mice/zf_log/>.
- * See LICENSE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <pthread.h>
-#include <assert.h>
-
-#ifdef __CYGWIN__
-extern unsigned long pthread_getsequence_np(pthread_t *);
-#endif
-
-/* When defined, Android log (android/log.h) will be used by default instead of
- * stderr (ignored on non-Android platforms). Date, time, pid and tid (context)
- * will be provided by Android log. Android log features will be used to output
- * log level and tag.
- */
-#ifdef BT_LOG_USE_ANDROID_LOG
-       #undef BT_LOG_USE_ANDROID_LOG
-       #if defined(__ANDROID__)
-               #define BT_LOG_USE_ANDROID_LOG 1
-       #else
-               #define BT_LOG_USE_ANDROID_LOG 0
-       #endif
-#else
-       #define BT_LOG_USE_ANDROID_LOG 0
-#endif
-/* When defined, NSLog (uses Apple System Log) will be used instead of stderr
- * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be
- * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on
- * non-public CFLog() function. Both use Apple System Log internally, but it's
- * easier to call CFLog() from C than NSLog(). Current implementation doesn't
- * support "%@" format specifier.
- */
-#ifdef BT_LOG_USE_NSLOG
-       #undef BT_LOG_USE_NSLOG
-       #if defined(__APPLE__) && defined(__MACH__)
-               #define BT_LOG_USE_NSLOG 1
-       #else
-               #define BT_LOG_USE_NSLOG 0
-       #endif
-#else
-       #define BT_LOG_USE_NSLOG 0
-#endif
-/* When defined, OutputDebugString() will be used instead of stderr (ignored on
- * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with
- * UTF-8 data.
- */
-#ifdef BT_LOG_USE_DEBUGSTRING
-       #undef BT_LOG_USE_DEBUGSTRING
-       #if defined(_WIN32) || defined(_WIN64)
-               #define BT_LOG_USE_DEBUGSTRING 1
-       #else
-               #define BT_LOG_USE_DEBUGSTRING 0
-       #endif
-#else
-       #define BT_LOG_USE_DEBUGSTRING 0
-#endif
-/* When defined, bt_log library will not contain definition of tag prefix
- * variable. In that case it must be defined elsewhere using
- * BT_LOG_DEFINE_TAG_PREFIX macro, for example:
- *
- *   BT_LOG_DEFINE_TAG_PREFIX = "ProcessName";
- *
- * This allows to specify custom value for static initialization and avoid
- * overhead of setting this value in runtime.
- */
-#ifdef BT_LOG_EXTERN_TAG_PREFIX
-       #undef BT_LOG_EXTERN_TAG_PREFIX
-       #define BT_LOG_EXTERN_TAG_PREFIX 1
-#else
-       #define BT_LOG_EXTERN_TAG_PREFIX 0
-#endif
-/* When defined, bt_log library will not contain definition of global format
- * variable. In that case it must be defined elsewhere using
- * BT_LOG_DEFINE_GLOBAL_FORMAT macro, for example:
- *
- *   BT_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH};
- *
- * This allows to specify custom value for static initialization and avoid
- * overhead of setting this value in runtime.
- */
-#ifdef BT_LOG_EXTERN_GLOBAL_FORMAT
-       #undef BT_LOG_EXTERN_GLOBAL_FORMAT
-       #define BT_LOG_EXTERN_GLOBAL_FORMAT 1
-#else
-       #define BT_LOG_EXTERN_GLOBAL_FORMAT 0
-#endif
-/* When defined, bt_log library will not contain definition of global output
- * variable. In that case it must be defined elsewhere using
- * BT_LOG_DEFINE_GLOBAL_OUTPUT macro, for example:
- *
- *   BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_PUT_STD, custom_output_callback};
- *
- * This allows to specify custom value for static initialization and avoid
- * overhead of setting this value in runtime.
- */
-#ifdef BT_LOG_EXTERN_GLOBAL_OUTPUT
-       #undef BT_LOG_EXTERN_GLOBAL_OUTPUT
-       #define BT_LOG_EXTERN_GLOBAL_OUTPUT 1
-#else
-       #define BT_LOG_EXTERN_GLOBAL_OUTPUT 0
-#endif
-/* When defined, bt_log library will not contain definition of global output
- * level variable. In that case it must be defined elsewhere using
- * BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example:
- *
- *   BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = BT_LOG_WARN;
- *
- * This allows to specify custom value for static initialization and avoid
- * overhead of setting this value in runtime.
- */
-#ifdef BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
-       #undef BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
-       #define BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1
-#else
-       #define BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0
-#endif
-/* When defined, implementation will prefer smaller code size over speed.
- * Very rough estimate is that code will be up to 2x smaller and up to 2x
- * slower. Disabled by default.
- */
-#ifdef BT_LOG_OPTIMIZE_SIZE
-       #undef BT_LOG_OPTIMIZE_SIZE
-       #define BT_LOG_OPTIMIZE_SIZE 1
-#else
-       #define BT_LOG_OPTIMIZE_SIZE 0
-#endif
-/* Size of the log line buffer. The buffer is a globally allocated per thread.
- */
-#ifndef BT_LOG_BUF_SZ
-       #define BT_LOG_BUF_SZ (4 * 4096)
-#endif
-/* Default number of bytes in one line of memory output. For large values
- * BT_LOG_BUF_SZ also must be increased.
- */
-#ifndef BT_LOG_MEM_WIDTH
-       #define BT_LOG_MEM_WIDTH 32
-#endif
-/* String to put in the end of each log line (can be empty). Its value used by
- * stderr output callback. Its size used as a default value for BT_LOG_EOL_SZ.
- */
-#ifndef BT_LOG_EOL
-       #define BT_LOG_EOL "\n"
-#endif
-/* Default delimiter that separates parts of log message. Can NOT contain '%'
- * or '\0'.
- *
- * Log message format specifications can override (or ignore) this value. For
- * more details see BT_LOG_MESSAGE_CTX_FORMAT, BT_LOG_MESSAGE_SRC_FORMAT and
- * BT_LOG_MESSAGE_TAG_FORMAT.
- */
-#ifndef BT_LOG_DEF_DELIMITER
-       #define BT_LOG_DEF_DELIMITER " "
-#endif
-/* Specifies log message context format. Log message context includes date,
- * time, process id, thread id and message's log level. Custom information can
- * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,
- * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements),
- * F_UINT(width, value).
- *
- * Must be defined as a tuple, for example:
- *
- *   #define BT_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY, S(" > "))
- *
- * In that case, resulting log message will be:
- *
- *   2016.12.22 > TAG function@filename.c:line Message text
- *
- * Note, that tag, source location and message text are not impacted by
- * this setting. See BT_LOG_MESSAGE_TAG_FORMAT and BT_LOG_MESSAGE_SRC_FORMAT.
- *
- * If message context must be visually separated from the rest of the message,
- * it must be reflected in context format (notice trailing S(" > ") in the
- * example above).
- *
- * S(str) adds constant string str. String can NOT contain '%' or '\0'.
- *
- * F_INIT(statements) adds initialization statement(s) that will be evaluated
- * once for each log message. All statements are evaluated in specified order.
- * Several F_INIT() fields can be used in every log message format
- * specification. Fields, like F_UINT(width, value), are allowed to use results
- * of initialization statements. If statement introduces variables (or other
- * names, like structures) they must be prefixed with "f_". Statements  must be
- * enclosed into additional "()". Example:
- *
- *   #define BT_LOG_MESSAGE_CTX_FORMAT \
- *       (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \
- *        YEAR, S("."), MONTH, S("."), DAY, S(" "), \
- *        F_UINT(5, f_ru.ru_nsignals), \
- *        S(" "))
- *
- * F_UINT(width, value) adds unsigned integer value extended with up to width
- * spaces (for alignment purposes). Value can be any expression that evaluates
- * to unsigned integer. If expression contains non-standard functions, they
- * must be declared with F_INIT(). Example:
- *
- *   #define BT_LOG_MESSAGE_CTX_FORMAT \
- *        (YEAR, S("."), MONTH, S("."), DAY, S(" "), \
- *        F_INIT(( unsigned tickcount(); )), \
- *        F_UINT(5, tickcount()), \
- *        S(" "))
- *
- * Other log message format specifications follow same rules, but have a
- * different set of supported fields.
- */
-#ifndef BT_LOG_MESSAGE_CTX_FORMAT
-       #define BT_LOG_MESSAGE_CTX_FORMAT \
-               (MONTH, S("-"), DAY, S(BT_LOG_DEF_DELIMITER), \
-                HOUR, S(":"), MINUTE, S(":"), SECOND, S("."), MILLISECOND, S(BT_LOG_DEF_DELIMITER), \
-                PID, S(BT_LOG_DEF_DELIMITER), TID, S(BT_LOG_DEF_DELIMITER), \
-                LEVEL, S(BT_LOG_DEF_DELIMITER))
-#endif
-/* Example:
- */
-/* Specifies log message tag format. It includes tag prefix and tag. Custom
- * information can be added as well. Supported fields:
- * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements),
- * F_UINT(width, value).
- *
- * TAG(prefix_delimiter, tag_delimiter) adds following string to log message:
- *
- *   PREFIX<prefix_delimiter>TAG<tag_delimiter>
- *
- * Prefix delimiter will be used only when prefix is not empty. Tag delimiter
- * will be used only when prefixed tag is not empty. Example:
- *
- *   #define BT_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] "))
- *
- * See BT_LOG_MESSAGE_CTX_FORMAT for details.
- */
-#ifndef BT_LOG_MESSAGE_TAG_FORMAT
-       #define BT_LOG_MESSAGE_TAG_FORMAT \
-               (TAG(".", BT_LOG_DEF_DELIMITER))
-#endif
-/* Specifies log message source location format. It includes function name,
- * file name and file line. Custom information can be added as well. Supported
- * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements),
- * F_UINT(width, value).
- *
- * See BT_LOG_MESSAGE_CTX_FORMAT for details.
- */
-#ifndef BT_LOG_MESSAGE_SRC_FORMAT
-       #define BT_LOG_MESSAGE_SRC_FORMAT \
-               (FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(BT_LOG_DEF_DELIMITER))
-#endif
-/* Fields that can be used in log message format specifications (see above).
- * Mentioning them here explicitly, so we know that nobody else defined them
- * before us. See BT_LOG_MESSAGE_CTX_FORMAT for details.
- */
-#define YEAR YEAR
-#define MONTH MONTH
-#define DAY DAY
-#define MINUTE MINUTE
-#define SECOND SECOND
-#define MILLISECOND MILLISECOND
-#define PID PID
-#define TID TID
-#define LEVEL LEVEL
-#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim)
-#define FUNCTION FUNCTION
-#define FILENAME FILENAME
-#define FILELINE FILELINE
-#define S(str) S(str)
-#define F_INIT(statements) F_INIT(statements)
-#define F_UINT(width, value) F_UINT(width, value)
-/* Number of bytes to reserve for EOL in the log line buffer (must be >0).
- * Must be larger than or equal to length of BT_LOG_EOL with terminating null.
- */
-#ifndef BT_LOG_EOL_SZ
-       #define BT_LOG_EOL_SZ sizeof(BT_LOG_EOL)
-#endif
-/* Compile instrumented version of the library to facilitate unit testing.
- */
-#ifndef BT_LOG_INSTRUMENTED
-       #define BT_LOG_INSTRUMENTED 0
-#endif
-
-#if defined(__linux__)
-       #if !defined(__ANDROID__) && !defined(_GNU_SOURCE)
-               #define _GNU_SOURCE
-       #endif
-#endif
-#if defined(__MINGW32__)
-       #ifdef __STRICT_ANSI__
-               #undef __STRICT_ANSI__
-       #endif
-#endif
-#include <babeltrace2/assert-internal.h>
-#include <ctype.h>
-#include <string.h>
-#include <time.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#define BT_LOG_OUTPUT_LEVEL dummy
-
-#include <babeltrace2/logging-internal.h>
-#include <babeltrace2/logging.h>
-
-#if defined(_WIN32) || defined(_WIN64)
-       #include <windows.h>
-#else
-       #include <unistd.h>
-       #include <sys/time.h>
-       #if defined(__linux__)
-               #include <linux/limits.h>
-       #elif (defined(__sun__) || defined(__CYGWIN__))
-               /* Solaris and Cygwin have no sys/syslimits.h */
-       #else
-               #include <sys/syslimits.h>
-       #endif
-#endif
-
-#if defined(__linux__)
-       #include <sys/prctl.h>
-       #include <sys/types.h>
-       #if !defined(__ANDROID__)
-               #include <sys/syscall.h>
-       #endif
-#endif
-#if defined(__MACH__)
-       #include <pthread.h>
-#endif
-
-#define INLINE _BT_LOG_INLINE
-#define VAR_UNUSED(var) (void)var
-#define RETVAL_UNUSED(expr) do { while(expr) break; } while(0)
-#define STATIC_ASSERT(name, cond) \
-       typedef char assert_##name[(cond)? 1: -1]
-#define ASSERT_UNREACHABLE(why) assert(!sizeof(why))
-#ifndef _countof
-       #define _countof(xs) (sizeof(xs) / sizeof((xs)[0]))
-#endif
-
-#if BT_LOG_INSTRUMENTED
-       #define INSTRUMENTED_CONST
-#else
-       #define INSTRUMENTED_CONST const
-#endif
-
-#define _PP_PASTE_2(a, b) a ## b
-#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b)
-
-#define _PP_PASTE_3(a, b, c) a ## b ## c
-#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c)
-
-/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__
- * as a single token and requires additional expansion to realize that it's
- * actually a list. If not for it, there would be no need in this extra
- * expansion.
- */
-#define _PP_ID(x) x
-#define _PP_NARGS_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,...) _24
-#define _PP_NARGS(...) _PP_ID(_PP_NARGS_N(__VA_ARGS__,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))
-
-/* There is a more efficient way to implement this, but it requires
- * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't
- * have one.
- */
-#define _PP_HEAD__(x, ...) x
-#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~))
-#define _PP_HEAD(xs) _PP_HEAD_ xs
-#define _PP_TAIL_(x, ...) (__VA_ARGS__)
-#define _PP_TAIL(xs) _PP_TAIL_ xs
-#define _PP_UNTUPLE_(...) __VA_ARGS__
-#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs
-
-/* Apply function macro to each element in tuple. Output is not
- * enforced to be a tuple.
- */
-#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs))
-#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs))
-#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs))
-#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs))
-#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs))
-#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs))
-#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs))
-#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs))
-#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs))
-#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs))
-#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs))
-#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs))
-#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs))
-#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs))
-#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs))
-#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs))
-#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs))
-#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs))
-#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs))
-#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs))
-#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs))
-#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs))
-#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs))
-#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs))
-#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs) (f, xs)
-
-/* Apply function macro to each element in tuple in reverse order.
- * Output is not enforced to be a tuple.
- */
-#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs))
-#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
-#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs) (f, xs)
-
-/* Used to implement _BT_LOG_MESSAGE_FORMAT_CONTAINS() macro. All possible
- * fields must be mentioned here. Not counting F_INIT() here because it's
- * somewhat special and is handled spearatly (at least for now).
- */
-#define _BT_LOG_MESSAGE_FORMAT_MASK__             (0<<0)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__YEAR         (1<<1)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__MONTH        (1<<2)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__DAY          (1<<3)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__HOUR         (1<<4)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__MINUTE       (1<<5)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__SECOND       (1<<6)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__MILLISECOND  (1<<7)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__PID          (1<<8)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__TID          (1<<9)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__LEVEL        (1<<10)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts)  (1<<11)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__FUNCTION     (1<<12)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__FILENAME     (1<<13)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__FILELINE     (1<<14)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__S(s)         (1<<15)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0<<16)
-#define _BT_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1<<17)
-#define _BT_LOG_MESSAGE_FORMAT_MASK(field) \
-       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_MASK_, _, field)
-
-/* Logical "or" of masks of fields used in specified format specification.
- */
-#define _BT_LOG_MESSAGE_FORMAT_FIELDS(format) \
-       (0 _PP_MAP(| _BT_LOG_MESSAGE_FORMAT_MASK, format))
-
-/* Expands to expressions that evaluates to true if field is used in
- * specified format specification. Example:
- *
- *   #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT, BT_LOG_MESSAGE_CTX_FORMAT)
- *       ...
- *   #endif
- */
-#define _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \
-       (_BT_LOG_MESSAGE_FORMAT_MASK(field) & _BT_LOG_MESSAGE_FORMAT_FIELDS(format))
-
-/* Same, but checks all supported format specifications.
- */
-#define _BT_LOG_MESSAGE_FORMAT_FIELD_USED(field) \
-       (_BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_CTX_FORMAT) || \
-        _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_TAG_FORMAT) || \
-        _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_SRC_FORMAT))
-
-#define _BT_LOG_MESSAGE_FORMAT_DATETIME_USED \
-       (_BT_LOG_MESSAGE_FORMAT_CONTAINS(YEAR, BT_LOG_MESSAGE_CTX_FORMAT) || \
-        _BT_LOG_MESSAGE_FORMAT_CONTAINS(MONTH, BT_LOG_MESSAGE_CTX_FORMAT) || \
-        _BT_LOG_MESSAGE_FORMAT_CONTAINS(DAY, BT_LOG_MESSAGE_CTX_FORMAT) || \
-        _BT_LOG_MESSAGE_FORMAT_CONTAINS(HOUR, BT_LOG_MESSAGE_CTX_FORMAT) || \
-        _BT_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE, BT_LOG_MESSAGE_CTX_FORMAT) || \
-        _BT_LOG_MESSAGE_FORMAT_CONTAINS(SECOND, BT_LOG_MESSAGE_CTX_FORMAT) || \
-        _BT_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND, BT_LOG_MESSAGE_CTX_FORMAT))
-
-#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
-       #pragma warning(disable:4204) /* nonstandard extension used: non-constant aggregate initializer */
-       #define memccpy _memccpy
-#endif
-
-#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || \
-               (defined(__MINGW64__) && !defined(__USE_MINGW_ANSI_STDIO))
-       #define vsnprintf(s, sz, fmt, va) fake_vsnprintf(s, sz, fmt, va)
-       static int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap)
-       {
-               const int n = vsnprintf_s(s, sz, _TRUNCATE, fmt, ap);
-               return 0 < n? n: (int)sz + 1; /* no need in _vscprintf() for now */
-       }
-       #if BT_LOG_OPTIMIZE_SIZE
-       #define snprintf(s, sz, ...) fake_snprintf(s, sz, __VA_ARGS__)
-       static int fake_snprintf(char *s, size_t sz, const char *fmt, ...)
-       {
-               va_list va;
-               va_start(va, fmt);
-               const int n = fake_vsnprintf(s, sz, fmt, va);
-               va_end(va);
-               return n;
-       }
-       #endif
-#endif
-
-typedef void (*time_cb)(struct tm *const tm, unsigned *const usec);
-typedef void (*pid_cb)(int *const pid, int *const tid);
-typedef void (*buffer_cb)(bt_log_message *msg, char *buf);
-
-typedef struct src_location
-{
-       const char *const func;
-       const char *const file;
-       const unsigned line;
-}
-src_location;
-
-typedef struct mem_block
-{
-       const void *const d;
-       const unsigned d_sz;
-}
-mem_block;
-
-static void time_callback(struct tm *const tm, unsigned *const usec);
-static void pid_callback(int *const pid, int *const tid);
-static void buffer_callback(bt_log_message *msg, char *buf);
-
-STATIC_ASSERT(eol_fits_eol_sz, sizeof(BT_LOG_EOL) <= BT_LOG_EOL_SZ);
-STATIC_ASSERT(eol_sz_greater_than_zero, 0 < BT_LOG_EOL_SZ);
-STATIC_ASSERT(eol_sz_less_than_buf_sz, BT_LOG_EOL_SZ < BT_LOG_BUF_SZ);
-static const char c_hex[] = "0123456789abcdef";
-
-static __thread char logging_buf[4 * 4096];
-
-static INSTRUMENTED_CONST unsigned g_buf_sz = BT_LOG_BUF_SZ - BT_LOG_EOL_SZ;
-static INSTRUMENTED_CONST time_cb g_time_cb = time_callback;
-static INSTRUMENTED_CONST pid_cb g_pid_cb = pid_callback;
-static INSTRUMENTED_CONST buffer_cb g_buffer_cb = buffer_callback;
-
-#if BT_LOG_USE_ANDROID_LOG
-       #include <android/log.h>
-
-       static INLINE int android_lvl(const int lvl)
-       {
-               switch (lvl)
-               {
-               case BT_LOG_VERBOSE:
-                       return ANDROID_LOG_VERBOSE;
-               case BT_LOG_DEBUG:
-                       return ANDROID_LOG_DEBUG;
-               case BT_LOG_INFO:
-                       return ANDROID_LOG_INFO;
-               case BT_LOG_WARN:
-                       return ANDROID_LOG_WARN;
-               case BT_LOG_ERROR:
-                       return ANDROID_LOG_ERROR;
-               case BT_LOG_FATAL:
-                       return ANDROID_LOG_FATAL;
-               default:
-                       ASSERT_UNREACHABLE("Bad log level");
-                       return ANDROID_LOG_UNKNOWN;
-               }
-       }
-
-       static void out_android_callback(const bt_log_message *const msg, void *arg)
-       {
-               VAR_UNUSED(arg);
-               *msg->p = 0;
-               const char *tag = msg->p;
-               if (msg->tag_e != msg->tag_b)
-               {
-                       tag = msg->tag_b;
-                       *msg->tag_e = 0;
-               }
-               __android_log_print(android_lvl(msg->lvl), tag, "%s", msg->msg_b);
-       }
-
-       enum { OUT_ANDROID_MASK = BT_LOG_PUT_STD & ~BT_LOG_PUT_CTX };
-       #define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback
-#endif
-
-#if BT_LOG_USE_NSLOG
-       #include <CoreFoundation/CoreFoundation.h>
-       CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...);
-
-       static INLINE int apple_lvl(const int lvl)
-       {
-               switch (lvl)
-               {
-               case BT_LOG_VERBOSE:
-                       return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;
-               case BT_LOG_DEBUG:
-                       return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;
-               case BT_LOG_INFO:
-                       return 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */;
-               case BT_LOG_WARN:
-                       return 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */;
-               case BT_LOG_ERROR:
-                       return 3; /* ASL_LEVEL_ERR / kCFLogLevelError */;
-               case BT_LOG_FATAL:
-                       return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;
-               default:
-                       ASSERT_UNREACHABLE("Bad log level");
-                       return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;
-               }
-       }
-
-       static void out_nslog_callback(const bt_log_message *const msg, void *arg)
-       {
-               VAR_UNUSED(arg);
-               *msg->p = 0;
-               CFLog(apple_lvl(msg->lvl), CFSTR("%s"), msg->tag_b);
-       }
-
-       enum { OUT_NSLOG_MASK = BT_LOG_PUT_STD & ~BT_LOG_PUT_CTX };
-       #define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback
-#endif
-
-#if BT_LOG_USE_DEBUGSTRING
-       #include <windows.h>
-
-       static void out_debugstring_callback(const bt_log_message *const msg, void *arg)
-       {
-               VAR_UNUSED(arg);
-               msg->p[0] = '\n';
-               msg->p[1] = '\0';
-               OutputDebugStringA(msg->buf);
-       }
-
-       enum { OUT_DEBUGSTRING_MASK = BT_LOG_PUT_STD };
-       #define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback
-#endif
-
-BT_HIDDEN
-void bt_log_out_stderr_callback(const bt_log_message *const msg, void *arg)
-{
-       VAR_UNUSED(arg);
-       const size_t eol_len = sizeof(BT_LOG_EOL) - 1;
-       memcpy(msg->p, BT_LOG_EOL, eol_len);
-#if defined(_WIN32) || defined(_WIN64)
-       /* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and
-          without FILE_WRITE_DATA */
-       WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg->buf,
-                         (DWORD)(msg->p - msg->buf + eol_len), 0, 0);
-#else
-       /* write() is atomic for buffers less than or equal to PIPE_BUF. */
-       RETVAL_UNUSED(write(STDERR_FILENO, msg->buf,
-                                               (size_t)(msg->p - msg->buf) + eol_len));
-#endif
-}
-
-static const bt_log_output out_stderr = {BT_LOG_OUT_STDERR};
-
-#if !BT_LOG_EXTERN_TAG_PREFIX
-       BT_LOG_DEFINE_TAG_PREFIX = 0;
-#endif
-
-#if !BT_LOG_EXTERN_GLOBAL_FORMAT
-       BT_LOG_DEFINE_GLOBAL_FORMAT = {BT_LOG_MEM_WIDTH};
-#endif
-
-#if !BT_LOG_EXTERN_GLOBAL_OUTPUT
-       #if BT_LOG_USE_ANDROID_LOG
-               BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_ANDROID};
-       #elif BT_LOG_USE_NSLOG
-               BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_NSLOG};
-       #elif BT_LOG_USE_DEBUGSTRING
-               BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_DEBUGSTRING};
-       #else
-               BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_OUT_STDERR};
-       #endif
-#endif
-
-#if !BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
-       BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0;
-#endif
-
-BT_HIDDEN
-const bt_log_spec _bt_log_stderr_spec =
-{
-       BT_LOG_GLOBAL_FORMAT,
-       &out_stderr,
-};
-
-static const bt_log_spec global_spec =
-{
-       BT_LOG_GLOBAL_FORMAT,
-       BT_LOG_GLOBAL_OUTPUT,
-};
-
-#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, BT_LOG_MESSAGE_CTX_FORMAT)
-static char lvl_char(const int lvl)
-{
-       switch (lvl)
-       {
-       case BT_LOG_VERBOSE:
-               return 'V';
-       case BT_LOG_DEBUG:
-               return 'D';
-       case BT_LOG_INFO:
-               return 'I';
-       case BT_LOG_WARN:
-               return 'W';
-       case BT_LOG_ERROR:
-               return 'E';
-       case BT_LOG_FATAL:
-               return 'F';
-       default:
-               ASSERT_UNREACHABLE("Bad log level");
-               return '?';
-       }
-}
-#endif
-
-#define GCCVER_LESS(MAJOR, MINOR, PATCH) \
-       (__GNUC__ < MAJOR || \
-               (__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR || \
-                       (__GNUC_MINOR__ == MINOR && __GNUC_PATCHLEVEL__ < PATCH))))
-
-#if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4,7,0)
-       #define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0)
-       #define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n)
-       #define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n)
-       #define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n)
-       #define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n)
-       /* Note: will not store old value of *vp in *ep (non-standard behaviour) */
-       #define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \
-               __sync_bool_compare_and_swap(vp, *(ep), d)
-#endif
-
-#if !BT_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64)
-#define TCACHE
-#define TCACHE_STALE (0x40000000)
-#define TCACHE_FLUID (0x40000000 | 0x80000000)
-static unsigned g_tcache_mode = TCACHE_STALE;
-static struct timeval g_tcache_tv = {0, 0};
-static struct tm g_tcache_tm = {0};
-
-static INLINE int tcache_get(const struct timeval *const tv, struct tm *const tm)
-{
-       unsigned mode;
-       mode = __atomic_load_n(&g_tcache_mode, __ATOMIC_RELAXED);
-       if (0 == (mode & TCACHE_FLUID))
-       {
-               mode = __atomic_fetch_add(&g_tcache_mode, 1, __ATOMIC_ACQUIRE);
-               if (0 == (mode & TCACHE_FLUID))
-               {
-                       if (g_tcache_tv.tv_sec == tv->tv_sec)
-                       {
-                               *tm = g_tcache_tm;
-                               __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
-                               return !0;
-                       }
-                       __atomic_or_fetch(&g_tcache_mode, TCACHE_STALE, __ATOMIC_RELAXED);
-               }
-               __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
-       }
-       return 0;
-}
-
-static INLINE void tcache_set(const struct timeval *const tv, struct tm *const tm)
-{
-       unsigned stale = TCACHE_STALE;
-       if (__atomic_compare_exchange_n(&g_tcache_mode, &stale, TCACHE_FLUID,
-                                                                       0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
-       {
-               g_tcache_tv = *tv;
-               g_tcache_tm = *tm;
-               __atomic_and_fetch(&g_tcache_mode, ~TCACHE_FLUID, __ATOMIC_RELEASE);
-       }
-}
-#endif
-
-static void time_callback(struct tm *const tm, unsigned *const msec)
-{
-#if !_BT_LOG_MESSAGE_FORMAT_DATETIME_USED
-       VAR_UNUSED(tm);
-       VAR_UNUSED(msec);
-#else
-       #if defined(_WIN32) || defined(_WIN64)
-       SYSTEMTIME st;
-       GetLocalTime(&st);
-       tm->tm_year = st.wYear;
-       tm->tm_mon = st.wMonth;
-       tm->tm_mday = st.wDay;
-       tm->tm_wday = st.wDayOfWeek;
-       tm->tm_hour = st.wHour;
-       tm->tm_min = st.wMinute;
-       tm->tm_sec = st.wSecond;
-       *msec = st.wMilliseconds;
-       #else
-       struct timeval tv;
-       gettimeofday(&tv, 0);
-               #ifndef TCACHE
-               localtime_r(&tv.tv_sec, tm);
-               #else
-               if (!tcache_get(&tv, tm))
-               {
-                       localtime_r(&tv.tv_sec, tm);
-                       tcache_set(&tv, tm);
-               }
-               #endif
-       *msec = (unsigned)tv.tv_usec / 1000;
-       #endif
-#endif
-}
-
-static void pid_callback(int *const pid, int *const tid)
-{
-#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(PID, BT_LOG_MESSAGE_CTX_FORMAT)
-       VAR_UNUSED(pid);
-#else
-       #if defined(_WIN32) || defined(_WIN64)
-       *pid = GetCurrentProcessId();
-       #else
-       *pid = getpid();
-       #endif
-#endif
-
-#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(TID, BT_LOG_MESSAGE_CTX_FORMAT)
-       VAR_UNUSED(tid);
-#else
-       #if defined(_WIN32) || defined(_WIN64)
-       *tid = GetCurrentThreadId();
-       #elif defined(__CYGWIN__)
-       pthread_t thr = pthread_self();
-       *tid = (int)pthread_getsequence_np(&thr);
-       #elif defined(__sun__)
-       *tid = (int)pthread_self();
-       #elif defined(__ANDROID__)
-       *tid = gettid();
-       #elif defined(__linux__)
-       *tid = syscall(SYS_gettid);
-       #elif defined(__MACH__)
-       *tid = (int)pthread_mach_thread_np(pthread_self());
-       #else
-               #define Platform not supported
-       #endif
-#endif
-}
-
-static void buffer_callback(bt_log_message *msg, char *buf)
-{
-       msg->e = (msg->p = msg->buf = buf) + g_buf_sz;
-}
-
-#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, BT_LOG_MESSAGE_SRC_FORMAT)
-static const char *funcname(const char *func)
-{
-       return func? func: "";
-}
-#endif
-
-#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, BT_LOG_MESSAGE_SRC_FORMAT)
-static const char *filename(const char *file)
-{
-       const char *f = file;
-       for (const char *p = file; 0 != *p; ++p)
-       {
-               if ('/' == *p || '\\' == *p)
-               {
-                       f = p + 1;
-               }
-       }
-       return f;
-}
-#endif
-
-static INLINE size_t nprintf_size(bt_log_message *const msg)
-{
-       // *nprintf() always puts 0 in the end when input buffer is not empty. This
-       // 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which
-       // leaves space for one more character. Some put_xxx() functions don't use
-       // *nprintf() and could use that last character. In that case log line will
-       // have multiple (two) half-written parts which is confusing. To workaround
-       // that we allow *nprintf() to write its 0 in the eol area (which is always
-       // not empty).
-       return (size_t)(msg->e - msg->p + 1);
-}
-
-static INLINE void put_nprintf(bt_log_message *const msg, const int n)
-{
-       if (0 < n)
-       {
-               msg->p = n < msg->e - msg->p? msg->p + n: msg->e;
-       }
-}
-
-static INLINE char *put_padding_r(const unsigned w, const char wc,
-                                                                 char *p, char *e)
-{
-       for (char *const b = e - w; b < p; *--p = wc) {}
-       return p;
-}
-
-static char *put_integer_r(unsigned v, const int sign,
-                                                  const unsigned w, const char wc, char *const e)
-{
-       static const char _signs[] = {'-', '0', '+'};
-       const char *const signs = _signs + 1;
-       char *p = e;
-       do { *--p = '0' + v % 10; } while (0 != (v /= 10));
-       if (0 == sign) return put_padding_r(w, wc, p, e);
-       if ('0' != wc)
-       {
-               *--p = signs[sign];
-               return put_padding_r(w, wc, p, e);
-       }
-       p = put_padding_r(w, wc, p, e + 1);
-       *--p = signs[sign];
-       return p;
-}
-
-static INLINE char *put_uint_r(const unsigned v, const unsigned w, const char wc,
-                                                          char *const e)
-{
-       return put_integer_r(v, 0, w, wc, e);
-}
-
-static INLINE char *put_int_r(const int v, const unsigned w, const char wc,
-                                                         char *const e)
-{
-       return 0 <= v? put_integer_r((unsigned)v, 0, w, wc, e)
-                                : put_integer_r((unsigned)-v, -1, w, wc, e);
-}
-
-static INLINE char *put_stringn(const char *const s_p, const char *const s_e,
-                                                               char *const p, char *const e)
-{
-       const ptrdiff_t m = e - p;
-       ptrdiff_t n = s_e - s_p;
-       if (n > m)
-       {
-               n = m;
-       }
-       memcpy(p, s_p, n);
-       return p + n;
-}
-
-static INLINE char *put_string(const char *s, char *p, char *const e)
-{
-       const ptrdiff_t n = e - p;
-       char *const c = (char *)memccpy(p, s, '\0', n);
-       return 0 != c? c - 1: e;
-}
-
-static INLINE char *put_uint(unsigned v, const unsigned w, const char wc,
-                                                        char *const p, char *const e)
-{
-       char buf[16];
-       char *const se = buf + _countof(buf);
-       char *sp = put_uint_r(v, w, wc, se);
-       return put_stringn(sp, se, p, e);
-}
-
-#define PUT_CSTR_R(p, STR) \
-       do { \
-               for (unsigned i = sizeof(STR) - 1; 0 < i--;) { \
-                       *--(p) = (STR)[i]; \
-               } \
-       } _BT_LOG_ONCE
-
-#define PUT_CSTR_CHECKED(p, e, STR) \
-       do { \
-               for (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \
-                       *(p)++ = (STR)[i]; \
-               } \
-       } _BT_LOG_ONCE
-
-/* F_INIT field support.
- */
-#define _BT_LOG_MESSAGE_FORMAT_INIT__
-#define _BT_LOG_MESSAGE_FORMAT_INIT__YEAR
-#define _BT_LOG_MESSAGE_FORMAT_INIT__MONTH
-#define _BT_LOG_MESSAGE_FORMAT_INIT__DAY
-#define _BT_LOG_MESSAGE_FORMAT_INIT__HOUR
-#define _BT_LOG_MESSAGE_FORMAT_INIT__MINUTE
-#define _BT_LOG_MESSAGE_FORMAT_INIT__SECOND
-#define _BT_LOG_MESSAGE_FORMAT_INIT__MILLISECOND
-#define _BT_LOG_MESSAGE_FORMAT_INIT__PID
-#define _BT_LOG_MESSAGE_FORMAT_INIT__TID
-#define _BT_LOG_MESSAGE_FORMAT_INIT__LEVEL
-#define _BT_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts)
-#define _BT_LOG_MESSAGE_FORMAT_INIT__FUNCTION
-#define _BT_LOG_MESSAGE_FORMAT_INIT__FILENAME
-#define _BT_LOG_MESSAGE_FORMAT_INIT__FILELINE
-#define _BT_LOG_MESSAGE_FORMAT_INIT__S(s)
-#define _BT_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr);
-#define _BT_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v)
-#define _BT_LOG_MESSAGE_FORMAT_INIT(field) \
-       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_INIT_, _, field)
-
-/* Implements generation of printf-like format string for log message
- * format specification.
- */
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__             ""
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR         "%04u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH        "%02u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY          "%02u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR         "%02u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE       "%02u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND       "%02u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND  "%03u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID          "%5i"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID          "%5i"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL        "%c"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG          UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION     "%s"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME     "%s"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE     "%u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s)         s
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) ""
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) "%" #w "u"
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \
-       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field)
-
-/* Implements generation of printf-like format parameters for log message
- * format specification.
- */
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR         ,(unsigned)(tm.tm_year + 1900)
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH        ,(unsigned)(tm.tm_mon + 1)
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY          ,(unsigned)tm.tm_mday
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR         ,(unsigned)tm.tm_hour
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE       ,(unsigned)tm.tm_min
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND       ,(unsigned)tm.tm_sec
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND  ,(unsigned)msec
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID          ,pid
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID          ,tid
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL        ,(char)lvl_char(msg->lvl)
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG          UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION     ,funcname(src->func)
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME     ,filename(src->file)
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE     ,src->line
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s)
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr)
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) ,v
-#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \
-       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field)
-
-/* Implements generation of put_xxx_t statements for log message specification.
- */
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__YEAR         p = put_uint_r(tm.tm_year + 1900, 4, '0', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MONTH        p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__DAY          p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__HOUR         p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MINUTE       p = put_uint_r((unsigned)tm.tm_min, 2, '0', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__SECOND       p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND  p = put_uint_r(msec, 3, '0', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__PID          p = put_int_r(pid, 5, ' ', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__TID          p = put_int_r(tid, 5, ' ', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__LEVEL        *--p = lvl_char(msg->lvl);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__TAG          UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION     UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FILENAME     UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FILELINE     UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__S(s)         PUT_CSTR_R(p, s);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr)
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) p = put_uint_r(v, w, ' ', p);
-#define _BT_LOG_MESSAGE_FORMAT_PUT_R(field) \
-       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PUT_R_, _, field)
-
-static void put_ctx(bt_log_message *const msg)
-{
-       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_CTX_FORMAT)
-#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_CTX_FORMAT)
-       VAR_UNUSED(msg);
-#else
-       #if _BT_LOG_MESSAGE_FORMAT_DATETIME_USED
-       struct tm tm;
-       unsigned msec;
-       g_time_cb(&tm, &msec);
-       #endif
-       #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(PID, BT_LOG_MESSAGE_CTX_FORMAT) || \
-               _BT_LOG_MESSAGE_FORMAT_CONTAINS(TID, BT_LOG_MESSAGE_CTX_FORMAT)
-       int pid, tid;
-       g_pid_cb(&pid, &tid);
-       #endif
-
-       #if BT_LOG_OPTIMIZE_SIZE
-       int n;
-       n = snprintf(msg->p, nprintf_size(msg),
-                                _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT, BT_LOG_MESSAGE_CTX_FORMAT)
-                 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL, BT_LOG_MESSAGE_CTX_FORMAT));
-       put_nprintf(msg, n);
-       #else
-       char buf[64];
-       char *const e = buf + sizeof(buf);
-       char *p = e;
-       _PP_RMAP(_BT_LOG_MESSAGE_FORMAT_PUT_R, BT_LOG_MESSAGE_CTX_FORMAT)
-       msg->p = put_stringn(p, e, msg->p, msg->e);
-       #endif
-#endif
-}
-
-#define PUT_TAG(msg, tag, prefix_delim, tag_delim) \
-       do { \
-               const char *ch; \
-               msg->tag_b = msg->p; \
-               if (0 != (ch = _bt_log_tag_prefix)) { \
-                       for (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \
-               } \
-               if (0 != (ch = tag) && 0 != tag[0]) { \
-                       if (msg->tag_b != msg->p) { \
-                               PUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim); \
-                       } \
-                       for (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \
-               } \
-               msg->tag_e = msg->p; \
-               if (msg->tag_b != msg->p) { \
-                       PUT_CSTR_CHECKED(msg->p, msg->e, tag_delim); \
-               } \
-       } _BT_LOG_ONCE
-
-/* Implements simple put statements for log message specification.
- */
-#define _BT_LOG_MESSAGE_FORMAT_PUT__
-#define _BT_LOG_MESSAGE_FORMAT_PUT__YEAR         UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__MONTH        UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__DAY          UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__HOUR         UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__MINUTE       UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__SECOND       UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__MILLISECOND  UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__PID          UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__TID          UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__LEVEL        UNDEFINED
-#define _BT_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td)  PUT_TAG(msg, tag, pd, td);
-#define _BT_LOG_MESSAGE_FORMAT_PUT__FUNCTION     msg->p = put_string(funcname(src->func), msg->p, msg->e);
-#define _BT_LOG_MESSAGE_FORMAT_PUT__FILENAME     msg->p = put_string(filename(src->file), msg->p, msg->e);
-#define _BT_LOG_MESSAGE_FORMAT_PUT__FILELINE     msg->p = put_uint(src->line, 0, '\0', msg->p, msg->e);
-#define _BT_LOG_MESSAGE_FORMAT_PUT__S(s)         PUT_CSTR_CHECKED(msg->p, msg->e, s);
-#define _BT_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr)
-#define _BT_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) msg->p = put_uint(v, w, ' ', msg->p, msg->e);
-#define _BT_LOG_MESSAGE_FORMAT_PUT(field) \
-       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PUT_, _, field)
-
-static void put_tag(bt_log_message *const msg, const char *const tag)
-{
-       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_TAG_FORMAT)
-#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(TAG, BT_LOG_MESSAGE_TAG_FORMAT)
-       VAR_UNUSED(tag);
-#endif
-#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_TAG_FORMAT)
-       VAR_UNUSED(msg);
-#else
-       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PUT, BT_LOG_MESSAGE_TAG_FORMAT)
-#endif
-}
-
-static void put_src(bt_log_message *const msg, const src_location *const src)
-{
-       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_SRC_FORMAT)
-#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, BT_LOG_MESSAGE_SRC_FORMAT) && \
-       !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, BT_LOG_MESSAGE_SRC_FORMAT) && \
-       !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE, BT_LOG_MESSAGE_SRC_FORMAT)
-       VAR_UNUSED(src);
-#endif
-#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_SRC_FORMAT)
-       VAR_UNUSED(msg);
-#else
-       #if BT_LOG_OPTIMIZE_SIZE
-       int n;
-       n = snprintf(msg->p, nprintf_size(msg),
-                                _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT, BT_LOG_MESSAGE_SRC_FORMAT)
-                 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL, BT_LOG_MESSAGE_SRC_FORMAT));
-       put_nprintf(msg, n);
-       #else
-       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PUT, BT_LOG_MESSAGE_SRC_FORMAT)
-       #endif
-#endif
-}
-
-static void put_msg(bt_log_message *const msg,
-                                       const char *const fmt, va_list va)
-{
-       int n;
-       msg->msg_b = msg->p;
-       n = vsnprintf(msg->p, nprintf_size(msg), fmt, va);
-       put_nprintf(msg, n);
-}
-
-static void output_mem(const bt_log_spec *log, bt_log_message *const msg,
-                                          const mem_block *const mem)
-{
-       if (0 == mem->d || 0 == mem->d_sz)
-       {
-               return;
-       }
-       const unsigned char *mem_p = (const unsigned char *)mem->d;
-       const unsigned char *const mem_e = mem_p + mem->d_sz;
-       const unsigned char *mem_cut;
-       const ptrdiff_t mem_width = (ptrdiff_t)log->format->mem_width;
-       char *const hex_b = msg->msg_b;
-       char *const ascii_b = hex_b + 2 * mem_width + 2;
-       char *const ascii_e = ascii_b + mem_width;
-       if (msg->e < ascii_e)
-       {
-               return;
-       }
-       while (mem_p != mem_e)
-       {
-               char *hex = hex_b;
-               char *ascii = ascii_b;
-               for (mem_cut = mem_width < mem_e - mem_p? mem_p + mem_width: mem_e;
-                        mem_cut != mem_p; ++mem_p)
-               {
-                       const unsigned char ch = *mem_p;
-                       *hex++ = c_hex[(0xf0 & ch) >> 4];
-                       *hex++ = c_hex[(0x0f & ch)];
-                       *ascii++ = isprint(ch)? (char)ch: '?';
-               }
-               while (hex != ascii_b)
-               {
-                       *hex++ = ' ';
-               }
-               msg->p = ascii;
-               log->output->callback(msg, log->output->arg);
-       }
-}
-
-BT_HIDDEN
-void bt_log_set_tag_prefix(const char *const prefix)
-{
-       _bt_log_tag_prefix = prefix;
-}
-
-BT_HIDDEN
-void bt_log_set_mem_width(const unsigned w)
-{
-       _bt_log_global_format.mem_width = w;
-}
-
-BT_HIDDEN
-void bt_log_set_output_level(const int lvl)
-{
-       _bt_log_global_output_lvl = lvl;
-}
-
-BT_HIDDEN
-void bt_log_set_output_v(const unsigned mask, void *const arg,
-                                                const bt_log_output_cb callback)
-{
-       _bt_log_global_output.mask = mask;
-       _bt_log_global_output.arg = arg;
-       _bt_log_global_output.callback = callback;
-}
-
-static void _bt_log_write_imp(
-               const bt_log_spec *log,
-               const src_location *const src, const mem_block *const mem,
-               const int lvl, const char *const tag, const char *const fmt, va_list va)
-{
-       bt_log_message msg;
-       char *buf = logging_buf;
-       const unsigned mask = log->output->mask;
-       msg.lvl = lvl;
-       msg.tag = tag;
-       g_buffer_cb(&msg, buf);
-       const char *rst_color_p = bt_common_color_reset();
-       const char *rst_color_e = rst_color_p + strlen(rst_color_p);
-       const char *color_p = "";
-       const char *color_e = color_p;
-
-       switch (lvl) {
-       case BT_LOG_INFO:
-               color_p = bt_common_color_fg_blue();
-               color_e = color_p + strlen(color_p);
-               break;
-       case BT_LOG_WARN:
-               color_p = bt_common_color_fg_yellow();
-               color_e = color_p + strlen(color_p);
-               break;
-       case BT_LOG_ERROR:
-       case BT_LOG_FATAL:
-               color_p = bt_common_color_fg_red();
-               color_e = color_p + strlen(color_p);
-               break;
-       default:
-               break;
-       }
-
-       msg.p = put_stringn(color_p, color_e, msg.p, msg.e);
-
-       if (BT_LOG_PUT_CTX & mask)
-       {
-               put_ctx(&msg);
-       }
-       if (BT_LOG_PUT_TAG & mask)
-       {
-               put_tag(&msg, tag);
-       }
-       if (0 != src && BT_LOG_PUT_SRC & mask)
-       {
-               put_src(&msg, src);
-       }
-       if (BT_LOG_PUT_MSG & mask)
-       {
-               put_msg(&msg, fmt, va);
-       }
-       msg.p = put_stringn(rst_color_p, rst_color_e, msg.p, msg.e);
-       log->output->callback(&msg, log->output->arg);
-       if (0 != mem && BT_LOG_PUT_MSG & mask)
-       {
-               output_mem(log, &msg, mem);
-       }
-}
-
-BT_HIDDEN
-void _bt_log_write_d(
-               const char *const func, const char *const file, const unsigned line,
-               const int lvl, const char *const tag,
-               const char *const fmt, ...)
-{
-       const src_location src = {func, file, line};
-       va_list va;
-       va_start(va, fmt);
-       _bt_log_write_imp(&global_spec, &src, 0, lvl, tag, fmt, va);
-       va_end(va);
-}
-
-BT_HIDDEN
-void _bt_log_write_aux_d(
-               const char *const func, const char *const file, const unsigned line,
-               const bt_log_spec *const log, const int lvl, const char *const tag,
-               const char *const fmt, ...)
-{
-       const src_location src = {func, file, line};
-       va_list va;
-       va_start(va, fmt);
-       _bt_log_write_imp(log, &src, 0, lvl, tag, fmt, va);
-       va_end(va);
-}
-
-BT_HIDDEN
-void _bt_log_write(const int lvl, const char *const tag,
-                                  const char *const fmt, ...)
-{
-       va_list va;
-       va_start(va, fmt);
-       _bt_log_write_imp(&global_spec, 0, 0, lvl, tag, fmt, va);
-       va_end(va);
-}
-
-BT_HIDDEN
-void _bt_log_write_aux(
-               const bt_log_spec *const log, const int lvl, const char *const tag,
-               const char *const fmt, ...)
-{
-       va_list va;
-       va_start(va, fmt);
-       _bt_log_write_imp(log, 0, 0, lvl, tag, fmt, va);
-       va_end(va);
-}
-
-BT_HIDDEN
-void _bt_log_write_mem_d(
-               const char *const func, const char *const file, const unsigned line,
-               const int lvl, const char *const tag,
-               const void *const d, const unsigned d_sz,
-               const char *const fmt, ...)
-{
-       const src_location src = {func, file, line};
-       const mem_block mem = {d, d_sz};
-       va_list va;
-       va_start(va, fmt);
-       _bt_log_write_imp(&global_spec, &src, &mem, lvl, tag, fmt, va);
-       va_end(va);
-}
-
-BT_HIDDEN
-void _bt_log_write_mem_aux_d(
-               const char *const func, const char *const file, const unsigned line,
-               const bt_log_spec *const log, const int lvl, const char *const tag,
-               const void *const d, const unsigned d_sz,
-               const char *const fmt, ...)
-{
-       const src_location src = {func, file, line};
-       const mem_block mem = {d, d_sz};
-       va_list va;
-       va_start(va, fmt);
-       _bt_log_write_imp(log, &src, &mem, lvl, tag, fmt, va);
-       va_end(va);
-}
-
-BT_HIDDEN
-void _bt_log_write_mem(const int lvl, const char *const tag,
-                                          const void *const d, const unsigned d_sz,
-                                          const char *const fmt, ...)
-{
-       const mem_block mem = {d, d_sz};
-       va_list va;
-       va_start(va, fmt);
-       _bt_log_write_imp(&global_spec, 0, &mem, lvl, tag, fmt, va);
-       va_end(va);
-}
-
-BT_HIDDEN
-void _bt_log_write_mem_aux(
-               const bt_log_spec *const log, const int lvl, const char *const tag,
-               const void *const d, const unsigned d_sz,
-               const char *const fmt, ...)
-{
-       const mem_block mem = {d, d_sz};
-       va_list va;
-       va_start(va, fmt);
-       _bt_log_write_imp(log, 0, &mem, lvl, tag, fmt, va);
-       va_end(va);
-}
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
deleted file mode 100644 (file)
index 9b23e3c..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-SUBDIRS = utils text ctf
-
-if ENABLE_DEBUG_INFO
-SUBDIRS += lttng-utils
-endif
-
-noinst_HEADERS = plugins-common.h
diff --git a/plugins/ctf/Makefile.am b/plugins/ctf/Makefile.am
deleted file mode 100644 (file)
index 5f5c859..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-SUBDIRS = common \
-       fs-src \
-       fs-sink \
-       lttng-live
-
-noinst_HEADERS = print.h
-
-plugindir = "$(PLUGINSDIR)"
-plugin_LTLIBRARIES = babeltrace-plugin-ctf.la
-
-# ctf plugin
-babeltrace_plugin_ctf_la_SOURCES = plugin.c
-
-babeltrace_plugin_ctf_la_LDFLAGS = \
-       $(LT_NO_UNDEFINED) \
-       -avoid-version -module
-
-babeltrace_plugin_ctf_la_LIBADD = \
-       common/libbabeltrace2-plugin-ctf-common.la \
-       fs-sink/libbabeltrace2-plugin-ctf-fs-sink.la \
-       fs-src/libbabeltrace2-plugin-ctf-fs-src.la \
-       lttng-live/libbabeltrace2-plugin-ctf-lttng-live.la
-
-if !ENABLE_BUILT_IN_PLUGINS
-babeltrace_plugin_ctf_la_LIBADD += \
-       $(top_builddir)/lib/libbabeltrace2.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/ctfser/libbabeltrace2-ctfser.la
-endif
diff --git a/plugins/ctf/common/Makefile.am b/plugins/ctf/common/Makefile.am
deleted file mode 100644 (file)
index 055355b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-SUBDIRS = metadata bfcr msg-iter utils
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-ctf-common.la
-libbabeltrace2_plugin_ctf_common_la_SOURCES = print.h
-libbabeltrace2_plugin_ctf_common_la_LIBADD =           \
-       $(builddir)/metadata/libctf-parser.la           \
-       $(builddir)/metadata/libctf-ast.la              \
-       $(builddir)/bfcr/libctf-bfcr.la                 \
-       $(builddir)/msg-iter/libctf-msg-iter.la \
-       $(builddir)/utils/libctf-utils.la
diff --git a/plugins/ctf/common/bfcr/Makefile.am b/plugins/ctf/common/bfcr/Makefile.am
deleted file mode 100644 (file)
index d0dd8c6..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LTLIBRARIES = libctf-bfcr.la
-libctf_bfcr_la_SOURCES = \
-       bfcr.c \
-       bfcr.h \
-       logging.c \
-       logging.h
diff --git a/plugins/ctf/common/bfcr/bfcr.c b/plugins/ctf/common/bfcr/bfcr.c
deleted file mode 100644 (file)
index 91d6788..0000000
+++ /dev/null
@@ -1,1344 +0,0 @@
-/*
- * Babeltrace - CTF binary field class reader (BFCR)
- *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-BFCR"
-#include "logging.h"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <babeltrace2/assert-internal.h>
-#include <string.h>
-#include <babeltrace2/bitfield-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/align-internal.h>
-#include <glib.h>
-
-#include "bfcr.h"
-#include "../metadata/ctf-meta.h"
-
-#define DIV8(_x)                       ((_x) >> 3)
-#define BYTES_TO_BITS(_x)              ((_x) * 8)
-#define BITS_TO_BYTES_FLOOR(_x)                DIV8(_x)
-#define BITS_TO_BYTES_CEIL(_x)         DIV8((_x) + 7)
-#define IN_BYTE_OFFSET(_at)            ((_at) & 7)
-
-/* A visit stack entry */
-struct stack_entry {
-       /*
-        * Current class of base field, one of:
-        *
-        *   * Structure
-        *   * Array
-        *   * Sequence
-        *   * Variant
-        */
-       struct ctf_field_class *base_class;
-
-       /* Length of base field (always 1 for a variant class) */
-       int64_t base_len;
-
-       /* Index of next field to read */
-       int64_t index;
-};
-
-/* Visit stack */
-struct stack {
-       /* Entries (struct stack_entry) */
-       GArray *entries;
-
-       /* Number of active entries */
-       size_t size;
-};
-
-/* Reading states */
-enum bfcr_state {
-       BFCR_STATE_NEXT_FIELD,
-       BFCR_STATE_ALIGN_BASIC,
-       BFCR_STATE_ALIGN_COMPOUND,
-       BFCR_STATE_READ_BASIC_BEGIN,
-       BFCR_STATE_READ_BASIC_CONTINUE,
-       BFCR_STATE_DONE,
-};
-
-/* Binary class reader */
-struct bt_bfcr {
-       /* Bisit stack */
-       struct stack *stack;
-
-       /* Current basic field class */
-       struct ctf_field_class *cur_basic_field_class;
-
-       /* Current state */
-       enum bfcr_state state;
-
-       /*
-        * Last basic field class's byte order.
-        *
-        * This is used to detect errors since two contiguous basic
-        * classes for which the common boundary is not the boundary of
-        * a byte cannot have different byte orders.
-        *
-        * This is set to -1 on reset and when the last basic field class
-        * was a string class.
-        */
-       enum ctf_byte_order last_bo;
-
-       /* Current byte order (copied to last_bo after a successful read) */
-       enum ctf_byte_order cur_bo;
-
-       /* Stitch buffer infos */
-       struct {
-               /* Stitch buffer */
-               uint8_t buf[16];
-
-               /* Offset, within stitch buffer, of first bit */
-               size_t offset;
-
-               /* Length (bits) of data in stitch buffer from offset */
-               size_t at;
-       } stitch;
-
-       /* User buffer infos */
-       struct {
-               /* Address */
-               const uint8_t *addr;
-
-               /* Offset of data from address (bits) */
-               size_t offset;
-
-               /* Current position from offset (bits) */
-               size_t at;
-
-               /* Offset of offset within whole packet (bits) */
-               size_t packet_offset;
-
-               /* Data size in buffer (bits) */
-               size_t sz;
-
-               /* Buffer size (bytes) */
-               size_t buf_sz;
-       } buf;
-
-       /* User stuff */
-       struct {
-               /* Callback functions */
-               struct bt_bfcr_cbs cbs;
-
-               /* Private data */
-               void *data;
-       } user;
-};
-
-static inline
-const char *bfcr_state_string(enum bfcr_state state)
-{
-       switch (state) {
-       case BFCR_STATE_NEXT_FIELD:
-               return "BFCR_STATE_NEXT_FIELD";
-       case BFCR_STATE_ALIGN_BASIC:
-               return "BFCR_STATE_ALIGN_BASIC";
-       case BFCR_STATE_ALIGN_COMPOUND:
-               return "BFCR_STATE_ALIGN_COMPOUND";
-       case BFCR_STATE_READ_BASIC_BEGIN:
-               return "BFCR_STATE_READ_BASIC_BEGIN";
-       case BFCR_STATE_READ_BASIC_CONTINUE:
-               return "BFCR_STATE_READ_BASIC_CONTINUE";
-       case BFCR_STATE_DONE:
-               return "BFCR_STATE_DONE";
-       default:
-               return "(unknown)";
-       }
-}
-
-static
-struct stack *stack_new(void)
-{
-       struct stack *stack = NULL;
-
-       stack = g_new0(struct stack, 1);
-       if (!stack) {
-               BT_LOGE_STR("Failed to allocate one stack.");
-               goto error;
-       }
-
-       stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
-       if (!stack->entries) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               goto error;
-       }
-
-       BT_LOGD("Created stack: addr=%p", stack);
-       return stack;
-
-error:
-       g_free(stack);
-       return NULL;
-}
-
-static
-void stack_destroy(struct stack *stack)
-{
-       if (!stack) {
-               return;
-       }
-
-       BT_LOGD("Destroying stack: addr=%p", stack);
-
-       if (stack->entries) {
-               g_array_free(stack->entries, TRUE);
-       }
-
-       g_free(stack);
-}
-
-static
-int stack_push(struct stack *stack, struct ctf_field_class *base_class,
-       size_t base_len)
-{
-       struct stack_entry *entry;
-
-       BT_ASSERT(stack);
-       BT_ASSERT(base_class);
-       BT_LOGV("Pushing field class on stack: stack-addr=%p, "
-               "fc-addr=%p, fc-type=%d, base-length=%zu, "
-               "stack-size-before=%zu, stack-size-after=%zu",
-               stack, base_class, base_class->type,
-               base_len, stack->size, stack->size + 1);
-
-       if (stack->entries->len == stack->size) {
-               g_array_set_size(stack->entries, stack->size + 1);
-       }
-
-       entry = &g_array_index(stack->entries, struct stack_entry, stack->size);
-       entry->base_class = base_class;
-       entry->base_len = base_len;
-       entry->index = 0;
-       stack->size++;
-       return 0;
-}
-
-static inline
-int64_t get_compound_field_class_length(struct bt_bfcr *bfcr,
-               struct ctf_field_class *fc)
-{
-       int64_t length;
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               length = (int64_t) struct_fc->members->len;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               /* Variant field classes always "contain" a single class */
-               length = 1;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       {
-               struct ctf_field_class_array *array_fc = (void *) fc;
-
-               length = (int64_t) array_fc->length;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-               length = bfcr->user.cbs.query.get_sequence_length(fc,
-                       bfcr->user.data);
-               break;
-       default:
-               abort();
-       }
-
-       return length;
-}
-
-static
-int stack_push_with_len(struct bt_bfcr *bfcr, struct ctf_field_class *base_class)
-{
-       int ret;
-       int64_t length = get_compound_field_class_length(bfcr, base_class);
-
-       if (length < 0) {
-               BT_LOGW("Cannot get compound field class's field count: "
-                       "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
-                       bfcr, base_class, base_class->type);
-               ret = BT_BFCR_STATUS_ERROR;
-               goto end;
-       }
-
-       ret = stack_push(bfcr->stack, base_class, (size_t) length);
-
-end:
-       return ret;
-}
-
-static inline
-unsigned int stack_size(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       return stack->size;
-}
-
-static
-void stack_pop(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       BT_ASSERT(stack_size(stack));
-       BT_LOGV("Popping from stack: "
-               "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
-               stack, stack->entries->len, stack->entries->len - 1);
-       stack->size--;
-}
-
-static inline
-bool stack_empty(struct stack *stack)
-{
-       return stack_size(stack) == 0;
-}
-
-static
-void stack_clear(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       stack->size = 0;
-}
-
-static inline
-struct stack_entry *stack_top(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       BT_ASSERT(stack_size(stack));
-       return &g_array_index(stack->entries, struct stack_entry,
-               stack->size - 1);
-}
-
-static inline
-size_t available_bits(struct bt_bfcr *bfcr)
-{
-       return bfcr->buf.sz - bfcr->buf.at;
-}
-
-static inline
-void consume_bits(struct bt_bfcr *bfcr, size_t incr)
-{
-       BT_LOGV("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu",
-               bfcr, bfcr->buf.at, bfcr->buf.at + incr);
-       bfcr->buf.at += incr;
-}
-
-static inline
-bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz)
-{
-       return available_bits(bfcr) >= sz;
-}
-
-static inline
-bool at_least_one_bit_left(struct bt_bfcr *bfcr)
-{
-       return has_enough_bits(bfcr, 1);
-}
-
-static inline
-size_t packet_at(struct bt_bfcr *bfcr)
-{
-       return bfcr->buf.packet_offset + bfcr->buf.at;
-}
-
-static inline
-size_t buf_at_from_addr(struct bt_bfcr *bfcr)
-{
-       /*
-        * Considering this:
-        *
-        *     ====== offset ===== (17)
-        *
-        *     xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
-        *     ^
-        *     addr (0)           ==== at ==== (12)
-        *
-        * We want this:
-        *
-        *     =============================== (29)
-        */
-       return bfcr->buf.offset + bfcr->buf.at;
-}
-
-static
-void stitch_reset(struct bt_bfcr *bfcr)
-{
-       bfcr->stitch.offset = 0;
-       bfcr->stitch.at = 0;
-}
-
-static inline
-size_t stitch_at_from_addr(struct bt_bfcr *bfcr)
-{
-       return bfcr->stitch.offset + bfcr->stitch.at;
-}
-
-static
-void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz)
-{
-       size_t stitch_byte_at;
-       size_t buf_byte_at;
-       size_t nb_bytes;
-
-       if (sz == 0) {
-               return;
-       }
-
-       stitch_byte_at =
-               BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr));
-       buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
-       nb_bytes = BITS_TO_BYTES_CEIL(sz);
-       BT_ASSERT(nb_bytes > 0);
-       BT_ASSERT(bfcr->buf.addr);
-       memcpy(&bfcr->stitch.buf[stitch_byte_at], &bfcr->buf.addr[buf_byte_at],
-               nb_bytes);
-       bfcr->stitch.at += sz;
-       consume_bits(bfcr, sz);
-}
-
-static
-void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr)
-{
-       stitch_append_from_buf(bfcr, available_bits(bfcr));
-}
-
-static
-void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr)
-{
-       stitch_reset(bfcr);
-       bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr));
-       stitch_append_from_remaining_buf(bfcr);
-}
-
-static inline
-void read_unsigned_bitfield(const uint8_t *buf, size_t at,
-               unsigned int field_size, enum ctf_byte_order bo,
-               uint64_t *v)
-{
-       switch (bo) {
-       case CTF_BYTE_ORDER_BIG:
-               bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
-               break;
-       case CTF_BYTE_ORDER_LITTLE:
-               bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
-               break;
-       default:
-               abort();
-       }
-
-       BT_LOGV("Read unsigned bit array: cur=%zu, size=%u, "
-               "bo=%d, val=%" PRIu64, at, field_size, bo, *v);
-}
-
-static inline
-void read_signed_bitfield(const uint8_t *buf, size_t at,
-               unsigned int field_size, enum ctf_byte_order bo, int64_t *v)
-{
-       switch (bo) {
-       case CTF_BYTE_ORDER_BIG:
-               bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
-               break;
-       case CTF_BYTE_ORDER_LITTLE:
-               bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
-               break;
-       default:
-               abort();
-       }
-
-       BT_LOGV("Read signed bit array: cur=%zu, size=%u, "
-               "bo=%d, val=%" PRId64, at, field_size, bo, *v);
-}
-
-typedef enum bt_bfcr_status (* read_basic_and_call_cb_t)(struct bt_bfcr *,
-               const uint8_t *, size_t);
-
-static inline
-enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr,
-               enum ctf_byte_order next_bo)
-{
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-
-       /* Always valid when at a byte boundary */
-       if (packet_at(bfcr) % 8 == 0) {
-               goto end;
-       }
-
-       /* Always valid if last byte order is unknown */
-       if (bfcr->last_bo == -1) {
-               goto end;
-       }
-
-       /* Always valid if next byte order is unknown */
-       if (next_bo == -1) {
-               goto end;
-       }
-
-       /* Make sure last byte order is compatible with the next byte order */
-       switch (bfcr->last_bo) {
-       case CTF_BYTE_ORDER_BIG:
-               if (next_bo != CTF_BYTE_ORDER_BIG) {
-                       status = BT_BFCR_STATUS_ERROR;
-               }
-               break;
-       case CTF_BYTE_ORDER_LITTLE:
-               if (next_bo != CTF_BYTE_ORDER_LITTLE) {
-                       status = BT_BFCR_STATUS_ERROR;
-               }
-               break;
-       default:
-               status = BT_BFCR_STATUS_ERROR;
-       }
-
-end:
-       if (status < 0) {
-               BT_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
-                       "bfcr-addr=%p, last-bo=%d, next-bo=%d",
-                       bfcr, bfcr->last_bo, next_bo);
-       }
-
-       return status;
-}
-
-static
-enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr,
-               const uint8_t *buf, size_t at)
-{
-       double dblval;
-       unsigned int field_size;
-       enum ctf_byte_order bo;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       struct ctf_field_class_float *fc = (void *) bfcr->cur_basic_field_class;
-
-       BT_ASSERT(fc);
-       field_size = fc->base.size;
-       bo = fc->base.byte_order;
-       bfcr->cur_bo = bo;
-
-       switch (field_size) {
-       case 32:
-       {
-               uint64_t v;
-               union {
-                       uint32_t u;
-                       float f;
-               } f32;
-
-               read_unsigned_bitfield(buf, at, field_size, bo, &v);
-               f32.u = (uint32_t) v;
-               dblval = (double) f32.f;
-               break;
-       }
-       case 64:
-       {
-               union {
-                       uint64_t u;
-                       double d;
-               } f64;
-
-               read_unsigned_bitfield(buf, at, field_size, bo, &f64.u);
-               dblval = f64.d;
-               break;
-       }
-       default:
-               /* Only 32-bit and 64-bit fields are supported currently */
-               abort();
-       }
-
-       BT_LOGV("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
-               bfcr, at, dblval);
-
-       if (bfcr->user.cbs.classes.floating_point) {
-               BT_LOGV("Calling user function (floating point number).");
-               status = bfcr->user.cbs.classes.floating_point(dblval,
-                       bfcr->cur_basic_field_class, bfcr->user.data);
-               BT_LOGV("User function returned: status=%s",
-                       bt_bfcr_status_string(status));
-               if (status != BT_BFCR_STATUS_OK) {
-                       BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
-                               bfcr, bt_bfcr_status_string(status));
-               }
-       }
-
-       return status;
-}
-
-static inline
-enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr,
-               const uint8_t *buf, size_t at)
-{
-       unsigned int field_size;
-       enum ctf_byte_order bo;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       struct ctf_field_class_int *fc = (void *) bfcr->cur_basic_field_class;
-
-       field_size = fc->base.size;
-       bo = fc->base.byte_order;
-
-       /*
-        * Update current byte order now because we could be reading
-        * the integer value of an enumeration class, and thus we know
-        * here the actual supporting integer class's byte order.
-        */
-       bfcr->cur_bo = bo;
-
-       if (fc->is_signed) {
-               int64_t v;
-
-               read_signed_bitfield(buf, at, field_size, bo, &v);
-
-               if (bfcr->user.cbs.classes.signed_int) {
-                       BT_LOGV("Calling user function (signed integer).");
-                       status = bfcr->user.cbs.classes.signed_int(v,
-                               bfcr->cur_basic_field_class, bfcr->user.data);
-                       BT_LOGV("User function returned: status=%s",
-                               bt_bfcr_status_string(status));
-                       if (status != BT_BFCR_STATUS_OK) {
-                               BT_LOGW("User function failed: "
-                                       "bfcr-addr=%p, status=%s",
-                                       bfcr, bt_bfcr_status_string(status));
-                       }
-               }
-       } else {
-               uint64_t v;
-
-               read_unsigned_bitfield(buf, at, field_size, bo, &v);
-
-               if (bfcr->user.cbs.classes.unsigned_int) {
-                       BT_LOGV("Calling user function (unsigned integer).");
-                       status = bfcr->user.cbs.classes.unsigned_int(v,
-                               bfcr->cur_basic_field_class, bfcr->user.data);
-                       BT_LOGV("User function returned: status=%s",
-                               bt_bfcr_status_string(status));
-                       if (status != BT_BFCR_STATUS_OK) {
-                               BT_LOGW("User function failed: "
-                                       "bfcr-addr=%p, status=%s",
-                                       bfcr, bt_bfcr_status_string(status));
-                       }
-               }
-       }
-
-       return status;
-}
-
-static inline
-enum bt_bfcr_status read_bit_array_class_and_call_continue(struct bt_bfcr *bfcr,
-               read_basic_and_call_cb_t read_basic_and_call_cb)
-{
-       size_t available;
-       size_t needed_bits;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       struct ctf_field_class_bit_array *fc =
-               (void *) bfcr->cur_basic_field_class;
-
-       if (!at_least_one_bit_left(bfcr)) {
-               BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr);
-               status = BT_BFCR_STATUS_EOF;
-               goto end;
-       }
-
-       available = available_bits(bfcr);
-       needed_bits = fc->size - bfcr->stitch.at;
-       BT_LOGV("Continuing basic field decoding: "
-               "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
-               "available-size=%zu",
-               bfcr, fc->size, needed_bits, available);
-       if (needed_bits <= available) {
-               /* We have all the bits; append to stitch, then decode */
-               stitch_append_from_buf(bfcr, needed_bits);
-               status = read_basic_and_call_cb(bfcr, bfcr->stitch.buf,
-                       bfcr->stitch.offset);
-               if (status != BT_BFCR_STATUS_OK) {
-                       BT_LOGW("Cannot read basic field: "
-                               "bfcr-addr=%p, fc-addr=%p, status=%s",
-                               bfcr, bfcr->cur_basic_field_class,
-                               bt_bfcr_status_string(status));
-                       goto end;
-               }
-
-               if (stack_empty(bfcr->stack)) {
-                       /* Root is a basic class */
-                       bfcr->state = BFCR_STATE_DONE;
-               } else {
-                       /* Go to next field */
-                       stack_top(bfcr->stack)->index++;
-                       bfcr->state = BFCR_STATE_NEXT_FIELD;
-                       bfcr->last_bo = bfcr->cur_bo;
-               }
-               goto end;
-       }
-
-       /* We are here; it means we don't have enough data to decode this */
-       BT_LOGV_STR("Not enough data to read the next basic field: appending to stitch buffer.");
-       stitch_append_from_remaining_buf(bfcr);
-       status = BT_BFCR_STATUS_EOF;
-
-end:
-       return status;
-}
-
-static inline
-enum bt_bfcr_status read_bit_array_class_and_call_begin(struct bt_bfcr *bfcr,
-               read_basic_and_call_cb_t read_basic_and_call_cb)
-{
-       size_t available;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       struct ctf_field_class_bit_array *fc =
-               (void *) bfcr->cur_basic_field_class;
-
-       if (!at_least_one_bit_left(bfcr)) {
-               BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr);
-               status = BT_BFCR_STATUS_EOF;
-               goto end;
-       }
-
-       status = validate_contiguous_bo(bfcr, fc->byte_order);
-       if (status != BT_BFCR_STATUS_OK) {
-               /* validate_contiguous_bo() logs errors */
-               goto end;
-       }
-
-       available = available_bits(bfcr);
-
-       if (fc->size <= available) {
-               /* We have all the bits; decode and set now */
-               BT_ASSERT(bfcr->buf.addr);
-               status = read_basic_and_call_cb(bfcr, bfcr->buf.addr,
-                       buf_at_from_addr(bfcr));
-               if (status != BT_BFCR_STATUS_OK) {
-                       BT_LOGW("Cannot read basic field: "
-                               "bfcr-addr=%p, fc-addr=%p, status=%s",
-                               bfcr, bfcr->cur_basic_field_class,
-                               bt_bfcr_status_string(status));
-                       goto end;
-               }
-
-               consume_bits(bfcr, fc->size);
-
-               if (stack_empty(bfcr->stack)) {
-                       /* Root is a basic class */
-                       bfcr->state = BFCR_STATE_DONE;
-               } else {
-                       /* Go to next field */
-                       stack_top(bfcr->stack)->index++;
-                       bfcr->state = BFCR_STATE_NEXT_FIELD;
-                       bfcr->last_bo = bfcr->cur_bo;
-               }
-
-               goto end;
-       }
-
-       /* We are here; it means we don't have enough data to decode this */
-       BT_LOGV_STR("Not enough data to read the next basic field: setting stitch buffer.");
-       stitch_set_from_remaining_buf(bfcr);
-       bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
-       status = BT_BFCR_STATUS_EOF;
-
-end:
-       return status;
-}
-
-static inline
-enum bt_bfcr_status read_basic_int_class_and_call_begin(
-               struct bt_bfcr *bfcr)
-{
-       return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb);
-}
-
-static inline
-enum bt_bfcr_status read_basic_int_class_and_call_continue(
-               struct bt_bfcr *bfcr)
-{
-       return read_bit_array_class_and_call_continue(bfcr,
-               read_basic_int_and_call_cb);
-}
-
-static inline
-enum bt_bfcr_status read_basic_float_class_and_call_begin(
-               struct bt_bfcr *bfcr)
-{
-       return read_bit_array_class_and_call_begin(bfcr,
-               read_basic_float_and_call_cb);
-}
-
-static inline
-enum bt_bfcr_status read_basic_float_class_and_call_continue(
-               struct bt_bfcr *bfcr)
-{
-       return read_bit_array_class_and_call_continue(bfcr,
-               read_basic_float_and_call_cb);
-}
-
-static inline
-enum bt_bfcr_status read_basic_string_class_and_call(
-               struct bt_bfcr *bfcr, bool begin)
-{
-       size_t buf_at_bytes;
-       const uint8_t *result;
-       size_t available_bytes;
-       const uint8_t *first_chr;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-
-       if (!at_least_one_bit_left(bfcr)) {
-               BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr);
-               status = BT_BFCR_STATUS_EOF;
-               goto end;
-       }
-
-       BT_ASSERT(buf_at_from_addr(bfcr) % 8 == 0);
-       available_bytes = BITS_TO_BYTES_FLOOR(available_bits(bfcr));
-       buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
-       BT_ASSERT(bfcr->buf.addr);
-       first_chr = &bfcr->buf.addr[buf_at_bytes];
-       result = memchr(first_chr, '\0', available_bytes);
-
-       if (begin && bfcr->user.cbs.classes.string_begin) {
-               BT_LOGV("Calling user function (string, beginning).");
-               status = bfcr->user.cbs.classes.string_begin(
-                       bfcr->cur_basic_field_class, bfcr->user.data);
-               BT_LOGV("User function returned: status=%s",
-                       bt_bfcr_status_string(status));
-               if (status != BT_BFCR_STATUS_OK) {
-                       BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
-                               bfcr, bt_bfcr_status_string(status));
-                       goto end;
-               }
-       }
-
-       if (!result) {
-               /* No null character yet */
-               if (bfcr->user.cbs.classes.string) {
-                       BT_LOGV("Calling user function (substring).");
-                       status = bfcr->user.cbs.classes.string(
-                               (const char *) first_chr,
-                               available_bytes, bfcr->cur_basic_field_class,
-                               bfcr->user.data);
-                       BT_LOGV("User function returned: status=%s",
-                               bt_bfcr_status_string(status));
-                       if (status != BT_BFCR_STATUS_OK) {
-                               BT_LOGW("User function failed: "
-                                       "bfcr-addr=%p, status=%s",
-                                       bfcr, bt_bfcr_status_string(status));
-                               goto end;
-                       }
-               }
-
-               consume_bits(bfcr, BYTES_TO_BITS(available_bytes));
-               bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
-               status = BT_BFCR_STATUS_EOF;
-       } else {
-               /* Found the null character */
-               size_t result_len = (size_t) (result - first_chr);
-
-               if (bfcr->user.cbs.classes.string && result_len) {
-                       BT_LOGV("Calling user function (substring).");
-                       status = bfcr->user.cbs.classes.string(
-                               (const char *) first_chr,
-                               result_len, bfcr->cur_basic_field_class,
-                               bfcr->user.data);
-                       BT_LOGV("User function returned: status=%s",
-                               bt_bfcr_status_string(status));
-                       if (status != BT_BFCR_STATUS_OK) {
-                               BT_LOGW("User function failed: "
-                                       "bfcr-addr=%p, status=%s",
-                                       bfcr, bt_bfcr_status_string(status));
-                               goto end;
-                       }
-               }
-
-               if (bfcr->user.cbs.classes.string_end) {
-                       BT_LOGV("Calling user function (string, end).");
-                       status = bfcr->user.cbs.classes.string_end(
-                               bfcr->cur_basic_field_class, bfcr->user.data);
-                       BT_LOGV("User function returned: status=%s",
-                               bt_bfcr_status_string(status));
-                       if (status != BT_BFCR_STATUS_OK) {
-                               BT_LOGW("User function failed: "
-                                       "bfcr-addr=%p, status=%s",
-                                       bfcr, bt_bfcr_status_string(status));
-                               goto end;
-                       }
-               }
-
-               consume_bits(bfcr, BYTES_TO_BITS(result_len + 1));
-
-               if (stack_empty(bfcr->stack)) {
-                       /* Root is a basic class */
-                       bfcr->state = BFCR_STATE_DONE;
-               } else {
-                       /* Go to next field */
-                       stack_top(bfcr->stack)->index++;
-                       bfcr->state = BFCR_STATE_NEXT_FIELD;
-                       bfcr->last_bo = bfcr->cur_bo;
-               }
-       }
-
-end:
-       return status;
-}
-
-static inline
-enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr)
-{
-       enum bt_bfcr_status status;
-
-       BT_ASSERT(bfcr->cur_basic_field_class);
-
-       switch (bfcr->cur_basic_field_class->type) {
-       case CTF_FIELD_CLASS_TYPE_INT:
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-               status = read_basic_int_class_and_call_begin(bfcr);
-               break;
-       case CTF_FIELD_CLASS_TYPE_FLOAT:
-               status = read_basic_float_class_and_call_begin(bfcr);
-               break;
-       case CTF_FIELD_CLASS_TYPE_STRING:
-               status = read_basic_string_class_and_call(bfcr, true);
-               break;
-       default:
-               abort();
-       }
-
-       return status;
-}
-
-static inline
-enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
-{
-       enum bt_bfcr_status status;
-
-       BT_ASSERT(bfcr->cur_basic_field_class);
-
-       switch (bfcr->cur_basic_field_class->type) {
-       case CTF_FIELD_CLASS_TYPE_INT:
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-               status = read_basic_int_class_and_call_continue(bfcr);
-               break;
-       case CTF_FIELD_CLASS_TYPE_FLOAT:
-               status = read_basic_float_class_and_call_continue(bfcr);
-               break;
-       case CTF_FIELD_CLASS_TYPE_STRING:
-               status = read_basic_string_class_and_call(bfcr, false);
-               break;
-       default:
-               abort();
-       }
-
-       return status;
-}
-
-static inline
-size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align)
-{
-       size_t aligned_packet_at;
-
-       aligned_packet_at = ALIGN(packet_at(bfcr), align);
-       return aligned_packet_at - packet_at(bfcr);
-}
-
-static inline
-enum bt_bfcr_status align_class_state(struct bt_bfcr *bfcr,
-               struct ctf_field_class *field_class, enum bfcr_state next_state)
-{
-       unsigned int field_alignment;
-       size_t skip_bits;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-
-       /* Get field's alignment */
-       field_alignment = field_class->alignment;
-
-       /*
-        * 0 means "undefined" for variants; what we really want is 1
-        * (always aligned)
-        */
-       BT_ASSERT(field_alignment >= 1);
-
-       /* Compute how many bits we need to skip */
-       skip_bits = bits_to_skip_to_align_to(bfcr, (size_t) field_alignment);
-
-       /* Nothing to skip? aligned */
-       if (skip_bits == 0) {
-               bfcr->state = next_state;
-               goto end;
-       }
-
-       /* Make sure there's at least one bit left */
-       if (!at_least_one_bit_left(bfcr)) {
-               status = BT_BFCR_STATUS_EOF;
-               goto end;
-       }
-
-       /* Consume as many bits as possible in what's left */
-       consume_bits(bfcr, MIN(available_bits(bfcr), skip_bits));
-
-       /* Are we done now? */
-       skip_bits = bits_to_skip_to_align_to(bfcr, field_alignment);
-       if (skip_bits == 0) {
-               /* Yes: go to next state */
-               bfcr->state = next_state;
-               goto end;
-       } else {
-               /* No: need more data */
-               BT_LOGV("Reached end of data when aligning: bfcr-addr=%p", bfcr);
-               status = BT_BFCR_STATUS_EOF;
-       }
-
-end:
-       return status;
-}
-
-static inline
-enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr)
-{
-       int ret;
-       struct stack_entry *top;
-       struct ctf_field_class *next_field_class = NULL;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-
-       if (stack_empty(bfcr->stack)) {
-               goto end;
-       }
-
-       top = stack_top(bfcr->stack);
-
-       /* Are we done with this base class? */
-       while (top->index == top->base_len) {
-               if (bfcr->user.cbs.classes.compound_end) {
-                       BT_LOGV("Calling user function (compound, end).");
-                       status = bfcr->user.cbs.classes.compound_end(
-                               top->base_class, bfcr->user.data);
-                       BT_LOGV("User function returned: status=%s",
-                               bt_bfcr_status_string(status));
-                       if (status != BT_BFCR_STATUS_OK) {
-                               BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
-                                       bfcr, bt_bfcr_status_string(status));
-                               goto end;
-                       }
-               }
-
-               stack_pop(bfcr->stack);
-
-               /* Are we done with the root class? */
-               if (stack_empty(bfcr->stack)) {
-                       bfcr->state = BFCR_STATE_DONE;
-                       goto end;
-               }
-
-               top = stack_top(bfcr->stack);
-               top->index++;
-       }
-
-       /* Get next field's class */
-       switch (top->base_class->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-               next_field_class = ctf_field_class_struct_borrow_member_by_index(
-                       (void *) top->base_class, (uint64_t) top->index)->fc;
-               break;
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc =
-                       (void *) top->base_class;
-
-               next_field_class = array_fc->elem_fc;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-               /* Variant classes are dynamic: the user should know! */
-               next_field_class =
-                       bfcr->user.cbs.query.borrow_variant_selected_field_class(
-                               top->base_class, bfcr->user.data);
-               break;
-       default:
-               break;
-       }
-
-       if (!next_field_class) {
-               BT_LOGW("Cannot get the field class of the next field: "
-                       "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
-                       "index=%" PRId64,
-                       bfcr, top->base_class, top->base_class->type,
-                       top->index);
-               status = BT_BFCR_STATUS_ERROR;
-               goto end;
-       }
-
-       if (next_field_class->is_compound) {
-               if (bfcr->user.cbs.classes.compound_begin) {
-                       BT_LOGV("Calling user function (compound, begin).");
-                       status = bfcr->user.cbs.classes.compound_begin(
-                               next_field_class, bfcr->user.data);
-                       BT_LOGV("User function returned: status=%s",
-                               bt_bfcr_status_string(status));
-                       if (status != BT_BFCR_STATUS_OK) {
-                               BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
-                                       bfcr, bt_bfcr_status_string(status));
-                               goto end;
-                       }
-               }
-
-               ret = stack_push_with_len(bfcr, next_field_class);
-               if (ret) {
-                       /* stack_push_with_len() logs errors */
-                       status = BT_BFCR_STATUS_ERROR;
-                       goto end;
-               }
-
-               /* Next state: align a compound class */
-               bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
-       } else {
-               /* Replace current basic field class */
-               BT_LOGV("Replacing current basic field class: "
-                       "bfcr-addr=%p, cur-basic-fc-addr=%p, "
-                       "next-basic-fc-addr=%p",
-                       bfcr, bfcr->cur_basic_field_class, next_field_class);
-               bfcr->cur_basic_field_class = next_field_class;
-
-               /* Next state: align a basic class */
-               bfcr->state = BFCR_STATE_ALIGN_BASIC;
-       }
-
-end:
-       return status;
-}
-
-static inline
-enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr)
-{
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-
-       BT_LOGV("Handling state: bfcr-addr=%p, state=%s",
-               bfcr, bfcr_state_string(bfcr->state));
-
-       switch (bfcr->state) {
-       case BFCR_STATE_NEXT_FIELD:
-               status = next_field_state(bfcr);
-               break;
-       case BFCR_STATE_ALIGN_BASIC:
-               status = align_class_state(bfcr, bfcr->cur_basic_field_class,
-                       BFCR_STATE_READ_BASIC_BEGIN);
-               break;
-       case BFCR_STATE_ALIGN_COMPOUND:
-               status = align_class_state(bfcr, stack_top(bfcr->stack)->base_class,
-                       BFCR_STATE_NEXT_FIELD);
-               break;
-       case BFCR_STATE_READ_BASIC_BEGIN:
-               status = read_basic_begin_state(bfcr);
-               break;
-       case BFCR_STATE_READ_BASIC_CONTINUE:
-               status = read_basic_continue_state(bfcr);
-               break;
-       case BFCR_STATE_DONE:
-               break;
-       }
-
-       BT_LOGV("Handled state: bfcr-addr=%p, status=%s",
-               bfcr, bt_bfcr_status_string(status));
-       return status;
-}
-
-BT_HIDDEN
-struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data)
-{
-       struct bt_bfcr *bfcr;
-
-       BT_LOGD_STR("Creating binary class reader (BFCR).");
-       bfcr = g_new0(struct bt_bfcr, 1);
-       if (!bfcr) {
-               BT_LOGE_STR("Failed to allocate one binary class reader.");
-               goto end;
-       }
-
-       bfcr->stack = stack_new();
-       if (!bfcr->stack) {
-               BT_LOGE_STR("Cannot create BFCR's stack.");
-               bt_bfcr_destroy(bfcr);
-               bfcr = NULL;
-               goto end;
-       }
-
-       bfcr->state = BFCR_STATE_NEXT_FIELD;
-       bfcr->user.cbs = cbs;
-       bfcr->user.data = data;
-       BT_LOGD("Created BFCR: addr=%p", bfcr);
-
-end:
-       return bfcr;
-}
-
-BT_HIDDEN
-void bt_bfcr_destroy(struct bt_bfcr *bfcr)
-{
-       if (bfcr->stack) {
-               stack_destroy(bfcr->stack);
-       }
-
-       BT_LOGD("Destroying BFCR: addr=%p", bfcr);
-       g_free(bfcr);
-}
-
-static
-void reset(struct bt_bfcr *bfcr)
-{
-       BT_LOGD("Resetting BFCR: addr=%p", bfcr);
-       stack_clear(bfcr->stack);
-       stitch_reset(bfcr);
-       bfcr->buf.addr = NULL;
-       bfcr->last_bo = -1;
-}
-
-static
-void update_packet_offset(struct bt_bfcr *bfcr)
-{
-       BT_LOGV("Updating packet offset for next call: "
-               "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
-               bfcr, bfcr->buf.packet_offset,
-               bfcr->buf.packet_offset + bfcr->buf.at);
-       bfcr->buf.packet_offset += bfcr->buf.at;
-}
-
-BT_HIDDEN
-size_t bt_bfcr_start(struct bt_bfcr *bfcr,
-       struct ctf_field_class *cls, const uint8_t *buf,
-       size_t offset, size_t packet_offset, size_t sz,
-       enum bt_bfcr_status *status)
-{
-       BT_ASSERT(bfcr);
-       BT_ASSERT(BYTES_TO_BITS(sz) >= offset);
-       reset(bfcr);
-       bfcr->buf.addr = buf;
-       bfcr->buf.offset = offset;
-       bfcr->buf.at = 0;
-       bfcr->buf.packet_offset = packet_offset;
-       bfcr->buf.buf_sz = sz;
-       bfcr->buf.sz = BYTES_TO_BITS(sz) - offset;
-       *status = BT_BFCR_STATUS_OK;
-
-       BT_LOGV("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
-               "buf-addr=%p, buf-size=%zu, offset=%zu, "
-               "packet-offset=%zu",
-               bfcr, cls, buf, sz, offset, packet_offset);
-
-       /* Set root class */
-       if (cls->is_compound) {
-               /* Compound class: push on visit stack */
-               int stack_ret;
-
-               if (bfcr->user.cbs.classes.compound_begin) {
-                       BT_LOGV("Calling user function (compound, begin).");
-                       *status = bfcr->user.cbs.classes.compound_begin(
-                               cls, bfcr->user.data);
-                       BT_LOGV("User function returned: status=%s",
-                               bt_bfcr_status_string(*status));
-                       if (*status != BT_BFCR_STATUS_OK) {
-                               BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
-                                       bfcr, bt_bfcr_status_string(*status));
-                               goto end;
-                       }
-               }
-
-               stack_ret = stack_push_with_len(bfcr, cls);
-               if (stack_ret) {
-                       /* stack_push_with_len() logs errors */
-                       *status = BT_BFCR_STATUS_ERROR;
-                       goto end;
-               }
-
-               bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
-       } else {
-               /* Basic class: set as current basic class */
-               bfcr->cur_basic_field_class = cls;
-               bfcr->state = BFCR_STATE_ALIGN_BASIC;
-       }
-
-       /* Run the machine! */
-       BT_LOGV_STR("Running the state machine.");
-
-       while (true) {
-               *status = handle_state(bfcr);
-               if (*status != BT_BFCR_STATUS_OK ||
-                               bfcr->state == BFCR_STATE_DONE) {
-                       break;
-               }
-       }
-
-       /* Update packet offset for next time */
-       update_packet_offset(bfcr);
-
-end:
-       return bfcr->buf.at;
-}
-
-BT_HIDDEN
-size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
-               enum bt_bfcr_status *status)
-{
-       BT_ASSERT(bfcr);
-       BT_ASSERT(buf);
-       BT_ASSERT(sz > 0);
-       bfcr->buf.addr = buf;
-       bfcr->buf.offset = 0;
-       bfcr->buf.at = 0;
-       bfcr->buf.buf_sz = sz;
-       bfcr->buf.sz = BYTES_TO_BITS(sz);
-       *status = BT_BFCR_STATUS_OK;
-
-       BT_LOGV("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu",
-               bfcr, buf, sz);
-
-       /* Continue running the machine */
-       BT_LOGV_STR("Running the state machine.");
-
-       while (true) {
-               *status = handle_state(bfcr);
-               if (*status != BT_BFCR_STATUS_OK ||
-                               bfcr->state == BFCR_STATE_DONE) {
-                       break;
-               }
-       }
-
-       /* Update packet offset for next time */
-       update_packet_offset(bfcr);
-       return bfcr->buf.at;
-}
-
-BT_HIDDEN
-void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr,
-               bt_bfcr_unsigned_int_cb_func cb)
-{
-       BT_ASSERT(bfcr);
-       BT_ASSERT(cb);
-       bfcr->user.cbs.classes.unsigned_int = cb;
-}
diff --git a/plugins/ctf/common/bfcr/bfcr.h b/plugins/ctf/common/bfcr/bfcr.h
deleted file mode 100644 (file)
index 66a7ef7..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-#ifndef CTF_BFCR_H
-#define CTF_BFCR_H
-
-/*
- * Babeltrace - CTF binary field class reader (BFCR)
- *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#include "../metadata/ctf-meta.h"
-
-/**
- * @file bfcr.h
- *
- * Event-driven CTF binary field class reader (BFCR).
- *
- * This is a common, internal API used by CTF source plugins. It allows
- * a binary CTF IR field class to be decoded from user-provided buffers.
- * As the class is decoded (and, possibly, its nested classes),
- * registered user callback functions are called.
- *
- * This API is only concerned with reading one CTF class at a time from
- * one or more buffer of bytes. It does not know CTF dynamic scopes,
- * events, or streams. Sequence lengths and selected variant classes are
- * requested to the user when needed.
- */
-
-/**
- * Binary class reader API status codes.
- */
-enum bt_bfcr_status {
-       /** Out of memory. */
-       BT_BFCR_STATUS_ENOMEM =         -5,
-       /**
-        * The binary stream reader reached the end of the user-provided
-        * buffer, but data is still needed to finish decoding the
-        * requested class.
-        *
-        * The user needs to call bt_bfcr_continue() as long as
-        * #BT_BFCR_STATUS_EOF is returned to complete the decoding
-        * process of a given class.
-        */
-       BT_BFCR_STATUS_EOF =            1,
-
-       /** Invalid argument. */
-       BT_BFCR_STATUS_INVAL =          -3,
-
-       /** General error. */
-       BT_BFCR_STATUS_ERROR =          -1,
-
-       /** Everything okay. */
-       BT_BFCR_STATUS_OK =             0,
-};
-
-/** Field class reader. */
-struct bt_bfcr;
-
-typedef enum bt_bfcr_status (* bt_bfcr_unsigned_int_cb_func)(uint64_t,
-               struct ctf_field_class *, void *);
-
-/*
- * Field class reader user callback functions.
- */
-struct bt_bfcr_cbs {
-       /**
-        * Field class callback functions.
-        *
-        * This CTF binary class reader is event-driven. The following
-        * functions are called during the decoding process, either when
-        * a compound class begins/ends, or when a basic class is
-        * completely decoded (along with its value).
-        *
-        * Each function also receives the CTF field class associated
-        * with the call, and user data (registered to the class reader
-        * calling them).
-        *
-        * Actual trace IR fields are \em not created here; this would
-        * be the responsibility of a class reader's user (the provider
-        * of those callback functions).
-        *
-        * All the class callback functions return one of the following
-        * values:
-        *
-        *   - <b>#BT_BFCR_STATUS_OK</b>: Everything is okay;
-        *     continue the decoding process.
-        *   - <b>#BT_BFCR_STATUS_ERROR</b>: General error (reported
-        *     to class reader's user).
-        *
-        * Any member of this structure may be set to \c NULL, should
-        * a specific message be not needed.
-        */
-       struct {
-               /**
-                * Called when a signed integer class is completely
-                * decoded. This could also be the supporting signed
-                * integer class of an enumeration class (\p class will
-                * indicate this).
-                *
-                * @param value         Signed integer value
-                * @param class         Integer or enumeration class
-                * @param data          User data
-                * @returns             #BT_BFCR_STATUS_OK or
-                *                      #BT_BFCR_STATUS_ERROR
-                */
-               enum bt_bfcr_status (* signed_int)(int64_t value,
-                               struct ctf_field_class *cls, void *data);
-
-               /**
-                * Called when an unsigned integer class is completely
-                * decoded. This could also be the supporting signed
-                * integer class of an enumeration class (\p class will
-                * indicate this).
-                *
-                * @param value         Unsigned integer value
-                * @param class         Integer or enumeration class
-                * @param data          User data
-                * @returns             #BT_BFCR_STATUS_OK or
-                *                      #BT_BFCR_STATUS_ERROR
-                */
-               bt_bfcr_unsigned_int_cb_func unsigned_int;
-
-               /**
-                * Called when a floating point number class is
-                * completely decoded.
-                *
-                * @param value         Floating point number value
-                * @param class         Floating point number class
-                * @param data          User data
-                * @returns             #BT_BFCR_STATUS_OK or
-                *                      #BT_BFCR_STATUS_ERROR
-                */
-               enum bt_bfcr_status (* floating_point)(double value,
-                               struct ctf_field_class *cls, void *data);
-
-               /**
-                * Called when a string class begins.
-                *
-                * All the following user callback function calls will
-                * be made to bt_bfcr_cbs::classes::string(), each of
-                * them providing one substring of the complete string
-                * class's value.
-                *
-                * @param class         Beginning string class
-                * @param data          User data
-                * @returns             #BT_BFCR_STATUS_OK or
-                *                      #BT_BFCR_STATUS_ERROR
-                */
-               enum bt_bfcr_status (* string_begin)(
-                               struct ctf_field_class *cls, void *data);
-
-               /**
-                * Called when a string class's substring is decoded
-                * (between a call to bt_bfcr_cbs::classes::string_begin()
-                * and a call to bt_bfcr_cbs::classes::string_end()).
-                *
-                * @param value         String value (\em not null-terminated)
-                * @param len           String value length
-                * @param class         String class
-                * @param data          User data
-                * @returns             #BT_BFCR_STATUS_OK or
-                *                      #BT_BFCR_STATUS_ERROR
-                */
-               enum bt_bfcr_status (* string)(const char *value,
-                               size_t len, struct ctf_field_class *cls,
-                               void *data);
-
-               /**
-                * Called when a string class ends.
-                *
-                * @param class         Ending string class
-                * @param data          User data
-                * @returns             #BT_BFCR_STATUS_OK or
-                *                      #BT_BFCR_STATUS_ERROR
-                */
-               enum bt_bfcr_status (* string_end)(
-                               struct ctf_field_class *cls, void *data);
-
-               /**
-                * Called when a compound class begins.
-                *
-                * All the following class callback function calls will
-                * signal sequential elements of this compound class,
-                * until the next corresponding
-                * bt_bfcr_cbs::classes::compound_end() is called.
-                *
-                * If \p class is a variant class, then only one class
-                * callback function call will follow before the call to
-                * bt_bfcr_cbs::classes::compound_end(). This single
-                * call indicates the selected class of this variant
-                * class.
-                *
-                * @param class         Beginning compound class
-                * @param data          User data
-                * @returns             #BT_BFCR_STATUS_OK or
-                *                      #BT_BFCR_STATUS_ERROR
-                */
-               enum bt_bfcr_status (* compound_begin)(
-                               struct ctf_field_class *cls, void *data);
-
-               /**
-                * Called when a compound class ends.
-                *
-                * @param class         Ending compound class
-                * @param data          User data
-                * @returns             #BT_BFCR_STATUS_OK or
-                *                      #BT_BFCR_STATUS_ERROR
-                */
-               enum bt_bfcr_status (* compound_end)(
-                               struct ctf_field_class *cls, void *data);
-       } classes;
-
-       /**
-        * Query callback functions are used when the class reader needs
-        * dynamic information, i.e. a sequence class's current length
-        * or a variant class's current selected class.
-        *
-        * Both functions need to be set unless it is known that no
-        * sequences or variants will have to be decoded.
-        */
-       struct {
-               /**
-                * Called to query the current length of a given sequence
-                * class.
-                *
-                * @param class         Sequence class
-                * @param data          User data
-                * @returns             Sequence length or
-                *                      #BT_BFCR_STATUS_ERROR on error
-                */
-               int64_t (* get_sequence_length)(struct ctf_field_class *cls,
-                               void *data);
-
-               /**
-                * Called to query the current selected class of a given
-                * variant class.
-                *
-                * @param class         Variant class
-                * @param data          User data
-                * @returns             Current selected class (owned by
-                *                      this) or \c NULL on error
-                */
-               struct ctf_field_class * (* borrow_variant_selected_field_class)(
-                               struct ctf_field_class *cls, void *data);
-       } query;
-};
-
-/**
- * Creates a CTF binary class reader.
- *
- * @param cbs          User callback functions
- * @param data         User data (passed to user callback functions)
- * @returns            New binary class reader on success, or \c NULL on error
- */
-BT_HIDDEN
-struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data);
-
-/**
- * Destroys a CTF binary class reader, freeing all internal resources.
- *
- * @param bfcr Binary class reader
- */
-BT_HIDDEN
-void bt_bfcr_destroy(struct bt_bfcr *bfcr);
-
-/**
- * Decodes a given CTF class from a buffer of bytes.
- *
- * The number of \em bits consumed by this function is returned.
- *
- * The \p status output parameter is where a status is written, amongst
- * the following:
- *
- *   - <b>#BT_BFCR_STATUS_OK</b>: Decoding is done.
- *   - <b>#BT_BFCR_STATUS_EOF</b>: The end of the buffer was reached,
- *     but more data is needed to finish the decoding process of the
- *     requested class. The user needs to call bt_bfcr_continue()
- *     as long as #BT_BFCR_STATUS_EOF is returned to complete the
- *     decoding process of the original class.
- *   - <b>#BT_BFCR_STATUS_INVAL</b>: Invalid argument.
- *   - <b>#BT_BFCR_STATUS_ERROR</b>: General error.
- *
- * Calling this function resets the class reader's internal state. If
- * #BT_BFCR_STATUS_EOF is returned, bt_bfcr_continue() needs to
- * be called next, \em not bt_bfcr_decode().
- *
- * @param bfcr                 Binary class reader
- * @param class                        Field class to decode
- * @param buf                  Buffer
- * @param offset               Offset of first bit from \p buf (bits)
- * @param packet_offset                Offset of \p offset within the CTF
- *                             binary packet containing \p class (bits)
- * @param sz                   Size of buffer in bytes (from \p buf)
- * @param status               Returned status (see description above)
- * @returns                    Number of consumed bits
- */
-BT_HIDDEN
-size_t bt_bfcr_start(struct bt_bfcr *bfcr,
-               struct ctf_field_class *cls, const uint8_t *buf,
-               size_t offset, size_t packet_offset, size_t sz,
-               enum bt_bfcr_status *status);
-
-/**
- * Continues the decoding process a given CTF class.
- *
- * The number of bits consumed by this function is returned.
- *
- * The \p status output parameter is where a status is placed, amongst
- * the following:
- *
- *   - <b>#BT_BFCR_STATUS_OK</b>: decoding is done.
- *   - <b>#BT_BFCR_STATUS_EOF</b>: the end of the buffer was reached,
- *     but more data is needed to finish the decoding process of the
- *     requested class. The user needs to call bt_bfcr_continue()
- *     as long as #BT_BFCR_STATUS_EOF is returned to complete the
- *     decoding process of the original class.
- *   - <b>#BT_BFCR_STATUS_INVAL</b>: invalid argument.
- *   - <b>#BT_BFCR_STATUS_ERROR</b>: general error.
- *
- * @param bfcr         Binary class reader
- * @param buf          Buffer
- * @param sz           Size of buffer in bytes (from \p offset)
- * @param status       Returned status (see description above)
- * @returns            Number of consumed bits
- */
-BT_HIDDEN
-size_t bt_bfcr_continue(struct bt_bfcr *bfcr,
-               const uint8_t *buf, size_t sz,
-               enum bt_bfcr_status *status);
-
-BT_HIDDEN
-void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr,
-               bt_bfcr_unsigned_int_cb_func cb);
-
-static inline
-const char *bt_bfcr_status_string(enum bt_bfcr_status status)
-{
-       switch (status) {
-       case BT_BFCR_STATUS_ENOMEM:
-               return "BT_BFCR_STATUS_ENOMEM";
-       case BT_BFCR_STATUS_EOF:
-               return "BT_BFCR_STATUS_EOF";
-       case BT_BFCR_STATUS_INVAL:
-               return "BT_BFCR_STATUS_INVAL";
-       case BT_BFCR_STATUS_ERROR:
-               return "BT_BFCR_STATUS_ERROR";
-       case BT_BFCR_STATUS_OK:
-               return "BT_BFCR_STATUS_OK";
-       default:
-               return "(unknown)";
-       }
-}
-
-#endif /* CTF_BFCR_H */
diff --git a/plugins/ctf/common/bfcr/btr.gdb b/plugins/ctf/common/bfcr/btr.gdb
deleted file mode 100644 (file)
index 71cc0f6..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-define ctf-btr-show-stack
-    if (stack_empty($arg0))
-        printf "stack is empty!\n"
-    else
-        set $stack_size = stack_size($arg0)
-        set $stack_at = (int) ($stack_size - 1)
-        printf "%3s    %10s   %4s    %3s\n", "pos", "base addr", "blen", "idx"
-
-        while ($stack_at >= 0)
-            set $stack_entry = (struct stack_entry *) g_ptr_array_index($arg0->entries, $stack_at)
-
-            if ($stack_at == $stack_size - 1)
-                printf "%3d    %10p    %3d    %3d  <-- top\n", $stack_at, \
-                    $stack_entry->base_class, $stack_entry->base_len, \
-                    $stack_entry->index
-            else
-                printf "%3d    %10p    %3d    %3d\n", $stack_at, \
-                    $stack_entry->base_class, $stack_entry->base_len, \
-                    $stack_entry->index
-            end
-            set $stack_at = $stack_at - 1
-        end
-    end
-end
diff --git a/plugins/ctf/common/bfcr/logging.c b/plugins/ctf/common/bfcr/logging.c
deleted file mode 100644 (file)
index 2dd5a5b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bfcr_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bfcr_log_level, "BABELTRACE_PLUGIN_CTF_BFCR_LOG_LEVEL");
diff --git a/plugins/ctf/common/bfcr/logging.h b/plugins/ctf/common/bfcr/logging.h
deleted file mode 100644 (file)
index cd6fb68..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef CTF_BFCR_LOGGING_H
-#define CTF_BFCR_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bfcr_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bfcr_log_level);
-
-#endif /* CTF_BFCR_LOGGING_H */
diff --git a/plugins/ctf/common/metadata/Makefile.am b/plugins/ctf/common/metadata/Makefile.am
deleted file mode 100644 (file)
index fa5b6f8..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-AM_CPPFLAGS += -I$(builddir) -I$(srcdir)
-AM_YFLAGS = -t -d -v
-
-noinst_LTLIBRARIES = libctf-parser.la libctf-ast.la
-
-BUILT_SOURCES = parser.h
-
-libctf_parser_la_SOURCES = lexer.l parser.y objstack.c
-# scanner-symbols.h is included to prefix generated yy_* symbols
-# with bt_.
-libctf_parser_la_CPPFLAGS = $(AM_CPPFLAGS) \
-               -include $(srcdir)/scanner-symbols.h
-libctf_parser_la_CFLAGS = $(AM_CFLAGS) -Wno-unused-function
-
-libctf_ast_la_SOURCES = \
-       visitor-generate-ir.c \
-       visitor-semantic-validator.c \
-       visitor-parent-links.c \
-       ast.h \
-       objstack.h \
-       parser.h \
-       scanner.h \
-       scanner-symbols.h \
-       decoder.c \
-       decoder.h \
-       logging.c \
-       logging.h \
-       ctf-meta.h \
-       ctf-meta-visitors.h \
-       ctf-meta-validate.c \
-       ctf-meta-update-meanings.c \
-       ctf-meta-update-in-ir.c \
-       ctf-meta-update-default-clock-classes.c \
-       ctf-meta-update-text-array-sequence.c \
-       ctf-meta-update-value-storing-indexes.c \
-       ctf-meta-update-stream-class-config.c \
-       ctf-meta-warn-meaningless-header-fields.c \
-       ctf-meta-translate.c \
-       ctf-meta-resolve.c
-
-libctf_ast_la_LIBADD = $(UUID_LIBS)
-
-if BABELTRACE_BUILD_WITH_MINGW
-libctf_ast_la_LIBADD += -lrpcrt4 -lintl -liconv -lole32 $(POPT_LIBS)
-endif
-
-# start with empty files to clean
-CLEANFILES =
-
-if HAVE_BISON
-# we have bison: we can clean the generated parser files
-CLEANFILES += parser.c parser.h parser.output
-else # HAVE_BISON
-# create target used to stop the build if we want to build the parser,
-# but we don't have the necessary tool to do so
-ERR_MSG = "Error: Cannot build target because bison is missing."
-ERR_MSG += "Make sure bison is installed and run the configure script again."
-
-parser.c parser.h: parser.y
-       @echo $(ERR_MSG)
-       @false
-
-all-local: parser.c parser.h
-endif # HAVE_BISON
-
-if HAVE_FLEX
-# we have flex: we can clean the generated lexer files
-CLEANFILES += lexer.c
-else # HAVE_FLEX
-# create target used to stop the build if we want to build the lexer,
-# but we don't have the necessary tool to do so
-ERR_MSG = "Error: Cannot build target because flex is missing."
-ERR_MSG += "Make sure flex is installed and run the configure script again."
-
-filter-lexer.c: lexer.l
-       @echo $(ERR_MSG)
-       @false
-
-all-local: lexer.c
-endif # HAVE_FLEX
diff --git a/plugins/ctf/common/metadata/ast.h b/plugins/ctf/common/metadata/ast.h
deleted file mode 100644 (file)
index b2eec36..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-#ifndef _CTF_AST_H
-#define _CTF_AST_H
-
-/*
- * ctf-ast.h
- *
- * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace2/list-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#include "decoder.h"
-#include "ctf-meta.h"
-
-// the parameter name (of the reentrant 'yyparse' function)
-// data is a pointer to a 'SParserParam' structure
-//#define YYPARSE_PARAM        scanner
-
-struct ctf_node;
-struct ctf_parser;
-struct ctf_visitor_generate_ir;
-
-#define EINCOMPLETE    1000
-
-#define FOREACH_CTF_NODES(F) \
-       F(NODE_UNKNOWN) \
-       F(NODE_ROOT) \
-       F(NODE_ERROR) \
-       F(NODE_EVENT) \
-       F(NODE_STREAM) \
-       F(NODE_ENV) \
-       F(NODE_TRACE) \
-       F(NODE_CLOCK) \
-       F(NODE_CALLSITE) \
-       F(NODE_CTF_EXPRESSION) \
-       F(NODE_UNARY_EXPRESSION) \
-       F(NODE_TYPEDEF) \
-       F(NODE_TYPEALIAS_TARGET) \
-       F(NODE_TYPEALIAS_ALIAS) \
-       F(NODE_TYPEALIAS) \
-       F(NODE_TYPE_SPECIFIER) \
-       F(NODE_TYPE_SPECIFIER_LIST) \
-       F(NODE_POINTER) \
-       F(NODE_TYPE_DECLARATOR) \
-       F(NODE_FLOATING_POINT) \
-       F(NODE_INTEGER) \
-       F(NODE_STRING) \
-       F(NODE_ENUMERATOR) \
-       F(NODE_ENUM) \
-       F(NODE_STRUCT_OR_VARIANT_DECLARATION) \
-       F(NODE_VARIANT) \
-       F(NODE_STRUCT)
-
-enum node_type {
-#define ENTRY(S)       S,
-       FOREACH_CTF_NODES(ENTRY)
-#undef ENTRY
-       NR_NODE_TYPES,
-};
-
-struct ctf_node {
-       /*
-        * Parent node is only set on demand by specific visitor.
-        */
-       struct ctf_node *parent;
-       struct bt_list_head siblings;
-       struct bt_list_head tmp_head;
-       unsigned int lineno;
-       /*
-        * We mark nodes visited in the generate-ir phase (last
-        * phase). We only mark the 1-depth level nodes as visited
-        * (never the root node, and not their sub-nodes). This allows
-        * skipping already visited nodes when doing incremental
-        * metadata append.
-        */
-       int visited;
-
-       enum node_type type;
-       union {
-               struct {
-               } unknown;
-               struct {
-                       /*
-                        * Children nodes are ctf_expression, field_class_def,
-                        * field_class_alias and field_class_specifier_list.
-                        */
-                       struct bt_list_head declaration_list;
-                       struct bt_list_head trace;
-                       struct bt_list_head env;
-                       struct bt_list_head stream;
-                       struct bt_list_head event;
-                       struct bt_list_head clock;
-                       struct bt_list_head callsite;
-               } root;
-               struct {
-                       /*
-                        * Children nodes are ctf_expression, field_class_def,
-                        * field_class_alias and field_class_specifier_list.
-                        */
-                       struct bt_list_head declaration_list;
-               } event;
-               struct {
-                       /*
-                        * Children nodes are ctf_expression, field_class_def,
-                        * field_class_alias and field_class_specifier_list.
-                        */
-                       struct bt_list_head declaration_list;
-               } stream;
-               struct {
-                       /*
-                        * Children nodes are ctf_expression, field_class_def,
-                        * field_class_alias and field_class_specifier_list.
-                        */
-                       struct bt_list_head declaration_list;
-               } env;
-               struct {
-                       /*
-                        * Children nodes are ctf_expression, field_class_def,
-                        * field_class_alias and field_class_specifier_list.
-                        */
-                       struct bt_list_head declaration_list;
-               } trace;
-               struct {
-                       /*
-                        * Children nodes are ctf_expression, field_class_def,
-                        * field_class_alias and field_class_specifier_list.
-                        */
-                       struct bt_list_head declaration_list;
-               } clock;
-               struct {
-                       /*
-                        * Children nodes are ctf_expression, field_class_def,
-                        * field_class_alias and field_class_specifier_list.
-                        */
-                       struct bt_list_head declaration_list;
-               } callsite;
-               struct {
-                       struct bt_list_head left;       /* Should be string */
-                       struct bt_list_head right;      /* Unary exp. or type */
-               } ctf_expression;
-               struct {
-                       enum {
-                               UNARY_UNKNOWN = 0,
-                               UNARY_STRING,
-                               UNARY_SIGNED_CONSTANT,
-                               UNARY_UNSIGNED_CONSTANT,
-                               UNARY_SBRAC,
-                       } type;
-                       union {
-                               /*
-                                * string for identifier, id_type, keywords,
-                                * string literals and character constants.
-                                */
-                               char *string;
-                               int64_t signed_constant;
-                               uint64_t unsigned_constant;
-                               struct ctf_node *sbrac_exp;
-                       } u;
-                       enum {
-                               UNARY_LINK_UNKNOWN = 0,
-                               UNARY_DOTLINK,
-                               UNARY_ARROWLINK,
-                               UNARY_DOTDOTDOT,
-                       } link;
-               } unary_expression;
-               struct {
-                       struct ctf_node *field_class_specifier_list;
-                       struct bt_list_head field_class_declarators;
-               } field_class_def;
-               /* new type is "alias", existing type "target" */
-               struct {
-                       struct ctf_node *field_class_specifier_list;
-                       struct bt_list_head field_class_declarators;
-               } field_class_alias_target;
-               struct {
-                       struct ctf_node *field_class_specifier_list;
-                       struct bt_list_head field_class_declarators;
-               } field_class_alias_name;
-               struct {
-                       struct ctf_node *target;
-                       struct ctf_node *alias;
-               } field_class_alias;
-               struct {
-                       enum {
-                               TYPESPEC_UNKNOWN = 0,
-                               TYPESPEC_VOID,
-                               TYPESPEC_CHAR,
-                               TYPESPEC_SHORT,
-                               TYPESPEC_INT,
-                               TYPESPEC_LONG,
-                               TYPESPEC_FLOAT,
-                               TYPESPEC_DOUBLE,
-                               TYPESPEC_SIGNED,
-                               TYPESPEC_UNSIGNED,
-                               TYPESPEC_BOOL,
-                               TYPESPEC_COMPLEX,
-                               TYPESPEC_IMAGINARY,
-                               TYPESPEC_CONST,
-                               TYPESPEC_ID_TYPE,
-                               TYPESPEC_FLOATING_POINT,
-                               TYPESPEC_INTEGER,
-                               TYPESPEC_STRING,
-                               TYPESPEC_STRUCT,
-                               TYPESPEC_VARIANT,
-                               TYPESPEC_ENUM,
-                       } type;
-                       /* For struct, variant and enum */
-                       struct ctf_node *node;
-                       const char *id_type;
-               } field_class_specifier;
-               struct {
-                       /* list of field_class_specifier */
-                       struct bt_list_head head;
-               } field_class_specifier_list;
-               struct {
-                       unsigned int const_qualifier;
-               } pointer;
-               struct {
-                       struct bt_list_head pointers;
-                       enum {
-                               TYPEDEC_UNKNOWN = 0,
-                               TYPEDEC_ID,     /* identifier */
-                               TYPEDEC_NESTED, /* (), array or sequence */
-                       } type;
-                       union {
-                               char *id;
-                               struct {
-                                       /* typedec has no pointer list */
-                                       struct ctf_node *field_class_declarator;
-                                       /*
-                                        * unary expression (value) or
-                                        * field_class_specifier_list.
-                                        */
-                                       struct bt_list_head length;
-                                       /* for abstract type declarator */
-                                       unsigned int abstract_array;
-                               } nested;
-                       } u;
-                       struct ctf_node *bitfield_len;
-               } field_class_declarator;
-               struct {
-                       /* Children nodes are ctf_expression. */
-                       struct bt_list_head expressions;
-               } floating_point;
-               struct {
-                       /* Children nodes are ctf_expression. */
-                       struct bt_list_head expressions;
-               } integer;
-               struct {
-                       /* Children nodes are ctf_expression. */
-                       struct bt_list_head expressions;
-               } string;
-               struct {
-                       char *id;
-                       /*
-                        * Range list or single value node. Contains unary
-                        * expressions.
-                        */
-                       struct bt_list_head values;
-               } enumerator;
-               struct {
-                       char *enum_id;
-                       /*
-                        * Either NULL, or points to unary expression or
-                        * field_class_specifier_list.
-                        */
-                       struct ctf_node *container_field_class;
-                       struct bt_list_head enumerator_list;
-                       int has_body;
-               } _enum;
-               struct {
-                       struct ctf_node *field_class_specifier_list;
-                       struct bt_list_head field_class_declarators;
-               } struct_or_variant_declaration;
-               struct {
-                       char *name;
-                       char *choice;
-                       /*
-                        * list of field_class_def, field_class_alias and
-                        * declarations
-                        */
-                       struct bt_list_head declaration_list;
-                       int has_body;
-               } variant;
-               struct {
-                       char *name;
-                       /*
-                        * list of field_class_def, field_class_alias and
-                        * declarations
-                        */
-                       struct bt_list_head declaration_list;
-                       int has_body;
-                       struct bt_list_head min_align;  /* align() attribute */
-               } _struct;
-       } u;
-};
-
-struct ctf_ast {
-       struct ctf_node root;
-};
-
-const char *node_type(struct ctf_node *node);
-
-BT_HIDDEN
-struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(
-               bt_self_component_source *self_comp,
-               const struct ctf_metadata_decoder_config *config);
-
-void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor);
-
-BT_HIDDEN
-bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(
-               struct ctf_visitor_generate_ir *visitor);
-
-BT_HIDDEN
-struct ctf_trace_class *ctf_visitor_generate_ir_borrow_ctf_trace_class(
-               struct ctf_visitor_generate_ir *visitor);
-
-BT_HIDDEN
-int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
-               struct ctf_node *node);
-
-BT_HIDDEN
-int ctf_visitor_semantic_check(int depth, struct ctf_node *node);
-
-BT_HIDDEN
-int ctf_visitor_parent_links(int depth, struct ctf_node *node);
-
-#endif /* _CTF_AST_H */
diff --git a/plugins/ctf/common/metadata/ctf-meta-resolve.c b/plugins/ctf/common/metadata/ctf-meta-resolve.c
deleted file mode 100644 (file)
index 2d54d0f..0000000
+++ /dev/null
@@ -1,1316 +0,0 @@
-/*
- * Copyright 2016-2018 - Philippe Proulx <pproulx@efficios.com>
- * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-RESOLVE"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <glib.h>
-
-#include "ctf-meta-visitors.h"
-
-typedef GPtrArray field_class_stack;
-
-/*
- * A stack frame.
- *
- * `fc` contains a compound field class (structure, variant, array,
- * or sequence) and `index` indicates the index of the field class in
- * the upper frame (-1 for array and sequence field classes). `name`
- * indicates the name of the field class in the upper frame (empty
- * string for array and sequence field classes).
- */
-struct field_class_stack_frame {
-       struct ctf_field_class *fc;
-       int64_t index;
-};
-
-/*
- * The current context of the resolving engine.
- */
-struct resolve_context {
-       struct ctf_trace_class *tc;
-       struct ctf_stream_class *sc;
-       struct ctf_event_class *ec;
-
-       struct {
-               struct ctf_field_class *packet_header;
-               struct ctf_field_class *packet_context;
-               struct ctf_field_class *event_header;
-               struct ctf_field_class *event_common_context;
-               struct ctf_field_class *event_spec_context;
-               struct ctf_field_class *event_payload;
-       } scopes;
-
-       /* Root scope being visited */
-       enum ctf_scope root_scope;
-       field_class_stack *field_class_stack;
-       struct ctf_field_class *cur_fc;
-};
-
-/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
-static const char * const absolute_path_prefixes[] = {
-       [CTF_SCOPE_PACKET_HEADER]               = "trace.packet.header.",
-       [CTF_SCOPE_PACKET_CONTEXT]              = "stream.packet.context.",
-       [CTF_SCOPE_EVENT_HEADER]                = "stream.event.header.",
-       [CTF_SCOPE_EVENT_COMMON_CONTEXT]        = "stream.event.context.",
-       [CTF_SCOPE_EVENT_SPECIFIC_CONTEXT]      = "event.context.",
-       [CTF_SCOPE_EVENT_PAYLOAD]               = "event.fields.",
-};
-
-/* Number of path tokens used for the absolute prefixes */
-static const uint64_t absolute_path_prefix_ptoken_counts[] = {
-       [CTF_SCOPE_PACKET_HEADER]               = 3,
-       [CTF_SCOPE_PACKET_CONTEXT]              = 3,
-       [CTF_SCOPE_EVENT_HEADER]                = 3,
-       [CTF_SCOPE_EVENT_COMMON_CONTEXT]        = 3,
-       [CTF_SCOPE_EVENT_SPECIFIC_CONTEXT]      = 2,
-       [CTF_SCOPE_EVENT_PAYLOAD]               = 2,
-};
-
-static
-void destroy_field_class_stack_frame(struct field_class_stack_frame *frame)
-{
-       if (!frame) {
-               return;
-       }
-
-       g_free(frame);
-}
-
-/*
- * Creates a class stack.
- */
-static
-field_class_stack *field_class_stack_create(void)
-{
-       return g_ptr_array_new_with_free_func(
-               (GDestroyNotify) destroy_field_class_stack_frame);
-}
-
-/*
- * Destroys a class stack.
- */
-static
-void field_class_stack_destroy(field_class_stack *stack)
-{
-       if (stack) {
-               g_ptr_array_free(stack, TRUE);
-       }
-}
-
-/*
- * Pushes a field class onto a class stack.
- */
-static
-int field_class_stack_push(field_class_stack *stack, struct ctf_field_class *fc)
-{
-       int ret = 0;
-       struct field_class_stack_frame *frame = NULL;
-
-       if (!stack || !fc) {
-               BT_LOGE("Invalid parameter: stack or field class is NULL.");
-               ret = -1;
-               goto end;
-       }
-
-       frame = g_new0(struct field_class_stack_frame, 1);
-       if (!frame) {
-               BT_LOGE_STR("Failed to allocate one field class stack frame.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_LOGV("Pushing field class on context's stack: "
-               "fc-addr=%p, stack-size-before=%u", fc, stack->len);
-       frame->fc = fc;
-       g_ptr_array_add(stack, frame);
-
-end:
-       return ret;
-}
-
-/*
- * Checks whether or not `stack` is empty.
- */
-static
-bool field_class_stack_empty(field_class_stack *stack)
-{
-       return stack->len == 0;
-}
-
-/*
- * Returns the number of frames in `stack`.
- */
-static
-size_t field_class_stack_size(field_class_stack *stack)
-{
-       return stack->len;
-}
-
-/*
- * Returns the top frame of `stack`.
- */
-static
-struct field_class_stack_frame *field_class_stack_peek(field_class_stack *stack)
-{
-       struct field_class_stack_frame *entry = NULL;
-
-       if (!stack || field_class_stack_empty(stack)) {
-               goto end;
-       }
-
-       entry = g_ptr_array_index(stack, stack->len - 1);
-end:
-       return entry;
-}
-
-/*
- * Returns the frame at index `index` in `stack`.
- */
-static
-struct field_class_stack_frame *field_class_stack_at(field_class_stack *stack,
-               size_t index)
-{
-       struct field_class_stack_frame *entry = NULL;
-
-       if (!stack || index >= stack->len) {
-               goto end;
-       }
-
-       entry = g_ptr_array_index(stack, index);
-
-end:
-       return entry;
-}
-
-/*
- * Removes the top frame of `stack`.
- */
-static
-void field_class_stack_pop(field_class_stack *stack)
-{
-       if (!field_class_stack_empty(stack)) {
-               /*
-                * This will call the frame's destructor and free it, as
-                * well as put its contained field class.
-                */
-               BT_LOGV("Popping context's stack: stack-size-before=%u",
-                       stack->len);
-               g_ptr_array_set_size(stack, stack->len - 1);
-       }
-}
-
-/*
- * Returns the scope field class of `scope` in the context `ctx`.
- */
-static
-struct ctf_field_class *borrow_class_from_ctx(struct resolve_context *ctx,
-               enum ctf_scope scope)
-{
-       switch (scope) {
-       case CTF_SCOPE_PACKET_HEADER:
-               return ctx->scopes.packet_header;
-       case CTF_SCOPE_PACKET_CONTEXT:
-               return ctx->scopes.packet_context;
-       case CTF_SCOPE_EVENT_HEADER:
-               return ctx->scopes.event_header;
-       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
-               return ctx->scopes.event_common_context;
-       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               return ctx->scopes.event_spec_context;
-       case CTF_SCOPE_EVENT_PAYLOAD:
-               return ctx->scopes.event_payload;
-       default:
-               abort();
-       }
-
-       return NULL;
-}
-
-/*
- * Returns the CTF scope from a path string. May return -1 if the path
- * is found to be relative.
- */
-static
-enum ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
-{
-       enum ctf_scope scope;
-       enum ctf_scope ret = -1;
-       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
-               sizeof(*absolute_path_prefixes);
-
-       for (scope = CTF_SCOPE_PACKET_HEADER; scope < CTF_SCOPE_PACKET_HEADER +
-                       prefixes_count; scope++) {
-               /*
-                * Chech if path string starts with a known absolute
-                * path prefix.
-                *
-                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
-                */
-               if (strncmp(pathstr, absolute_path_prefixes[scope],
-                               strlen(absolute_path_prefixes[scope]))) {
-                       /* Prefix does not match: try the next one */
-                       BT_LOGV("Prefix does not match: trying the next one: "
-                               "path=\"%s\", path-prefix=\"%s\", scope=%s",
-                               pathstr, absolute_path_prefixes[scope],
-                               ctf_scope_string(scope));
-                       continue;
-               }
-
-               /* Found it! */
-               ret = scope;
-               BT_LOGV("Found root scope from absolute path: "
-                       "path=\"%s\", scope=%s", pathstr,
-                       ctf_scope_string(scope));
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Destroys a path token.
- */
-static
-void ptokens_destroy_func(gpointer ptoken, gpointer data)
-{
-       g_string_free(ptoken, TRUE);
-}
-
-/*
- * Destroys a path token list.
- */
-static
-void ptokens_destroy(GList *ptokens)
-{
-       if (!ptokens) {
-               return;
-       }
-
-       g_list_foreach(ptokens, ptokens_destroy_func, NULL);
-       g_list_free(ptokens);
-}
-
-/*
- * Returns the string contained in a path token.
- */
-static
-const char *ptoken_get_string(GList *ptoken)
-{
-       GString *tokenstr = (GString *) ptoken->data;
-
-       return tokenstr->str;
-}
-
-/*
- * Converts a path string to a path token list, that is, splits the
- * individual words of a path string into a list of individual
- * strings.
- */
-static
-GList *pathstr_to_ptokens(const char *pathstr)
-{
-       const char *at = pathstr;
-       const char *last = at;
-       GList *ptokens = NULL;
-
-       for (;;) {
-               if (*at == '.' || *at == '\0') {
-                       GString *tokenstr;
-
-                       if (at == last) {
-                               /* Error: empty token */
-                               BT_LOGE("Empty path token: path=\"%s\", pos=%u",
-                                       pathstr, (unsigned int) (at - pathstr));
-                               goto error;
-                       }
-
-                       tokenstr = g_string_new(NULL);
-                       g_string_append_len(tokenstr, last, at - last);
-                       ptokens = g_list_append(ptokens, tokenstr);
-                       last = at + 1;
-               }
-
-               if (*at == '\0') {
-                       break;
-               }
-
-               at++;
-       }
-
-       return ptokens;
-
-error:
-       ptokens_destroy(ptokens);
-       return NULL;
-}
-
-/*
- * Converts a path token list to a field path object. The path token
- * list is relative from `fc`. The index of the source looking for its
- * target within `fc` is indicated by `src_index`. This can be `INT64_MAX`
- * if the source is contained in `fc`.
- *
- * `field_path` is an output parameter owned by the caller that must be
- * filled here.
- */
-static
-int ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path,
-               struct ctf_field_class *fc, int64_t src_index)
-{
-       int ret = 0;
-       GList *cur_ptoken = ptokens;
-       bool first_level_done = false;
-
-       /* Locate target */
-       while (cur_ptoken) {
-               int64_t child_index;
-               struct ctf_field_class *child_fc;
-               const char *ft_name = ptoken_get_string(cur_ptoken);
-
-               BT_LOGV("Current path token: token=\"%s\"", ft_name);
-
-               /* Find to which index corresponds the current path token */
-               if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY ||
-                               fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
-                       child_index = -1;
-               } else {
-                       child_index =
-                               ctf_field_class_compound_get_field_class_index_from_name(
-                                       fc, ft_name);
-                       if (child_index < 0) {
-                               /*
-                                * Error: field name does not exist or
-                                * wrong current class.
-                                */
-                               BT_LOGV("Cannot get index of field class: "
-                                       "field-name=\"%s\", "
-                                       "src-index=%" PRId64 ", "
-                                       "child-index=%" PRId64 ", "
-                                       "first-level-done=%d",
-                                       ft_name, src_index, child_index,
-                                       first_level_done);
-                               ret = -1;
-                               goto end;
-                       } else if (child_index > src_index &&
-                                       !first_level_done) {
-                               BT_LOGV("Child field class is located after source field class: "
-                                       "field-name=\"%s\", "
-                                       "src-index=%" PRId64 ", "
-                                       "child-index=%" PRId64 ", "
-                                       "first-level-done=%d",
-                                       ft_name, src_index, child_index,
-                                       first_level_done);
-                               ret = -1;
-                               goto end;
-                       }
-
-                       /* Next path token */
-                       cur_ptoken = g_list_next(cur_ptoken);
-                       first_level_done = true;
-               }
-
-               /* Create new field path entry */
-               ctf_field_path_append_index(field_path, child_index);
-
-               /* Get child field class */
-               child_fc = ctf_field_class_compound_borrow_field_class_by_index(
-                       fc, child_index);
-               BT_ASSERT(child_fc);
-
-               /* Move child class to current class */
-               fc = child_fc;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Converts a known absolute path token list to a field path object
- * within the resolving context `ctx`.
- *
- * `field_path` is an output parameter owned by the caller that must be
- * filled here.
- */
-static
-int absolute_ptokens_to_field_path(GList *ptokens,
-               struct ctf_field_path *field_path,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       GList *cur_ptoken;
-       struct ctf_field_class *fc;
-
-       /*
-        * Make sure we're not referring to a scope within a translated
-        * object.
-        */
-       switch (field_path->root) {
-       case CTF_SCOPE_PACKET_HEADER:
-               if (ctx->tc->is_translated) {
-                       BT_LOGE("Trace class is already translated: "
-                               "root-scope=%s",
-                               ctf_scope_string(field_path->root));
-                       ret = -1;
-                       goto end;
-               }
-
-               break;
-       case CTF_SCOPE_PACKET_CONTEXT:
-       case CTF_SCOPE_EVENT_HEADER:
-       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
-               if (!ctx->sc) {
-                       BT_LOGE("No current stream class: "
-                               "root-scope=%s",
-                               ctf_scope_string(field_path->root));
-                       ret = -1;
-                       goto end;
-               }
-
-               if (ctx->sc->is_translated) {
-                       BT_LOGE("Stream class is already translated: "
-                               "root-scope=%s",
-                               ctf_scope_string(field_path->root));
-                       ret = -1;
-                       goto end;
-               }
-
-               break;
-       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
-       case CTF_SCOPE_EVENT_PAYLOAD:
-               if (!ctx->ec) {
-                       BT_LOGE("No current event class: "
-                               "root-scope=%s",
-                               ctf_scope_string(field_path->root));
-                       ret = -1;
-                       goto end;
-               }
-
-               if (ctx->ec->is_translated) {
-                       BT_LOGE("Event class is already translated: "
-                               "root-scope=%s",
-                               ctf_scope_string(field_path->root));
-                       ret = -1;
-                       goto end;
-               }
-
-               break;
-
-       default:
-               abort();
-       }
-
-       /* Skip absolute path tokens */
-       cur_ptoken = g_list_nth(ptokens,
-               absolute_path_prefix_ptoken_counts[field_path->root]);
-
-       /* Start with root class */
-       fc = borrow_class_from_ctx(ctx, field_path->root);
-       if (!fc) {
-               /* Error: root class is not available */
-               BT_LOGE("Root field class is not available: "
-                       "root-scope=%s",
-                       ctf_scope_string(field_path->root));
-               ret = -1;
-               goto end;
-       }
-
-       /* Locate target */
-       ret = ptokens_to_field_path(cur_ptoken, field_path, fc, INT64_MAX);
-
-end:
-       return ret;
-}
-
-/*
- * Converts a known relative path token list to a field path object
- * within the resolving context `ctx`.
- *
- * `field_path` is an output parameter owned by the caller that must be
- * filled here.
- */
-static
-int relative_ptokens_to_field_path(GList *ptokens,
-               struct ctf_field_path *field_path, struct resolve_context *ctx)
-{
-       int ret = 0;
-       int64_t parent_pos_in_stack;
-       struct ctf_field_path tail_field_path;
-
-       ctf_field_path_init(&tail_field_path);
-       parent_pos_in_stack = field_class_stack_size(ctx->field_class_stack) - 1;
-
-       while (parent_pos_in_stack >= 0) {
-               struct ctf_field_class *parent_class =
-                       field_class_stack_at(ctx->field_class_stack,
-                               parent_pos_in_stack)->fc;
-               int64_t cur_index = field_class_stack_at(ctx->field_class_stack,
-                       parent_pos_in_stack)->index;
-
-               BT_LOGV("Locating target field class from current parent field class: "
-                       "parent-pos=%" PRId64 ", parent-fc-addr=%p, "
-                       "cur-index=%" PRId64,
-                       parent_pos_in_stack, parent_class, cur_index);
-
-               /* Locate target from current parent class */
-               ret = ptokens_to_field_path(ptokens, &tail_field_path,
-                       parent_class, cur_index);
-               if (ret) {
-                       /* Not found... yet */
-                       BT_LOGV_STR("Not found at this point.");
-                       ctf_field_path_clear(&tail_field_path);
-               } else {
-                       /* Found: stitch tail field path to head field path */
-                       uint64_t i = 0;
-                       size_t tail_field_path_len =
-                               tail_field_path.path->len;
-
-                       while (BT_TRUE) {
-                               struct ctf_field_class *cur_class =
-                                       field_class_stack_at(
-                                               ctx->field_class_stack, i)->fc;
-                               int64_t index = field_class_stack_at(
-                                       ctx->field_class_stack, i)->index;
-
-                               if (cur_class == parent_class) {
-                                       break;
-                               }
-
-                               ctf_field_path_append_index(field_path,
-                                       index);
-                               i++;
-                       }
-
-                       for (i = 0; i < tail_field_path_len; i++) {
-                               int64_t index =
-                                       ctf_field_path_borrow_index_by_index(
-                                               &tail_field_path, i);
-
-                               ctf_field_path_append_index(field_path,
-                                       (int64_t) index);
-                       }
-                       break;
-               }
-
-               parent_pos_in_stack--;
-       }
-
-       if (parent_pos_in_stack < 0) {
-               /* Not found */
-               ret = -1;
-       }
-
-       ctf_field_path_fini(&tail_field_path);
-       return ret;
-}
-
-/*
- * Converts a path string to a field path object within the resolving
- * context `ctx`.
- */
-static
-int pathstr_to_field_path(const char *pathstr,
-               struct ctf_field_path *field_path, struct resolve_context *ctx)
-{
-       int ret = 0;
-       enum ctf_scope root_scope;
-       GList *ptokens = NULL;
-
-       /* Convert path string to path tokens */
-       ptokens = pathstr_to_ptokens(pathstr);
-       if (!ptokens) {
-               BT_LOGE("Cannot convert path string to path tokens: "
-                       "path=\"%s\"", pathstr);
-               ret = -1;
-               goto end;
-       }
-
-       /* Absolute or relative path? */
-       root_scope = get_root_scope_from_absolute_pathstr(pathstr);
-
-       if (root_scope == -1) {
-               /* Relative path: start with current root scope */
-               field_path->root = ctx->root_scope;
-               BT_LOGV("Detected relative path: starting with current root scope: "
-                       "scope=%s", ctf_scope_string(field_path->root));
-               ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
-               if (ret) {
-                       BT_LOGE("Cannot get relative field path of path string: "
-                               "path=\"%s\", start-scope=%s, end-scope=%s",
-                               pathstr, ctf_scope_string(ctx->root_scope),
-                               ctf_scope_string(field_path->root));
-                       goto end;
-               }
-       } else {
-               /* Absolute path: use found root scope */
-               field_path->root = root_scope;
-               BT_LOGV("Detected absolute path: using root scope: "
-                       "scope=%s", ctf_scope_string(field_path->root));
-               ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
-               if (ret) {
-                       BT_LOGE("Cannot get absolute field path of path string: "
-                               "path=\"%s\", root-scope=%s",
-                               pathstr, ctf_scope_string(root_scope));
-                       goto end;
-               }
-       }
-
-       if (BT_LOG_ON_VERBOSE && ret == 0) {
-               GString *field_path_pretty = ctf_field_path_string(field_path);
-               const char *field_path_pretty_str =
-                       field_path_pretty ? field_path_pretty->str : NULL;
-
-               BT_LOGV("Found field path: path=\"%s\", field-path=\"%s\"",
-                       pathstr, field_path_pretty_str);
-
-               if (field_path_pretty) {
-                       g_string_free(field_path_pretty, TRUE);
-               }
-       }
-
-end:
-       ptokens_destroy(ptokens);
-       return ret;
-}
-
-/*
- * Retrieves a field class by following the field path `field_path` in
- * the resolving context `ctx`.
- */
-static
-struct ctf_field_class *field_path_to_field_class(
-               struct ctf_field_path *field_path, struct resolve_context *ctx)
-{
-       uint64_t i;
-       struct ctf_field_class *fc;
-
-       /* Start with root class */
-       fc = borrow_class_from_ctx(ctx, field_path->root);
-       if (!fc) {
-               /* Error: root class is not available */
-               BT_LOGE("Root field class is not available: root-scope=%s",
-                       ctf_scope_string(field_path->root));
-               goto end;
-       }
-
-       /* Locate target */
-       for (i = 0; i < field_path->path->len; i++) {
-               struct ctf_field_class *child_fc;
-               int64_t child_index =
-                       ctf_field_path_borrow_index_by_index(field_path, i);
-
-               /* Get child field class */
-               child_fc = ctf_field_class_compound_borrow_field_class_by_index(
-                       fc, child_index);
-               BT_ASSERT(child_fc);
-
-               /* Move child class to current class */
-               fc = child_fc;
-       }
-
-end:
-       return fc;
-}
-
-/*
- * Fills the equivalent field path object of the context class stack.
- */
-static
-void get_ctx_stack_field_path(struct resolve_context *ctx,
-               struct ctf_field_path *field_path)
-{
-       uint64_t i;
-
-       BT_ASSERT(field_path);
-       field_path->root = ctx->root_scope;
-       ctf_field_path_clear(field_path);
-
-       for (i = 0; i < field_class_stack_size(ctx->field_class_stack); i++) {
-               struct field_class_stack_frame *frame =
-                       field_class_stack_at(ctx->field_class_stack, i);
-
-               ctf_field_path_append_index(field_path, frame->index);
-       }
-}
-
-/*
- * Returns the index of the lowest common ancestor of two field path
- * objects having the same root scope.
- */
-int64_t get_field_paths_lca_index(struct ctf_field_path *field_path1,
-               struct ctf_field_path *field_path2)
-{
-       int64_t lca_index = 0;
-       uint64_t field_path1_len, field_path2_len;
-
-       if (BT_LOG_ON_VERBOSE) {
-               GString *field_path1_pretty =
-                       ctf_field_path_string(field_path1);
-               GString *field_path2_pretty =
-                       ctf_field_path_string(field_path2);
-               const char *field_path1_pretty_str =
-                       field_path1_pretty ? field_path1_pretty->str : NULL;
-               const char *field_path2_pretty_str =
-                       field_path2_pretty ? field_path2_pretty->str : NULL;
-
-               BT_LOGV("Finding lowest common ancestor (LCA) between two field paths: "
-                       "field-path-1=\"%s\", field-path-2=\"%s\"",
-                       field_path1_pretty_str, field_path2_pretty_str);
-
-               if (field_path1_pretty) {
-                       g_string_free(field_path1_pretty, TRUE);
-               }
-
-               if (field_path2_pretty) {
-                       g_string_free(field_path2_pretty, TRUE);
-               }
-       }
-
-       /*
-        * Start from both roots and find the first mismatch.
-        */
-       BT_ASSERT(field_path1->root == field_path2->root);
-       field_path1_len = field_path1->path->len;
-       field_path2_len = field_path2->path->len;
-
-       while (true) {
-               int64_t target_index, ctx_index;
-
-               if (lca_index == (int64_t) field_path2_len ||
-                               lca_index == (int64_t) field_path1_len) {
-                       /*
-                        * This means that both field paths never split.
-                        * This is invalid because the target cannot be
-                        * an ancestor of the source.
-                        */
-                       BT_LOGE("Source field class is an ancestor of target field class or vice versa: "
-                               "lca-index=%" PRId64 ", "
-                               "field-path-1-len=%" PRIu64 ", "
-                               "field-path-2-len=%" PRIu64,
-                               lca_index, field_path1_len, field_path2_len);
-                       lca_index = -1;
-                       break;
-               }
-
-               target_index = ctf_field_path_borrow_index_by_index(field_path1,
-                       lca_index);
-               ctx_index = ctf_field_path_borrow_index_by_index(field_path2,
-                       lca_index);
-
-               if (target_index != ctx_index) {
-                       /* LCA index is the previous */
-                       break;
-               }
-
-               lca_index++;
-       }
-
-       BT_LOGV("Found LCA: lca-index=%" PRId64, lca_index);
-       return lca_index;
-}
-
-/*
- * Validates a target field path.
- */
-static
-int validate_target_field_path(struct ctf_field_path *target_field_path,
-               struct ctf_field_class *target_fc,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       struct ctf_field_path ctx_field_path;
-       uint64_t target_field_path_len = target_field_path->path->len;
-       int64_t lca_index;
-
-       /* Get context field path */
-       ctf_field_path_init(&ctx_field_path);
-       get_ctx_stack_field_path(ctx, &ctx_field_path);
-
-       /*
-        * Make sure the target is not a root.
-        */
-       if (target_field_path_len == 0) {
-               BT_LOGE_STR("Target field path's length is 0 (targeting the root).");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Make sure the root of the target field path is not located
-        * after the context field path's root.
-        */
-       if (target_field_path->root > ctx_field_path.root) {
-               BT_LOGE("Target field class is located after source field class: "
-                       "target-root=%s, source-root=%s",
-                       ctf_scope_string(target_field_path->root),
-                       ctf_scope_string(ctx_field_path.root));
-               ret = -1;
-               goto end;
-       }
-
-       if (target_field_path->root == ctx_field_path.root) {
-               int64_t target_index, ctx_index;
-
-               /*
-                * Find the index of the lowest common ancestor of both field
-                * paths.
-                */
-               lca_index = get_field_paths_lca_index(target_field_path,
-                       &ctx_field_path);
-               if (lca_index < 0) {
-                       BT_LOGE_STR("Cannot get least common ancestor.");
-                       ret = -1;
-                       goto end;
-               }
-
-               /*
-                * Make sure the target field path is located before the
-                * context field path.
-                */
-               target_index = ctf_field_path_borrow_index_by_index(
-                       target_field_path, (uint64_t) lca_index);
-               ctx_index = ctf_field_path_borrow_index_by_index(
-                       &ctx_field_path, (uint64_t) lca_index);
-
-               if (target_index >= ctx_index) {
-                       BT_LOGE("Target field class's index is greater than or equal to source field class's index in LCA: "
-                               "lca-index=%" PRId64 ", "
-                               "target-index=%" PRId64 ", "
-                               "source-index=%" PRId64,
-                               lca_index, target_index, ctx_index);
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /*
-        * Make sure the target class has the right class and properties.
-        */
-       switch (ctx->cur_fc->type) {
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-               if (target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE("Variant field class's tag field class is not an enumeration field class: "
-                               "tag-fc-addr=%p, tag-fc-id=%d",
-                               target_fc, target_fc->type);
-                       ret = -1;
-                       goto end;
-               }
-               break;
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_int *int_fc = (void *) target_fc;
-
-               if (target_fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE("Sequence field class's length field class is not an unsigned integer field class: "
-                               "length-fc-addr=%p, length-fc-id=%d",
-                               target_fc, target_fc->type);
-                       ret = -1;
-                       goto end;
-               }
-
-               if (int_fc->is_signed) {
-                       BT_LOGE("Sequence field class's length field class is not an unsigned integer field class: "
-                               "length-fc-addr=%p, length-fc-id=%d",
-                               target_fc, target_fc->type);
-                       ret = -1;
-                       goto end;
-               }
-               break;
-       }
-       default:
-               abort();
-       }
-
-end:
-       ctf_field_path_fini(&ctx_field_path);
-       return ret;
-}
-
-/*
- * Resolves a variant or sequence field class `fc`.
- */
-static
-int resolve_sequence_or_variant_field_class(struct ctf_field_class *fc,
-               struct resolve_context *ctx)
-{
-       int ret = 0;
-       const char *pathstr;
-       struct ctf_field_path target_field_path;
-       struct ctf_field_class *target_fc = NULL;
-       GString *target_field_path_pretty = NULL;
-       const char *target_field_path_pretty_str;
-
-       ctf_field_path_init(&target_field_path);
-
-       /* Get path string */
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_sequence *seq_fc = (void *) fc;
-               pathstr = seq_fc->length_ref->str;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-               pathstr = var_fc->tag_ref->str;
-               break;
-       }
-       default:
-               abort();
-       }
-
-       if (!pathstr) {
-               BT_LOGE_STR("Cannot get path string.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Get target field path out of path string */
-       ret = pathstr_to_field_path(pathstr, &target_field_path, ctx);
-       if (ret) {
-               BT_LOGE("Cannot get target field path for path string: "
-                       "path=\"%s\"", pathstr);
-               goto end;
-       }
-
-       target_field_path_pretty = ctf_field_path_string(
-               &target_field_path);
-       target_field_path_pretty_str =
-               target_field_path_pretty ? target_field_path_pretty->str : NULL;
-
-       /* Get target field class */
-       target_fc = field_path_to_field_class(&target_field_path, ctx);
-       if (!target_fc) {
-               BT_LOGE("Cannot get target field class for path string: "
-                       "path=\"%s\", target-field-path=\"%s\"",
-                       pathstr, target_field_path_pretty_str);
-               ret = -1;
-               goto end;
-       }
-
-       ret = validate_target_field_path(&target_field_path,
-               target_fc, ctx);
-       if (ret) {
-               BT_LOGE("Invalid target field path for path string: "
-                       "path=\"%s\", target-field-path=\"%s\"",
-                       pathstr, target_field_path_pretty_str);
-               goto end;
-       }
-
-       /* Set target field path and target field class */
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_sequence *seq_fc = (void *) fc;
-
-               ctf_field_path_copy_content(&seq_fc->length_path,
-                       &target_field_path);
-               seq_fc->length_fc = (void *) target_fc;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               ctf_field_path_copy_content(&var_fc->tag_path,
-                       &target_field_path);
-               ctf_field_class_variant_set_tag_field_class(var_fc,
-                       (void *) target_fc);
-               break;
-       }
-       default:
-               abort();
-       }
-
-end:
-       if (target_field_path_pretty) {
-               g_string_free(target_field_path_pretty, TRUE);
-       }
-
-       ctf_field_path_fini(&target_field_path);
-       return ret;
-}
-
-/*
- * Resolves a field class `fc`.
- */
-static
-int resolve_field_class(struct ctf_field_class *fc, struct resolve_context *ctx)
-{
-       int ret = 0;
-
-       if (!fc) {
-               /* Field class is not available; still valid */
-               goto end;
-       }
-
-       ctx->cur_fc = fc;
-
-       /* Resolve sequence/variant field class */
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-               ret = resolve_sequence_or_variant_field_class(fc, ctx);
-               if (ret) {
-                       BT_LOGE("Cannot resolve sequence field class's length or variant field class's tag: "
-                               "ret=%d, fc-addr=%p", ret, fc);
-                       goto end;
-               }
-
-               break;
-       default:
-               break;
-       }
-
-       /* Recurse into compound classes */
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       {
-               uint64_t i;
-               uint64_t field_count =
-                       ctf_field_class_compound_get_field_class_count(fc);
-
-               ret = field_class_stack_push(ctx->field_class_stack, fc);
-               if (ret) {
-                       BT_LOGE("Cannot push field class on context's stack: "
-                               "fc-addr=%p", fc);
-                       goto end;
-               }
-
-               for (i = 0; i < field_count; i++) {
-                       struct ctf_field_class *child_fc =
-                               ctf_field_class_compound_borrow_field_class_by_index(
-                                       fc, i);
-
-                       BT_ASSERT(child_fc);
-
-                       if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY||
-                                       fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
-                               field_class_stack_peek(
-                                       ctx->field_class_stack)->index = -1;
-                       } else {
-                               field_class_stack_peek(
-                                       ctx->field_class_stack)->index =
-                                               (int64_t) i;
-                       }
-
-                       BT_LOGV("Resolving field class's child field class: "
-                               "parent-fc-addr=%p, child-fc-addr=%p, "
-                               "index=%" PRIu64 ", count=%" PRIu64,
-                               fc, child_fc, i, field_count);
-                       ret = resolve_field_class(child_fc, ctx);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               field_class_stack_pop(ctx->field_class_stack);
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Resolves the root field class corresponding to the scope `root_scope`.
- */
-static
-int resolve_root_class(enum ctf_scope root_scope, struct resolve_context *ctx)
-{
-       int ret;
-
-       BT_ASSERT(field_class_stack_size(ctx->field_class_stack) == 0);
-       ctx->root_scope = root_scope;
-       ret = resolve_field_class(borrow_class_from_ctx(ctx, root_scope), ctx);
-       ctx->root_scope = -1;
-       return ret;
-}
-
-static
-int resolve_event_class_field_classes(struct resolve_context *ctx,
-               struct ctf_event_class *ec)
-{
-       int ret = 0;
-
-       BT_ASSERT(!ctx->scopes.event_spec_context);
-       BT_ASSERT(!ctx->scopes.event_payload);
-
-       if (ec->is_translated) {
-               goto end;
-       }
-
-       ctx->ec = ec;
-       ctx->scopes.event_spec_context = ec->spec_context_fc;
-       ret = resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT, ctx);
-       if (ret) {
-               BT_LOGE("Cannot resolve event specific context field class: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       ctx->scopes.event_payload = ec->payload_fc;
-       ret = resolve_root_class(CTF_SCOPE_EVENT_PAYLOAD, ctx);
-       if (ret) {
-               BT_LOGE("Cannot resolve event payload field class: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-end:
-       ctx->scopes.event_spec_context = NULL;
-       ctx->scopes.event_payload = NULL;
-       ctx->ec = NULL;
-       return ret;
-}
-
-static
-int resolve_stream_class_field_classes(struct resolve_context *ctx,
-               struct ctf_stream_class *sc)
-{
-       int ret = 0;
-       uint64_t i;
-
-       BT_ASSERT(!ctx->scopes.packet_context);
-       BT_ASSERT(!ctx->scopes.event_header);
-       BT_ASSERT(!ctx->scopes.event_common_context);
-       ctx->sc = sc;
-
-       if (!sc->is_translated) {
-               ctx->scopes.packet_context = sc->packet_context_fc;
-               ret = resolve_root_class(CTF_SCOPE_PACKET_CONTEXT, ctx);
-               if (ret) {
-                       BT_LOGE("Cannot resolve packet context field class: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-
-               ctx->scopes.event_header = sc->event_header_fc;
-               ret = resolve_root_class(CTF_SCOPE_EVENT_HEADER, ctx);
-               if (ret) {
-                       BT_LOGE("Cannot resolve event header field class: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-
-               ctx->scopes.event_common_context = sc->event_common_context_fc;
-               ret = resolve_root_class(CTF_SCOPE_EVENT_SPECIFIC_CONTEXT, ctx);
-               if (ret) {
-                       BT_LOGE("Cannot resolve event common context field class: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       ctx->scopes.packet_context = sc->packet_context_fc;
-       ctx->scopes.event_header = sc->event_header_fc;
-       ctx->scopes.event_common_context = sc->event_common_context_fc;
-
-       for (i = 0; i < sc->event_classes->len; i++) {
-               struct ctf_event_class *ec = sc->event_classes->pdata[i];
-
-               ret = resolve_event_class_field_classes(ctx, ec);
-               if (ret) {
-                       BT_LOGE("Cannot resolve event class's field classes: "
-                               "ec-id=%" PRIu64 ", ec-name=\"%s\"",
-                               ec->id, ec->name->str);
-                       goto end;
-               }
-       }
-
-end:
-       ctx->scopes.packet_context = NULL;
-       ctx->scopes.event_header = NULL;
-       ctx->scopes.event_common_context = NULL;
-       ctx->sc = NULL;
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc)
-{
-       int ret = 0;
-       uint64_t i;
-       struct resolve_context ctx = {
-               .tc = tc,
-               .sc = NULL,
-               .ec = NULL,
-               .scopes = {
-                       .packet_header = tc->packet_header_fc,
-                       .packet_context = NULL,
-                       .event_header = NULL,
-                       .event_common_context = NULL,
-                       .event_spec_context = NULL,
-                       .event_payload = NULL,
-               },
-               .root_scope = CTF_SCOPE_PACKET_HEADER,
-               .cur_fc = NULL,
-       };
-
-       /* Initialize class stack */
-       ctx.field_class_stack = field_class_stack_create();
-       if (!ctx.field_class_stack) {
-               BT_LOGE_STR("Cannot create field class stack.");
-               ret = -1;
-               goto end;
-       }
-
-       if (!tc->is_translated) {
-               ctx.scopes.packet_header = tc->packet_header_fc;
-               ret = resolve_root_class(CTF_SCOPE_PACKET_HEADER, &ctx);
-               if (ret) {
-                       BT_LOGE("Cannot resolve packet header field class: "
-                               "ret=%d", ret);
-                       goto end;
-               }
-       }
-
-       ctx.scopes.packet_header = tc->packet_header_fc;
-
-       for (i = 0; i < tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc = tc->stream_classes->pdata[i];
-
-               ret = resolve_stream_class_field_classes(&ctx, sc);
-               if (ret) {
-                       BT_LOGE("Cannot resolve stream class's field classes: "
-                               "sc-id=%" PRIu64, sc->id);
-                       goto end;
-               }
-       }
-
-end:
-       field_class_stack_destroy(ctx.field_class_stack);
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-translate.c b/plugins/ctf/common/metadata/ctf-meta-translate.c
deleted file mode 100644 (file)
index ca3069a..0000000
+++ /dev/null
@@ -1,626 +0,0 @@
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-TRANSLATE"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "ctf-meta-visitors.h"
-
-struct ctx {
-       bt_self_component_source *self_comp;
-       bt_trace_class *ir_tc;
-       bt_stream_class *ir_sc;
-       struct ctf_trace_class *tc;
-       struct ctf_stream_class *sc;
-       struct ctf_event_class *ec;
-       enum ctf_scope scope;
-};
-
-static inline
-bt_field_class *ctf_field_class_to_ir(struct ctx *ctx,
-               struct ctf_field_class *fc);
-
-static inline
-void ctf_field_class_int_set_props(struct ctf_field_class_int *fc,
-               bt_field_class *ir_fc)
-{
-       bt_field_class_integer_set_field_value_range(ir_fc,
-               fc->base.size);
-       bt_field_class_integer_set_preferred_display_base(ir_fc,
-               fc->disp_base);
-}
-
-static inline
-bt_field_class *ctf_field_class_int_to_ir(struct ctx *ctx,
-               struct ctf_field_class_int *fc)
-{
-       bt_field_class *ir_fc;
-
-       if (fc->is_signed) {
-               ir_fc = bt_field_class_signed_integer_create(ctx->ir_tc);
-       } else {
-               ir_fc = bt_field_class_unsigned_integer_create(ctx->ir_tc);
-       }
-
-       BT_ASSERT(ir_fc);
-       ctf_field_class_int_set_props(fc, ir_fc);
-       return ir_fc;
-}
-
-static inline
-bt_field_class *ctf_field_class_enum_to_ir(struct ctx *ctx,
-               struct ctf_field_class_enum *fc)
-{
-       int ret;
-       bt_field_class *ir_fc;
-       uint64_t i;
-
-       if (fc->base.is_signed) {
-               ir_fc = bt_field_class_signed_enumeration_create(ctx->ir_tc);
-       } else {
-               ir_fc = bt_field_class_unsigned_enumeration_create(ctx->ir_tc);
-       }
-
-       BT_ASSERT(ir_fc);
-       ctf_field_class_int_set_props((void *) fc, ir_fc);
-
-       for (i = 0; i < fc->mappings->len; i++) {
-               struct ctf_field_class_enum_mapping *mapping =
-                       ctf_field_class_enum_borrow_mapping_by_index(fc, i);
-
-               if (fc->base.is_signed) {
-                       ret = bt_field_class_signed_enumeration_map_range(
-                               ir_fc, mapping->label->str,
-                               mapping->range.lower.i, mapping->range.upper.i);
-               } else {
-                       ret = bt_field_class_unsigned_enumeration_map_range(
-                               ir_fc, mapping->label->str,
-                               mapping->range.lower.u, mapping->range.upper.u);
-               }
-
-               BT_ASSERT(ret == 0);
-       }
-
-       return ir_fc;
-}
-
-static inline
-bt_field_class *ctf_field_class_float_to_ir(struct ctx *ctx,
-               struct ctf_field_class_float *fc)
-{
-       bt_field_class *ir_fc;
-
-       ir_fc = bt_field_class_real_create(ctx->ir_tc);
-       BT_ASSERT(ir_fc);
-
-       if (fc->base.size == 32) {
-               bt_field_class_real_set_is_single_precision(ir_fc,
-                       BT_TRUE);
-       }
-
-       return ir_fc;
-}
-
-static inline
-bt_field_class *ctf_field_class_string_to_ir(struct ctx *ctx,
-               struct ctf_field_class_string *fc)
-{
-       bt_field_class *ir_fc = bt_field_class_string_create(ctx->ir_tc);
-
-       BT_ASSERT(ir_fc);
-       return ir_fc;
-}
-
-static inline
-void translate_struct_field_class_members(struct ctx *ctx,
-               struct ctf_field_class_struct *fc, bt_field_class *ir_fc,
-               bool with_header_prefix,
-               struct ctf_field_class_struct *context_fc)
-{
-       uint64_t i;
-       int ret;
-
-       for (i = 0; i < fc->members->len; i++) {
-               struct ctf_named_field_class *named_fc =
-                       ctf_field_class_struct_borrow_member_by_index(fc, i);
-               bt_field_class *member_ir_fc;
-               const char *name = named_fc->name->str;
-
-               if (!named_fc->fc->in_ir) {
-                       continue;
-               }
-
-               member_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc);
-               BT_ASSERT(member_ir_fc);
-               ret = bt_field_class_structure_append_member(ir_fc, name,
-                       member_ir_fc);
-               BT_ASSERT(ret == 0);
-               bt_field_class_put_ref(member_ir_fc);
-       }
-}
-
-static inline
-bt_field_class *ctf_field_class_struct_to_ir(struct ctx *ctx,
-               struct ctf_field_class_struct *fc)
-{
-       bt_field_class *ir_fc = bt_field_class_structure_create(ctx->ir_tc);
-
-       BT_ASSERT(ir_fc);
-       translate_struct_field_class_members(ctx, fc, ir_fc, false, NULL);
-       return ir_fc;
-}
-
-static inline
-bt_field_class *borrow_ir_fc_from_field_path(struct ctx *ctx,
-               struct ctf_field_path *field_path)
-{
-       bt_field_class *ir_fc = NULL;
-       struct ctf_field_class *fc = ctf_field_path_borrow_field_class(
-               field_path, ctx->tc, ctx->sc, ctx->ec);
-
-       BT_ASSERT(fc);
-
-       if (fc->in_ir) {
-               ir_fc = fc->ir_fc;
-       }
-
-       return ir_fc;
-}
-
-static inline
-bt_field_class *ctf_field_class_variant_to_ir(struct ctx *ctx,
-               struct ctf_field_class_variant *fc)
-{
-       int ret;
-       bt_field_class *ir_fc = bt_field_class_variant_create(ctx->ir_tc);
-       uint64_t i;
-
-       BT_ASSERT(ir_fc);
-
-       if (fc->tag_path.root != CTF_SCOPE_PACKET_HEADER &&
-                       fc->tag_path.root != CTF_SCOPE_EVENT_HEADER) {
-               ret = bt_field_class_variant_set_selector_field_class(
-                       ir_fc, borrow_ir_fc_from_field_path(ctx,
-                               &fc->tag_path));
-               BT_ASSERT(ret == 0);
-       }
-
-       for (i = 0; i < fc->options->len; i++) {
-               struct ctf_named_field_class *named_fc =
-                       ctf_field_class_variant_borrow_option_by_index(fc, i);
-               bt_field_class *option_ir_fc;
-
-               BT_ASSERT(named_fc->fc->in_ir);
-               option_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc);
-               BT_ASSERT(option_ir_fc);
-               ret = bt_field_class_variant_append_option(
-                       ir_fc, named_fc->name->str, option_ir_fc);
-               BT_ASSERT(ret == 0);
-               bt_field_class_put_ref(option_ir_fc);
-       }
-
-       return ir_fc;
-}
-
-static inline
-bt_field_class *ctf_field_class_array_to_ir(struct ctx *ctx,
-               struct ctf_field_class_array *fc)
-{
-       bt_field_class *ir_fc;
-       bt_field_class *elem_ir_fc;
-
-       if (fc->base.is_text) {
-               ir_fc = bt_field_class_string_create(ctx->ir_tc);
-               BT_ASSERT(ir_fc);
-               goto end;
-       }
-
-       elem_ir_fc = ctf_field_class_to_ir(ctx, fc->base.elem_fc);
-       BT_ASSERT(elem_ir_fc);
-       ir_fc = bt_field_class_static_array_create(ctx->ir_tc, elem_ir_fc,
-               fc->length);
-       BT_ASSERT(ir_fc);
-       bt_field_class_put_ref(elem_ir_fc);
-
-end:
-       return ir_fc;
-}
-
-static inline
-bt_field_class *ctf_field_class_sequence_to_ir(struct ctx *ctx,
-               struct ctf_field_class_sequence *fc)
-{
-       int ret;
-       bt_field_class *ir_fc;
-       bt_field_class *elem_ir_fc;
-
-       if (fc->base.is_text) {
-               ir_fc = bt_field_class_string_create(ctx->ir_tc);
-               BT_ASSERT(ir_fc);
-               goto end;
-       }
-
-       elem_ir_fc = ctf_field_class_to_ir(ctx, fc->base.elem_fc);
-       BT_ASSERT(elem_ir_fc);
-       ir_fc = bt_field_class_dynamic_array_create(ctx->ir_tc, elem_ir_fc);
-       BT_ASSERT(ir_fc);
-       bt_field_class_put_ref(elem_ir_fc);
-       BT_ASSERT(ir_fc);
-
-       if (fc->length_path.root != CTF_SCOPE_PACKET_HEADER &&
-                       fc->length_path.root != CTF_SCOPE_EVENT_HEADER) {
-               ret = bt_field_class_dynamic_array_set_length_field_class(
-                       ir_fc, borrow_ir_fc_from_field_path(ctx, &fc->length_path));
-               BT_ASSERT(ret == 0);
-       }
-
-end:
-       return ir_fc;
-}
-
-static inline
-bt_field_class *ctf_field_class_to_ir(struct ctx *ctx,
-               struct ctf_field_class *fc)
-{
-       bt_field_class *ir_fc = NULL;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(fc->in_ir);
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_INT:
-               ir_fc = ctf_field_class_int_to_ir(ctx, (void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-               ir_fc = ctf_field_class_enum_to_ir(ctx, (void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_FLOAT:
-               ir_fc = ctf_field_class_float_to_ir(ctx, (void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_STRING:
-               ir_fc = ctf_field_class_string_to_ir(ctx, (void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-               ir_fc = ctf_field_class_struct_to_ir(ctx, (void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-               ir_fc = ctf_field_class_array_to_ir(ctx, (void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-               ir_fc = ctf_field_class_sequence_to_ir(ctx, (void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-               ir_fc = ctf_field_class_variant_to_ir(ctx, (void *) fc);
-               break;
-       default:
-               abort();
-       }
-
-       fc->ir_fc = ir_fc;
-       return ir_fc;
-}
-
-static inline
-bool ctf_field_class_struct_has_immediate_member_in_ir(
-               struct ctf_field_class_struct *fc)
-{
-       uint64_t i;
-       bool has_immediate_member_in_ir = false;
-
-       /*
-        * If the structure field class has no members at all, then it
-        * was an empty structure in the beginning, so leave it existing
-        * and empty.
-        */
-       if (fc->members->len == 0) {
-               has_immediate_member_in_ir = true;
-               goto end;
-       }
-
-       for (i = 0; i < fc->members->len; i++) {
-               struct ctf_named_field_class *named_fc =
-                       ctf_field_class_struct_borrow_member_by_index(fc, i);
-
-               if (named_fc->fc->in_ir) {
-                       has_immediate_member_in_ir = true;
-                       goto end;
-               }
-       }
-
-end:
-       return has_immediate_member_in_ir;
-}
-
-static inline
-bt_field_class *scope_ctf_field_class_to_ir(struct ctx *ctx)
-{
-       bt_field_class *ir_fc = NULL;
-       struct ctf_field_class *fc = NULL;
-
-       switch (ctx->scope) {
-       case CTF_SCOPE_PACKET_CONTEXT:
-               fc = ctx->sc->packet_context_fc;
-               break;
-       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
-               fc = ctx->sc->event_common_context_fc;
-               break;
-       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               fc = ctx->ec->spec_context_fc;
-               break;
-       case CTF_SCOPE_EVENT_PAYLOAD:
-               fc = ctx->ec->payload_fc;
-               break;
-       default:
-               abort();
-       }
-
-       if (fc && ctf_field_class_struct_has_immediate_member_in_ir(
-                       (void *) fc)) {
-               ir_fc = ctf_field_class_to_ir(ctx, fc);
-       }
-
-       return ir_fc;
-}
-
-static inline
-void ctf_event_class_to_ir(struct ctx *ctx)
-{
-       int ret;
-       bt_event_class *ir_ec = NULL;
-       bt_field_class *ir_fc;
-
-       BT_ASSERT(ctx->ec);
-
-       if (ctx->ec->is_translated) {
-               ir_ec = bt_stream_class_borrow_event_class_by_id(
-                       ctx->ir_sc, ctx->ec->id);
-               BT_ASSERT(ir_ec);
-               goto end;
-       }
-
-       ir_ec = bt_event_class_create_with_id(ctx->ir_sc, ctx->ec->id);
-       BT_ASSERT(ir_ec);
-       bt_event_class_put_ref(ir_ec);
-       ctx->scope = CTF_SCOPE_EVENT_SPECIFIC_CONTEXT;
-       ir_fc = scope_ctf_field_class_to_ir(ctx);
-       if (ir_fc) {
-               ret = bt_event_class_set_specific_context_field_class(
-                       ir_ec, ir_fc);
-               BT_ASSERT(ret == 0);
-               bt_field_class_put_ref(ir_fc);
-       }
-
-       ctx->scope = CTF_SCOPE_EVENT_PAYLOAD;
-       ir_fc = scope_ctf_field_class_to_ir(ctx);
-       if (ir_fc) {
-               ret = bt_event_class_set_payload_field_class(ir_ec,
-                       ir_fc);
-               BT_ASSERT(ret == 0);
-               bt_field_class_put_ref(ir_fc);
-       }
-
-       if (ctx->ec->name->len > 0) {
-               ret = bt_event_class_set_name(ir_ec, ctx->ec->name->str);
-               BT_ASSERT(ret == 0);
-       }
-
-       if (ctx->ec->emf_uri->len > 0) {
-               ret = bt_event_class_set_emf_uri(ir_ec, ctx->ec->emf_uri->str);
-               BT_ASSERT(ret == 0);
-       }
-
-       if (ctx->ec->log_level != -1) {
-               bt_event_class_set_log_level(ir_ec, ctx->ec->log_level);
-       }
-
-       ctx->ec->is_translated = true;
-       ctx->ec->ir_ec = ir_ec;
-
-end:
-       return;
-}
-
-
-static inline
-void ctf_stream_class_to_ir(struct ctx *ctx)
-{
-       int ret;
-       bt_field_class *ir_fc;
-
-       BT_ASSERT(ctx->sc);
-
-       if (ctx->sc->is_translated) {
-               ctx->ir_sc = bt_trace_class_borrow_stream_class_by_id(
-                       ctx->ir_tc, ctx->sc->id);
-               BT_ASSERT(ctx->ir_sc);
-               goto end;
-       }
-
-       ctx->ir_sc = bt_stream_class_create_with_id(ctx->ir_tc, ctx->sc->id);
-       BT_ASSERT(ctx->ir_sc);
-       bt_stream_class_put_ref(ctx->ir_sc);
-       ctx->scope = CTF_SCOPE_PACKET_CONTEXT;
-       ir_fc = scope_ctf_field_class_to_ir(ctx);
-       if (ir_fc) {
-               ret = bt_stream_class_set_packet_context_field_class(
-                       ctx->ir_sc, ir_fc);
-               BT_ASSERT(ret == 0);
-               bt_field_class_put_ref(ir_fc);
-       }
-
-       ctx->scope = CTF_SCOPE_EVENT_COMMON_CONTEXT;
-       ir_fc = scope_ctf_field_class_to_ir(ctx);
-       if (ir_fc) {
-               ret = bt_stream_class_set_event_common_context_field_class(
-                       ctx->ir_sc, ir_fc);
-               BT_ASSERT(ret == 0);
-               bt_field_class_put_ref(ir_fc);
-       }
-
-       bt_stream_class_set_assigns_automatic_event_class_id(ctx->ir_sc,
-               BT_FALSE);
-       bt_stream_class_set_assigns_automatic_stream_id(ctx->ir_sc, BT_FALSE);
-
-       if (ctx->sc->default_clock_class) {
-               BT_ASSERT(ctx->sc->default_clock_class->ir_cc);
-               ret = bt_stream_class_set_default_clock_class(ctx->ir_sc,
-                       ctx->sc->default_clock_class->ir_cc);
-               BT_ASSERT(ret == 0);
-       }
-
-       bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
-               ctx->ir_sc, ctx->sc->packets_have_ts_begin);
-       bt_stream_class_set_packets_have_end_default_clock_snapshot(
-               ctx->ir_sc, ctx->sc->packets_have_ts_end);
-       bt_stream_class_set_supports_discarded_events(ctx->ir_sc,
-               ctx->sc->has_discarded_events,
-               ctx->sc->discarded_events_have_default_cs);
-       bt_stream_class_set_supports_discarded_packets(ctx->ir_sc,
-               ctx->sc->has_discarded_packets,
-               ctx->sc->discarded_packets_have_default_cs);
-       ctx->sc->is_translated = true;
-       ctx->sc->ir_sc = ctx->ir_sc;
-
-end:
-       return;
-}
-
-static inline
-void ctf_clock_class_to_ir(bt_clock_class *ir_cc, struct ctf_clock_class *cc)
-{
-       int ret;
-
-       if (strlen(cc->name->str) > 0) {
-               ret = bt_clock_class_set_name(ir_cc, cc->name->str);
-               BT_ASSERT(ret == 0);
-       }
-
-       if (strlen(cc->description->str) > 0) {
-               ret = bt_clock_class_set_description(ir_cc, cc->description->str);
-               BT_ASSERT(ret == 0);
-       }
-
-       bt_clock_class_set_frequency(ir_cc, cc->frequency);
-       bt_clock_class_set_precision(ir_cc, cc->precision);
-       bt_clock_class_set_offset(ir_cc, cc->offset_seconds, cc->offset_cycles);
-
-       if (cc->has_uuid) {
-               bt_clock_class_set_uuid(ir_cc, cc->uuid);
-       }
-
-       bt_clock_class_set_origin_is_unix_epoch(ir_cc, cc->is_absolute);
-}
-
-static inline
-int ctf_trace_class_to_ir(struct ctx *ctx)
-{
-       int ret = 0;
-       uint64_t i;
-
-       BT_ASSERT(ctx->tc);
-       BT_ASSERT(ctx->ir_tc);
-
-       if (ctx->tc->is_translated) {
-               goto end;
-       }
-
-       if (ctx->tc->is_uuid_set) {
-               bt_trace_class_set_uuid(ctx->ir_tc, ctx->tc->uuid);
-       }
-
-       for (i = 0; i < ctx->tc->env_entries->len; i++) {
-               struct ctf_trace_class_env_entry *env_entry =
-                       ctf_trace_class_borrow_env_entry_by_index(ctx->tc, i);
-
-               switch (env_entry->type) {
-               case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT:
-                       ret = bt_trace_class_set_environment_entry_integer(
-                               ctx->ir_tc, env_entry->name->str,
-                               env_entry->value.i);
-                       break;
-               case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR:
-                       ret = bt_trace_class_set_environment_entry_string(
-                               ctx->ir_tc, env_entry->name->str,
-                               env_entry->value.str->str);
-                       break;
-               default:
-                       abort();
-               }
-
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < ctx->tc->clock_classes->len; i++) {
-               struct ctf_clock_class *cc = ctx->tc->clock_classes->pdata[i];
-
-               cc->ir_cc = bt_clock_class_create(
-                               bt_self_component_source_as_self_component(
-                                       ctx->self_comp));
-               ctf_clock_class_to_ir(cc->ir_cc, cc);
-       }
-
-       bt_trace_class_set_assigns_automatic_stream_class_id(ctx->ir_tc,
-               BT_FALSE);
-       ctx->tc->is_translated = true;
-       ctx->tc->ir_tc = ctx->ir_tc;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_trace_class_translate(bt_self_component_source *self_comp,
-               bt_trace_class *ir_tc, struct ctf_trace_class *tc)
-{
-       int ret = 0;
-       uint64_t i;
-       struct ctx ctx = { 0 };
-
-       ctx.self_comp = self_comp;
-       ctx.tc = tc;
-       ctx.ir_tc = ir_tc;
-       ret = ctf_trace_class_to_ir(&ctx);
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < tc->stream_classes->len; i++) {
-               uint64_t j;
-               ctx.sc = tc->stream_classes->pdata[i];
-
-               ctf_stream_class_to_ir(&ctx);
-
-               for (j = 0; j < ctx.sc->event_classes->len; j++) {
-                       ctx.ec = ctx.sc->event_classes->pdata[j];
-
-                       ctf_event_class_to_ir(&ctx);
-                       ctx.ec = NULL;
-               }
-
-               ctx.sc = NULL;
-       }
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c b/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c
deleted file mode 100644 (file)
index 057e0b4..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-DEF-CC"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "ctf-meta-visitors.h"
-
-static inline
-int find_mapped_clock_class(struct ctf_field_class *fc,
-               struct ctf_clock_class **clock_class)
-{
-       int ret = 0;
-       uint64_t i;
-
-       if (!fc) {
-               goto end;
-       }
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_INT:
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-       {
-               struct ctf_field_class_int *int_fc = (void *) fc;
-
-               if (int_fc->mapped_clock_class) {
-                       if (*clock_class && *clock_class !=
-                                       int_fc->mapped_clock_class) {
-                               BT_LOGE("Stream class contains more than one "
-                                       "clock class: expected-cc-name=\"%s\", "
-                                       "other-cc-name=\"%s\"",
-                                       (*clock_class)->name->str,
-                                       int_fc->mapped_clock_class->name->str);
-                               ret = -1;
-                               goto end;
-                       }
-
-                       *clock_class = int_fc->mapped_clock_class;
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               for (i = 0; i < struct_fc->members->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-
-                       ret = find_mapped_clock_class(named_fc->fc,
-                               clock_class);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               for (i = 0; i < var_fc->options->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-
-                       ret = find_mapped_clock_class(named_fc->fc,
-                               clock_class);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               ret = find_mapped_clock_class(array_fc->elem_fc, clock_class);
-               if (ret) {
-                       goto end;
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int update_stream_class_default_clock_class(
-               struct ctf_stream_class *stream_class)
-{
-       int ret = 0;
-       struct ctf_clock_class *clock_class =
-               stream_class->default_clock_class;
-       uint64_t i;
-
-       ret = find_mapped_clock_class(stream_class->packet_context_fc,
-               &clock_class);
-       if (ret) {
-               goto end;
-       }
-
-       ret = find_mapped_clock_class(stream_class->event_header_fc,
-               &clock_class);
-       if (ret) {
-               goto end;
-       }
-
-       ret = find_mapped_clock_class(stream_class->event_common_context_fc,
-               &clock_class);
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < stream_class->event_classes->len; i++) {
-               struct ctf_event_class *event_class =
-                       stream_class->event_classes->pdata[i];
-
-               ret = find_mapped_clock_class(event_class->spec_context_fc,
-                       &clock_class);
-               if (ret) {
-                       goto end;
-               }
-
-               ret = find_mapped_clock_class(event_class->payload_fc,
-                       &clock_class);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       if (!stream_class->default_clock_class) {
-               stream_class->default_clock_class = clock_class;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc)
-{
-       uint64_t i;
-       int ret = 0;
-       struct ctf_clock_class *clock_class = NULL;
-
-       ret = find_mapped_clock_class(ctf_tc->packet_header_fc, &clock_class);
-       if (ret) {
-               goto end;
-       }
-
-       if (clock_class) {
-               ret = -1;
-               goto end;
-       }
-
-       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc =
-                       ctf_tc->stream_classes->pdata[i];
-
-               ret = update_stream_class_default_clock_class(
-                       ctf_tc->stream_classes->pdata[i]);
-               if (ret) {
-                       BT_LOGE("Stream class contains more than one "
-                               "clock class: stream-class-id=%" PRIu64,
-                               sc->id);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-in-ir.c b/plugins/ctf/common/metadata/ctf-meta-update-in-ir.c
deleted file mode 100644 (file)
index 806a919..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-IN-IR"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/glib-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-#include <assert.h>
-
-#include "ctf-meta-visitors.h"
-
-static
-void force_update_field_class_in_ir(struct ctf_field_class *fc, bool in_ir)
-{
-       uint64_t i;
-
-       if (!fc) {
-               goto end;
-       }
-
-       fc->in_ir = in_ir;
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               for (i = 0; i < struct_fc->members->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-
-                       force_update_field_class_in_ir(named_fc->fc, in_ir);
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_named_field_class *named_fc;
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               for (i = 0; i < var_fc->options->len; i++) {
-                       named_fc =
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-
-                       force_update_field_class_in_ir(named_fc->fc, in_ir);
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               force_update_field_class_in_ir(array_fc->elem_fc, in_ir);
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return;
-}
-
-static
-void update_field_class_in_ir(struct ctf_field_class *fc,
-               GHashTable *ft_dependents)
-{
-       int64_t i;
-
-       if (!fc) {
-               goto end;
-       }
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_INT:
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-       {
-               struct ctf_field_class_int *int_fc = (void *) fc;
-
-               /*
-                * Conditions to be in trace IR; one of:
-                *
-                * 1. Does NOT have a mapped clock class AND does not
-                *    have a special meaning.
-                * 2. Another field class depends on it.
-                */
-               if ((!int_fc->mapped_clock_class &&
-                               int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE) ||
-                               bt_g_hash_table_contains(ft_dependents, fc)) {
-                       fc->in_ir = true;
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               /*
-                * Make it part of IR if it's empty because it was
-                * originally empty.
-                */
-               if (struct_fc->members->len == 0) {
-                       fc->in_ir = true;
-               }
-
-               /* Reverse order */
-               for (i = (int64_t) struct_fc->members->len - 1; i >= 0; i--) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-
-                       update_field_class_in_ir(named_fc->fc, ft_dependents);
-
-                       if (named_fc->fc->in_ir) {
-                               /* At least one member is part of IR */
-                               fc->in_ir = true;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_named_field_class *named_fc;
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               /*
-                * Reverse order, although it is not important for this
-                * loop because a field class within a variant field
-                * type's option cannot depend on a field class in
-                * another option of the same variant field class.
-                */
-               for (i = (int64_t) var_fc->options->len - 1; i >= 0; i--) {
-                       named_fc =
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-
-                       update_field_class_in_ir(named_fc->fc, ft_dependents);
-
-                       if (named_fc->fc->in_ir) {
-                               /* At least one option is part of IR */
-                               fc->in_ir = true;
-                       }
-               }
-
-               if (fc->in_ir) {
-                       /*
-                        * At least one option will make it to IR. In
-                        * this case, make all options part of IR
-                        * because the variant's tag could still select
-                        * (dynamically) a removed option. This can mean
-                        * having an empty structure as an option, for
-                        * example, but at least all the options are
-                        * selectable.
-                        */
-                       for (i = 0; i < var_fc->options->len; i++) {
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i)->fc->in_ir = true;
-                       }
-
-                       /*
-                        * This variant field class is part of IR and
-                        * depends on a tag field class (which must also
-                        * be part of IR).
-                        */
-                       g_hash_table_insert(ft_dependents, var_fc->tag_fc,
-                               var_fc->tag_fc);
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               update_field_class_in_ir(array_fc->elem_fc, ft_dependents);
-               fc->in_ir = array_fc->elem_fc->in_ir;
-
-               if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) {
-                       struct ctf_field_class_array *arr_fc = (void *) fc;
-
-                       assert(arr_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE ||
-                               arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID);
-
-                       /*
-                        * UUID field class: nothing depends on this, so
-                        * it's not part of IR.
-                        */
-                       if (arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID) {
-                               fc->in_ir = false;
-                               array_fc->elem_fc->in_ir = false;
-                       }
-               } else if (fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
-                       if (fc->in_ir) {
-                               struct ctf_field_class_sequence *seq_fc = (void *) fc;
-
-                               /*
-                                * This sequence field class is part of
-                                * IR and depends on a length field class
-                                * (which must also be part of IR).
-                                */
-                               g_hash_table_insert(ft_dependents,
-                                       seq_fc->length_fc, seq_fc->length_fc);
-                       }
-               }
-
-               break;
-       }
-       default:
-               fc->in_ir = true;
-               break;
-       }
-
-end:
-       return;
-}
-
-/*
- * Scopes and field classes are processed in reverse order because we need
- * to know if a given integer field class has dependents (sequence or
- * variant field classes) when we reach it. Dependents can only be located
- * after the length/tag field class in the metadata tree.
- */
-BT_HIDDEN
-int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc)
-{
-       int ret = 0;
-       uint64_t i;
-
-       GHashTable *ft_dependents = g_hash_table_new(g_direct_hash,
-               g_direct_equal);
-
-       BT_ASSERT(ft_dependents);
-
-       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
-               uint64_t j;
-
-               for (j = 0; j < sc->event_classes->len; j++) {
-                       struct ctf_event_class *ec = sc->event_classes->pdata[j];
-
-                       if (ec->is_translated) {
-                               continue;
-                       }
-
-                       update_field_class_in_ir(ec->payload_fc, ft_dependents);
-                       update_field_class_in_ir(ec->spec_context_fc,
-                               ft_dependents);
-               }
-
-               if (!sc->is_translated) {
-                       update_field_class_in_ir(sc->event_common_context_fc,
-                               ft_dependents);
-                       force_update_field_class_in_ir(sc->event_header_fc,
-                               false);
-                       update_field_class_in_ir(sc->packet_context_fc,
-                               ft_dependents);
-               }
-       }
-
-       if (!ctf_tc->is_translated) {
-               force_update_field_class_in_ir(ctf_tc->packet_header_fc,
-                       false);
-       }
-
-       g_hash_table_destroy(ft_dependents);
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-meanings.c b/plugins/ctf/common/metadata/ctf-meta-update-meanings.c
deleted file mode 100644 (file)
index 1e78c3a..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-MEANINGS"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "ctf-meta-visitors.h"
-
-static
-int set_int_field_class_meaning_by_name(struct ctf_field_class *fc,
-               const char *field_name, const char *id_name,
-               enum ctf_field_class_meaning meaning)
-{
-       int ret = 0;
-       uint64_t i;
-
-       if (!fc) {
-               goto end;
-       }
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_INT:
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-       {
-               struct ctf_field_class_int *int_fc = (void *) fc;
-
-               if (field_name && strcmp(field_name, id_name) == 0) {
-                       int_fc->meaning = meaning;
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               for (i = 0; i < struct_fc->members->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-
-                       ret = set_int_field_class_meaning_by_name(named_fc->fc,
-                               named_fc->name->str, id_name, meaning);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               for (i = 0; i < var_fc->options->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-
-                       ret = set_int_field_class_meaning_by_name(named_fc->fc,
-                               NULL, id_name, meaning);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               ret = set_int_field_class_meaning_by_name(array_fc->elem_fc,
-                       NULL, id_name, meaning);
-               if (ret) {
-                       goto end;
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-static
-int update_stream_class_meanings(struct ctf_stream_class *sc)
-{
-       int ret = 0;
-       struct ctf_field_class_int *int_fc;
-       uint64_t i;
-
-       if (!sc->is_translated) {
-               if (sc->packet_context_fc) {
-                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                               (void *) sc->packet_context_fc, "timestamp_begin");
-                       if (int_fc) {
-                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME;
-                       }
-
-                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                               (void *) sc->packet_context_fc, "timestamp_end");
-                       if (int_fc) {
-                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_END_TIME;
-
-                               /*
-                                * Remove mapped clock class to avoid updating
-                                * the clock immediately when decoding.
-                                */
-                               int_fc->mapped_clock_class = NULL;
-                       }
-
-                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                               (void *) sc->packet_context_fc, "events_discarded");
-                       if (int_fc) {
-                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT;
-                       }
-
-                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                               (void *) sc->packet_context_fc, "packet_seq_num");
-                       if (int_fc) {
-                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT;
-
-                       }
-
-                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                               (void *) sc->packet_context_fc, "packet_size");
-                       if (int_fc) {
-                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE;
-                       }
-
-                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                               (void *) sc->packet_context_fc, "content_size");
-                       if (int_fc) {
-                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE;
-                       }
-               }
-
-               if (sc->event_header_fc) {
-                       ret = set_int_field_class_meaning_by_name(
-                               sc->event_header_fc, NULL, "id",
-                               CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-       }
-
-       for (i = 0; i < sc->event_classes->len; i++) {
-               struct ctf_event_class *ec = sc->event_classes->pdata[i];
-
-               if (ec->is_translated) {
-                       continue;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc)
-{
-       int ret = 0;
-       struct ctf_field_class_int *int_fc;
-       struct ctf_named_field_class *named_fc;
-       uint64_t i;
-
-       if (!ctf_tc->is_translated && ctf_tc->packet_header_fc) {
-               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                       (void *) ctf_tc->packet_header_fc, "magic");
-               if (int_fc) {
-                       int_fc->meaning = CTF_FIELD_CLASS_MEANING_MAGIC;
-               }
-
-               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                       (void *) ctf_tc->packet_header_fc, "stream_id");
-               if (int_fc) {
-                       int_fc->meaning = CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID;
-               }
-
-               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                       (void *) ctf_tc->packet_header_fc,
-                       "stream_instance_id");
-               if (int_fc) {
-                       int_fc->meaning = CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID;
-               }
-
-               named_fc = ctf_field_class_struct_borrow_member_by_name(
-                       (void *) ctf_tc->packet_header_fc, "uuid");
-               if (named_fc && named_fc->fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) {
-                       struct ctf_field_class_array *array_fc =
-                               (void *) named_fc->fc;
-
-                       array_fc->meaning = CTF_FIELD_CLASS_MEANING_UUID;
-               }
-       }
-
-       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-               ret = update_stream_class_meanings(
-                       ctf_tc->stream_classes->pdata[i]);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.c b/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.c
deleted file mode 100644 (file)
index 9bd0bc6..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2019 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-SC-CONFIG"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "ctf-meta-visitors.h"
-
-BT_HIDDEN
-int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc)
-{
-       struct ctf_field_class_int *int_fc;
-       uint64_t i;
-
-       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc =
-                       ctf_tc->stream_classes->pdata[i];
-
-               if (sc->is_translated) {
-                       continue;
-               }
-
-               if (!sc->packet_context_fc) {
-                       continue;
-               }
-
-               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                       (void *) sc->packet_context_fc, "timestamp_begin");
-               if (int_fc && int_fc->meaning ==
-                               CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME) {
-                       sc->packets_have_ts_begin = true;
-               }
-
-               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                       (void *) sc->packet_context_fc, "timestamp_end");
-               if (int_fc && int_fc->meaning ==
-                               CTF_FIELD_CLASS_MEANING_PACKET_END_TIME) {
-                       sc->packets_have_ts_end = true;
-               }
-
-               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                       (void *) sc->packet_context_fc, "events_discarded");
-               if (int_fc && int_fc->meaning ==
-                               CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT) {
-                       sc->has_discarded_events = true;
-               }
-
-               sc->discarded_events_have_default_cs =
-                       sc->has_discarded_events && sc->packets_have_ts_begin &&
-                       sc->packets_have_ts_end;
-               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
-                       (void *) sc->packet_context_fc, "packet_seq_num");
-               if (int_fc && int_fc->meaning ==
-                               CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT) {
-                       sc->has_discarded_packets = true;
-               }
-
-               sc->discarded_packets_have_default_cs =
-                       sc->has_discarded_packets &&
-                       sc->packets_have_ts_begin && sc->packets_have_ts_end;
-       }
-
-       return 0;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c b/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c
deleted file mode 100644 (file)
index 29d231f..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-TEXT-ARRAY-SEQ"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "ctf-meta-visitors.h"
-
-static inline
-int set_text_array_sequence_field_class(struct ctf_field_class *fc)
-{
-       int ret = 0;
-       uint64_t i;
-
-       if (!fc) {
-               goto end;
-       }
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               for (i = 0; i < struct_fc->members->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-
-                       ret = set_text_array_sequence_field_class(named_fc->fc);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               for (i = 0; i < var_fc->options->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-
-                       ret = set_text_array_sequence_field_class(named_fc->fc);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               if (array_fc->elem_fc->type == CTF_FIELD_CLASS_TYPE_INT ||
-                               array_fc->elem_fc->type == CTF_FIELD_CLASS_TYPE_ENUM) {
-                       struct ctf_field_class_int *int_fc =
-                               (void *) array_fc->elem_fc;
-
-                       if (int_fc->base.base.alignment == 8 &&
-                                       int_fc->base.size == 8 &&
-                                       int_fc->encoding == CTF_ENCODING_UTF8) {
-                               array_fc->is_text = true;
-
-                               /*
-                                * Force integer element to be unsigned;
-                                * this makes the decoder enter a single
-                                * path when reading a text
-                                * array/sequence and we can safely
-                                * decode bytes as characters anyway.
-                                */
-                               int_fc->is_signed = false;
-                       }
-               }
-
-               ret = set_text_array_sequence_field_class(array_fc->elem_fc);
-               if (ret) {
-                       goto end;
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc)
-{
-       int ret = 0;
-       uint64_t i;
-
-       if (!ctf_tc->is_translated) {
-               ret = set_text_array_sequence_field_class(
-                       ctf_tc->packet_header_fc);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
-               uint64_t j;
-
-               if (!sc->is_translated) {
-                       ret = set_text_array_sequence_field_class(
-                               sc->packet_context_fc);
-                       if (ret) {
-                               goto end;
-                       }
-
-                       ret = set_text_array_sequence_field_class(
-                               sc->event_header_fc);
-                       if (ret) {
-                               goto end;
-                       }
-
-                       ret = set_text_array_sequence_field_class(
-                               sc->event_common_context_fc);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               for (j = 0; j < sc->event_classes->len; j++) {
-                       struct ctf_event_class *ec =
-                               sc->event_classes->pdata[j];
-
-                       if (ec->is_translated) {
-                               continue;
-                       }
-
-                       ret = set_text_array_sequence_field_class(
-                               ec->spec_context_fc);
-                       if (ret) {
-                               goto end;
-                       }
-
-                       ret = set_text_array_sequence_field_class(
-                               ec->payload_fc);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-       }
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c b/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c
deleted file mode 100644 (file)
index 05abb49..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-VALUE-STORING-INDEXES"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "ctf-meta-visitors.h"
-
-static
-int update_field_class_stored_value_index(struct ctf_field_class *fc,
-               struct ctf_trace_class *tc,
-               struct ctf_stream_class *sc,
-               struct ctf_event_class *ec)
-{
-       int ret = 0;
-       uint64_t i;
-       struct ctf_field_path *field_path = NULL;
-       struct ctf_field_class_int *tgt_fc = NULL;
-       uint64_t *stored_value_index = NULL;
-
-       if (!fc) {
-               goto end;
-       }
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               field_path = &var_fc->tag_path;
-               stored_value_index = &var_fc->stored_tag_index;
-               tgt_fc = (void *) var_fc->tag_fc;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_sequence *seq_fc = (void *) fc;
-
-               field_path = &seq_fc->length_path;
-               stored_value_index = &seq_fc->stored_length_index;
-               tgt_fc = seq_fc->length_fc;
-               break;
-       }
-       default:
-               break;
-       }
-
-       if (field_path) {
-               BT_ASSERT(tgt_fc);
-               BT_ASSERT(tgt_fc->base.base.type == CTF_FIELD_CLASS_TYPE_INT ||
-                       tgt_fc->base.base.type == CTF_FIELD_CLASS_TYPE_ENUM);
-               if (tgt_fc->storing_index >= 0) {
-                       /* Already storing its value */
-                       *stored_value_index = (uint64_t) tgt_fc->storing_index;
-               } else {
-                       /* Not storing its value: allocate new index */
-                       tgt_fc->storing_index = tc->stored_value_count;
-                       *stored_value_index = (uint64_t) tgt_fc->storing_index;
-                       tc->stored_value_count++;
-               }
-       }
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               for (i = 0; i < struct_fc->members->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-
-                       ret = update_field_class_stored_value_index(named_fc->fc,
-                               tc, sc, ec);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               for (i = 0; i < var_fc->options->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-
-                       ret = update_field_class_stored_value_index(named_fc->fc,
-                               tc, sc, ec);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               ret = update_field_class_stored_value_index(array_fc->elem_fc,
-                       tc, sc, ec);
-               if (ret) {
-                       goto end;
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc)
-{
-       uint64_t i;
-
-       if (!ctf_tc->is_translated) {
-               update_field_class_stored_value_index(
-                       ctf_tc->packet_header_fc, ctf_tc, NULL, NULL);
-       }
-
-       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-               uint64_t j;
-               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
-
-               if (!sc->is_translated) {
-                       update_field_class_stored_value_index(sc->packet_context_fc,
-                               ctf_tc, sc, NULL);
-                       update_field_class_stored_value_index(sc->event_header_fc,
-                               ctf_tc, sc, NULL);
-                       update_field_class_stored_value_index(
-                               sc->event_common_context_fc, ctf_tc, sc, NULL);
-               }
-
-               for (j = 0; j < sc->event_classes->len; j++) {
-                       struct ctf_event_class *ec =
-                               sc->event_classes->pdata[j];
-
-                       if (!ec->is_translated) {
-                               update_field_class_stored_value_index(
-                                       ec->spec_context_fc, ctf_tc, sc, ec);
-                               update_field_class_stored_value_index(
-                                       ec->payload_fc, ctf_tc, sc, ec);
-                       }
-               }
-       }
-
-       return 0;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-validate.c b/plugins/ctf/common/metadata/ctf-meta-validate.c
deleted file mode 100644 (file)
index 6070070..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-VALIDATE"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "ctf-meta-visitors.h"
-
-static
-int validate_stream_class(struct ctf_stream_class *sc)
-{
-       int ret = 0;
-       struct ctf_field_class_int *int_fc;
-       struct ctf_field_class *fc;
-
-       if (sc->is_translated) {
-               goto end;
-       }
-
-       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-               (void *) sc->packet_context_fc, "timestamp_begin");
-       if (fc) {
-               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`timestamp_begin` member is not an integer field class.");
-                       goto invalid;
-               }
-
-               int_fc = (void *) fc;
-
-               if (int_fc->is_signed) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`timestamp_begin` member is signed.");
-                       goto invalid;
-               }
-       }
-
-       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-               (void *) sc->packet_context_fc, "timestamp_end");
-       if (fc) {
-               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`timestamp_end` member is not an integer field class.");
-                       goto invalid;
-               }
-
-               int_fc = (void *) fc;
-
-               if (int_fc->is_signed) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`timestamp_end` member is signed.");
-                       goto invalid;
-               }
-       }
-
-       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-               (void *) sc->packet_context_fc, "events_discarded");
-       if (fc) {
-               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`events_discarded` member is not an integer field class.");
-                       goto invalid;
-               }
-
-               int_fc = (void *) fc;
-
-               if (int_fc->is_signed) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`events_discarded` member is signed.");
-                       goto invalid;
-               }
-       }
-
-       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-               (void *) sc->packet_context_fc, "packet_seq_num");
-       if (fc) {
-               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`packet_seq_num` member is not an integer field class.");
-                       goto invalid;
-               }
-
-               int_fc = (void *) fc;
-
-               if (int_fc->is_signed) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`packet_seq_num` member is signed.");
-                       goto invalid;
-               }
-       }
-
-       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-               (void *) sc->packet_context_fc, "packet_size");
-       if (fc) {
-               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`packet_size` member is not an integer field class.");
-                       goto invalid;
-               }
-
-               int_fc = (void *) fc;
-
-               if (int_fc->is_signed) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`packet_size` member is signed.");
-                       goto invalid;
-               }
-       }
-
-       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-               (void *) sc->packet_context_fc, "content_size");
-       if (fc) {
-               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`content_size` member is not an integer field class.");
-                       goto invalid;
-               }
-
-               int_fc = (void *) fc;
-
-               if (int_fc->is_signed) {
-                       BT_LOGE_STR("Invalid packet context field class: "
-                               "`content_size` member is signed.");
-                       goto invalid;
-               }
-       }
-
-       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-               (void *) sc->event_header_fc, "id");
-       if (fc) {
-               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       BT_LOGE_STR("Invalid event header field class: "
-                               "`id` member is not an integer field class.");
-                       goto invalid;
-               }
-
-               int_fc = (void *) fc;
-
-               if (int_fc->is_signed) {
-                       BT_LOGE_STR("Invalid event header field class: "
-                               "`id` member is signed.");
-                       goto invalid;
-               }
-       } else {
-               if (sc->event_classes->len > 1) {
-                       BT_LOGE_STR("Invalid event header field class: "
-                               "missing `id` member as there's "
-                               "more than one event class.");
-                       goto invalid;
-               }
-       }
-
-       goto end;
-
-invalid:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc)
-{
-       int ret = 0;
-       struct ctf_field_class_int *int_fc;
-       uint64_t i;
-
-       if (!ctf_tc->is_translated) {
-               struct ctf_field_class *fc;
-
-               fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-                       (void *) ctf_tc->packet_header_fc, "magic");
-               if (fc) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       (void *) ctf_tc->packet_header_fc,
-                                       0);
-
-                       if (named_fc->fc != fc) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`magic` member is not the first member.");
-                               goto invalid;
-                       }
-
-                       if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                                       fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`magic` member is not an integer field class.");
-                               goto invalid;
-                       }
-
-                       int_fc = (void *) fc;
-
-                       if (int_fc->is_signed) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`magic` member is signed.");
-                               goto invalid;
-                       }
-
-                       if (int_fc->base.size != 32) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`magic` member is not 32-bit.");
-                               goto invalid;
-                       }
-               }
-
-               fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-                       (void *) ctf_tc->packet_header_fc, "stream_id");
-               if (fc) {
-                       if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                                       fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`stream_id` member is not an integer field class.");
-                               goto invalid;
-                       }
-
-                       int_fc = (void *) fc;
-
-                       if (int_fc->is_signed) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`stream_id` member is signed.");
-                               goto invalid;
-                       }
-               } else {
-                       if (ctf_tc->stream_classes->len > 1) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "missing `stream_id` member as there's "
-                                       "more than one stream class.");
-                               goto invalid;
-                       }
-               }
-
-               fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-                       (void *) ctf_tc->packet_header_fc,
-                       "stream_instance_id");
-               if (fc) {
-                       if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                                       fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`stream_instance_id` member is not an integer field class.");
-                               goto invalid;
-                       }
-
-                       int_fc = (void *) fc;
-
-                       if (int_fc->is_signed) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`stream_instance_id` member is signed.");
-                               goto invalid;
-                       }
-               }
-
-               fc = ctf_field_class_struct_borrow_member_field_class_by_name(
-                       (void *) ctf_tc->packet_header_fc, "uuid");
-               if (fc) {
-                       struct ctf_field_class_array *array_fc = (void *) fc;
-
-                       if (fc->type != CTF_FIELD_CLASS_TYPE_ARRAY) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`uuid` member is not an array field class.");
-                               goto invalid;
-                       }
-
-                       array_fc = (void *) fc;
-
-                       if (array_fc->length != 16) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`uuid` member is not a 16-element array field class.");
-                               goto invalid;
-                       }
-
-                       if (array_fc->base.elem_fc->type != CTF_FIELD_CLASS_TYPE_INT) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`uuid` member's element field class is not "
-                                       "an integer field class.");
-                               goto invalid;
-                       }
-
-                       int_fc = (void *) array_fc->base.elem_fc;
-
-                       if (int_fc->is_signed) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`uuid` member's element field class "
-                                       "is a signed integer field class.");
-                               goto invalid;
-                       }
-
-                       if (int_fc->base.size != 8) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`uuid` member's element field class "
-                                       "is not an 8-bit integer field class.");
-                               goto invalid;
-                       }
-
-                       if (int_fc->base.base.alignment != 8) {
-                               BT_LOGE_STR("Invalid packet header field class: "
-                                       "`uuid` member's element field class's "
-                                       "alignment is not 8.");
-                               goto invalid;
-                       }
-               }
-       }
-
-       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc =
-                       ctf_tc->stream_classes->pdata[i];
-
-               ret = validate_stream_class(sc);
-               if (ret) {
-                       BT_LOGE("Invalid stream class: sc-id=%" PRIu64, sc->id);
-                       goto invalid;
-               }
-       }
-
-       goto end;
-
-invalid:
-       ret = -1;
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta-visitors.h b/plugins/ctf/common/metadata/ctf-meta-visitors.h
deleted file mode 100644 (file)
index 91ad929..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef _CTF_META_VISITORS_H
-#define _CTF_META_VISITORS_H
-
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#include "ctf-meta.h"
-
-BT_HIDDEN
-int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc);
-
-BT_HIDDEN
-int ctf_trace_class_translate(bt_self_component_source *self_comp,
-               bt_trace_class *ir_tc, struct ctf_trace_class *tc);
-
-BT_HIDDEN
-int ctf_trace_class_update_default_clock_classes(
-               struct ctf_trace_class *ctf_tc);
-
-BT_HIDDEN
-int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc);
-
-BT_HIDDEN
-int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc);
-
-BT_HIDDEN
-int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc);
-
-BT_HIDDEN
-int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc);
-
-BT_HIDDEN
-int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc);
-
-BT_HIDDEN
-int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc);
-
-BT_HIDDEN
-void ctf_trace_class_warn_meaningless_header_fields(
-               struct ctf_trace_class *ctf_tc);
-
-#endif /* _CTF_META_VISITORS_H */
diff --git a/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.c b/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.c
deleted file mode 100644 (file)
index 78bb458..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-WARN-MEANINGLESS-HEADER-FIELDS"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "ctf-meta-visitors.h"
-
-static inline
-void warn_meaningless_field(const char *name, const char *scope_name)
-{
-       BT_LOGW("User field found in %s: ignoring: name=\"%s\"",
-               scope_name, name);
-}
-
-static inline
-void warn_meaningless_fields(struct ctf_field_class *fc, const char *name,
-               const char *scope_name)
-{
-       uint64_t i;
-
-       if (!fc) {
-               goto end;
-       }
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_FLOAT:
-       case CTF_FIELD_CLASS_TYPE_STRING:
-               warn_meaningless_field(name, scope_name);
-               break;
-       case CTF_FIELD_CLASS_TYPE_INT:
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-       {
-               struct ctf_field_class_int *int_fc = (void *) fc;
-
-               if (int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE &&
-                               !int_fc->mapped_clock_class) {
-                       warn_meaningless_field(name, scope_name);
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               for (i = 0; i < struct_fc->members->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-
-                       warn_meaningless_fields(named_fc->fc,
-                               named_fc->name->str, scope_name);
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               for (i = 0; i < var_fc->options->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-
-                       warn_meaningless_fields(named_fc->fc,
-                               named_fc->name->str, scope_name);
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       {
-               struct ctf_field_class_array *array_fc = (void *) fc;
-
-               if (array_fc->meaning != CTF_FIELD_CLASS_MEANING_NONE) {
-                       goto end;
-               }
-
-       }
-       /* fall-through */
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               warn_meaningless_fields(array_fc->elem_fc, name, scope_name);
-               break;
-       }
-       default:
-               abort();
-       }
-
-end:
-       return;
-}
-
-BT_HIDDEN
-void ctf_trace_class_warn_meaningless_header_fields(
-               struct ctf_trace_class *ctf_tc)
-{
-       uint64_t i;
-
-       if (!ctf_tc->is_translated) {
-               warn_meaningless_fields(
-                       ctf_tc->packet_header_fc, NULL, "packet header");
-       }
-
-       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
-
-               if (!sc->is_translated) {
-                       warn_meaningless_fields(sc->event_header_fc, NULL,
-                               "event header");
-               }
-       }
-}
diff --git a/plugins/ctf/common/metadata/ctf-meta.h b/plugins/ctf/common/metadata/ctf-meta.h
deleted file mode 100644 (file)
index 3e78963..0000000
+++ /dev/null
@@ -1,1680 +0,0 @@
-#ifndef _CTF_META_H
-#define _CTF_META_H
-
-/*
- * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-
-enum ctf_field_class_type {
-       CTF_FIELD_CLASS_TYPE_INT,
-       CTF_FIELD_CLASS_TYPE_ENUM,
-       CTF_FIELD_CLASS_TYPE_FLOAT,
-       CTF_FIELD_CLASS_TYPE_STRING,
-       CTF_FIELD_CLASS_TYPE_STRUCT,
-       CTF_FIELD_CLASS_TYPE_ARRAY,
-       CTF_FIELD_CLASS_TYPE_SEQUENCE,
-       CTF_FIELD_CLASS_TYPE_VARIANT,
-};
-
-enum ctf_field_class_meaning {
-       CTF_FIELD_CLASS_MEANING_NONE,
-       CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME,
-       CTF_FIELD_CLASS_MEANING_PACKET_END_TIME,
-       CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID,
-       CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID,
-       CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID,
-       CTF_FIELD_CLASS_MEANING_MAGIC,
-       CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT,
-       CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT,
-       CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE,
-       CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE,
-       CTF_FIELD_CLASS_MEANING_UUID,
-};
-
-enum ctf_byte_order {
-       CTF_BYTE_ORDER_DEFAULT,
-       CTF_BYTE_ORDER_LITTLE,
-       CTF_BYTE_ORDER_BIG,
-};
-
-enum ctf_encoding {
-       CTF_ENCODING_NONE,
-       CTF_ENCODING_UTF8,
-};
-
-enum ctf_scope {
-       CTF_SCOPE_PACKET_HEADER,
-       CTF_SCOPE_PACKET_CONTEXT,
-       CTF_SCOPE_EVENT_HEADER,
-       CTF_SCOPE_EVENT_COMMON_CONTEXT,
-       CTF_SCOPE_EVENT_SPECIFIC_CONTEXT,
-       CTF_SCOPE_EVENT_PAYLOAD,
-};
-
-struct ctf_clock_class {
-       GString *name;
-       GString *description;
-       uint64_t frequency;
-       uint64_t precision;
-       int64_t offset_seconds;
-       uint64_t offset_cycles;
-       uint8_t uuid[16];
-       bool has_uuid;
-       bool is_absolute;
-
-       /* Weak, set during translation */
-       bt_clock_class *ir_cc;
-};
-
-struct ctf_field_class {
-       enum ctf_field_class_type type;
-       unsigned int alignment;
-       bool is_compound;
-       bool in_ir;
-
-       /* Weak, set during translation. NULL if `in_ir` is false below. */
-       bt_field_class *ir_fc;
-};
-
-struct ctf_field_class_bit_array {
-       struct ctf_field_class base;
-       enum ctf_byte_order byte_order;
-       unsigned int size;
-};
-
-struct ctf_field_class_int {
-       struct ctf_field_class_bit_array base;
-       enum ctf_field_class_meaning meaning;
-       bool is_signed;
-       bt_field_class_integer_preferred_display_base disp_base;
-       enum ctf_encoding encoding;
-       int64_t storing_index;
-
-       /* Weak */
-       struct ctf_clock_class *mapped_clock_class;
-};
-
-struct ctf_range {
-       union {
-               uint64_t u;
-               int64_t i;
-       } lower;
-
-       union {
-               uint64_t u;
-               int64_t i;
-       } upper;
-};
-
-struct ctf_field_class_enum_mapping {
-       GString *label;
-       struct ctf_range range;
-};
-
-struct ctf_field_class_enum {
-       struct ctf_field_class_int base;
-
-       /* Array of `struct ctf_field_class_enum_mapping` */
-       GArray *mappings;
-};
-
-struct ctf_field_class_float {
-       struct ctf_field_class_bit_array base;
-};
-
-struct ctf_field_class_string {
-       struct ctf_field_class base;
-       enum ctf_encoding encoding;
-};
-
-struct ctf_named_field_class {
-       GString *name;
-
-       /* Owned by this */
-       struct ctf_field_class *fc;
-};
-
-struct ctf_field_class_struct {
-       struct ctf_field_class base;
-
-       /* Array of `struct ctf_named_field_class` */
-       GArray *members;
-};
-
-struct ctf_field_path {
-       enum ctf_scope root;
-
-       /* Array of `int64_t` */
-       GArray *path;
-};
-
-struct ctf_field_class_variant_range {
-       struct ctf_range range;
-       uint64_t option_index;
-};
-
-struct ctf_field_class_variant {
-       struct ctf_field_class base;
-       GString *tag_ref;
-       struct ctf_field_path tag_path;
-       uint64_t stored_tag_index;
-
-       /* Array of `struct ctf_named_field_class` */
-       GArray *options;
-
-       /* Array of `struct ctf_field_class_variant_range` */
-       GArray *ranges;
-
-       /* Weak */
-       struct ctf_field_class_enum *tag_fc;
-};
-
-struct ctf_field_class_array_base {
-       struct ctf_field_class base;
-       struct ctf_field_class *elem_fc;
-       bool is_text;
-};
-
-struct ctf_field_class_array {
-       struct ctf_field_class_array_base base;
-       enum ctf_field_class_meaning meaning;
-       uint64_t length;
-};
-
-struct ctf_field_class_sequence {
-       struct ctf_field_class_array_base base;
-       GString *length_ref;
-       struct ctf_field_path length_path;
-       uint64_t stored_length_index;
-
-       /* Weak */
-       struct ctf_field_class_int *length_fc;
-};
-
-struct ctf_event_class {
-       GString *name;
-       uint64_t id;
-       GString *emf_uri;
-       bt_event_class_log_level log_level;
-       bool is_translated;
-
-       /* Owned by this */
-       struct ctf_field_class *spec_context_fc;
-
-       /* Owned by this */
-       struct ctf_field_class *payload_fc;
-
-       /* Weak, set during translation */
-       bt_event_class *ir_ec;
-};
-
-struct ctf_stream_class {
-       uint64_t id;
-       bool is_translated;
-       bool packets_have_ts_begin;
-       bool packets_have_ts_end;
-       bool has_discarded_events;
-       bool has_discarded_packets;
-       bool discarded_events_have_default_cs;
-       bool discarded_packets_have_default_cs;
-
-       /* Owned by this */
-       struct ctf_field_class *packet_context_fc;
-
-       /* Owned by this */
-       struct ctf_field_class *event_header_fc;
-
-       /* Owned by this */
-       struct ctf_field_class *event_common_context_fc;
-
-       /* Array of `struct ctf_event_class *`, owned by this */
-       GPtrArray *event_classes;
-
-       /*
-        * Hash table mapping event class IDs to `struct ctf_event_class *`,
-        * weak.
-        */
-       GHashTable *event_classes_by_id;
-
-       /* Weak */
-       struct ctf_clock_class *default_clock_class;
-
-       /* Weak, set during translation */
-       bt_stream_class *ir_sc;
-};
-
-enum ctf_trace_class_env_entry_type {
-       CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT,
-       CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR,
-};
-
-struct ctf_trace_class_env_entry {
-       enum ctf_trace_class_env_entry_type type;
-       GString *name;
-
-       struct {
-               int64_t i;
-               GString *str;
-       } value;
-};
-
-struct ctf_trace_class {
-       unsigned int major;
-       unsigned int minor;
-       uint8_t uuid[16];
-       bool is_uuid_set;
-       enum ctf_byte_order default_byte_order;
-
-       /* Owned by this */
-       struct ctf_field_class *packet_header_fc;
-
-       uint64_t stored_value_count;
-
-       /* Array of `struct ctf_clock_class *` (owned by this) */
-       GPtrArray *clock_classes;
-
-       /* Array of `struct ctf_stream_class *` */
-       GPtrArray *stream_classes;
-
-       /* Array of `struct ctf_trace_class_env_entry` */
-       GArray *env_entries;
-
-       bool is_translated;
-
-       /* Weak, set during translation */
-       bt_trace_class *ir_tc;
-};
-
-static inline
-void ctf_field_class_destroy(struct ctf_field_class *fc);
-
-static inline
-void _ctf_field_class_init(struct ctf_field_class *fc,
-               enum ctf_field_class_type type, unsigned int alignment)
-{
-       BT_ASSERT(fc);
-       fc->type = type;
-       fc->alignment = alignment;
-       fc->in_ir = false;
-}
-
-static inline
-void _ctf_field_class_bit_array_init(struct ctf_field_class_bit_array *fc,
-               enum ctf_field_class_type type)
-{
-       _ctf_field_class_init((void *) fc, type, 1);
-}
-
-static inline
-void _ctf_field_class_int_init(struct ctf_field_class_int *fc,
-               enum ctf_field_class_type type)
-{
-       _ctf_field_class_bit_array_init((void *) fc, type);
-       fc->meaning = CTF_FIELD_CLASS_MEANING_NONE;
-       fc->storing_index = -1;
-}
-
-static inline
-void ctf_field_path_init(struct ctf_field_path *field_path)
-{
-       BT_ASSERT(field_path);
-       field_path->path = g_array_new(FALSE, TRUE, sizeof(int64_t));
-       BT_ASSERT(field_path->path);
-}
-
-static inline
-void ctf_field_path_fini(struct ctf_field_path *field_path)
-{
-       BT_ASSERT(field_path);
-
-       if (field_path->path) {
-               g_array_free(field_path->path, TRUE);
-       }
-}
-
-static inline
-void _ctf_named_field_class_init(struct ctf_named_field_class *named_fc)
-{
-       BT_ASSERT(named_fc);
-       named_fc->name = g_string_new(NULL);
-       BT_ASSERT(named_fc->name);
-}
-
-static inline
-void _ctf_named_field_class_fini(struct ctf_named_field_class *named_fc)
-{
-       BT_ASSERT(named_fc);
-
-       if (named_fc->name) {
-               g_string_free(named_fc->name, TRUE);
-       }
-
-       ctf_field_class_destroy(named_fc->fc);
-}
-
-static inline
-void _ctf_field_class_enum_mapping_init(
-               struct ctf_field_class_enum_mapping *mapping)
-{
-       BT_ASSERT(mapping);
-       mapping->label = g_string_new(NULL);
-       BT_ASSERT(mapping->label);
-}
-
-static inline
-void _ctf_field_class_enum_mapping_fini(
-               struct ctf_field_class_enum_mapping *mapping)
-{
-       BT_ASSERT(mapping);
-
-       if (mapping->label) {
-               g_string_free(mapping->label, TRUE);
-       }
-}
-
-static inline
-struct ctf_field_class_int *ctf_field_class_int_create(void)
-{
-       struct ctf_field_class_int *fc = g_new0(struct ctf_field_class_int, 1);
-
-       BT_ASSERT(fc);
-       _ctf_field_class_int_init(fc, CTF_FIELD_CLASS_TYPE_INT);
-       return fc;
-}
-
-static inline
-struct ctf_field_class_float *ctf_field_class_float_create(void)
-{
-       struct ctf_field_class_float *fc =
-               g_new0(struct ctf_field_class_float, 1);
-
-       BT_ASSERT(fc);
-       _ctf_field_class_bit_array_init((void *) fc, CTF_FIELD_CLASS_TYPE_FLOAT);
-       return fc;
-}
-
-static inline
-struct ctf_field_class_string *ctf_field_class_string_create(void)
-{
-       struct ctf_field_class_string *fc =
-               g_new0(struct ctf_field_class_string, 1);
-
-       BT_ASSERT(fc);
-       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_STRING, 8);
-       return fc;
-}
-
-static inline
-struct ctf_field_class_enum *ctf_field_class_enum_create(void)
-{
-       struct ctf_field_class_enum *fc = g_new0(struct ctf_field_class_enum, 1);
-
-       BT_ASSERT(fc);
-       _ctf_field_class_int_init((void *) fc, CTF_FIELD_CLASS_TYPE_ENUM);
-       fc->mappings = g_array_new(FALSE, TRUE,
-               sizeof(struct ctf_field_class_enum_mapping));
-       BT_ASSERT(fc->mappings);
-       return fc;
-}
-
-static inline
-struct ctf_field_class_struct *ctf_field_class_struct_create(void)
-{
-       struct ctf_field_class_struct *fc =
-               g_new0(struct ctf_field_class_struct, 1);
-
-       BT_ASSERT(fc);
-       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_STRUCT, 1);
-       fc->members = g_array_new(FALSE, TRUE,
-               sizeof(struct ctf_named_field_class));
-       BT_ASSERT(fc->members);
-       fc->base.is_compound = true;
-       return fc;
-}
-
-static inline
-struct ctf_field_class_variant *ctf_field_class_variant_create(void)
-{
-       struct ctf_field_class_variant *fc =
-               g_new0(struct ctf_field_class_variant, 1);
-
-       BT_ASSERT(fc);
-       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_VARIANT, 1);
-       fc->options = g_array_new(FALSE, TRUE,
-               sizeof(struct ctf_named_field_class));
-       BT_ASSERT(fc->options);
-       fc->ranges = g_array_new(FALSE, TRUE,
-               sizeof(struct ctf_field_class_variant_range));
-       BT_ASSERT(fc->ranges);
-       fc->tag_ref = g_string_new(NULL);
-       BT_ASSERT(fc->tag_ref);
-       ctf_field_path_init(&fc->tag_path);
-       fc->base.is_compound = true;
-       return fc;
-}
-
-static inline
-struct ctf_field_class_array *ctf_field_class_array_create(void)
-{
-       struct ctf_field_class_array *fc =
-               g_new0(struct ctf_field_class_array, 1);
-
-       BT_ASSERT(fc);
-       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_ARRAY, 1);
-       fc->base.base.is_compound = true;
-       return fc;
-}
-
-static inline
-struct ctf_field_class_sequence *ctf_field_class_sequence_create(void)
-{
-       struct ctf_field_class_sequence *fc =
-               g_new0(struct ctf_field_class_sequence, 1);
-
-       BT_ASSERT(fc);
-       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_SEQUENCE, 1);
-       fc->length_ref = g_string_new(NULL);
-       BT_ASSERT(fc->length_ref);
-       ctf_field_path_init(&fc->length_path);
-       fc->base.base.is_compound = true;
-       return fc;
-}
-
-static inline
-void _ctf_field_class_int_destroy(struct ctf_field_class_int *fc)
-{
-       BT_ASSERT(fc);
-       g_free(fc);
-}
-
-static inline
-void _ctf_field_class_enum_destroy(struct ctf_field_class_enum *fc)
-{
-       BT_ASSERT(fc);
-
-       if (fc->mappings) {
-               uint64_t i;
-
-               for (i = 0; i < fc->mappings->len; i++) {
-                       struct ctf_field_class_enum_mapping *mapping =
-                               &g_array_index(fc->mappings,
-                                       struct ctf_field_class_enum_mapping, i);
-
-                       _ctf_field_class_enum_mapping_fini(mapping);
-               }
-
-               g_array_free(fc->mappings, TRUE);
-       }
-
-       g_free(fc);
-}
-
-static inline
-void _ctf_field_class_float_destroy(struct ctf_field_class_float *fc)
-{
-       BT_ASSERT(fc);
-       g_free(fc);
-}
-
-static inline
-void _ctf_field_class_string_destroy(struct ctf_field_class_string *fc)
-{
-       BT_ASSERT(fc);
-       g_free(fc);
-}
-
-static inline
-void _ctf_field_class_struct_destroy(struct ctf_field_class_struct *fc)
-{
-       BT_ASSERT(fc);
-
-       if (fc->members) {
-               uint64_t i;
-
-               for (i = 0; i < fc->members->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               &g_array_index(fc->members,
-                                       struct ctf_named_field_class, i);
-
-                       _ctf_named_field_class_fini(named_fc);
-               }
-
-               g_array_free(fc->members, TRUE);
-       }
-
-       g_free(fc);
-}
-
-static inline
-void _ctf_field_class_array_base_fini(struct ctf_field_class_array_base *fc)
-{
-       BT_ASSERT(fc);
-       ctf_field_class_destroy(fc->elem_fc);
-}
-
-static inline
-void _ctf_field_class_array_destroy(struct ctf_field_class_array *fc)
-{
-       BT_ASSERT(fc);
-       _ctf_field_class_array_base_fini((void *) fc);
-       g_free(fc);
-}
-
-static inline
-void _ctf_field_class_sequence_destroy(struct ctf_field_class_sequence *fc)
-{
-       BT_ASSERT(fc);
-       _ctf_field_class_array_base_fini((void *) fc);
-
-       if (fc->length_ref) {
-               g_string_free(fc->length_ref, TRUE);
-       }
-
-       ctf_field_path_fini(&fc->length_path);
-       g_free(fc);
-}
-
-static inline
-void _ctf_field_class_variant_destroy(struct ctf_field_class_variant *fc)
-{
-       BT_ASSERT(fc);
-
-       if (fc->options) {
-               uint64_t i;
-
-               for (i = 0; i < fc->options->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               &g_array_index(fc->options,
-                                       struct ctf_named_field_class, i);
-
-                       _ctf_named_field_class_fini(named_fc);
-               }
-
-               g_array_free(fc->options, TRUE);
-       }
-
-       if (fc->ranges) {
-               g_array_free(fc->ranges, TRUE);
-       }
-
-       if (fc->tag_ref) {
-               g_string_free(fc->tag_ref, TRUE);
-       }
-
-       ctf_field_path_fini(&fc->tag_path);
-       g_free(fc);
-}
-
-static inline
-void ctf_field_class_destroy(struct ctf_field_class *fc)
-{
-       if (!fc) {
-               return;
-       }
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_INT:
-               _ctf_field_class_int_destroy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-               _ctf_field_class_enum_destroy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_FLOAT:
-               _ctf_field_class_float_destroy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_STRING:
-               _ctf_field_class_string_destroy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-               _ctf_field_class_struct_destroy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-               _ctf_field_class_array_destroy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-               _ctf_field_class_sequence_destroy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-               _ctf_field_class_variant_destroy((void *) fc);
-               break;
-       default:
-               abort();
-       }
-}
-
-static inline
-void ctf_field_class_enum_append_mapping(struct ctf_field_class_enum *fc,
-               const char *label, uint64_t u_lower, uint64_t u_upper)
-{
-       struct ctf_field_class_enum_mapping *mapping;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(label);
-       g_array_set_size(fc->mappings, fc->mappings->len + 1);
-
-       mapping = &g_array_index(fc->mappings,
-               struct ctf_field_class_enum_mapping, fc->mappings->len - 1);
-       _ctf_field_class_enum_mapping_init(mapping);
-       g_string_assign(mapping->label, label);
-       mapping->range.lower.u = u_lower;
-       mapping->range.upper.u = u_upper;
-}
-
-static inline
-struct ctf_field_class_enum_mapping *ctf_field_class_enum_borrow_mapping_by_index(
-               struct ctf_field_class_enum *fc, uint64_t index)
-{
-       BT_ASSERT(fc);
-       BT_ASSERT(index < fc->mappings->len);
-       return &g_array_index(fc->mappings, struct ctf_field_class_enum_mapping,
-               index);
-}
-
-static inline
-struct ctf_named_field_class *ctf_field_class_struct_borrow_member_by_index(
-               struct ctf_field_class_struct *fc, uint64_t index)
-{
-       BT_ASSERT(fc);
-       BT_ASSERT(index < fc->members->len);
-       return &g_array_index(fc->members, struct ctf_named_field_class,
-               index);
-}
-
-static inline
-struct ctf_named_field_class *ctf_field_class_struct_borrow_member_by_name(
-               struct ctf_field_class_struct *fc, const char *name)
-{
-       uint64_t i;
-       struct ctf_named_field_class *ret_named_fc = NULL;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(name);
-
-       for (i = 0; i < fc->members->len; i++) {
-               struct ctf_named_field_class *named_fc =
-                       ctf_field_class_struct_borrow_member_by_index(fc, i);
-
-               if (strcmp(name, named_fc->name->str) == 0) {
-                       ret_named_fc = named_fc;
-                       goto end;
-               }
-       }
-
-end:
-       return ret_named_fc;
-}
-
-static inline
-struct ctf_field_class *ctf_field_class_struct_borrow_member_field_class_by_name(
-               struct ctf_field_class_struct *struct_fc, const char *name)
-{
-       struct ctf_named_field_class *named_fc = NULL;
-       struct ctf_field_class *fc = NULL;
-
-       if (!struct_fc) {
-               goto end;
-       }
-
-       named_fc = ctf_field_class_struct_borrow_member_by_name(struct_fc, name);
-       if (!named_fc) {
-               goto end;
-       }
-
-       fc = named_fc->fc;
-
-end:
-       return fc;
-}
-
-static inline
-struct ctf_field_class_int *
-ctf_field_class_struct_borrow_member_int_field_class_by_name(
-               struct ctf_field_class_struct *struct_fc, const char *name)
-{
-       struct ctf_field_class_int *int_fc = NULL;
-
-       int_fc = (void *)
-               ctf_field_class_struct_borrow_member_field_class_by_name(
-                       struct_fc, name);
-       if (!int_fc) {
-               goto end;
-       }
-
-       if (int_fc->base.base.type != CTF_FIELD_CLASS_TYPE_INT &&
-                       int_fc->base.base.type != CTF_FIELD_CLASS_TYPE_ENUM) {
-               int_fc = NULL;
-               goto end;
-       }
-
-end:
-       return int_fc;
-}
-
-
-static inline
-void ctf_field_class_struct_append_member(struct ctf_field_class_struct *fc,
-               const char *name, struct ctf_field_class *member_fc)
-{
-       struct ctf_named_field_class *named_fc;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(name);
-       g_array_set_size(fc->members, fc->members->len + 1);
-
-       named_fc = &g_array_index(fc->members, struct ctf_named_field_class,
-               fc->members->len - 1);
-       _ctf_named_field_class_init(named_fc);
-       g_string_assign(named_fc->name, name);
-       named_fc->fc = member_fc;
-
-       if (member_fc->alignment > fc->base.alignment) {
-               fc->base.alignment = member_fc->alignment;
-       }
-}
-
-static inline
-struct ctf_named_field_class *ctf_field_class_variant_borrow_option_by_index(
-               struct ctf_field_class_variant *fc, uint64_t index)
-{
-       BT_ASSERT(fc);
-       BT_ASSERT(index < fc->options->len);
-       return &g_array_index(fc->options, struct ctf_named_field_class,
-               index);
-}
-
-static inline
-struct ctf_named_field_class *ctf_field_class_variant_borrow_option_by_name(
-               struct ctf_field_class_variant *fc, const char *name)
-{
-       uint64_t i;
-       struct ctf_named_field_class *ret_named_fc = NULL;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(name);
-
-       for (i = 0; i < fc->options->len; i++) {
-               struct ctf_named_field_class *named_fc =
-                       ctf_field_class_variant_borrow_option_by_index(fc, i);
-
-               if (strcmp(name, named_fc->name->str) == 0) {
-                       ret_named_fc = named_fc;
-                       goto end;
-               }
-       }
-
-end:
-       return ret_named_fc;
-}
-
-static inline
-struct ctf_field_class_variant_range *
-ctf_field_class_variant_borrow_range_by_index(
-               struct ctf_field_class_variant *fc, uint64_t index)
-{
-       BT_ASSERT(fc);
-       BT_ASSERT(index < fc->ranges->len);
-       return &g_array_index(fc->ranges, struct ctf_field_class_variant_range,
-               index);
-}
-
-static inline
-void ctf_field_class_variant_append_option(struct ctf_field_class_variant *fc,
-               const char *name, struct ctf_field_class *option_fc)
-{
-       struct ctf_named_field_class *named_fc;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(name);
-       g_array_set_size(fc->options, fc->options->len + 1);
-
-       named_fc = &g_array_index(fc->options, struct ctf_named_field_class,
-               fc->options->len - 1);
-       _ctf_named_field_class_init(named_fc);
-       g_string_assign(named_fc->name, name);
-       named_fc->fc = option_fc;
-}
-
-static inline
-void ctf_field_class_variant_set_tag_field_class(
-               struct ctf_field_class_variant *fc,
-               struct ctf_field_class_enum *tag_fc)
-{
-       uint64_t option_i;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(tag_fc);
-       fc->tag_fc = tag_fc;
-
-       for (option_i = 0; option_i < fc->options->len; option_i++) {
-               uint64_t mapping_i;
-               struct ctf_named_field_class *named_fc =
-                       ctf_field_class_variant_borrow_option_by_index(
-                               fc, option_i);
-
-               for (mapping_i = 0; mapping_i < tag_fc->mappings->len;
-                               mapping_i++) {
-                       struct ctf_field_class_enum_mapping *mapping =
-                               ctf_field_class_enum_borrow_mapping_by_index(
-                                       tag_fc, mapping_i);
-
-                       if (strcmp(named_fc->name->str,
-                                       mapping->label->str) == 0) {
-                               struct ctf_field_class_variant_range range;
-
-                               range.range = mapping->range;
-                               range.option_index = option_i;
-                               g_array_append_val(fc->ranges, range);
-                       }
-               }
-       }
-}
-
-static inline
-struct ctf_field_class *ctf_field_class_compound_borrow_field_class_by_index(
-               struct ctf_field_class *comp_fc, uint64_t index)
-{
-       struct ctf_field_class *fc = NULL;
-
-       switch (comp_fc->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_named_field_class *named_fc =
-                       ctf_field_class_struct_borrow_member_by_index(
-                               (void *) comp_fc, index);
-
-               BT_ASSERT(named_fc);
-               fc = named_fc->fc;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_named_field_class *named_fc =
-                       ctf_field_class_variant_borrow_option_by_index(
-                               (void *) comp_fc, index);
-
-               BT_ASSERT(named_fc);
-               fc = named_fc->fc;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct ctf_field_class_array_base *array_fc = (void *) comp_fc;
-
-               fc = array_fc->elem_fc;
-               break;
-       }
-       default:
-               break;
-       }
-
-       return fc;
-}
-
-static inline
-uint64_t ctf_field_class_compound_get_field_class_count(struct ctf_field_class *fc)
-{
-       uint64_t field_count;
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               field_count = struct_fc->members->len;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               field_count = var_fc->options->len;
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-               /*
-                * Array and sequence types always contain a single
-                * member (the element type).
-                */
-               field_count = 1;
-               break;
-       default:
-               abort();
-       }
-
-       return field_count;
-}
-
-static inline
-int64_t ctf_field_class_compound_get_field_class_index_from_name(
-               struct ctf_field_class *fc, const char *name)
-{
-       int64_t ret_index = -1;
-       uint64_t i;
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-       {
-               struct ctf_field_class_struct *struct_fc = (void *) fc;
-
-               for (i = 0; i < struct_fc->members->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-
-                       if (strcmp(name, named_fc->name->str) == 0) {
-                               ret_index = (int64_t) i;
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct ctf_field_class_variant *var_fc = (void *) fc;
-
-               for (i = 0; i < var_fc->options->len; i++) {
-                       struct ctf_named_field_class *named_fc =
-                               ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-
-                       if (strcmp(name, named_fc->name->str) == 0) {
-                               ret_index = (int64_t) i;
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret_index;
-}
-
-static inline
-void ctf_field_path_append_index(struct ctf_field_path *fp, int64_t index)
-{
-       BT_ASSERT(fp);
-       g_array_append_val(fp->path, index);
-}
-
-static inline
-int64_t ctf_field_path_borrow_index_by_index(struct ctf_field_path *fp,
-               uint64_t index)
-{
-       BT_ASSERT(fp);
-       BT_ASSERT(index < fp->path->len);
-       return g_array_index(fp->path, int64_t, index);
-}
-
-static inline
-void ctf_field_path_clear(struct ctf_field_path *fp)
-{
-       BT_ASSERT(fp);
-       g_array_set_size(fp->path, 0);
-}
-
-static inline
-const char *ctf_scope_string(enum ctf_scope scope)
-{
-       switch (scope) {
-       case CTF_SCOPE_PACKET_HEADER:
-               return "CTF_SCOPE_PACKET_HEADER";
-       case CTF_SCOPE_PACKET_CONTEXT:
-               return "CTF_SCOPE_PACKET_CONTEXT";
-       case CTF_SCOPE_EVENT_HEADER:
-               return "CTF_SCOPE_EVENT_HEADER";
-       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
-               return "CTF_SCOPE_EVENT_COMMON_CONTEXT";
-       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               return "CTF_SCOPE_EVENT_SPECIFIC_CONTEXT";
-       case CTF_SCOPE_EVENT_PAYLOAD:
-               return "CTF_SCOPE_EVENT_PAYLOAD";
-       default:
-               abort();
-       }
-}
-
-static inline
-GString *ctf_field_path_string(struct ctf_field_path *path)
-{
-       GString *str = g_string_new(NULL);
-       uint64_t i;
-
-       BT_ASSERT(path);
-
-       if (!str) {
-               goto end;
-       }
-
-       g_string_append_printf(str, "[%s", ctf_scope_string(path->root));
-
-       for (i = 0; i < path->path->len; i++) {
-               g_string_append_printf(str, ", %" PRId64,
-                       ctf_field_path_borrow_index_by_index(path, i));
-       }
-
-       g_string_append(str, "]");
-
-end:
-       return str;
-}
-
-static inline
-struct ctf_field_class *ctf_field_path_borrow_field_class(
-               struct ctf_field_path *field_path,
-               struct ctf_trace_class *tc,
-               struct ctf_stream_class *sc,
-               struct ctf_event_class *ec)
-{
-       uint64_t i;
-       struct ctf_field_class *fc;
-
-       switch (field_path->root) {
-       case CTF_SCOPE_PACKET_HEADER:
-               fc = tc->packet_header_fc;
-               break;
-       case CTF_SCOPE_PACKET_CONTEXT:
-               fc = sc->packet_context_fc;
-               break;
-       case CTF_SCOPE_EVENT_HEADER:
-               fc = sc->event_header_fc;
-               break;
-       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
-               fc = sc->event_common_context_fc;
-               break;
-       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               fc = ec->spec_context_fc;
-               break;
-       case CTF_SCOPE_EVENT_PAYLOAD:
-               fc = ec->payload_fc;
-               break;
-       default:
-               abort();
-       }
-
-       BT_ASSERT(fc);
-
-       for (i = 0; i < field_path->path->len; i++) {
-               int64_t child_index =
-                       ctf_field_path_borrow_index_by_index(field_path, i);
-               struct ctf_field_class *child_fc =
-                       ctf_field_class_compound_borrow_field_class_by_index(
-                               fc, child_index);
-               BT_ASSERT(child_fc);
-               fc = child_fc;
-       }
-
-       BT_ASSERT(fc);
-       return fc;
-}
-
-static inline
-struct ctf_field_class *ctf_field_class_copy(struct ctf_field_class *fc);
-
-static inline
-void ctf_field_class_bit_array_copy_content(
-               struct ctf_field_class_bit_array *dst_fc,
-               struct ctf_field_class_bit_array *src_fc)
-{
-       BT_ASSERT(dst_fc);
-       BT_ASSERT(src_fc);
-       dst_fc->byte_order = src_fc->byte_order;
-       dst_fc->size = src_fc->size;
-}
-
-static inline
-void ctf_field_class_int_copy_content(
-               struct ctf_field_class_int *dst_fc,
-               struct ctf_field_class_int *src_fc)
-{
-       ctf_field_class_bit_array_copy_content((void *) dst_fc, (void *) src_fc);
-       dst_fc->meaning = src_fc->meaning;
-       dst_fc->is_signed = src_fc->is_signed;
-       dst_fc->disp_base = src_fc->disp_base;
-       dst_fc->encoding = src_fc->encoding;
-       dst_fc->mapped_clock_class = src_fc->mapped_clock_class;
-       dst_fc->storing_index = src_fc->storing_index;
-}
-
-static inline
-struct ctf_field_class_int *_ctf_field_class_int_copy(
-               struct ctf_field_class_int *fc)
-{
-       struct ctf_field_class_int *copy_fc = ctf_field_class_int_create();
-
-       BT_ASSERT(copy_fc);
-       ctf_field_class_int_copy_content(copy_fc, fc);
-       return copy_fc;
-}
-
-static inline
-struct ctf_field_class_enum *_ctf_field_class_enum_copy(
-               struct ctf_field_class_enum *fc)
-{
-       struct ctf_field_class_enum *copy_fc = ctf_field_class_enum_create();
-       uint64_t i;
-
-       BT_ASSERT(copy_fc);
-       ctf_field_class_int_copy_content((void *) copy_fc, (void *) fc);
-
-       for (i = 0; i < fc->mappings->len; i++) {
-               struct ctf_field_class_enum_mapping *mapping =
-                       &g_array_index(fc->mappings,
-                               struct ctf_field_class_enum_mapping, i);
-
-               ctf_field_class_enum_append_mapping(copy_fc, mapping->label->str,
-                       mapping->range.lower.u, mapping->range.upper.u);
-       }
-
-       return copy_fc;
-}
-
-static inline
-struct ctf_field_class_float *_ctf_field_class_float_copy(
-               struct ctf_field_class_float *fc)
-{
-       struct ctf_field_class_float *copy_fc = ctf_field_class_float_create();
-
-       BT_ASSERT(copy_fc);
-       ctf_field_class_bit_array_copy_content((void *) copy_fc, (void *) fc);
-       return copy_fc;
-}
-
-static inline
-struct ctf_field_class_string *_ctf_field_class_string_copy(
-               struct ctf_field_class_string *fc)
-{
-       struct ctf_field_class_string *copy_fc = ctf_field_class_string_create();
-
-       BT_ASSERT(copy_fc);
-       return copy_fc;
-}
-
-static inline
-struct ctf_field_class_struct *_ctf_field_class_struct_copy(
-               struct ctf_field_class_struct *fc)
-{
-       struct ctf_field_class_struct *copy_fc = ctf_field_class_struct_create();
-       uint64_t i;
-
-       BT_ASSERT(copy_fc);
-
-       for (i = 0; i < fc->members->len; i++) {
-               struct ctf_named_field_class *named_fc =
-                       &g_array_index(fc->members,
-                               struct ctf_named_field_class, i);
-
-               ctf_field_class_struct_append_member(copy_fc,
-                       named_fc->name->str,
-                       ctf_field_class_copy(named_fc->fc));
-       }
-
-       return copy_fc;
-}
-
-static inline
-void ctf_field_path_copy_content(struct ctf_field_path *dst_fp,
-               struct ctf_field_path *src_fp)
-{
-       uint64_t i;
-
-       BT_ASSERT(dst_fp);
-       BT_ASSERT(src_fp);
-       dst_fp->root = src_fp->root;
-       ctf_field_path_clear(dst_fp);
-
-       for (i = 0; i < src_fp->path->len; i++) {
-               int64_t index = ctf_field_path_borrow_index_by_index(
-                       src_fp, i);
-
-               ctf_field_path_append_index(dst_fp, index);
-       }
-}
-
-static inline
-struct ctf_field_class_variant *_ctf_field_class_variant_copy(
-               struct ctf_field_class_variant *fc)
-{
-       struct ctf_field_class_variant *copy_fc =
-               ctf_field_class_variant_create();
-       uint64_t i;
-
-       BT_ASSERT(copy_fc);
-
-       for (i = 0; i < fc->options->len; i++) {
-               struct ctf_named_field_class *named_fc =
-                       &g_array_index(fc->options,
-                               struct ctf_named_field_class, i);
-
-               ctf_field_class_variant_append_option(copy_fc,
-                       named_fc->name->str,
-                       ctf_field_class_copy(named_fc->fc));
-       }
-
-       for (i = 0; i < fc->ranges->len; i++) {
-               struct ctf_field_class_variant_range *range =
-                       &g_array_index(fc->ranges,
-                               struct ctf_field_class_variant_range, i);
-
-               g_array_append_val(copy_fc->ranges, *range);
-       }
-
-       ctf_field_path_copy_content(&copy_fc->tag_path, &fc->tag_path);
-       g_string_assign(copy_fc->tag_ref, fc->tag_ref->str);
-       copy_fc->stored_tag_index = fc->stored_tag_index;
-       return copy_fc;
-}
-
-static inline
-void ctf_field_class_array_base_copy_content(
-               struct ctf_field_class_array_base *dst_fc,
-               struct ctf_field_class_array_base *src_fc)
-{
-       BT_ASSERT(dst_fc);
-       BT_ASSERT(src_fc);
-       dst_fc->elem_fc = ctf_field_class_copy(src_fc->elem_fc);
-       dst_fc->is_text = src_fc->is_text;
-}
-
-static inline
-struct ctf_field_class_array *_ctf_field_class_array_copy(
-               struct ctf_field_class_array *fc)
-{
-       struct ctf_field_class_array *copy_fc = ctf_field_class_array_create();
-
-       BT_ASSERT(copy_fc);
-       ctf_field_class_array_base_copy_content((void *) copy_fc, (void *) fc);
-       copy_fc->length = fc->length;
-       return copy_fc;
-}
-
-static inline
-struct ctf_field_class_sequence *_ctf_field_class_sequence_copy(
-               struct ctf_field_class_sequence *fc)
-{
-       struct ctf_field_class_sequence *copy_fc =
-               ctf_field_class_sequence_create();
-
-       BT_ASSERT(copy_fc);
-       ctf_field_class_array_base_copy_content((void *) copy_fc, (void *) fc);
-       ctf_field_path_copy_content(&copy_fc->length_path, &fc->length_path);
-       g_string_assign(copy_fc->length_ref, fc->length_ref->str);
-       copy_fc->stored_length_index = fc->stored_length_index;
-       return copy_fc;
-}
-
-static inline
-struct ctf_field_class *ctf_field_class_copy(struct ctf_field_class *fc)
-{
-       struct ctf_field_class *copy_fc = NULL;
-
-       if (!fc) {
-               goto end;
-       }
-
-       /*
-        * Translation should not have happened yet.
-        */
-       BT_ASSERT(!fc->ir_fc);
-
-       switch (fc->type) {
-       case CTF_FIELD_CLASS_TYPE_INT:
-               copy_fc = (void *) _ctf_field_class_int_copy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_ENUM:
-               copy_fc = (void *) _ctf_field_class_enum_copy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_FLOAT:
-               copy_fc = (void *) _ctf_field_class_float_copy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_STRING:
-               copy_fc = (void *) _ctf_field_class_string_copy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_STRUCT:
-               copy_fc = (void *) _ctf_field_class_struct_copy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_ARRAY:
-               copy_fc = (void *) _ctf_field_class_array_copy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
-               copy_fc = (void *) _ctf_field_class_sequence_copy((void *) fc);
-               break;
-       case CTF_FIELD_CLASS_TYPE_VARIANT:
-               copy_fc = (void *) _ctf_field_class_variant_copy((void *) fc);
-               break;
-       default:
-               abort();
-       }
-
-       copy_fc->type = fc->type;
-       copy_fc->alignment = fc->alignment;
-       copy_fc->in_ir = fc->in_ir;
-
-end:
-       return copy_fc;
-}
-
-static inline
-struct ctf_event_class *ctf_event_class_create(void)
-{
-       struct ctf_event_class *ec = g_new0(struct ctf_event_class, 1);
-
-       BT_ASSERT(ec);
-       ec->name = g_string_new(NULL);
-       BT_ASSERT(ec->name);
-       ec->emf_uri = g_string_new(NULL);
-       BT_ASSERT(ec->emf_uri);
-       ec->log_level = -1;
-       return ec;
-}
-
-static inline
-void ctf_event_class_destroy(struct ctf_event_class *ec)
-{
-       if (!ec) {
-               return;
-       }
-
-       if (ec->name) {
-               g_string_free(ec->name, TRUE);
-       }
-
-       if (ec->emf_uri) {
-               g_string_free(ec->emf_uri, TRUE);
-       }
-
-       ctf_field_class_destroy(ec->spec_context_fc);
-       ctf_field_class_destroy(ec->payload_fc);
-       g_free(ec);
-}
-
-static inline
-struct ctf_stream_class *ctf_stream_class_create(void)
-{
-       struct ctf_stream_class *sc = g_new0(struct ctf_stream_class, 1);
-
-       BT_ASSERT(sc);
-       sc->event_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) ctf_event_class_destroy);
-       BT_ASSERT(sc->event_classes);
-       sc->event_classes_by_id = g_hash_table_new(g_direct_hash,
-               g_direct_equal);
-       BT_ASSERT(sc->event_classes_by_id);
-       return sc;
-}
-
-static inline
-void ctf_stream_class_destroy(struct ctf_stream_class *sc)
-{
-       if (!sc) {
-               return;
-       }
-
-       if (sc->event_classes) {
-               g_ptr_array_free(sc->event_classes, TRUE);
-       }
-
-       if (sc->event_classes_by_id) {
-               g_hash_table_destroy(sc->event_classes_by_id);
-       }
-
-       ctf_field_class_destroy(sc->packet_context_fc);
-       ctf_field_class_destroy(sc->event_header_fc);
-       ctf_field_class_destroy(sc->event_common_context_fc);
-       g_free(sc);
-}
-
-static inline
-void ctf_stream_class_append_event_class(struct ctf_stream_class *sc,
-               struct ctf_event_class *ec)
-{
-       g_ptr_array_add(sc->event_classes, ec);
-       g_hash_table_insert(sc->event_classes_by_id,
-               GUINT_TO_POINTER((guint) ec->id), ec);
-}
-
-static inline
-struct ctf_event_class *ctf_stream_class_borrow_event_class_by_id(
-               struct ctf_stream_class *sc, uint64_t type)
-{
-       BT_ASSERT(sc);
-       return g_hash_table_lookup(sc->event_classes_by_id,
-               GUINT_TO_POINTER((guint) type));
-}
-
-static inline
-void _ctf_trace_class_env_entry_init(struct ctf_trace_class_env_entry *entry)
-{
-       BT_ASSERT(entry);
-       entry->name = g_string_new(NULL);
-       BT_ASSERT(entry->name);
-       entry->value.str = g_string_new(NULL);
-       BT_ASSERT(entry->value.str);
-}
-
-static inline
-void _ctf_trace_class_env_entry_fini(struct ctf_trace_class_env_entry *entry)
-{
-       BT_ASSERT(entry);
-
-       if (entry->name) {
-               g_string_free(entry->name, TRUE);
-       }
-
-       if (entry->value.str) {
-               g_string_free(entry->value.str, TRUE);
-       }
-}
-
-static inline
-struct ctf_clock_class *ctf_clock_class_create(void)
-{
-       struct ctf_clock_class *cc = g_new0(struct ctf_clock_class, 1);
-
-       BT_ASSERT(cc);
-       cc->name = g_string_new(NULL);
-       BT_ASSERT(cc->name);
-       cc->description = g_string_new(NULL);
-       BT_ASSERT(cc->description);
-       return cc;
-}
-
-static inline
-void ctf_clock_class_destroy(struct ctf_clock_class *cc)
-{
-       if (!cc) {
-               return;
-       }
-
-       if (cc->name) {
-               g_string_free(cc->name, TRUE);
-       }
-
-       if (cc->description) {
-               g_string_free(cc->description, TRUE);
-       }
-
-       bt_clock_class_put_ref(cc->ir_cc);
-       g_free(cc);
-}
-
-static inline
-struct ctf_trace_class *ctf_trace_class_create(void)
-{
-       struct ctf_trace_class *tc = g_new0(struct ctf_trace_class, 1);
-
-       BT_ASSERT(tc);
-       tc->default_byte_order = -1;
-       tc->clock_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) ctf_clock_class_destroy);
-       BT_ASSERT(tc->clock_classes);
-       tc->stream_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) ctf_stream_class_destroy);
-       BT_ASSERT(tc->stream_classes);
-       tc->env_entries = g_array_new(FALSE, TRUE,
-               sizeof(struct ctf_trace_class_env_entry));
-       return tc;
-}
-
-static inline
-void ctf_trace_class_destroy(struct ctf_trace_class *tc)
-{
-       if (!tc) {
-               return;
-       }
-
-       ctf_field_class_destroy(tc->packet_header_fc);
-
-       if (tc->clock_classes) {
-               g_ptr_array_free(tc->clock_classes, TRUE);
-       }
-
-       if (tc->stream_classes) {
-               g_ptr_array_free(tc->stream_classes, TRUE);
-       }
-
-       if (tc->env_entries) {
-               uint64_t i;
-
-               for (i = 0; i < tc->env_entries->len; i++) {
-                       struct ctf_trace_class_env_entry *entry =
-                               &g_array_index(tc->env_entries,
-                                       struct ctf_trace_class_env_entry, i);
-
-                       _ctf_trace_class_env_entry_fini(entry);
-               }
-
-               g_array_free(tc->env_entries, TRUE);
-       }
-
-       g_free(tc);
-}
-
-static inline
-void ctf_trace_class_append_env_entry(struct ctf_trace_class *tc,
-               const char *name, enum ctf_trace_class_env_entry_type type,
-               const char *str_value, int64_t i_value)
-{
-       struct ctf_trace_class_env_entry *entry;
-
-       BT_ASSERT(tc);
-       BT_ASSERT(name);
-       g_array_set_size(tc->env_entries, tc->env_entries->len + 1);
-
-       entry = &g_array_index(tc->env_entries,
-               struct ctf_trace_class_env_entry, tc->env_entries->len - 1);
-       entry->type = type;
-       _ctf_trace_class_env_entry_init(entry);
-       g_string_assign(entry->name, name);
-
-       if (str_value) {
-               g_string_assign(entry->value.str, str_value);
-       }
-
-       entry->value.i = i_value;
-}
-
-static inline
-struct ctf_stream_class *ctf_trace_class_borrow_stream_class_by_id(
-               struct ctf_trace_class *tc, uint64_t id)
-{
-       uint64_t i;
-       struct ctf_stream_class *ret_sc = NULL;
-
-       BT_ASSERT(tc);
-
-       for (i = 0; i < tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc = tc->stream_classes->pdata[i];
-
-               if (sc->id == id) {
-                       ret_sc = sc;
-                       goto end;
-               }
-       }
-
-end:
-       return ret_sc;
-}
-
-static inline
-struct ctf_clock_class *ctf_trace_class_borrow_clock_class_by_name(
-               struct ctf_trace_class *tc, const char *name)
-{
-       uint64_t i;
-       struct ctf_clock_class *ret_cc = NULL;
-
-       BT_ASSERT(tc);
-       BT_ASSERT(name);
-
-       for (i = 0; i < tc->clock_classes->len; i++) {
-               struct ctf_clock_class *cc = tc->clock_classes->pdata[i];
-
-               BT_ASSERT(cc->name);
-               if (strcmp(cc->name->str, name) == 0) {
-                       ret_cc = cc;
-                       goto end;
-               }
-       }
-
-end:
-       return ret_cc;
-}
-
-static inline
-struct ctf_trace_class_env_entry *ctf_trace_class_borrow_env_entry_by_index(
-               struct ctf_trace_class *tc, uint64_t index)
-{
-       BT_ASSERT(tc);
-       BT_ASSERT(index < tc->env_entries->len);
-       return &g_array_index(tc->env_entries, struct ctf_trace_class_env_entry,
-               index);
-}
-
-static inline
-struct ctf_trace_class_env_entry *ctf_trace_class_borrow_env_entry_by_name(
-               struct ctf_trace_class *tc, const char *name)
-{
-       struct ctf_trace_class_env_entry *ret_entry = NULL;
-       uint64_t i;
-
-       BT_ASSERT(tc);
-       BT_ASSERT(name);
-
-       for (i = 0; i < tc->env_entries->len; i++) {
-               struct ctf_trace_class_env_entry *env_entry =
-                       ctf_trace_class_borrow_env_entry_by_index(tc, i);
-
-               if (strcmp(env_entry->name->str, name) == 0) {
-                       ret_entry = env_entry;
-                       goto end;
-               }
-       }
-
-end:
-       return ret_entry;
-}
-
-#endif /* _CTF_META_H */
diff --git a/plugins/ctf/common/metadata/decoder.c b/plugins/ctf/common/metadata/decoder.c
deleted file mode 100644 (file)
index c39e79e..0000000
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-DECODER"
-#include "logging.h"
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/compat/memstream-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <glib.h>
-#include <string.h>
-
-#include "ast.h"
-#include "decoder.h"
-#include "scanner.h"
-
-#define TSDL_MAGIC     0x75d11d57
-
-extern
-int yydebug;
-
-struct ctf_metadata_decoder {
-       struct ctf_visitor_generate_ir *visitor;
-       uint8_t uuid[16];
-       bool is_uuid_set;
-       int bo;
-       struct ctf_metadata_decoder_config config;
-};
-
-struct packet_header {
-       uint32_t magic;
-       uint8_t  uuid[16];
-       uint32_t checksum;
-       uint32_t content_size;
-       uint32_t packet_size;
-       uint8_t  compression_scheme;
-       uint8_t  encryption_scheme;
-       uint8_t  checksum_scheme;
-       uint8_t  major;
-       uint8_t  minor;
-} __attribute__((__packed__));
-
-BT_HIDDEN
-bool ctf_metadata_decoder_is_packetized(FILE *fp, int *byte_order)
-{
-       uint32_t magic;
-       size_t len;
-       int ret = 0;
-
-       len = fread(&magic, sizeof(magic), 1, fp);
-       if (len != 1) {
-               BT_LOGD_STR("Cannot reade first metadata packet header: assuming the stream is not packetized.");
-               goto end;
-       }
-
-       if (byte_order) {
-               if (magic == TSDL_MAGIC) {
-                       ret = 1;
-                       *byte_order = BYTE_ORDER;
-               } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
-                       ret = 1;
-                       *byte_order = BYTE_ORDER == BIG_ENDIAN ?
-                               LITTLE_ENDIAN : BIG_ENDIAN;
-               }
-       }
-
-end:
-       rewind(fp);
-
-       return ret;
-}
-
-static
-bool is_version_valid(unsigned int major, unsigned int minor)
-{
-       return major == 1 && minor == 8;
-}
-
-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;
-}
-
-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
-int ctf_metadata_decoder_packetized_file_stream_to_buf(
-               FILE *fp, char **buf, int byte_order)
-{
-       return ctf_metadata_decoder_packetized_file_stream_to_buf_with_mdec(
-               NULL, fp, buf, byte_order);
-}
-
-BT_HIDDEN
-struct ctf_metadata_decoder *ctf_metadata_decoder_create(
-               bt_self_component_source *self_comp,
-               const struct ctf_metadata_decoder_config *config)
-{
-       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,
-               config->clock_class_offset_s, config->clock_class_offset_ns);
-
-       if (!mdec) {
-               BT_LOGE_STR("Failed to allocate one CTF metadata decoder.");
-               goto end;
-       }
-
-       mdec->config = *config;
-       mdec->visitor = ctf_visitor_generate_ir_create(self_comp, config);
-       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 ", addr=%p",
-               config->clock_class_offset_s, config->clock_class_offset_ns,
-               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;
-
-       BT_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;
-       }
-
-       BT_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
-bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(
-               struct ctf_metadata_decoder *mdec)
-{
-       return ctf_visitor_generate_ir_get_ir_trace_class(mdec->visitor);
-}
-
-BT_HIDDEN
-struct ctf_trace_class *ctf_metadata_decoder_borrow_ctf_trace_class(
-               struct ctf_metadata_decoder *mdec)
-{
-       return ctf_visitor_generate_ir_borrow_ctf_trace_class(mdec->visitor);
-}
diff --git a/plugins/ctf/common/metadata/decoder.h b/plugins/ctf/common/metadata/decoder.h
deleted file mode 100644 (file)
index b0f179b..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef _METADATA_DECODER_H
-#define _METADATA_DECODER_H
-
-/*
- * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#include <babeltrace2/babeltrace.h>
-
-/* A CTF metadata decoder object */
-struct ctf_metadata_decoder;
-
-/* CTF metadata decoder status */
-enum ctf_metadata_decoder_status {
-       CTF_METADATA_DECODER_STATUS_OK                  = 0,
-       CTF_METADATA_DECODER_STATUS_ERROR               = -1,
-       CTF_METADATA_DECODER_STATUS_INCOMPLETE          = -2,
-       CTF_METADATA_DECODER_STATUS_INVAL_VERSION       = -3,
-       CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR    = -4,
-};
-
-/* Decoding configuration */
-struct ctf_metadata_decoder_config {
-       int64_t clock_class_offset_s;
-       int64_t clock_class_offset_ns;
-};
-
-/*
- * Creates a CTF metadata decoder.
- *
- * Returns `NULL` on error.
- */
-BT_HIDDEN
-struct ctf_metadata_decoder *ctf_metadata_decoder_create(
-               bt_self_component_source *self_comp,
-               const struct ctf_metadata_decoder_config *config);
-
-/*
- * Destroys a CTF metadata decoder that you created with
- * ctf_metadata_decoder_create().
- */
-BT_HIDDEN
-void ctf_metadata_decoder_destroy(
-               struct ctf_metadata_decoder *metadata_decoder);
-
-/*
- * Decodes a new chunk of CTF metadata.
- *
- * This function reads the metadata from the current position of `fp`
- * until the end of this file stream. If it finds new information (new
- * event class, new stream class, or new clock class), it appends this
- * information to the decoder's trace object (as returned by
- * ctf_metadata_decoder_get_ir_trace_class()), or it creates this trace.
- *
- * The metadata can be packetized or not.
- *
- * The metadata chunk needs to be complete and scannable, that is,
- * zero or more complete top-level blocks. If it's incomplete, this
- * function returns `CTF_METADATA_DECODER_STATUS_INCOMPLETE`. If this
- * function returns `CTF_METADATA_DECODER_STATUS_INCOMPLETE`, then you
- * need to call it again with the same metadata and more to make it
- * complete. For example:
- *
- *     First call:  event { name = hell
- *     Second call: event { name = hello_world; ... };
- *
- * If the conversion from the metadata text to CTF IR objects fails,
- * this function returns `CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR`.
- *
- * If everything goes as expected, this function returns
- * `CTF_METADATA_DECODER_STATUS_OK`.
- */
-BT_HIDDEN
-enum ctf_metadata_decoder_status ctf_metadata_decoder_decode(
-               struct ctf_metadata_decoder *metadata_decoder, FILE *fp);
-
-BT_HIDDEN
-bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(
-               struct ctf_metadata_decoder *mdec);
-
-BT_HIDDEN
-struct ctf_trace_class *ctf_metadata_decoder_borrow_ctf_trace_class(
-               struct ctf_metadata_decoder *mdec);
-
-/*
- * Checks whether or not a given metadata file stream is packetized, and
- * if so, sets `*byte_order` to the byte order of the first packet.
- */
-BT_HIDDEN
-bool ctf_metadata_decoder_is_packetized(FILE *fp, int *byte_order);
-
-/*
- * Decodes a packetized metadata file stream to a NULL-terminated
- * text buffer using the given byte order.
- */
-BT_HIDDEN
-int ctf_metadata_decoder_packetized_file_stream_to_buf(
-               FILE *fp, char **buf, int byte_order);
-
-#endif /* _METADATA_DECODER_H */
diff --git a/plugins/ctf/common/metadata/lexer.l b/plugins/ctf/common/metadata/lexer.l
deleted file mode 100644 (file)
index 694ddc3..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-%{
-/*
- * lexer.l
- *
- * Common Trace Formal Lexer
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-LEXER"
-#include "logging.h"
-
-#include <stdio.h>
-#include <ctype.h>
-#include "scanner.h"
-#include "parser.h"
-#include "ast.h"
-
-#define YY_FATAL_ERROR(_msg)   BT_LOGF_STR(_msg)
-
-#define PARSE_INTEGER_LITERAL(base)                                    \
-       do {                                                            \
-               errno = 0;                                              \
-               yylval->ull = strtoull(yytext, NULL, base);             \
-               if (errno) {                                            \
-                       _BT_LOGE_LINENO(yylineno,                       \
-                               "Cannot parser constant integer: "      \
-                               "base=%d, text=\"%s\"", base, yytext);  \
-                       return CTF_ERROR;                               \
-               }                                                       \
-       } while (0)
-
-BT_HIDDEN
-void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src);
-
-static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
-       __attribute__((unused));
-static int input (yyscan_t yyscanner) __attribute__((unused));
-
-BT_HIDDEN
-int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim);
-
-%}
-
-%x comment_ml comment_sl string_lit char_const
-%option reentrant yylineno noyywrap bison-bridge
-%option extra-type="struct ctf_scanner *"
-       /* bison-locations */
-INTEGER_SUFFIX                 (U|UL|ULL|LU|LLU|Ul|Ull|lU|llU|u|uL|uLL|Lu|LLu|ul|ull|lu|llu)
-DIGIT                          [0-9]
-NONDIGIT                       [a-zA-Z_]
-HEXDIGIT                       [0-9A-Fa-f]
-OCTALDIGIT                     [0-7]
-UCHARLOWERCASE                 \\u{HEXDIGIT}{4}
-UCHARUPPERCASE                 \\U{HEXDIGIT}{8}
-ID_NONDIGIT                    {NONDIGIT}|{UCHARLOWERCASE}|{UCHARUPPERCASE}
-IDENTIFIER                     {ID_NONDIGIT}({ID_NONDIGIT}|{DIGIT})*
-%%
-
-                               /*
-                                * Using start conditions to deal with comments
-                                * and strings.
-                                */
-
-"/*"                           BEGIN(comment_ml);
-<comment_ml>[^*\n]*            /* eat anything that's not a '*' */
-<comment_ml>"*"+[^*/\n]*       /* eat up '*'s not followed by '/'s */
-<comment_ml>\n
-<comment_ml>"*"+"/"            BEGIN(INITIAL);
-
-"//"[^\n]*\n                   /* skip comment */
-
-L?\"(\\.|[^\\"])*\"            { if (import_string(yyextra, yylval, yytext, '\"') < 0) return CTF_ERROR; else return CTF_STRING_LITERAL; }
-L?\'(\\.|[^\\'])*\'            { if (import_string(yyextra, yylval, yytext, '\'') < 0) return CTF_ERROR; else return CTF_CHARACTER_LITERAL; }
-
-"["                            return CTF_LSBRAC;
-"]"                            return CTF_RSBRAC;
-"("                            return CTF_LPAREN;
-")"                            return CTF_RPAREN;
-"{"                            return CTF_LBRAC;
-"}"                            return CTF_RBRAC;
-"->"                           return CTF_RARROW;
-"*"                            return CTF_STAR;
-"+"                            return CTF_PLUS;
-"-"                            return CTF_MINUS;
-"<"                            return CTF_LT;
-">"                            return CTF_GT;
-:=                             return CTF_TYPEASSIGN;
-:                              return CTF_COLON;
-;                              return CTF_SEMICOLON;
-"..."                          return CTF_DOTDOTDOT;
-"."                            return CTF_DOT;
-=                              return CTF_EQUAL;
-","                            return CTF_COMMA;
-align                          setstring(yyextra, yylval, yytext); return CTF_TOK_ALIGN;
-const                          setstring(yyextra, yylval, yytext); return CTF_CONST;
-char                           setstring(yyextra, yylval, yytext); return CTF_CHAR;
-clock                          setstring(yyextra, yylval, yytext); return CTF_CLOCK;
-double                         setstring(yyextra, yylval, yytext); return CTF_DOUBLE;
-enum                           setstring(yyextra, yylval, yytext); return CTF_ENUM;
-env                            setstring(yyextra, yylval, yytext); return CTF_ENV;
-event                          setstring(yyextra, yylval, yytext); return CTF_EVENT;
-floating_point                 setstring(yyextra, yylval, yytext); return CTF_FLOATING_POINT;
-float                          setstring(yyextra, yylval, yytext); return CTF_FLOAT;
-integer                                setstring(yyextra, yylval, yytext); return CTF_INTEGER;
-int                            setstring(yyextra, yylval, yytext); return CTF_INT;
-long                           setstring(yyextra, yylval, yytext); return CTF_LONG;
-short                          setstring(yyextra, yylval, yytext); return CTF_SHORT;
-signed                         setstring(yyextra, yylval, yytext); return CTF_SIGNED;
-stream                         setstring(yyextra, yylval, yytext); return CTF_STREAM;
-string                         setstring(yyextra, yylval, yytext); return CTF_STRING;
-struct                         setstring(yyextra, yylval, yytext); return CTF_STRUCT;
-trace                          setstring(yyextra, yylval, yytext); return CTF_TRACE;
-callsite                       setstring(yyextra, yylval, yytext); return CTF_CALLSITE;
-typealias                      setstring(yyextra, yylval, yytext); return CTF_TYPEALIAS;
-typedef                                setstring(yyextra, yylval, yytext); return CTF_TYPEDEF;
-unsigned                       setstring(yyextra, yylval, yytext); return CTF_UNSIGNED;
-variant                                setstring(yyextra, yylval, yytext); return CTF_VARIANT;
-void                           setstring(yyextra, yylval, yytext); return CTF_VOID;
-_Bool                          setstring(yyextra, yylval, yytext); return CTF_BOOL;
-_Complex                       setstring(yyextra, yylval, yytext); return CTF_COMPLEX;
-_Imaginary                     setstring(yyextra, yylval, yytext); return CTF_IMAGINARY;
-[1-9]{DIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(10); return CTF_INTEGER_LITERAL;
-0{OCTALDIGIT}*{INTEGER_SUFFIX}?        PARSE_INTEGER_LITERAL(8); return CTF_INTEGER_LITERAL;
-0[xX]{HEXDIGIT}+{INTEGER_SUFFIX}?      PARSE_INTEGER_LITERAL(16); return CTF_INTEGER_LITERAL;
-
-{IDENTIFIER}                   BT_LOGV("Got identifier: id=\"%s\"", yytext); setstring(yyextra, yylval, yytext); if (is_type(yyextra, yytext)) return ID_TYPE; else return IDENTIFIER;
-[ \t\r\n]                      ; /* ignore */
-.                              _BT_LOGE_LINENO(yylineno, "Invalid character: char=\"%c\", val=0x%02x", isprint(yytext[0]) ? yytext[0] : '\0', yytext[0]); return CTF_ERROR;
-%%
diff --git a/plugins/ctf/common/metadata/logging.c b/plugins/ctf/common/metadata/logging.c
deleted file mode 100644 (file)
index c5140a3..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL metadata_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(metadata_log_level, "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL");
diff --git a/plugins/ctf/common/metadata/logging.h b/plugins/ctf/common/metadata/logging.h
deleted file mode 100644 (file)
index 236cbc2..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef CTF_METADATA_LOGGING_H
-#define CTF_METADATA_LOGGING_H
-
-/*
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL metadata_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(metadata_log_level);
-
-#define _BT_LOGV_LINENO(_lineno, _msg, args...) \
-       BT_LOGV("At line %u in metadata stream: " _msg, _lineno, ## args)
-
-#define _BT_LOGW_LINENO(_lineno, _msg, args...) \
-       BT_LOGW("At line %u in metadata stream: " _msg, _lineno, ## args)
-
-#define _BT_LOGE_LINENO(_lineno, _msg, args...) \
-       BT_LOGE("At line %u in metadata stream: " _msg, _lineno, ## args)
-
-#endif /* CTF_METADATA_LOGGING_H */
diff --git a/plugins/ctf/common/metadata/objstack.c b/plugins/ctf/common/metadata/objstack.c
deleted file mode 100644 (file)
index 2f70380..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * objstack.c
- *
- * Common Trace Format Object Stack.
- *
- * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-OBJSTACK"
-#include "logging.h"
-
-#include <stdlib.h>
-#include <babeltrace2/list-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/align-internal.h>
-
-#define OBJSTACK_ALIGN                 8       /* Object stack alignment */
-#define OBJSTACK_INIT_LEN              128
-#define OBJSTACK_POISON                        0xcc
-
-struct objstack {
-       struct bt_list_head head;       /* list of struct objstack_node */
-};
-
-struct objstack_node {
-       struct bt_list_head node;
-       size_t len;
-       size_t used_len;
-       char __attribute__ ((aligned (OBJSTACK_ALIGN))) data[];
-};
-
-BT_HIDDEN
-struct objstack *objstack_create(void)
-{
-       struct objstack *objstack;
-       struct objstack_node *node;
-
-       objstack = calloc(1, sizeof(*objstack));
-       if (!objstack) {
-               BT_LOGE_STR("Failed to allocate one object stack.");
-               return NULL;
-       }
-       node = calloc(sizeof(struct objstack_node) + OBJSTACK_INIT_LEN,
-                       sizeof(char));
-       if (!node) {
-               BT_LOGE_STR("Failed to allocate one object stack node.");
-               free(objstack);
-               return NULL;
-       }
-       BT_INIT_LIST_HEAD(&objstack->head);
-       bt_list_add_tail(&node->node, &objstack->head);
-       node->len = OBJSTACK_INIT_LEN;
-       return objstack;
-}
-
-static
-void objstack_node_free(struct objstack_node *node)
-{
-       size_t offset, len;
-       char *p;
-
-       if (!node)
-               return;
-       p = (char *) node;
-       len = sizeof(*node) + node->len;
-       for (offset = 0; offset < len; offset++)
-               p[offset] = OBJSTACK_POISON;
-       free(node);
-}
-
-BT_HIDDEN
-void objstack_destroy(struct objstack *objstack)
-{
-       struct objstack_node *node, *p;
-
-       if (!objstack)
-               return;
-       bt_list_for_each_entry_safe(node, p, &objstack->head, node) {
-               bt_list_del(&node->node);
-               objstack_node_free(node);
-       }
-       free(objstack);
-}
-
-static
-struct objstack_node *objstack_append_node(struct objstack *objstack)
-{
-       struct objstack_node *last_node, *new_node;
-
-       /* Get last node */
-       last_node = bt_list_entry(objstack->head.prev,
-                       struct objstack_node, node);
-
-       /* Allocate new node with double of size of last node */
-       new_node = calloc(sizeof(struct objstack_node) + (last_node->len << 1),
-                       sizeof(char));
-       if (!new_node) {
-               BT_LOGE_STR("Failed to allocate one object stack node.");
-               return NULL;
-       }
-       bt_list_add_tail(&new_node->node, &objstack->head);
-       new_node->len = last_node->len << 1;
-       return new_node;
-}
-
-BT_HIDDEN
-void *objstack_alloc(struct objstack *objstack, size_t len)
-{
-       struct objstack_node *last_node;
-       void *p;
-
-       len = ALIGN(len, OBJSTACK_ALIGN);
-
-       /* Get last node */
-       last_node = bt_list_entry(objstack->head.prev,
-                       struct objstack_node, node);
-       while (last_node->len - last_node->used_len < len) {
-               last_node = objstack_append_node(objstack);
-               if (!last_node) {
-                       return NULL;
-               }
-       }
-       p = &last_node->data[last_node->used_len];
-       last_node->used_len += len;
-       return p;
-}
diff --git a/plugins/ctf/common/metadata/objstack.h b/plugins/ctf/common/metadata/objstack.h
deleted file mode 100644 (file)
index c026eb5..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _OBJSTACK_H
-#define _OBJSTACK_H
-
-/*
- * objstack.h
- *
- * Common Trace Format Object Stack.
- *
- * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-struct objstack;
-
-BT_HIDDEN
-struct objstack *objstack_create(void);
-BT_HIDDEN
-void objstack_destroy(struct objstack *objstack);
-
-/*
- * Allocate len bytes of zeroed memory.
- * Return NULL on error.
- */
-BT_HIDDEN
-void *objstack_alloc(struct objstack *objstack, size_t len);
-
-#endif /* _OBJSTACK_H */
diff --git a/plugins/ctf/common/metadata/parser.y b/plugins/ctf/common/metadata/parser.y
deleted file mode 100644 (file)
index 4e666db..0000000
+++ /dev/null
@@ -1,2592 +0,0 @@
-%{
-/*
- * ctf-parser.y
- *
- * Common Trace Format Metadata Grammar.
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-PARSER"
-#include "logging.h"
-
-#include <stdio.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <glib.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <babeltrace2/list-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include "scanner.h"
-#include "parser.h"
-#include "ast.h"
-#include "objstack.h"
-
-#if BT_LOG_ENABLED_VERBOSE
-# define YYDEBUG 1
-# define YYFPRINTF(_stream, _fmt, args...) BT_LOGV(_fmt, ## args)
-#else
-# define YYDEBUG 0
-#endif
-
-/* Join two lists, put "add" at the end of "head".  */
-static inline void
-_bt_list_splice_tail (struct bt_list_head *add, struct bt_list_head *head)
-{
-       /* Do nothing if the list which gets added is empty.  */
-       if (add != add->next) {
-               add->next->prev = head->prev;
-               add->prev->next = head;
-               head->prev->next = add->next;
-               head->prev = add->prev;
-       }
-}
-
-BT_HIDDEN
-int yyparse(struct ctf_scanner *scanner, yyscan_t yyscanner);
-BT_HIDDEN
-int yylex(union YYSTYPE *yyval, yyscan_t yyscanner);
-BT_HIDDEN
-int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals);
-BT_HIDDEN
-int yylex_destroy(yyscan_t yyscanner);
-BT_HIDDEN
-void yyrestart(FILE * in_str, yyscan_t yyscanner);
-BT_HIDDEN
-int yyget_lineno(yyscan_t yyscanner);
-BT_HIDDEN
-char *yyget_text(yyscan_t yyscanner);
-
-static const char *node_type_to_str[] = {
-#define ENTRY(S)       [S] = #S,
-       FOREACH_CTF_NODES(ENTRY)
-#undef ENTRY
-};
-
-/*
- * Static node for out of memory errors. Only "type" is used. lineno is
- * always left at 0. The rest of the node content can be overwritten,
- * but is never used.
- */
-static struct ctf_node error_node = {
-       .type = NODE_ERROR,
-};
-
-BT_HIDDEN
-const char *node_type(struct ctf_node *node)
-{
-       if (node->type < NR_NODE_TYPES)
-               return node_type_to_str[node->type];
-       else
-               return NULL;
-}
-
-void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src)
-{
-       lvalp->s = objstack_alloc(scanner->objstack, strlen(src) + 1);
-       strcpy(lvalp->s, src);
-}
-
-static
-int str_check(size_t str_len, size_t offset, size_t len)
-{
-       /* check overflow */
-       if (offset + len < offset)
-               return -1;
-       if (offset + len > str_len)
-               return -1;
-       return 0;
-}
-
-static
-int bt_isodigit(int c)
-{
-       switch (c) {
-       case '0':
-       case '1':
-       case '2':
-       case '3':
-       case '4':
-       case '5':
-       case '6':
-       case '7':
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-static
-int parse_base_sequence(const char *src, size_t len, size_t pos,
-               char *buffer, size_t *buf_len, int base)
-{
-       const size_t max_char = 3;
-       int nr_char = 0;
-
-       while (!str_check(len, pos, 1) && nr_char < max_char) {
-               char c = src[pos++];
-
-               if (base == 8) {
-                       if (bt_isodigit(c))
-                               buffer[nr_char++] = c;
-                       else
-                               break;
-               } else if (base == 16) {
-                       if (isxdigit(c))
-                               buffer[nr_char++] = c;
-                       else
-                               break;
-
-               } else {
-                       /* Unsupported base */
-                       return -1;
-               }
-       }
-       BT_ASSERT(nr_char > 0);
-       buffer[nr_char] = '\0';
-       *buf_len = nr_char;
-       return 0;
-}
-
-static
-int import_basic_string(struct ctf_scanner *scanner, YYSTYPE *lvalp,
-               size_t len, const char *src, char delim)
-{
-       size_t pos = 0, dpos = 0;
-
-       if (str_check(len, pos, 1))
-               return -1;
-       if (src[pos++] != delim)
-               return -1;
-
-       while (src[pos] != delim) {
-               char c;
-
-               if (str_check(len, pos, 1))
-                       return -1;
-               c = src[pos++];
-               if (c == '\\') {
-                       if (str_check(len, pos, 1))
-                               return -1;
-                       c = src[pos++];
-
-                       switch (c) {
-                       case 'a':
-                               c = '\a';
-                               break;
-                       case 'b':
-                               c = '\b';
-                               break;
-                       case 'f':
-                               c = '\f';
-                               break;
-                       case 'n':
-                               c = '\n';
-                               break;
-                       case 'r':
-                               c = '\r';
-                               break;
-                       case 't':
-                               c = '\t';
-                               break;
-                       case 'v':
-                               c = '\v';
-                               break;
-                       case '\\':
-                               c = '\\';
-                               break;
-                       case '\'':
-                               c = '\'';
-                               break;
-                       case '\"':
-                               c = '\"';
-                               break;
-                       case '?':
-                               c = '?';
-                               break;
-                       case '0':
-                       case '1':
-                       case '2':
-                       case '3':
-                       case '4':
-                       case '5':
-                       case '6':
-                       case '7':
-                       {
-                               char oct_buffer[4];
-                               size_t oct_len;
-
-                               if (parse_base_sequence(src, len, pos - 1,
-                                               oct_buffer, &oct_len, 8))
-                                       return -1;
-                               c = strtoul(&oct_buffer[0], NULL, 8);
-                               pos += oct_len - 1;
-                               break;
-                       }
-                       case 'x':
-                       {
-                               char hex_buffer[4];
-                               size_t hex_len;
-
-                               if (parse_base_sequence(src, len, pos,
-                                               hex_buffer, &hex_len, 16))
-                                       return -1;
-                               c = strtoul(&hex_buffer[0], NULL, 16);
-                               pos += hex_len;
-                               break;
-                       }
-                       default:
-                               return -1;
-                       }
-               }
-               if (str_check(len, dpos, 1))
-                       return -1;
-               lvalp->s[dpos++] = c;
-       }
-
-       if (str_check(len, dpos, 1))
-               return -1;
-       lvalp->s[dpos++] = '\0';
-
-       if (str_check(len, pos, 1))
-               return -1;
-       if (src[pos++] != delim)
-               return -1;
-
-       if (str_check(len, pos, 1))
-               return -1;
-       if (src[pos] != '\0')
-               return -1;
-       return 0;
-}
-
-int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp,
-               const char *src, char delim)
-{
-       size_t len;
-
-       len = strlen(src) + 1;
-       lvalp->s = objstack_alloc(scanner->objstack, len);
-       if (src[0] == 'L') {
-               // TODO: import wide string
-               _BT_LOGE_LINENO(yyget_lineno(scanner),
-                       "wide characters are not supported as of this version: "
-                       "scanner-addr=%p", scanner);
-               return -1;
-       } else {
-               return import_basic_string(scanner, lvalp, len, src, delim);
-       }
-}
-
-static void init_scope(struct ctf_scanner_scope *scope,
-                      struct ctf_scanner_scope *parent)
-{
-       scope->parent = parent;
-       scope->classes = g_hash_table_new_full(g_str_hash, g_str_equal,
-                                            NULL, NULL);
-}
-
-static void finalize_scope(struct ctf_scanner_scope *scope)
-{
-       g_hash_table_destroy(scope->classes);
-}
-
-static void push_scope(struct ctf_scanner *scanner)
-{
-       struct ctf_scanner_scope *ns;
-
-       BT_LOGV("Pushing scope: scanner-addr=%p", scanner);
-       ns = malloc(sizeof(struct ctf_scanner_scope));
-       init_scope(ns, scanner->cs);
-       scanner->cs = ns;
-}
-
-static void pop_scope(struct ctf_scanner *scanner)
-{
-       struct ctf_scanner_scope *os;
-
-       BT_LOGV("Popping scope: scanner-addr=%p", scanner);
-       os = scanner->cs;
-       scanner->cs = os->parent;
-       finalize_scope(os);
-       free(os);
-}
-
-static int lookup_type(struct ctf_scanner_scope *s, const char *id)
-{
-       int ret;
-
-       ret = GPOINTER_TO_INT(g_hash_table_lookup(s->classes, id));
-       BT_LOGV("Looked up type: scanner-addr=%p, id=\"%s\", ret=%d",
-               s, id, ret);
-       return ret;
-}
-
-BT_HIDDEN
-int is_type(struct ctf_scanner *scanner, const char *id)
-{
-       struct ctf_scanner_scope *it;
-       int ret = 0;
-
-       for (it = scanner->cs; it != NULL; it = it->parent) {
-               if (lookup_type(it, id)) {
-                       ret = 1;
-                       break;
-               }
-       }
-       BT_LOGV("Found if ID is type: scanner-addr=%p, id=\"%s\", ret=%d",
-               scanner, id, ret);
-       return ret;
-}
-
-static void add_type(struct ctf_scanner *scanner, char *id)
-{
-       BT_LOGV("Adding type: scanner-addr=%p, id=\"%s\"",
-               scanner, id);
-       if (lookup_type(scanner->cs, id))
-               return;
-       g_hash_table_insert(scanner->cs->classes, id, id);
-}
-
-static struct ctf_node *make_node(struct ctf_scanner *scanner,
-                                 enum node_type type)
-{
-       struct ctf_node *node;
-
-       node = objstack_alloc(scanner->objstack, sizeof(*node));
-       if (!node) {
-               _BT_LOGE_LINENO(yyget_lineno(scanner->scanner),
-                       "failed to allocate one stack entry: "
-                       "scanner-addr=%p", scanner);
-               return &error_node;
-       }
-       node->type = type;
-       node->lineno = yyget_lineno(scanner->scanner);
-       BT_INIT_LIST_HEAD(&node->tmp_head);
-       bt_list_add(&node->siblings, &node->tmp_head);
-
-       switch (type) {
-       case NODE_ROOT:
-               node->type = NODE_ERROR;
-               BT_LOGE("Trying to create root node: scanner-addr=%p",
-                       scanner);
-               break;
-       case NODE_EVENT:
-               BT_INIT_LIST_HEAD(&node->u.event.declaration_list);
-               break;
-       case NODE_STREAM:
-               BT_INIT_LIST_HEAD(&node->u.stream.declaration_list);
-               break;
-       case NODE_ENV:
-               BT_INIT_LIST_HEAD(&node->u.env.declaration_list);
-               break;
-       case NODE_TRACE:
-               BT_INIT_LIST_HEAD(&node->u.trace.declaration_list);
-               break;
-       case NODE_CLOCK:
-               BT_INIT_LIST_HEAD(&node->u.clock.declaration_list);
-               break;
-       case NODE_CALLSITE:
-               BT_INIT_LIST_HEAD(&node->u.callsite.declaration_list);
-               break;
-       case NODE_CTF_EXPRESSION:
-               BT_INIT_LIST_HEAD(&node->u.ctf_expression.left);
-               BT_INIT_LIST_HEAD(&node->u.ctf_expression.right);
-               break;
-       case NODE_UNARY_EXPRESSION:
-               break;
-       case NODE_TYPEDEF:
-               BT_INIT_LIST_HEAD(&node->u.field_class_def.field_class_declarators);
-               break;
-       case NODE_TYPEALIAS_TARGET:
-               BT_INIT_LIST_HEAD(&node->u.field_class_alias_target.field_class_declarators);
-               break;
-       case NODE_TYPEALIAS_ALIAS:
-               BT_INIT_LIST_HEAD(&node->u.field_class_alias_name.field_class_declarators);
-               break;
-       case NODE_TYPEALIAS:
-               break;
-       case NODE_TYPE_SPECIFIER:
-               break;
-       case NODE_TYPE_SPECIFIER_LIST:
-               BT_INIT_LIST_HEAD(&node->u.field_class_specifier_list.head);
-               break;
-       case NODE_POINTER:
-               break;
-       case NODE_TYPE_DECLARATOR:
-               BT_INIT_LIST_HEAD(&node->u.field_class_declarator.pointers);
-               break;
-       case NODE_FLOATING_POINT:
-               BT_INIT_LIST_HEAD(&node->u.floating_point.expressions);
-               break;
-       case NODE_INTEGER:
-               BT_INIT_LIST_HEAD(&node->u.integer.expressions);
-               break;
-       case NODE_STRING:
-               BT_INIT_LIST_HEAD(&node->u.string.expressions);
-               break;
-       case NODE_ENUMERATOR:
-               BT_INIT_LIST_HEAD(&node->u.enumerator.values);
-               break;
-       case NODE_ENUM:
-               BT_INIT_LIST_HEAD(&node->u._enum.enumerator_list);
-               break;
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               BT_INIT_LIST_HEAD(&node->u.struct_or_variant_declaration.field_class_declarators);
-               break;
-       case NODE_VARIANT:
-               BT_INIT_LIST_HEAD(&node->u.variant.declaration_list);
-               break;
-       case NODE_STRUCT:
-               BT_INIT_LIST_HEAD(&node->u._struct.declaration_list);
-               BT_INIT_LIST_HEAD(&node->u._struct.min_align);
-               break;
-       case NODE_UNKNOWN:
-       default:
-               node->type = NODE_ERROR;
-               BT_LOGE("Unknown node type: scanner-addr=%p, node-type=%d",
-                       scanner, type);
-               break;
-       }
-
-       return node;
-}
-
-static int reparent_ctf_expression(struct ctf_node *node,
-                                  struct ctf_node *parent)
-{
-       switch (parent->type) {
-       case NODE_EVENT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list);
-               break;
-       case NODE_STREAM:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list);
-               break;
-       case NODE_ENV:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list);
-               break;
-       case NODE_TRACE:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list);
-               break;
-       case NODE_CLOCK:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
-               break;
-       case NODE_CALLSITE:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
-               break;
-       case NODE_FLOATING_POINT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.floating_point.expressions);
-               break;
-       case NODE_INTEGER:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.integer.expressions);
-               break;
-       case NODE_STRING:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.string.expressions);
-               break;
-
-       case NODE_ROOT:
-       case NODE_CTF_EXPRESSION:
-       case NODE_TYPEDEF:
-       case NODE_TYPEALIAS_TARGET:
-       case NODE_TYPEALIAS_ALIAS:
-       case NODE_TYPEALIAS:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_TYPE_SPECIFIER_LIST:
-       case NODE_POINTER:
-       case NODE_TYPE_DECLARATOR:
-       case NODE_ENUMERATOR:
-       case NODE_ENUM:
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-       case NODE_VARIANT:
-       case NODE_STRUCT:
-       case NODE_UNARY_EXPRESSION:
-               return -EPERM;
-
-       case NODE_UNKNOWN:
-       default:
-               BT_LOGE("Unknown node type: node-type=%d", parent->type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int reparent_typedef(struct ctf_node *node, struct ctf_node *parent)
-{
-       switch (parent->type) {
-       case NODE_ROOT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list);
-               break;
-       case NODE_EVENT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list);
-               break;
-       case NODE_STREAM:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list);
-               break;
-       case NODE_ENV:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list);
-               break;
-       case NODE_TRACE:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list);
-               break;
-       case NODE_CLOCK:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
-               break;
-       case NODE_CALLSITE:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
-               break;
-       case NODE_VARIANT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list);
-               break;
-       case NODE_STRUCT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list);
-               break;
-
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_CTF_EXPRESSION:
-       case NODE_TYPEDEF:
-       case NODE_TYPEALIAS_TARGET:
-       case NODE_TYPEALIAS_ALIAS:
-       case NODE_TYPEALIAS:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_TYPE_SPECIFIER_LIST:
-       case NODE_POINTER:
-       case NODE_TYPE_DECLARATOR:
-       case NODE_ENUMERATOR:
-       case NODE_ENUM:
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-       case NODE_UNARY_EXPRESSION:
-               return -EPERM;
-
-       case NODE_UNKNOWN:
-       default:
-               BT_LOGE("Unknown node type: node-type=%d", parent->type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int reparent_field_class_alias(struct ctf_node *node, struct ctf_node *parent)
-{
-       switch (parent->type) {
-       case NODE_ROOT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list);
-               break;
-       case NODE_EVENT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list);
-               break;
-       case NODE_STREAM:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list);
-               break;
-       case NODE_ENV:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list);
-               break;
-       case NODE_TRACE:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list);
-               break;
-       case NODE_CLOCK:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
-               break;
-       case NODE_CALLSITE:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
-               break;
-       case NODE_VARIANT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list);
-               break;
-       case NODE_STRUCT:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list);
-               break;
-
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_CTF_EXPRESSION:
-       case NODE_TYPEDEF:
-       case NODE_TYPEALIAS_TARGET:
-       case NODE_TYPEALIAS_ALIAS:
-       case NODE_TYPEALIAS:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_TYPE_SPECIFIER_LIST:
-       case NODE_POINTER:
-       case NODE_TYPE_DECLARATOR:
-       case NODE_ENUMERATOR:
-       case NODE_ENUM:
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-       case NODE_UNARY_EXPRESSION:
-               return -EPERM;
-
-       case NODE_UNKNOWN:
-       default:
-               BT_LOGE("Unknown node type: node-type=%d", parent->type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int reparent_field_class_specifier(struct ctf_node *node,
-                                  struct ctf_node *parent)
-{
-       switch (parent->type) {
-       case NODE_TYPE_SPECIFIER_LIST:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_specifier_list.head);
-               break;
-
-       case NODE_TYPE_SPECIFIER:
-       case NODE_EVENT:
-       case NODE_STREAM:
-       case NODE_ENV:
-       case NODE_TRACE:
-       case NODE_CLOCK:
-       case NODE_CALLSITE:
-       case NODE_VARIANT:
-       case NODE_STRUCT:
-       case NODE_TYPEDEF:
-       case NODE_TYPEALIAS_TARGET:
-       case NODE_TYPEALIAS_ALIAS:
-       case NODE_TYPE_DECLARATOR:
-       case NODE_ENUM:
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-       case NODE_TYPEALIAS:
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_CTF_EXPRESSION:
-       case NODE_POINTER:
-       case NODE_ENUMERATOR:
-       case NODE_UNARY_EXPRESSION:
-               return -EPERM;
-
-       case NODE_UNKNOWN:
-       default:
-               BT_LOGE("Unknown node type: node-type=%d", parent->type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int reparent_field_class_specifier_list(struct ctf_node *node,
-                                       struct ctf_node *parent)
-{
-       switch (parent->type) {
-       case NODE_ROOT:
-               bt_list_add_tail(&node->siblings, &parent->u.root.declaration_list);
-               break;
-       case NODE_EVENT:
-               bt_list_add_tail(&node->siblings, &parent->u.event.declaration_list);
-               break;
-       case NODE_STREAM:
-               bt_list_add_tail(&node->siblings, &parent->u.stream.declaration_list);
-               break;
-       case NODE_ENV:
-               bt_list_add_tail(&node->siblings, &parent->u.env.declaration_list);
-               break;
-       case NODE_TRACE:
-               bt_list_add_tail(&node->siblings, &parent->u.trace.declaration_list);
-               break;
-       case NODE_CLOCK:
-               bt_list_add_tail(&node->siblings, &parent->u.clock.declaration_list);
-               break;
-       case NODE_CALLSITE:
-               bt_list_add_tail(&node->siblings, &parent->u.callsite.declaration_list);
-               break;
-       case NODE_VARIANT:
-               bt_list_add_tail(&node->siblings, &parent->u.variant.declaration_list);
-               break;
-       case NODE_STRUCT:
-               bt_list_add_tail(&node->siblings, &parent->u._struct.declaration_list);
-               break;
-       case NODE_TYPEDEF:
-               parent->u.field_class_def.field_class_specifier_list = node;
-               break;
-       case NODE_TYPEALIAS_TARGET:
-               parent->u.field_class_alias_target.field_class_specifier_list = node;
-               break;
-       case NODE_TYPEALIAS_ALIAS:
-               parent->u.field_class_alias_name.field_class_specifier_list = node;
-               break;
-       case NODE_ENUM:
-               parent->u._enum.container_field_class = node;
-               break;
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               parent->u.struct_or_variant_declaration.field_class_specifier_list = node;
-               break;
-       case NODE_TYPE_DECLARATOR:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_TYPEALIAS:
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_CTF_EXPRESSION:
-       case NODE_POINTER:
-       case NODE_ENUMERATOR:
-       case NODE_UNARY_EXPRESSION:
-               return -EPERM;
-
-       case NODE_UNKNOWN:
-       default:
-               BT_LOGE("Unknown node type: node-type=%d", parent->type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int reparent_field_class_declarator(struct ctf_node *node,
-                                   struct ctf_node *parent)
-{
-       switch (parent->type) {
-       case NODE_TYPE_DECLARATOR:
-               parent->u.field_class_declarator.type = TYPEDEC_NESTED;
-               parent->u.field_class_declarator.u.nested.field_class_declarator = node;
-               break;
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.struct_or_variant_declaration.field_class_declarators);
-               break;
-       case NODE_TYPEDEF:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_def.field_class_declarators);
-               break;
-       case NODE_TYPEALIAS_TARGET:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_target.field_class_declarators);
-               break;
-       case NODE_TYPEALIAS_ALIAS:
-               _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_name.field_class_declarators);
-               break;
-
-       case NODE_ROOT:
-       case NODE_EVENT:
-       case NODE_STREAM:
-       case NODE_ENV:
-       case NODE_TRACE:
-       case NODE_CLOCK:
-       case NODE_CALLSITE:
-       case NODE_VARIANT:
-       case NODE_STRUCT:
-       case NODE_TYPEALIAS:
-       case NODE_ENUM:
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_CTF_EXPRESSION:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_TYPE_SPECIFIER_LIST:
-       case NODE_POINTER:
-       case NODE_ENUMERATOR:
-       case NODE_UNARY_EXPRESSION:
-               return -EPERM;
-
-       case NODE_UNKNOWN:
-       default:
-               BT_LOGE("Unknown node type: node-type=%d", parent->type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/*
- * set_parent_node
- *
- * Link node to parent. Returns 0 on success, -EPERM if it is not permitted to
- * create the link declared by the input, -ENOENT if node or parent is NULL,
- * -EINVAL if there is an internal structure problem.
- */
-static int set_parent_node(struct ctf_node *node,
-                        struct ctf_node *parent)
-{
-       if (!node || !parent)
-               return -ENOENT;
-
-       /* Note: Linking to parent will be done only by an external visitor */
-
-       switch (node->type) {
-       case NODE_ROOT:
-               BT_LOGE_STR("Trying to reparent root node.");
-               return -EINVAL;
-
-       case NODE_EVENT:
-               if (parent->type == NODE_ROOT) {
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.event);
-               } else {
-                       return -EPERM;
-               }
-               break;
-       case NODE_STREAM:
-               if (parent->type == NODE_ROOT) {
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.stream);
-               } else {
-                       return -EPERM;
-               }
-               break;
-       case NODE_ENV:
-               if (parent->type == NODE_ROOT) {
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.env);
-               } else {
-                       return -EPERM;
-               }
-               break;
-       case NODE_TRACE:
-               if (parent->type == NODE_ROOT) {
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.trace);
-               } else {
-                       return -EPERM;
-               }
-               break;
-       case NODE_CLOCK:
-               if (parent->type == NODE_ROOT) {
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.clock);
-               } else {
-                       return -EPERM;
-               }
-               break;
-       case NODE_CALLSITE:
-               if (parent->type == NODE_ROOT) {
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.callsite);
-               } else {
-                       return -EPERM;
-               }
-               break;
-
-       case NODE_CTF_EXPRESSION:
-               return reparent_ctf_expression(node, parent);
-       case NODE_UNARY_EXPRESSION:
-               if (parent->type == NODE_TYPE_DECLARATOR)
-                       parent->u.field_class_declarator.bitfield_len = node;
-               else
-                       return -EPERM;
-               break;
-
-       case NODE_TYPEDEF:
-               return reparent_typedef(node, parent);
-       case NODE_TYPEALIAS_TARGET:
-               if (parent->type == NODE_TYPEALIAS)
-                       parent->u.field_class_alias.target = node;
-               else
-                       return -EINVAL;
-               /* fall-through */
-       case NODE_TYPEALIAS_ALIAS:
-               if (parent->type == NODE_TYPEALIAS)
-                       parent->u.field_class_alias.alias = node;
-               else
-                       return -EINVAL;
-               /* fall-through */
-       case NODE_TYPEALIAS:
-               return reparent_field_class_alias(node, parent);
-
-       case NODE_POINTER:
-               if (parent->type == NODE_TYPE_DECLARATOR) {
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_declarator.pointers);
-               } else
-                       return -EPERM;
-               break;
-       case NODE_TYPE_DECLARATOR:
-               return reparent_field_class_declarator(node, parent);
-
-       case NODE_TYPE_SPECIFIER_LIST:
-               return reparent_field_class_specifier_list(node, parent);
-
-       case NODE_TYPE_SPECIFIER:
-               return reparent_field_class_specifier(node, parent);
-
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_ENUM:
-       case NODE_VARIANT:
-       case NODE_STRUCT:
-               return -EINVAL; /* Dealt with internally within grammar */
-
-       case NODE_ENUMERATOR:
-               if (parent->type == NODE_ENUM) {
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u._enum.enumerator_list);
-               } else {
-                       return -EPERM;
-               }
-               break;
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               switch (parent->type) {
-               case NODE_STRUCT:
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list);
-                       break;
-               case NODE_VARIANT:
-                       _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list);
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-
-       case NODE_UNKNOWN:
-       default:
-               BT_LOGE("Unknown node type: node-type=%d", parent->type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-BT_HIDDEN
-void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str)
-{
-       _BT_LOGE_LINENO(yyget_lineno(scanner->scanner),
-               "%s: token=\"%s\"", str, yyget_text(scanner->scanner));
-}
-
-BT_HIDDEN
-int yywrap(void)
-{
-       return 1;
-}
-
-#define reparent_error(scanner, str)                           \
-do {                                                           \
-       yyerror(scanner, scanner->scanner, YY_("reparent_error: " str)); \
-       YYERROR;                                                \
-} while (0)
-
-static struct ctf_ast *ctf_ast_alloc(struct ctf_scanner *scanner)
-{
-       struct ctf_ast *ast;
-
-       ast = objstack_alloc(scanner->objstack, sizeof(*ast));
-       if (!ast)
-               return NULL;
-       ast->root.type = NODE_ROOT;
-       BT_INIT_LIST_HEAD(&ast->root.tmp_head);
-       BT_INIT_LIST_HEAD(&ast->root.u.root.declaration_list);
-       BT_INIT_LIST_HEAD(&ast->root.u.root.trace);
-       BT_INIT_LIST_HEAD(&ast->root.u.root.env);
-       BT_INIT_LIST_HEAD(&ast->root.u.root.stream);
-       BT_INIT_LIST_HEAD(&ast->root.u.root.event);
-       BT_INIT_LIST_HEAD(&ast->root.u.root.clock);
-       BT_INIT_LIST_HEAD(&ast->root.u.root.callsite);
-       return ast;
-}
-
-int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input)
-{
-       /* Start processing new stream */
-       yyrestart(input, scanner->scanner);
-       return yyparse(scanner, scanner->scanner);
-}
-
-struct ctf_scanner *ctf_scanner_alloc(void)
-{
-       struct ctf_scanner *scanner;
-       int ret;
-
-       scanner = malloc(sizeof(*scanner));
-       if (!scanner)
-               return NULL;
-       memset(scanner, 0, sizeof(*scanner));
-       ret = yylex_init_extra(scanner, &scanner->scanner);
-       if (ret) {
-               BT_LOGE("yylex_init_extra() failed: ret=%d", ret);
-               goto cleanup_scanner;
-       }
-       scanner->objstack = objstack_create();
-       if (!scanner->objstack)
-               goto cleanup_lexer;
-       scanner->ast = ctf_ast_alloc(scanner);
-       if (!scanner->ast)
-               goto cleanup_objstack;
-       init_scope(&scanner->root_scope, NULL);
-       scanner->cs = &scanner->root_scope;
-
-       return scanner;
-
-cleanup_objstack:
-       objstack_destroy(scanner->objstack);
-cleanup_lexer:
-       ret = yylex_destroy(scanner->scanner);
-       if (!ret)
-               BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d",
-                       scanner, ret);
-cleanup_scanner:
-       free(scanner);
-       return NULL;
-}
-
-void ctf_scanner_free(struct ctf_scanner *scanner)
-{
-       int ret;
-
-       if (!scanner)
-               return;
-       finalize_scope(&scanner->root_scope);
-       objstack_destroy(scanner->objstack);
-       ret = yylex_destroy(scanner->scanner);
-       if (ret)
-               BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d",
-                       scanner, ret);
-       free(scanner);
-}
-
-%}
-
-%define api.pure
-       /* %locations */
-%error-verbose
-%parse-param {struct ctf_scanner *scanner}
-%parse-param {yyscan_t yyscanner}
-%lex-param {yyscan_t yyscanner}
-/*
- * Expect two shift-reduce conflicts. Caused by enum name-opt : type {}
- * vs struct { int :value; } (unnamed bit-field). The default is to
- * shift, so whenever we encounter an enumeration, we are doing the
- * proper thing (shift). It is illegal to declare an enumeration
- * "bit-field", so it is OK if this situation ends up in a parsing
- * error.
- */
-%expect 2
-%start file
-%token CTF_INTEGER_LITERAL CTF_STRING_LITERAL CTF_CHARACTER_LITERAL CTF_LSBRAC CTF_RSBRAC CTF_LPAREN CTF_RPAREN CTF_LBRAC CTF_RBRAC CTF_RARROW CTF_STAR CTF_PLUS CTF_MINUS CTF_LT CTF_GT CTF_TYPEASSIGN CTF_COLON CTF_SEMICOLON CTF_DOTDOTDOT CTF_DOT CTF_EQUAL CTF_COMMA CTF_CONST CTF_CHAR CTF_DOUBLE CTF_ENUM CTF_ENV CTF_EVENT CTF_FLOATING_POINT CTF_FLOAT CTF_INTEGER CTF_INT CTF_LONG CTF_SHORT CTF_SIGNED CTF_STREAM CTF_STRING CTF_STRUCT CTF_TRACE CTF_CALLSITE CTF_CLOCK CTF_TYPEALIAS CTF_TYPEDEF CTF_UNSIGNED CTF_VARIANT CTF_VOID CTF_BOOL CTF_COMPLEX CTF_IMAGINARY CTF_TOK_ALIGN
-%token <s> IDENTIFIER ID_TYPE
-%token CTF_ERROR
-%union
-{
-       long long ll;
-       unsigned long long ull;
-       char c;
-       char *s;
-       struct ctf_node *n;
-}
-
-%type <s> CTF_STRING_LITERAL CTF_CHARACTER_LITERAL
-
-%type <s> keywords
-
-%type <ull> CTF_INTEGER_LITERAL
-%type <n> postfix_expression unary_expression unary_expression_or_range
-
-%type <n> declaration
-%type <n> event_declaration
-%type <n> stream_declaration
-%type <n> env_declaration
-%type <n> trace_declaration
-%type <n> clock_declaration
-%type <n> callsite_declaration
-%type <n> integer_declaration_specifiers
-%type <n> declaration_specifiers
-%type <n> alias_declaration_specifiers
-
-%type <n> field_class_declarator_list
-%type <n> integer_field_class_specifier
-%type <n> field_class_specifier
-%type <n> struct_class_specifier
-%type <n> variant_field_class_specifier
-%type <n> enum_field_class_specifier
-%type <n> struct_or_variant_declaration_list
-%type <n> struct_or_variant_declaration
-%type <n> struct_or_variant_declarator_list
-%type <n> struct_or_variant_declarator
-%type <n> enumerator_list
-%type <n> enumerator
-%type <n> abstract_declarator_list
-%type <n> abstract_declarator
-%type <n> direct_abstract_declarator
-%type <n> alias_abstract_declarator_list
-%type <n> alias_abstract_declarator
-%type <n> direct_alias_abstract_declarator
-%type <n> declarator
-%type <n> direct_declarator
-%type <n> field_class_declarator
-%type <n> direct_field_class_declarator
-%type <n> pointer
-%type <n> ctf_assignment_expression_list
-%type <n> ctf_assignment_expression
-
-%%
-
-file:
-               declaration
-               {
-                       if (set_parent_node($1, &ctf_scanner_get_ast(scanner)->root))
-                               reparent_error(scanner, "error reparenting to root");
-               }
-       |       file declaration
-               {
-                       if (set_parent_node($2, &ctf_scanner_get_ast(scanner)->root))
-                               reparent_error(scanner, "error reparenting to root");
-               }
-       ;
-
-keywords:
-               CTF_VOID
-               {       $$ = yylval.s;          }
-       |       CTF_CHAR
-               {       $$ = yylval.s;          }
-       |       CTF_SHORT
-               {       $$ = yylval.s;          }
-       |       CTF_INT
-               {       $$ = yylval.s;          }
-       |       CTF_LONG
-               {       $$ = yylval.s;          }
-       |       CTF_FLOAT
-               {       $$ = yylval.s;          }
-       |       CTF_DOUBLE
-               {       $$ = yylval.s;          }
-       |       CTF_SIGNED
-               {       $$ = yylval.s;          }
-       |       CTF_UNSIGNED
-               {       $$ = yylval.s;          }
-       |       CTF_BOOL
-               {       $$ = yylval.s;          }
-       |       CTF_COMPLEX
-               {       $$ = yylval.s;          }
-       |       CTF_IMAGINARY
-               {       $$ = yylval.s;          }
-       |       CTF_FLOATING_POINT
-               {       $$ = yylval.s;          }
-       |       CTF_INTEGER
-               {       $$ = yylval.s;          }
-       |       CTF_STRING
-               {       $$ = yylval.s;          }
-       |       CTF_ENUM
-               {       $$ = yylval.s;          }
-       |       CTF_VARIANT
-               {       $$ = yylval.s;          }
-       |       CTF_STRUCT
-               {       $$ = yylval.s;          }
-       |       CTF_CONST
-               {       $$ = yylval.s;          }
-       |       CTF_TYPEDEF
-               {       $$ = yylval.s;          }
-       |       CTF_EVENT
-               {       $$ = yylval.s;          }
-       |       CTF_STREAM
-               {       $$ = yylval.s;          }
-       |       CTF_ENV
-               {       $$ = yylval.s;          }
-       |       CTF_TRACE
-               {       $$ = yylval.s;          }
-       |       CTF_CLOCK
-               {       $$ = yylval.s;          }
-       |       CTF_CALLSITE
-               {       $$ = yylval.s;          }
-       |       CTF_TOK_ALIGN
-               {       $$ = yylval.s;          }
-       ;
-
-
-/* 2: Phrase structure grammar */
-
-postfix_expression:
-               IDENTIFIER
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = yylval.s;
-               }
-       |       ID_TYPE
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = yylval.s;
-               }
-       |       keywords
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = yylval.s;
-               }
-       |       CTF_INTEGER_LITERAL
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_UNSIGNED_CONSTANT;
-                       $$->u.unary_expression.u.unsigned_constant = $1;
-               }
-       |       CTF_STRING_LITERAL
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = $1;
-               }
-       |       CTF_CHARACTER_LITERAL
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = $1;
-               }
-       |       CTF_LPAREN unary_expression CTF_RPAREN
-               {
-                       $$ = $2;
-               }
-       |       postfix_expression CTF_LSBRAC unary_expression CTF_RSBRAC
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_SBRAC;
-                       $$->u.unary_expression.u.sbrac_exp = $3;
-                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
-                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
-               }
-       |       postfix_expression CTF_DOT IDENTIFIER
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = yylval.s;
-                       $$->u.unary_expression.link = UNARY_DOTLINK;
-                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
-                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
-               }
-       |       postfix_expression CTF_DOT ID_TYPE
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = yylval.s;
-                       $$->u.unary_expression.link = UNARY_DOTLINK;
-                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
-                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
-               }
-       |       postfix_expression CTF_DOT keywords
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = yylval.s;
-                       $$->u.unary_expression.link = UNARY_DOTLINK;
-                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
-                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
-               }
-       |       postfix_expression CTF_RARROW IDENTIFIER
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = yylval.s;
-                       $$->u.unary_expression.link = UNARY_ARROWLINK;
-                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
-                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
-               }
-       |       postfix_expression CTF_RARROW ID_TYPE
-               {
-                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
-                       $$->u.unary_expression.type = UNARY_STRING;
-                       $$->u.unary_expression.u.string = yylval.s;
-                       $$->u.unary_expression.link = UNARY_ARROWLINK;
-                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
-                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
-               }
-       ;
-
-unary_expression:
-               postfix_expression
-               {       $$ = $1;                                }
-       |       CTF_PLUS postfix_expression
-               {
-                       $$ = $2;
-                       if ($$->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT
-                               && $$->u.unary_expression.type != UNARY_SIGNED_CONSTANT) {
-                               reparent_error(scanner, "expecting numeric constant");
-                       }
-               }
-       |       CTF_MINUS postfix_expression
-               {
-                       $$ = $2;
-                       if ($$->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT) {
-                               $$->u.unary_expression.type = UNARY_SIGNED_CONSTANT;
-                               $$->u.unary_expression.u.signed_constant =
-                                       -($$->u.unary_expression.u.unsigned_constant);
-                       } else if ($$->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT) {
-                               $$->u.unary_expression.u.signed_constant =
-                                       -($$->u.unary_expression.u.signed_constant);
-                       } else {
-                               reparent_error(scanner, "expecting numeric constant");
-                       }
-               }
-       ;
-
-unary_expression_or_range:
-               unary_expression CTF_DOTDOTDOT unary_expression
-               {
-                       $$ = $1;
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->tmp_head);
-                       $3->u.unary_expression.link = UNARY_DOTDOTDOT;
-               }
-       |       unary_expression
-               {       $$ = $1;                }
-       ;
-
-/* 2.2: Declarations */
-
-declaration:
-               declaration_specifiers CTF_SEMICOLON
-               {       $$ = $1;        }
-       |       event_declaration
-               {       $$ = $1;        }
-       |       stream_declaration
-               {       $$ = $1;        }
-       |       env_declaration
-               {       $$ = $1;        }
-       |       trace_declaration
-               {       $$ = $1;        }
-       |       clock_declaration
-               {       $$ = $1;        }
-       |       callsite_declaration
-               {       $$ = $1;        }
-       |       declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_def.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_def.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_def.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEALIAS);
-                       $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
-                       $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators);
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators);
-               }
-       ;
-
-event_declaration:
-               event_declaration_begin event_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_EVENT);
-               }
-       |       event_declaration_begin ctf_assignment_expression_list event_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_EVENT);
-                       if (set_parent_node($2, $$))
-                               reparent_error(scanner, "event_declaration");
-               }
-       ;
-
-event_declaration_begin:
-               CTF_EVENT CTF_LBRAC
-               {       push_scope(scanner);    }
-       ;
-
-event_declaration_end:
-               CTF_RBRAC CTF_SEMICOLON
-               {       pop_scope(scanner);     }
-       ;
-
-
-stream_declaration:
-               stream_declaration_begin stream_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_STREAM);
-               }
-       |       stream_declaration_begin ctf_assignment_expression_list stream_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_STREAM);
-                       if (set_parent_node($2, $$))
-                               reparent_error(scanner, "stream_declaration");
-               }
-       ;
-
-stream_declaration_begin:
-               CTF_STREAM CTF_LBRAC
-               {       push_scope(scanner);    }
-       ;
-
-stream_declaration_end:
-               CTF_RBRAC CTF_SEMICOLON
-               {       pop_scope(scanner);     }
-       ;
-
-env_declaration:
-               env_declaration_begin env_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_ENV);
-               }
-       |       env_declaration_begin ctf_assignment_expression_list env_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_ENV);
-                       if (set_parent_node($2, $$))
-                               reparent_error(scanner, "env declaration");
-               }
-       ;
-
-env_declaration_begin:
-               CTF_ENV CTF_LBRAC
-               {       push_scope(scanner);    }
-       ;
-
-env_declaration_end:
-               CTF_RBRAC CTF_SEMICOLON
-               {       pop_scope(scanner);     }
-       ;
-
-trace_declaration:
-               trace_declaration_begin trace_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_TRACE);
-               }
-       |       trace_declaration_begin ctf_assignment_expression_list trace_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_TRACE);
-                       if (set_parent_node($2, $$))
-                               reparent_error(scanner, "trace_declaration");
-               }
-       ;
-
-trace_declaration_begin:
-               CTF_TRACE CTF_LBRAC
-               {       push_scope(scanner);    }
-       ;
-
-trace_declaration_end:
-               CTF_RBRAC CTF_SEMICOLON
-               {       pop_scope(scanner);     }
-       ;
-
-clock_declaration:
-               CTF_CLOCK clock_declaration_begin clock_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_CLOCK);
-               }
-       |       CTF_CLOCK clock_declaration_begin ctf_assignment_expression_list clock_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_CLOCK);
-                       if (set_parent_node($3, $$))
-                               reparent_error(scanner, "trace_declaration");
-               }
-       ;
-
-clock_declaration_begin:
-               CTF_LBRAC
-               {       push_scope(scanner);    }
-       ;
-
-clock_declaration_end:
-               CTF_RBRAC CTF_SEMICOLON
-               {       pop_scope(scanner);     }
-       ;
-
-callsite_declaration:
-               CTF_CALLSITE callsite_declaration_begin callsite_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_CALLSITE);
-               }
-       |       CTF_CALLSITE callsite_declaration_begin ctf_assignment_expression_list callsite_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_CALLSITE);
-                       if (set_parent_node($3, $$))
-                               reparent_error(scanner, "trace_declaration");
-               }
-       ;
-
-callsite_declaration_begin:
-               CTF_LBRAC
-               {       push_scope(scanner);    }
-       ;
-
-callsite_declaration_end:
-               CTF_RBRAC CTF_SEMICOLON
-               {       pop_scope(scanner);     }
-       ;
-
-integer_declaration_specifiers:
-               CTF_CONST
-               {
-                       struct ctf_node *node;
-
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       node->u.field_class_specifier.type = TYPESPEC_CONST;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       integer_field_class_specifier
-               {
-                       struct ctf_node *node;
-
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       node = $1;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       integer_declaration_specifiers CTF_CONST
-               {
-                       struct ctf_node *node;
-
-                       $$ = $1;
-                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       node->u.field_class_specifier.type = TYPESPEC_CONST;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       integer_declaration_specifiers integer_field_class_specifier
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       ;
-
-declaration_specifiers:
-               CTF_CONST
-               {
-                       struct ctf_node *node;
-
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       node->u.field_class_specifier.type = TYPESPEC_CONST;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       field_class_specifier
-               {
-                       struct ctf_node *node;
-
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       node = $1;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       declaration_specifiers CTF_CONST
-               {
-                       struct ctf_node *node;
-
-                       $$ = $1;
-                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       node->u.field_class_specifier.type = TYPESPEC_CONST;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       declaration_specifiers field_class_specifier
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       ;
-
-field_class_declarator_list:
-               field_class_declarator
-               {       $$ = $1;        }
-       |       field_class_declarator_list CTF_COMMA field_class_declarator
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
-               }
-       ;
-
-integer_field_class_specifier:
-               CTF_CHAR
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_CHAR;
-               }
-       |       CTF_SHORT
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_SHORT;
-               }
-       |       CTF_INT
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_INT;
-               }
-       |       CTF_LONG
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_LONG;
-               }
-       |       CTF_SIGNED
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_SIGNED;
-               }
-       |       CTF_UNSIGNED
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED;
-               }
-       |       CTF_BOOL
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_BOOL;
-               }
-       |       ID_TYPE
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE;
-                       $$->u.field_class_specifier.id_type = yylval.s;
-               }
-       |       CTF_INTEGER CTF_LBRAC CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_INTEGER;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER);
-               }
-       |       CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_INTEGER;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER);
-                       if (set_parent_node($3, $$->u.field_class_specifier.node))
-                               reparent_error(scanner, "integer reparent error");
-               }
-       ;
-
-field_class_specifier:
-               CTF_VOID
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_VOID;
-               }
-       |       CTF_CHAR
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_CHAR;
-               }
-       |       CTF_SHORT
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_SHORT;
-               }
-       |       CTF_INT
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_INT;
-               }
-       |       CTF_LONG
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_LONG;
-               }
-       |       CTF_FLOAT
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_FLOAT;
-               }
-       |       CTF_DOUBLE
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_DOUBLE;
-               }
-       |       CTF_SIGNED
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_SIGNED;
-               }
-       |       CTF_UNSIGNED
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED;
-               }
-       |       CTF_BOOL
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_BOOL;
-               }
-       |       CTF_COMPLEX
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_COMPLEX;
-               }
-       |       CTF_IMAGINARY
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_IMAGINARY;
-               }
-       |       ID_TYPE
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE;
-                       $$->u.field_class_specifier.id_type = yylval.s;
-               }
-       |       CTF_FLOATING_POINT CTF_LBRAC CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT);
-               }
-       |       CTF_FLOATING_POINT CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT);
-                       if (set_parent_node($3, $$->u.field_class_specifier.node))
-                               reparent_error(scanner, "floating point reparent error");
-               }
-       |       CTF_INTEGER CTF_LBRAC CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_INTEGER;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER);
-               }
-       |       CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_INTEGER;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER);
-                       if (set_parent_node($3, $$->u.field_class_specifier.node))
-                               reparent_error(scanner, "integer reparent error");
-               }
-       |       CTF_STRING
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_STRING;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING);
-               }
-       |       CTF_STRING CTF_LBRAC CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_STRING;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING);
-               }
-       |       CTF_STRING CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_STRING;
-                       $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING);
-                       if (set_parent_node($3, $$->u.field_class_specifier.node))
-                               reparent_error(scanner, "string reparent error");
-               }
-       |       CTF_ENUM enum_field_class_specifier
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_ENUM;
-                       $$->u.field_class_specifier.node = $2;
-               }
-       |       CTF_VARIANT variant_field_class_specifier
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_VARIANT;
-                       $$->u.field_class_specifier.node = $2;
-               }
-       |       CTF_STRUCT struct_class_specifier
-               {
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       $$->u.field_class_specifier.type = TYPESPEC_STRUCT;
-                       $$->u.field_class_specifier.node = $2;
-               }
-       ;
-
-struct_class_specifier:
-               struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_STRUCT);
-                       $$->u._struct.has_body = 1;
-                       if ($2 && set_parent_node($2, $$))
-                               reparent_error(scanner, "struct reparent error");
-               }
-       |       IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_STRUCT);
-                       $$->u._struct.has_body = 1;
-                       $$->u._struct.name = $1;
-                       if ($3 && set_parent_node($3, $$))
-                               reparent_error(scanner, "struct reparent error");
-               }
-       |       ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_STRUCT);
-                       $$->u._struct.has_body = 1;
-                       $$->u._struct.name = $1;
-                       if ($3 && set_parent_node($3, $$))
-                               reparent_error(scanner, "struct reparent error");
-               }
-       |       IDENTIFIER
-               {
-                       $$ = make_node(scanner, NODE_STRUCT);
-                       $$->u._struct.has_body = 0;
-                       $$->u._struct.name = $1;
-               }
-       |       ID_TYPE
-               {
-                       $$ = make_node(scanner, NODE_STRUCT);
-                       $$->u._struct.has_body = 0;
-                       $$->u._struct.name = $1;
-               }
-       |       struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN
-               {
-                       $$ = make_node(scanner, NODE_STRUCT);
-                       $$->u._struct.has_body = 1;
-                       bt_list_add_tail(&($6)->siblings, &$$->u._struct.min_align);
-                       if ($2 && set_parent_node($2, $$))
-                               reparent_error(scanner, "struct reparent error");
-               }
-       |       IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN
-               {
-                       $$ = make_node(scanner, NODE_STRUCT);
-                       $$->u._struct.has_body = 1;
-                       $$->u._struct.name = $1;
-                       bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align);
-                       if ($3 && set_parent_node($3, $$))
-                               reparent_error(scanner, "struct reparent error");
-               }
-       |       ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN
-               {
-                       $$ = make_node(scanner, NODE_STRUCT);
-                       $$->u._struct.has_body = 1;
-                       $$->u._struct.name = $1;
-                       bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align);
-                       if ($3 && set_parent_node($3, $$))
-                               reparent_error(scanner, "struct reparent error");
-               }
-       ;
-
-struct_declaration_begin:
-               CTF_LBRAC
-               {       push_scope(scanner);    }
-       ;
-
-struct_declaration_end:
-               CTF_RBRAC
-               {       pop_scope(scanner);     }
-       ;
-
-variant_field_class_specifier:
-               variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       if ($2 && set_parent_node($2, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       $$->u.variant.choice = $2;
-                       if ($5 && set_parent_node($5, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       $$->u.variant.choice = $2;
-                       if ($5 && set_parent_node($5, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       IDENTIFIER variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       $$->u.variant.name = $1;
-                       if ($3 && set_parent_node($3, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       IDENTIFIER CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       $$->u.variant.name = $1;
-                       $$->u.variant.choice = $3;
-                       if ($6 && set_parent_node($6, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       IDENTIFIER CTF_LT IDENTIFIER CTF_GT
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 0;
-                       $$->u.variant.name = $1;
-                       $$->u.variant.choice = $3;
-               }
-       |       IDENTIFIER CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       $$->u.variant.name = $1;
-                       $$->u.variant.choice = $3;
-                       if ($6 && set_parent_node($6, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       IDENTIFIER CTF_LT ID_TYPE CTF_GT
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 0;
-                       $$->u.variant.name = $1;
-                       $$->u.variant.choice = $3;
-               }
-       |       ID_TYPE variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       $$->u.variant.name = $1;
-                       if ($3 && set_parent_node($3, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       ID_TYPE CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       $$->u.variant.name = $1;
-                       $$->u.variant.choice = $3;
-                       if ($6 && set_parent_node($6, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       ID_TYPE CTF_LT IDENTIFIER CTF_GT
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 0;
-                       $$->u.variant.name = $1;
-                       $$->u.variant.choice = $3;
-               }
-       |       ID_TYPE CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 1;
-                       $$->u.variant.name = $1;
-                       $$->u.variant.choice = $3;
-                       if ($6 && set_parent_node($6, $$))
-                               reparent_error(scanner, "variant reparent error");
-               }
-       |       ID_TYPE CTF_LT ID_TYPE CTF_GT
-               {
-                       $$ = make_node(scanner, NODE_VARIANT);
-                       $$->u.variant.has_body = 0;
-                       $$->u.variant.name = $1;
-                       $$->u.variant.choice = $3;
-               }
-       ;
-
-variant_declaration_begin:
-               CTF_LBRAC
-               {       push_scope(scanner);    }
-       ;
-
-variant_declaration_end:
-               CTF_RBRAC
-               {       pop_scope(scanner);     }
-       ;
-
-enum_field_class_specifier:
-               CTF_LBRAC enumerator_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       ($$)->u._enum.container_field_class = $2;
-                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       IDENTIFIER CTF_LBRAC enumerator_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       $$->u._enum.enum_id = $1;
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       $$->u._enum.enum_id = $1;
-                       ($$)->u._enum.container_field_class = $3;
-                       _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       ID_TYPE CTF_LBRAC enumerator_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       $$->u._enum.enum_id = $1;
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       $$->u._enum.enum_id = $1;
-                       ($$)->u._enum.container_field_class = $3;
-                       _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       ($$)->u._enum.container_field_class = $2;
-                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       IDENTIFIER CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       $$->u._enum.enum_id = $1;
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       $$->u._enum.enum_id = $1;
-                       ($$)->u._enum.container_field_class = $3;
-                       _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       IDENTIFIER
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 0;
-                       $$->u._enum.enum_id = $1;
-               }
-       |       ID_TYPE CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       $$->u._enum.enum_id = $1;
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 1;
-                       $$->u._enum.enum_id = $1;
-                       ($$)->u._enum.container_field_class = $3;
-                       _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
-               }
-       |       ID_TYPE
-               {
-                       $$ = make_node(scanner, NODE_ENUM);
-                       $$->u._enum.has_body = 0;
-                       $$->u._enum.enum_id = $1;
-               }
-       ;
-
-struct_or_variant_declaration_list:
-               /* empty */
-               {       $$ = NULL;      }
-       |       struct_or_variant_declaration_list struct_or_variant_declaration
-               {
-                       if ($1) {
-                               $$ = $1;
-                               bt_list_add_tail(&($2)->siblings, &($$)->tmp_head);
-                       } else {
-                               $$ = $2;
-                               bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
-                       }
-               }
-       ;
-
-struct_or_variant_declaration:
-               declaration_specifiers struct_or_variant_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       $$ = make_node(scanner, NODE_STRUCT_OR_VARIANT_DECLARATION);
-                       ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($2)->tmp_head, &($$)->u.struct_or_variant_declaration.field_class_declarators);
-               }
-       |       declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_def.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_def.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEALIAS);
-                       $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
-                       $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators);
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators);
-               }
-       ;
-
-alias_declaration_specifiers:
-               CTF_CONST
-               {
-                       struct ctf_node *node;
-
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       node->u.field_class_specifier.type = TYPESPEC_CONST;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       field_class_specifier
-               {
-                       struct ctf_node *node;
-
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       node = $1;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       IDENTIFIER
-               {
-                       struct ctf_node *node;
-
-                       add_type(scanner, $1);
-                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       node->u.field_class_specifier.type = TYPESPEC_ID_TYPE;
-                       node->u.field_class_specifier.id_type = yylval.s;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       alias_declaration_specifiers CTF_CONST
-               {
-                       struct ctf_node *node;
-
-                       $$ = $1;
-                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       node->u.field_class_specifier.type = TYPESPEC_CONST;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       alias_declaration_specifiers field_class_specifier
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       |       alias_declaration_specifiers IDENTIFIER
-               {
-                       struct ctf_node *node;
-
-                       add_type(scanner, $2);
-                       $$ = $1;
-                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
-                       node->u.field_class_specifier.type = TYPESPEC_ID_TYPE;
-                       node->u.field_class_specifier.id_type = yylval.s;
-                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
-               }
-       ;
-
-struct_or_variant_declarator_list:
-               struct_or_variant_declarator
-               {       $$ = $1;        }
-       |       struct_or_variant_declarator_list CTF_COMMA struct_or_variant_declarator
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
-               }
-       ;
-
-struct_or_variant_declarator:
-               declarator
-               {       $$ = $1;        }
-       |       CTF_COLON unary_expression
-               {       $$ = $2;        }
-       |       declarator CTF_COLON unary_expression
-               {
-                       $$ = $1;
-                       if (set_parent_node($3, $1))
-                               reparent_error(scanner, "struct_or_variant_declarator");
-               }
-       ;
-
-enumerator_list:
-               enumerator
-               {       $$ = $1;        }
-       |       enumerator_list CTF_COMMA enumerator
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
-               }
-       ;
-
-enumerator:
-               IDENTIFIER
-               {
-                       $$ = make_node(scanner, NODE_ENUMERATOR);
-                       $$->u.enumerator.id = $1;
-               }
-       |       ID_TYPE
-               {
-                       $$ = make_node(scanner, NODE_ENUMERATOR);
-                       $$->u.enumerator.id = $1;
-               }
-       |       keywords
-               {
-                       $$ = make_node(scanner, NODE_ENUMERATOR);
-                       $$->u.enumerator.id = $1;
-               }
-       |       CTF_STRING_LITERAL
-               {
-                       $$ = make_node(scanner, NODE_ENUMERATOR);
-                       $$->u.enumerator.id = $1;
-               }
-       |       IDENTIFIER CTF_EQUAL unary_expression_or_range
-               {
-                       $$ = make_node(scanner, NODE_ENUMERATOR);
-                       $$->u.enumerator.id = $1;
-                       bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
-               }
-       |       ID_TYPE CTF_EQUAL unary_expression_or_range
-               {
-                       $$ = make_node(scanner, NODE_ENUMERATOR);
-                       $$->u.enumerator.id = $1;
-                       bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
-               }
-       |       keywords CTF_EQUAL unary_expression_or_range
-               {
-                       $$ = make_node(scanner, NODE_ENUMERATOR);
-                       $$->u.enumerator.id = $1;
-                       bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
-               }
-       |       CTF_STRING_LITERAL CTF_EQUAL unary_expression_or_range
-               {
-                       $$ = make_node(scanner, NODE_ENUMERATOR);
-                       $$->u.enumerator.id = $1;
-                       bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
-               }
-       ;
-
-abstract_declarator_list:
-               abstract_declarator
-               {       $$ = $1;        }
-       |       abstract_declarator_list CTF_COMMA abstract_declarator
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
-               }
-       ;
-
-abstract_declarator:
-               direct_abstract_declarator
-               {       $$ = $1;        }
-       |       pointer direct_abstract_declarator
-               {
-                       $$ = $2;
-                       bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers);
-               }
-       ;
-
-direct_abstract_declarator:
-               /* empty */
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                        $$->u.field_class_declarator.type = TYPEDEC_ID;
-                       /* id is NULL */
-               }
-       |       IDENTIFIER
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_ID;
-                       $$->u.field_class_declarator.u.id = $1;
-               }
-       |       CTF_LPAREN abstract_declarator CTF_RPAREN
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $2;
-               }
-       |       direct_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
-                       BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length);
-               }
-       |       direct_abstract_declarator CTF_LSBRAC CTF_RSBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
-                       $$->u.field_class_declarator.u.nested.abstract_array = 1;
-               }
-       ;
-
-alias_abstract_declarator_list:
-               alias_abstract_declarator
-               {       $$ = $1;        }
-       |       alias_abstract_declarator_list CTF_COMMA alias_abstract_declarator
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
-               }
-       ;
-
-alias_abstract_declarator:
-               direct_alias_abstract_declarator
-               {       $$ = $1;        }
-       |       pointer direct_alias_abstract_declarator
-               {
-                       $$ = $2;
-                       bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers);
-               }
-       ;
-
-direct_alias_abstract_declarator:
-               /* empty */
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                        $$->u.field_class_declarator.type = TYPEDEC_ID;
-                       /* id is NULL */
-               }
-       |       CTF_LPAREN alias_abstract_declarator CTF_RPAREN
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $2;
-               }
-       |       direct_alias_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
-                       BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length);
-               }
-       |       direct_alias_abstract_declarator CTF_LSBRAC CTF_RSBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
-                       $$->u.field_class_declarator.u.nested.abstract_array = 1;
-               }
-       ;
-
-declarator:
-               direct_declarator
-               {       $$ = $1;        }
-       |       pointer direct_declarator
-               {
-                       $$ = $2;
-                       bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers);
-               }
-       ;
-
-direct_declarator:
-               IDENTIFIER
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_ID;
-                       $$->u.field_class_declarator.u.id = $1;
-               }
-       |       CTF_LPAREN declarator CTF_RPAREN
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $2;
-               }
-       |       direct_declarator CTF_LSBRAC unary_expression CTF_RSBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
-                       BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length);
-               }
-       ;
-
-field_class_declarator:
-               direct_field_class_declarator
-               {       $$ = $1;        }
-       |       pointer direct_field_class_declarator
-               {
-                       $$ = $2;
-                       bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers);
-               }
-       ;
-
-direct_field_class_declarator:
-               IDENTIFIER
-               {
-                       add_type(scanner, $1);
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_ID;
-                       $$->u.field_class_declarator.u.id = $1;
-               }
-       |       CTF_LPAREN field_class_declarator CTF_RPAREN
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $2;
-               }
-       |       direct_field_class_declarator CTF_LSBRAC unary_expression CTF_RSBRAC
-               {
-                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
-                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
-                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
-                       BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length);
-               }
-       ;
-
-pointer:
-               CTF_STAR
-               {
-                       $$ = make_node(scanner, NODE_POINTER);
-               }
-       |       CTF_STAR pointer
-               {
-                       $$ = make_node(scanner, NODE_POINTER);
-                       bt_list_splice(&($2)->tmp_head, &($$)->tmp_head);
-               }
-       |       CTF_STAR type_qualifier_list pointer
-               {
-                       $$ = make_node(scanner, NODE_POINTER);
-                       $$->u.pointer.const_qualifier = 1;
-                       bt_list_splice(&($3)->tmp_head, &($$)->tmp_head);
-               }
-       ;
-
-type_qualifier_list:
-               /* pointer assumes only const type qualifier */
-               CTF_CONST
-       |       type_qualifier_list CTF_CONST
-       ;
-
-/* 2.3: CTF-specific declarations */
-
-ctf_assignment_expression_list:
-               ctf_assignment_expression CTF_SEMICOLON
-               {       $$ = $1;        }
-       |       ctf_assignment_expression_list ctf_assignment_expression CTF_SEMICOLON
-               {
-                       $$ = $1;
-                       bt_list_add_tail(&($2)->siblings, &($$)->tmp_head);
-               }
-       ;
-
-ctf_assignment_expression:
-               unary_expression CTF_EQUAL unary_expression
-               {
-                       /*
-                        * Because we have left and right, cannot use
-                        * set_parent_node.
-                        */
-                       $$ = make_node(scanner, NODE_CTF_EXPRESSION);
-                       _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left);
-                       if ($1->u.unary_expression.type != UNARY_STRING)
-                               reparent_error(scanner, "ctf_assignment_expression left expects string");
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.ctf_expression.right);
-               }
-       |       unary_expression CTF_TYPEASSIGN declaration_specifiers  /* Only allow struct */
-               {
-                       /*
-                        * Because we have left and right, cannot use
-                        * set_parent_node.
-                        */
-                       $$ = make_node(scanner, NODE_CTF_EXPRESSION);
-                       _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left);
-                       if ($1->u.unary_expression.type != UNARY_STRING)
-                               reparent_error(scanner, "ctf_assignment_expression left expects string");
-                       bt_list_add_tail(&($3)->siblings, &($$)->u.ctf_expression.right);
-               }
-       |       declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list
-               {
-                       struct ctf_node *list;
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       CTF_TYPEDEF declaration_specifiers field_class_declarator_list
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_def.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       declaration_specifiers CTF_TYPEDEF field_class_declarator_list
-               {
-                       struct ctf_node *list;
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       $$ = make_node(scanner, NODE_TYPEDEF);
-                       ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
-               }
-       |       CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list
-               {
-                       struct ctf_node *list;
-
-                       $$ = make_node(scanner, NODE_TYPEALIAS);
-                       $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
-                       $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators);
-
-                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
-                       $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list;
-                       _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
-                       _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators);
-               }
-       ;
diff --git a/plugins/ctf/common/metadata/scanner-symbols.h b/plugins/ctf/common/metadata/scanner-symbols.h
deleted file mode 100644 (file)
index 9b9e363..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef _CTF_SCANNER_SYMBOLS
-#define _CTF_SCANNER_SYMBOLS
-
-/*
- * ctf-scanner-symbols.h
- *
- * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#define yy_create_buffer bt_yy_create_buffer
-#define yy_delete_buffer bt_yy_delete_buffer
-#define yy_flush_buffer bt_yy_flush_buffer
-#define yy_scan_buffer bt_yy_scan_buffer
-#define yy_scan_bytes bt_yy_scan_bytes
-#define yy_scan_string bt_yy_scan_string
-#define yy_switch_to_buffer bt_yy_switch_to_buffer
-#define yyalloc bt_yyalloc
-#define yyfree bt_yyfree
-#define yyget_column bt_yyget_column
-#define yyget_debug bt_yyget_debug
-#define yyget_extra bt_yyget_extra
-#define yyget_in bt_yyget_in
-#define yyget_leng bt_yyget_leng
-#define yyget_lineno bt_yyget_lineno
-#define yyget_lval bt_yyget_lval
-#define yyget_out bt_yyget_out
-#define yyget_text bt_yyget_text
-#define yylex_init bt_yylex_init
-#define yypop_buffer_state bt_yypop_buffer_state
-#define yypush_buffer_state bt_yypush_buffer_state
-#define yyrealloc bt_yyrealloc
-#define yyset_column bt_yyset_column
-#define yyset_debug bt_yyset_debug
-#define yyset_extra bt_yyset_extra
-#define yyset_in bt_yyset_in
-#define yyset_lineno bt_yyset_lineno
-#define yyset_lval bt_yyset_lval
-#define yyset_out bt_yyset_out
-
-#endif /* _CTF_SCANNER_SYMBOLS */
diff --git a/plugins/ctf/common/metadata/scanner.h b/plugins/ctf/common/metadata/scanner.h
deleted file mode 100644 (file)
index 34d6c46..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _CTF_SCANNER_H
-#define _CTF_SCANNER_H
-
-/*
- * ctf-scanner.h
- *
- * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#include <stdio.h>
-#include "ast.h"
-
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-typedef void* yyscan_t;
-#endif
-
-struct ctf_scanner_scope;
-struct ctf_scanner_scope {
-       struct ctf_scanner_scope *parent;
-       GHashTable *classes;
-};
-
-struct ctf_scanner {
-       yyscan_t scanner;
-       struct ctf_ast *ast;
-       struct ctf_scanner_scope root_scope;
-       struct ctf_scanner_scope *cs;
-       struct objstack *objstack;
-};
-
-struct ctf_scanner *ctf_scanner_alloc(void);
-void ctf_scanner_free(struct ctf_scanner *scanner);
-int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input);
-
-static inline
-struct ctf_ast *ctf_scanner_get_ast(struct ctf_scanner *scanner)
-{
-       return scanner->ast;
-}
-
-BT_HIDDEN
-int is_type(struct ctf_scanner *scanner, const char *id);
-
-#endif /* _CTF_SCANNER_H */
diff --git a/plugins/ctf/common/metadata/visitor-generate-ir.c b/plugins/ctf/common/metadata/visitor-generate-ir.c
deleted file mode 100644 (file)
index 9007423..0000000
+++ /dev/null
@@ -1,5090 +0,0 @@
-/*
- * ctf-visitor-generate-ir.c
- *
- * Common Trace Format metadata visitor (generates CTF IR objects).
- *
- * Based on older ctf-visitor-generate-io-struct.c.
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright 2015-2018 - Philippe Proulx <philippe.proulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-IR-VISITOR"
-#include "logging.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "scanner.h"
-#include "parser.h"
-#include "ast.h"
-#include "decoder.h"
-#include "ctf-meta.h"
-#include "ctf-meta-visitors.h"
-
-/* Bit value (left shift) */
-#define _BV(_val)              (1 << (_val))
-
-/* Bit is set in a set of bits */
-#define _IS_SET(_set, _mask)   (*(_set) & (_mask))
-
-/* Set bit in a set of bits */
-#define _SET(_set, _mask)      (*(_set) |= (_mask))
-
-/* Try to push scope, or go to the `error` label */
-#define _TRY_PUSH_SCOPE_OR_GOTO_ERROR()                                        \
-       do {                                                            \
-               ret = ctx_push_scope(ctx);                              \
-               if (ret) {                                              \
-                       BT_LOGE_STR("Cannot push scope.");              \
-                       goto error;                                     \
-               }                                                       \
-       } while (0)
-
-/* Bits for verifying existing attributes in various declarations */
-enum {
-       _CLOCK_NAME_SET =               _BV(0),
-       _CLOCK_UUID_SET =               _BV(1),
-       _CLOCK_FREQ_SET =               _BV(2),
-       _CLOCK_PRECISION_SET =          _BV(3),
-       _CLOCK_OFFSET_S_SET =           _BV(4),
-       _CLOCK_OFFSET_SET =             _BV(5),
-       _CLOCK_ABSOLUTE_SET =           _BV(6),
-       _CLOCK_DESCRIPTION_SET =        _BV(7),
-};
-
-enum {
-       _INTEGER_ALIGN_SET =            _BV(0),
-       _INTEGER_SIZE_SET =             _BV(1),
-       _INTEGER_BASE_SET =             _BV(2),
-       _INTEGER_ENCODING_SET =         _BV(3),
-       _INTEGER_BYTE_ORDER_SET =       _BV(4),
-       _INTEGER_SIGNED_SET =           _BV(5),
-       _INTEGER_MAP_SET =              _BV(6),
-};
-
-enum {
-       _FLOAT_ALIGN_SET =              _BV(0),
-       _FLOAT_MANT_DIG_SET =           _BV(1),
-       _FLOAT_EXP_DIG_SET =            _BV(2),
-       _FLOAT_BYTE_ORDER_SET =         _BV(3),
-};
-
-enum {
-       _STRING_ENCODING_SET =          _BV(0),
-};
-
-enum {
-       _TRACE_MINOR_SET =              _BV(0),
-       _TRACE_MAJOR_SET =              _BV(1),
-       _TRACE_BYTE_ORDER_SET =         _BV(2),
-       _TRACE_UUID_SET =               _BV(3),
-       _TRACE_PACKET_HEADER_SET =      _BV(4),
-};
-
-enum {
-       _STREAM_ID_SET =                _BV(0),
-       _STREAM_PACKET_CONTEXT_SET =    _BV(1),
-       _STREAM_EVENT_HEADER_SET =      _BV(2),
-       _STREAM_EVENT_CONTEXT_SET =     _BV(3),
-};
-
-enum {
-       _EVENT_NAME_SET =               _BV(0),
-       _EVENT_ID_SET =                 _BV(1),
-       _EVENT_MODEL_EMF_URI_SET =      _BV(2),
-       _EVENT_STREAM_ID_SET =          _BV(3),
-       _EVENT_LOG_LEVEL_SET =          _BV(4),
-       _EVENT_CONTEXT_SET =            _BV(5),
-       _EVENT_FIELDS_SET =             _BV(6),
-};
-
-enum loglevel {
-        LOG_LEVEL_EMERG                  = 0,
-        LOG_LEVEL_ALERT                  = 1,
-        LOG_LEVEL_CRIT                   = 2,
-        LOG_LEVEL_ERR                    = 3,
-        LOG_LEVEL_WARNING                = 4,
-        LOG_LEVEL_NOTICE                 = 5,
-        LOG_LEVEL_INFO                   = 6,
-        LOG_LEVEL_DEBUG_SYSTEM           = 7,
-        LOG_LEVEL_DEBUG_PROGRAM          = 8,
-        LOG_LEVEL_DEBUG_PROCESS          = 9,
-        LOG_LEVEL_DEBUG_MODULE           = 10,
-        LOG_LEVEL_DEBUG_UNIT             = 11,
-        LOG_LEVEL_DEBUG_FUNCTION         = 12,
-        LOG_LEVEL_DEBUG_LINE             = 13,
-        LOG_LEVEL_DEBUG                  = 14,
-       _NR_LOGLEVELS                   = 15,
-};
-
-/* Prefixes of class aliases */
-#define _PREFIX_ALIAS                  'a'
-#define _PREFIX_ENUM                   'e'
-#define _PREFIX_STRUCT                 's'
-#define _PREFIX_VARIANT                        'v'
-
-/* First entry in a BT list */
-#define _BT_LIST_FIRST_ENTRY(_ptr, _class, _member)                    \
-       bt_list_entry((_ptr)->next, _class, _member)
-
-#define _BT_LOGE_DUP_ATTR(_node, _attr, _entity)                       \
-       _BT_LOGE_LINENO((_node)->lineno,                                \
-               "Duplicate attribute in %s: attr-name=\"%s\"",          \
-               _entity, _attr)
-
-#define _BT_LOGE_NODE(_node, _msg, args...)                            \
-       _BT_LOGE_LINENO((_node)->lineno, _msg, ## args)
-
-#define _BT_LOGW_NODE(_node, _msg, args...)                            \
-       _BT_LOGW_LINENO((_node)->lineno, _msg, ## args)
-
-#define _BT_LOGV_NODE(_node, _msg, args...)                            \
-       _BT_LOGV_LINENO((_node)->lineno, _msg, ## args)
-
-/*
- * Declaration scope of a visitor context. This represents a TSDL
- * lexical scope, so that aliases and named structures, variants,
- * and enumerations may be registered and looked up hierarchically.
- */
-struct ctx_decl_scope {
-       /*
-        * Alias name to field class.
-        *
-        * GQuark -> struct ctf_field_class * (owned by this)
-        */
-       GHashTable *decl_map;
-
-       /* Parent scope; NULL if this is the root declaration scope */
-       struct ctx_decl_scope *parent_scope;
-};
-
-/*
- * Visitor context (private).
- */
-struct ctx {
-       bt_self_component_source *self_comp;
-       /* Trace IR trace class being filled (owned by this) */
-       bt_trace_class *trace_class;
-
-       /* CTF meta trace being filled (owned by this) */
-       struct ctf_trace_class *ctf_tc;
-
-       /* Current declaration scope (top of the stack) (owned by this) */
-       struct ctx_decl_scope *current_scope;
-
-       /* True if trace declaration is visited */
-       bool is_trace_visited;
-
-       /* True if this is an LTTng trace */
-       bool is_lttng;
-
-       /* Config passed by the user */
-       struct ctf_metadata_decoder_config decoder_config;
-};
-
-/*
- * Visitor (public).
- */
-struct ctf_visitor_generate_ir;
-
-/**
- * Creates a new declaration scope.
- *
- * @param par_scope    Parent scope (NULL if creating a root scope)
- * @returns            New declaration scope, or NULL on error
- */
-static
-struct ctx_decl_scope *ctx_decl_scope_create(struct ctx_decl_scope *par_scope)
-{
-       struct ctx_decl_scope *scope;
-
-       scope = g_new(struct ctx_decl_scope, 1);
-       if (!scope) {
-               BT_LOGE_STR("Failed to allocate one declaration scope.");
-               goto end;
-       }
-
-       scope->decl_map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-               NULL, (GDestroyNotify) ctf_field_class_destroy);
-       scope->parent_scope = par_scope;
-
-end:
-       return scope;
-}
-
-/**
- * Destroys a declaration scope.
- *
- * This function does not destroy the parent scope.
- *
- * @param scope        Scope to destroy
- */
-static
-void ctx_decl_scope_destroy(struct ctx_decl_scope *scope)
-{
-       if (!scope) {
-               goto end;
-       }
-
-       g_hash_table_destroy(scope->decl_map);
-       g_free(scope);
-
-end:
-       return;
-}
-
-/**
- * Returns the GQuark of a prefixed alias.
- *
- * @param prefix       Prefix character
- * @param name         Name
- * @returns            Associated GQuark, or 0 on error
- */
-static
-GQuark get_prefixed_named_quark(char prefix, const char *name)
-{
-       GQuark qname = 0;
-
-       BT_ASSERT(name);
-
-       /* Prefix character + original string + '\0' */
-       char *prname = g_new(char, strlen(name) + 2);
-       if (!prname) {
-               BT_LOGE_STR("Failed to allocate a string.");
-               goto end;
-       }
-
-       sprintf(prname, "%c%s", prefix, name);
-       qname = g_quark_from_string(prname);
-       g_free(prname);
-
-end:
-       return qname;
-}
-
-/**
- * Looks up a prefixed class alias within a declaration scope.
- *
- * @param scope                Declaration scope
- * @param prefix       Prefix character
- * @param name         Alias name
- * @param levels       Number of levels to dig into (-1 means infinite)
- * @param copy         True to return a copy
- * @returns            Declaration (owned by caller if \p copy is true),
- *                     or NULL if not found
- */
-static
-struct ctf_field_class *ctx_decl_scope_lookup_prefix_alias(
-               struct ctx_decl_scope *scope, char prefix, const char *name,
-               int levels, bool copy)
-{
-       GQuark qname = 0;
-       int cur_levels = 0;
-       struct ctf_field_class *decl = NULL;
-       struct ctx_decl_scope *cur_scope = scope;
-
-       BT_ASSERT(scope);
-       BT_ASSERT(name);
-       qname = get_prefixed_named_quark(prefix, name);
-       if (!qname) {
-               goto end;
-       }
-
-       if (levels < 0) {
-               levels = INT_MAX;
-       }
-
-       while (cur_scope && cur_levels < levels) {
-               decl = g_hash_table_lookup(cur_scope->decl_map,
-                       (gconstpointer) GUINT_TO_POINTER(qname));
-               if (decl) {
-                       /* Caller's reference */
-                       if (copy) {
-                               decl = ctf_field_class_copy(decl);
-                               BT_ASSERT(decl);
-                       }
-
-                       goto end;
-               }
-
-               cur_scope = cur_scope->parent_scope;
-               cur_levels++;
-       }
-
-end:
-       return decl;
-}
-
-/**
- * Looks up a class alias within a declaration scope.
- *
- * @param scope                Declaration scope
- * @param name         Alias name
- * @param levels       Number of levels to dig into (-1 means infinite)
- * @param copy         True to return a copy
- * @returns            Declaration (owned by caller if \p copy is true),
- *                     or NULL if not found
- */
-static
-struct ctf_field_class *ctx_decl_scope_lookup_alias(
-               struct ctx_decl_scope *scope, const char *name, int levels,
-               bool copy)
-{
-       return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ALIAS,
-               name, levels, copy);
-}
-
-/**
- * Looks up an enumeration within a declaration scope.
- *
- * @param scope                Declaration scope
- * @param name         Enumeration name
- * @param levels       Number of levels to dig into (-1 means infinite)
- * @param copy         True to return a copy
- * @returns            Declaration (owned by caller if \p copy is true),
- *                     or NULL if not found
- */
-static
-struct ctf_field_class_enum *ctx_decl_scope_lookup_enum(
-               struct ctx_decl_scope *scope, const char *name, int levels,
-               bool copy)
-{
-       return (void *) ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM,
-               name, levels, copy);
-}
-
-/**
- * Looks up a structure within a declaration scope.
- *
- * @param scope                Declaration scope
- * @param name         Structure name
- * @param levels       Number of levels to dig into (-1 means infinite)
- * @param copy         True to return a copy
- * @returns            Declaration (owned by caller if \p copy is true),
- *                     or NULL if not found
- */
-static
-struct ctf_field_class_struct *ctx_decl_scope_lookup_struct(
-               struct ctx_decl_scope *scope, const char *name, int levels,
-               bool copy)
-{
-       return (void *) ctx_decl_scope_lookup_prefix_alias(scope,
-               _PREFIX_STRUCT, name, levels, copy);
-}
-
-/**
- * Looks up a variant within a declaration scope.
- *
- * @param scope                Declaration scope
- * @param name         Variant name
- * @param levels       Number of levels to dig into (-1 means infinite)
- * @param copy         True to return a copy
- * @returns            Declaration (owned by caller if \p copy is true),
- *                     or NULL if not found
- */
-static
-struct ctf_field_class_variant *ctx_decl_scope_lookup_variant(
-               struct ctx_decl_scope *scope, const char *name, int levels,
-               bool copy)
-{
-       return (void *) ctx_decl_scope_lookup_prefix_alias(scope,
-               _PREFIX_VARIANT, name, levels, copy);
-}
-
-/**
- * Registers a prefixed class alias within a declaration scope.
- *
- * @param scope                Declaration scope
- * @param prefix       Prefix character
- * @param name         Alias name (non-NULL)
- * @param decl         Field class to register (copied)
- * @returns            0 if registration went okay, negative value otherwise
- */
-static
-int ctx_decl_scope_register_prefix_alias(struct ctx_decl_scope *scope,
-               char prefix, const char *name, struct ctf_field_class *decl)
-{
-       int ret = 0;
-       GQuark qname = 0;
-
-       BT_ASSERT(scope);
-       BT_ASSERT(name);
-       BT_ASSERT(decl);
-       qname = get_prefixed_named_quark(prefix, name);
-       if (!qname) {
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       /* Make sure alias does not exist in local scope */
-       if (ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1,
-                       false)) {
-               ret = -EEXIST;
-               goto end;
-       }
-
-       decl = ctf_field_class_copy(decl);
-       BT_ASSERT(decl);
-       g_hash_table_insert(scope->decl_map, GUINT_TO_POINTER(qname), decl);
-
-end:
-       return ret;
-}
-
-/**
- * Registers a class alias within a declaration scope.
- *
- * @param scope        Declaration scope
- * @param name Alias name (non-NULL)
- * @param decl Field class to register (copied)
- * @returns    0 if registration went okay, negative value otherwise
- */
-static
-int ctx_decl_scope_register_alias(struct ctx_decl_scope *scope,
-               const char *name, struct ctf_field_class *decl)
-{
-       return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ALIAS,
-               name, (void *) decl);
-}
-
-/**
- * Registers an enumeration declaration within a declaration scope.
- *
- * @param scope        Declaration scope
- * @param name Enumeration name (non-NULL)
- * @param decl Enumeration field class to register (copied)
- * @returns    0 if registration went okay, negative value otherwise
- */
-static
-int ctx_decl_scope_register_enum(struct ctx_decl_scope *scope,
-               const char *name, struct ctf_field_class_enum *decl)
-{
-       return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ENUM,
-               name, (void *) decl);
-}
-
-/**
- * Registers a structure declaration within a declaration scope.
- *
- * @param scope        Declaration scope
- * @param name Structure name (non-NULL)
- * @param decl Structure field class to register (copied)
- * @returns    0 if registration went okay, negative value otherwise
- */
-static
-int ctx_decl_scope_register_struct(struct ctx_decl_scope *scope,
-               const char *name, struct ctf_field_class_struct *decl)
-{
-       return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_STRUCT,
-               name, (void *) decl);
-}
-
-/**
- * Registers a variant declaration within a declaration scope.
- *
- * @param scope        Declaration scope
- * @param name Variant name (non-NULL)
- * @param decl Variant field class to register
- * @returns    0 if registration went okay, negative value otherwise
- */
-static
-int ctx_decl_scope_register_variant(struct ctx_decl_scope *scope,
-               const char *name, struct ctf_field_class_variant *decl)
-{
-       return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_VARIANT,
-               name, (void *) decl);
-}
-
-/**
- * Destroys a visitor context.
- *
- * @param ctx  Visitor context to destroy
- */
-static
-void ctx_destroy(struct ctx *ctx)
-{
-       struct ctx_decl_scope *scope;
-
-       if (!ctx) {
-               goto end;
-       }
-
-       scope = ctx->current_scope;
-
-       /*
-        * Destroy all scopes, from current one to the root scope.
-        */
-       while (scope) {
-               struct ctx_decl_scope *parent_scope = scope->parent_scope;
-
-               ctx_decl_scope_destroy(scope);
-               scope = parent_scope;
-       }
-
-       bt_trace_class_put_ref(ctx->trace_class);
-
-       if (ctx->ctf_tc) {
-               ctf_trace_class_destroy(ctx->ctf_tc);
-       }
-
-       g_free(ctx);
-
-end:
-       return;
-}
-
-/**
- * Creates a new visitor context.
- *
- * @param trace        Associated trace
- * @returns    New visitor context, or NULL on error
- */
-static
-struct ctx *ctx_create(bt_self_component_source *self_comp,
-               const struct ctf_metadata_decoder_config *decoder_config)
-{
-       struct ctx *ctx = NULL;
-
-       BT_ASSERT(decoder_config);
-
-       ctx = g_new0(struct ctx, 1);
-       if (!ctx) {
-               BT_LOGE_STR("Failed to allocate one visitor context.");
-               goto error;
-       }
-
-       if (self_comp) {
-               ctx->trace_class = bt_trace_class_create(
-                       bt_self_component_source_as_self_component(self_comp));
-               if (!ctx->trace_class) {
-                       BT_LOGE_STR("Cannot create empty trace class.");
-                       goto error;
-               }
-               ctx->self_comp = self_comp;
-       }
-
-       ctx->ctf_tc = ctf_trace_class_create();
-       if (!ctx->ctf_tc) {
-               BT_LOGE_STR("Cannot create CTF trace class.");
-               goto error;
-       }
-
-       /* Root declaration scope */
-       ctx->current_scope = ctx_decl_scope_create(NULL);
-       if (!ctx->current_scope) {
-               BT_LOGE_STR("Cannot create declaration scope.");
-               goto error;
-       }
-
-       ctx->decoder_config = *decoder_config;
-       goto end;
-
-error:
-       ctx_destroy(ctx);
-       ctx = NULL;
-
-end:
-       return ctx;
-}
-
-/**
- * Pushes a new declaration scope on top of a visitor context's
- * declaration scope stack.
- *
- * @param ctx  Visitor context
- * @returns    0 on success, or a negative value on error
- */
-static
-int ctx_push_scope(struct ctx *ctx)
-{
-       int ret = 0;
-       struct ctx_decl_scope *new_scope;
-
-       BT_ASSERT(ctx);
-       new_scope = ctx_decl_scope_create(ctx->current_scope);
-       if (!new_scope) {
-               BT_LOGE_STR("Cannot create declaration scope.");
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       ctx->current_scope = new_scope;
-
-end:
-       return ret;
-}
-
-static
-void ctx_pop_scope(struct ctx *ctx)
-{
-       struct ctx_decl_scope *parent_scope = NULL;
-
-       BT_ASSERT(ctx);
-
-       if (!ctx->current_scope) {
-               goto end;
-       }
-
-       parent_scope = ctx->current_scope->parent_scope;
-       ctx_decl_scope_destroy(ctx->current_scope);
-       ctx->current_scope = parent_scope;
-
-end:
-       return;
-}
-
-static
-int visit_field_class_specifier_list(struct ctx *ctx, struct ctf_node *ts_list,
-               struct ctf_field_class **decl);
-
-static
-char *remove_underscores_from_field_ref(const char *field_ref)
-{
-       const char *in_ch;
-       char *out_ch;
-       char *ret;
-       enum {
-               UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE,
-               UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE,
-       } state = UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE;
-
-       BT_ASSERT(field_ref);
-       ret = calloc(strlen(field_ref) + 1, 1);
-       if (!ret) {
-               BT_LOGE("Failed to allocate a string: size=%zu",
-                       strlen(field_ref) + 1);
-               goto end;
-       }
-
-       in_ch = field_ref;
-       out_ch = ret;
-
-       while (*in_ch != '\0') {
-               switch (*in_ch) {
-               case ' ':
-               case '\t':
-                       /* Remove whitespace */
-                       in_ch++;
-                       continue;
-               case '_':
-                       if (state == UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE) {
-                               in_ch++;
-                               state = UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE;
-                               continue;
-                       }
-
-                       goto copy;
-               case '.':
-                       state = UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE;
-                       goto copy;
-               default:
-                       state = UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE;
-                       goto copy;
-               }
-
-copy:
-               *out_ch = *in_ch;
-               in_ch++;
-               out_ch++;
-       }
-
-end:
-       return ret;
-}
-
-static
-int is_unary_string(struct bt_list_head *head)
-{
-       int ret = TRUE;
-       struct ctf_node *node;
-
-       bt_list_for_each_entry(node, head, siblings) {
-               if (node->type != NODE_UNARY_EXPRESSION) {
-                       ret = FALSE;
-               }
-
-               if (node->u.unary_expression.type != UNARY_STRING) {
-                       ret = FALSE;
-               }
-       }
-
-       return ret;
-}
-
-static
-char *concatenate_unary_strings(struct bt_list_head *head)
-{
-       int i = 0;
-       GString *str;
-       struct ctf_node *node;
-
-       str = g_string_new(NULL);
-       BT_ASSERT(str);
-
-       bt_list_for_each_entry(node, head, siblings) {
-               char *src_string;
-
-               if (
-                       node->type != NODE_UNARY_EXPRESSION ||
-                       node->u.unary_expression.type != UNARY_STRING ||
-                       !(
-                               (
-                                       node->u.unary_expression.link !=
-                                       UNARY_LINK_UNKNOWN
-                               ) ^ (i == 0)
-                       )
-               ) {
-                       goto error;
-               }
-
-               switch (node->u.unary_expression.link) {
-               case UNARY_DOTLINK:
-                       g_string_append(str, ".");
-                       break;
-               case UNARY_ARROWLINK:
-                       g_string_append(str, "->");
-                       break;
-               case UNARY_DOTDOTDOT:
-                       g_string_append(str, "...");
-                       break;
-               default:
-                       break;
-               }
-
-               src_string = node->u.unary_expression.u.string;
-               g_string_append(str, src_string);
-               i++;
-       }
-
-       /* Destroys the container, returns the underlying string */
-       return g_string_free(str, FALSE);
-
-error:
-       /* This always returns NULL */
-       return g_string_free(str, TRUE);
-}
-
-static
-const char *get_map_clock_name_value(struct bt_list_head *head)
-{
-       int i = 0;
-       struct ctf_node *node;
-       const char *name = NULL;
-
-       bt_list_for_each_entry(node, head, siblings) {
-               char *src_string;
-               int uexpr_type = node->u.unary_expression.type;
-               int uexpr_link = node->u.unary_expression.link;
-               int cond = node->type != NODE_UNARY_EXPRESSION ||
-                       uexpr_type != UNARY_STRING ||
-                       !((uexpr_link != UNARY_LINK_UNKNOWN) ^ (i == 0));
-               if (cond) {
-                       goto error;
-               }
-
-               /* Needs to be chained with . */
-               switch (node->u.unary_expression.link) {
-               case UNARY_DOTLINK:
-                       break;
-               case UNARY_ARROWLINK:
-               case UNARY_DOTDOTDOT:
-                       goto error;
-               default:
-                       break;
-               }
-
-               src_string = node->u.unary_expression.u.string;
-
-               switch (i) {
-               case 0:
-                       if (strcmp("clock", src_string)) {
-                               goto error;
-                       }
-                       break;
-               case 1:
-                       name = src_string;
-                       break;
-               case 2:
-                       if (strcmp("value", src_string)) {
-                               goto error;
-                       }
-                       break;
-               default:
-                       /* Extra identifier, unknown */
-                       goto error;
-               }
-
-               i++;
-       }
-
-       return name;
-
-error:
-       return NULL;
-}
-
-static
-int is_unary_unsigned(struct bt_list_head *head)
-{
-       int ret = TRUE;
-       struct ctf_node *node;
-
-       bt_list_for_each_entry(node, head, siblings) {
-               if (node->type != NODE_UNARY_EXPRESSION) {
-                       ret = FALSE;
-               }
-
-               if (node->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
-                       ret = FALSE;
-               }
-       }
-
-       return ret;
-}
-
-static
-int get_unary_unsigned(struct bt_list_head *head, uint64_t *value)
-{
-       int i = 0;
-       int ret = 0;
-       struct ctf_node *node;
-
-       *value = 0;
-
-       if (bt_list_empty(head)) {
-               ret = -1;
-               goto end;
-       }
-
-       bt_list_for_each_entry(node, head, siblings) {
-               int uexpr_type = node->u.unary_expression.type;
-               int uexpr_link = node->u.unary_expression.link;
-               int cond = node->type != NODE_UNARY_EXPRESSION ||
-                       uexpr_type != UNARY_UNSIGNED_CONSTANT ||
-                       uexpr_link != UNARY_LINK_UNKNOWN || i != 0;
-               if (cond) {
-                       _BT_LOGE_NODE(node, "Invalid constant unsigned integer.");
-                       ret = -EINVAL;
-                       goto end;
-               }
-
-               *value = node->u.unary_expression.u.unsigned_constant;
-               i++;
-       }
-
-end:
-       return ret;
-}
-
-static
-int is_unary_signed(struct bt_list_head *head)
-{
-       int ret = TRUE;
-       struct ctf_node *node;
-
-       bt_list_for_each_entry(node, head, siblings) {
-               if (node->type != NODE_UNARY_EXPRESSION) {
-                       ret = FALSE;
-               }
-
-               if (node->u.unary_expression.type != UNARY_SIGNED_CONSTANT) {
-                       ret = FALSE;
-               }
-       }
-
-       return ret;
-}
-
-static
-int get_unary_signed(struct bt_list_head *head, int64_t *value)
-{
-       int i = 0;
-       int ret = 0;
-       struct ctf_node *node;
-
-       bt_list_for_each_entry(node, head, siblings) {
-               int uexpr_type = node->u.unary_expression.type;
-               int uexpr_link = node->u.unary_expression.link;
-               int cond = node->type != NODE_UNARY_EXPRESSION ||
-                       (uexpr_type != UNARY_UNSIGNED_CONSTANT &&
-                               uexpr_type != UNARY_SIGNED_CONSTANT) ||
-                       uexpr_link != UNARY_LINK_UNKNOWN || i != 0;
-               if (cond) {
-                       ret = -EINVAL;
-                       goto end;
-               }
-
-               switch (uexpr_type) {
-               case UNARY_UNSIGNED_CONSTANT:
-                       *value = (int64_t)
-                               node->u.unary_expression.u.unsigned_constant;
-                       break;
-               case UNARY_SIGNED_CONSTANT:
-                       *value = node->u.unary_expression.u.signed_constant;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       goto end;
-               }
-
-               i++;
-       }
-
-end:
-       return ret;
-}
-
-static
-int get_unary_uuid(struct bt_list_head *head, unsigned char *uuid)
-{
-       int i = 0;
-       int ret = 0;
-       struct ctf_node *node;
-
-       bt_list_for_each_entry(node, head, siblings) {
-               int uexpr_type = node->u.unary_expression.type;
-               int uexpr_link = node->u.unary_expression.link;
-               const char *src_string;
-
-               if (node->type != NODE_UNARY_EXPRESSION ||
-                               uexpr_type != UNARY_STRING ||
-                               uexpr_link != UNARY_LINK_UNKNOWN ||
-                               i != 0) {
-                       ret = -EINVAL;
-                       goto end;
-               }
-
-               src_string = node->u.unary_expression.u.string;
-               ret = bt_uuid_parse(src_string, uuid);
-               if (ret) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot parse UUID: uuid=\"%s\"", src_string);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int get_boolean(struct ctf_node *unary_expr)
-{
-       int ret = 0;
-
-       if (unary_expr->type != NODE_UNARY_EXPRESSION) {
-               _BT_LOGE_NODE(unary_expr,
-                       "Expecting unary expression: node-type=%d",
-                       unary_expr->type);
-               ret = -EINVAL;
-               goto end;
-       }
-
-       switch (unary_expr->u.unary_expression.type) {
-       case UNARY_UNSIGNED_CONSTANT:
-               ret = (unary_expr->u.unary_expression.u.unsigned_constant != 0);
-               break;
-       case UNARY_SIGNED_CONSTANT:
-               ret = (unary_expr->u.unary_expression.u.signed_constant != 0);
-               break;
-       case UNARY_STRING:
-       {
-               const char *str = unary_expr->u.unary_expression.u.string;
-
-               if (!strcmp(str, "true") || !strcmp(str, "TRUE")) {
-                       ret = TRUE;
-               } else if (!strcmp(str, "false") || !strcmp(str, "FALSE")) {
-                       ret = FALSE;
-               } else {
-                       _BT_LOGE_NODE(unary_expr,
-                               "Unexpected boolean value: value=\"%s\"", str);
-                       ret = -EINVAL;
-                       goto end;
-               }
-               break;
-       }
-       default:
-               _BT_LOGE_NODE(unary_expr,
-                       "Unexpected unary expression type: node-type=%d",
-                       unary_expr->u.unary_expression.type);
-               ret = -EINVAL;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-enum ctf_byte_order byte_order_from_unary_expr(struct ctf_node *unary_expr)
-{
-       const char *str;
-       enum ctf_byte_order bo = -1;
-
-       if (unary_expr->u.unary_expression.type != UNARY_STRING) {
-               _BT_LOGE_NODE(unary_expr,
-                       "\"byte_order\" attribute: expecting `be`, `le`, `network`, or `native`.");
-               goto end;
-       }
-
-       str = unary_expr->u.unary_expression.u.string;
-
-       if (!strcmp(str, "be") || !strcmp(str, "network")) {
-               bo = CTF_BYTE_ORDER_BIG;
-       } else if (!strcmp(str, "le")) {
-               bo = CTF_BYTE_ORDER_LITTLE;
-       } else if (!strcmp(str, "native")) {
-               bo = CTF_BYTE_ORDER_DEFAULT;
-       } else {
-               _BT_LOGE_NODE(unary_expr,
-                       "Unexpected \"byte_order\" attribute value: "
-                       "expecting `be`, `le`, `network`, or `native`: value=\"%s\"",
-                       str);
-               goto end;
-       }
-
-end:
-       return bo;
-}
-
-static
-enum ctf_byte_order get_real_byte_order(struct ctx *ctx,
-               struct ctf_node *uexpr)
-{
-       enum ctf_byte_order bo = byte_order_from_unary_expr(uexpr);
-
-       if (bo == CTF_BYTE_ORDER_DEFAULT) {
-               bo = ctx->ctf_tc->default_byte_order;
-       }
-
-       return bo;
-}
-
-static
-int is_align_valid(uint64_t align)
-{
-       return (align != 0) && !(align & (align - UINT64_C(1)));
-}
-
-static
-int get_class_specifier_name(struct ctx *ctx, struct ctf_node *cls_specifier,
-               GString *str)
-{
-       int ret = 0;
-
-       if (cls_specifier->type != NODE_TYPE_SPECIFIER) {
-               _BT_LOGE_NODE(cls_specifier,
-                       "Unexpected node type: node-type=%d",
-                       cls_specifier->type);
-               ret = -EINVAL;
-               goto end;
-       }
-
-       switch (cls_specifier->u.field_class_specifier.type) {
-       case TYPESPEC_VOID:
-               g_string_append(str, "void");
-               break;
-       case TYPESPEC_CHAR:
-               g_string_append(str, "char");
-               break;
-       case TYPESPEC_SHORT:
-               g_string_append(str, "short");
-               break;
-       case TYPESPEC_INT:
-               g_string_append(str, "int");
-               break;
-       case TYPESPEC_LONG:
-               g_string_append(str, "long");
-               break;
-       case TYPESPEC_FLOAT:
-               g_string_append(str, "float");
-               break;
-       case TYPESPEC_DOUBLE:
-               g_string_append(str, "double");
-               break;
-       case TYPESPEC_SIGNED:
-               g_string_append(str, "signed");
-               break;
-       case TYPESPEC_UNSIGNED:
-               g_string_append(str, "unsigned");
-               break;
-       case TYPESPEC_BOOL:
-               g_string_append(str, "bool");
-               break;
-       case TYPESPEC_COMPLEX:
-               g_string_append(str, "_Complex");
-               break;
-       case TYPESPEC_IMAGINARY:
-               g_string_append(str, "_Imaginary");
-               break;
-       case TYPESPEC_CONST:
-               g_string_append(str, "const");
-               break;
-       case TYPESPEC_ID_TYPE:
-               if (cls_specifier->u.field_class_specifier.id_type) {
-                       g_string_append(str,
-                               cls_specifier->u.field_class_specifier.id_type);
-               }
-               break;
-       case TYPESPEC_STRUCT:
-       {
-               struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
-
-               if (!node->u._struct.name) {
-                       _BT_LOGE_NODE(node, "Unexpected empty structure field class name.");
-                       ret = -EINVAL;
-                       goto end;
-               }
-
-               g_string_append(str, "struct ");
-               g_string_append(str, node->u._struct.name);
-               break;
-       }
-       case TYPESPEC_VARIANT:
-       {
-               struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
-
-               if (!node->u.variant.name) {
-                       _BT_LOGE_NODE(node, "Unexpected empty variant field class name.");
-                       ret = -EINVAL;
-                       goto end;
-               }
-
-               g_string_append(str, "variant ");
-               g_string_append(str, node->u.variant.name);
-               break;
-       }
-       case TYPESPEC_ENUM:
-       {
-               struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
-
-               if (!node->u._enum.enum_id) {
-                       _BT_LOGE_NODE(node,
-                               "Unexpected empty enumeration field class (`enum`) name.");
-                       ret = -EINVAL;
-                       goto end;
-               }
-
-               g_string_append(str, "enum ");
-               g_string_append(str, node->u._enum.enum_id);
-               break;
-       }
-       case TYPESPEC_FLOATING_POINT:
-       case TYPESPEC_INTEGER:
-       case TYPESPEC_STRING:
-       default:
-               _BT_LOGE_NODE(cls_specifier->u.field_class_specifier.node,
-                       "Unexpected field class specifier type: %d",
-                       cls_specifier->u.field_class_specifier.type);
-               ret = -EINVAL;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int get_class_specifier_list_name(struct ctx *ctx,
-               struct ctf_node *cls_specifier_list, GString *str)
-{
-       int ret = 0;
-       struct ctf_node *iter;
-       int alias_item_nr = 0;
-       struct bt_list_head *head =
-               &cls_specifier_list->u.field_class_specifier_list.head;
-
-       bt_list_for_each_entry(iter, head, siblings) {
-               if (alias_item_nr != 0) {
-                       g_string_append(str, " ");
-               }
-
-               alias_item_nr++;
-               ret = get_class_specifier_name(ctx, iter, str);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-GQuark create_class_alias_identifier(struct ctx *ctx,
-               struct ctf_node *cls_specifier_list,
-               struct ctf_node *node_field_class_declarator)
-{
-       int ret;
-       char *str_c;
-       GString *str;
-       GQuark qalias = 0;
-       struct ctf_node *iter;
-       struct bt_list_head *pointers =
-               &node_field_class_declarator->u.field_class_declarator.pointers;
-
-       str = g_string_new("");
-       ret = get_class_specifier_list_name(ctx, cls_specifier_list, str);
-       if (ret) {
-               g_string_free(str, TRUE);
-               goto end;
-       }
-
-       bt_list_for_each_entry(iter, pointers, siblings) {
-               g_string_append(str, " *");
-
-               if (iter->u.pointer.const_qualifier) {
-                       g_string_append(str, " const");
-               }
-       }
-
-       str_c = g_string_free(str, FALSE);
-       qalias = g_quark_from_string(str_c);
-       g_free(str_c);
-
-end:
-       return qalias;
-}
-
-static
-int visit_field_class_declarator(struct ctx *ctx,
-               struct ctf_node *cls_specifier_list,
-               GQuark *field_name, struct ctf_node *node_field_class_declarator,
-               struct ctf_field_class **field_decl,
-               struct ctf_field_class *nested_decl)
-{
-       /*
-        * During this whole function, nested_decl is always OURS,
-        * whereas field_decl is an output which we create, but
-        * belongs to the caller (it is moved).
-        */
-       int ret = 0;
-       *field_decl = NULL;
-
-       /* Validate field class declarator node */
-       if (node_field_class_declarator) {
-               if (node_field_class_declarator->u.field_class_declarator.type ==
-                               TYPEDEC_UNKNOWN) {
-                       _BT_LOGE_NODE(node_field_class_declarator,
-                               "Unexpected field class declarator type: type=%d",
-                               node_field_class_declarator->u.field_class_declarator.type);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               /* TODO: GCC bitfields not supported yet */
-               if (node_field_class_declarator->u.field_class_declarator.bitfield_len !=
-                               NULL) {
-                       _BT_LOGE_NODE(node_field_class_declarator,
-                               "GCC bitfields are not supported as of this version.");
-                       ret = -EPERM;
-                       goto error;
-               }
-       }
-
-       /* Find the right nested declaration if not provided */
-       if (!nested_decl) {
-               struct bt_list_head *pointers =
-                       &node_field_class_declarator->u.field_class_declarator.pointers;
-
-               if (node_field_class_declarator && !bt_list_empty(pointers)) {
-                       GQuark qalias;
-
-                       /*
-                        * If we have a pointer declarator, it HAS to
-                        * be present in the field class aliases (else
-                        * fail).
-                        */
-                       qalias = create_class_alias_identifier(ctx,
-                               cls_specifier_list, node_field_class_declarator);
-                       nested_decl =
-                               ctx_decl_scope_lookup_alias(ctx->current_scope,
-                                       g_quark_to_string(qalias), -1, true);
-                       if (!nested_decl) {
-                               _BT_LOGE_NODE(node_field_class_declarator,
-                                       "Cannot find class alias: name=\"%s\"",
-                                       g_quark_to_string(qalias));
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (nested_decl->type == CTF_FIELD_CLASS_TYPE_INT) {
-                               /* Pointer: force integer's base to 16 */
-                               struct ctf_field_class_int *int_fc =
-                                       (void *) nested_decl;
-
-                               int_fc->disp_base =
-                                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
-                       }
-               } else {
-                       ret = visit_field_class_specifier_list(ctx,
-                               cls_specifier_list, &nested_decl);
-                       if (ret) {
-                               BT_ASSERT(!nested_decl);
-                               goto error;
-                       }
-               }
-       }
-
-       BT_ASSERT(nested_decl);
-
-       if (!node_field_class_declarator) {
-               *field_decl = nested_decl;
-               nested_decl = NULL;
-               goto end;
-       }
-
-       if (node_field_class_declarator->u.field_class_declarator.type == TYPEDEC_ID) {
-               if (node_field_class_declarator->u.field_class_declarator.u.id) {
-                       const char *id =
-                               node_field_class_declarator->u.field_class_declarator.u.id;
-
-                       if (id[0] == '_') {
-                               id++;
-                       }
-
-                       *field_name = g_quark_from_string(id);
-               } else {
-                       *field_name = 0;
-               }
-
-               *field_decl = nested_decl;
-               nested_decl = NULL;
-               goto end;
-       } else {
-               struct ctf_node *first;
-               struct ctf_field_class *decl = NULL;
-               struct ctf_field_class *outer_field_decl = NULL;
-               struct bt_list_head *length =
-                       &node_field_class_declarator->
-                               u.field_class_declarator.u.nested.length;
-
-               /* Create array/sequence, pass nested_decl as child */
-               if (bt_list_empty(length)) {
-                       _BT_LOGE_NODE(node_field_class_declarator,
-                               "Expecting length field reference or value.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               first = _BT_LIST_FIRST_ENTRY(length, struct ctf_node, siblings);
-               if (first->type != NODE_UNARY_EXPRESSION) {
-                       _BT_LOGE_NODE(first,
-                               "Unexpected node type: node-type=%d",
-                               first->type);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               switch (first->u.unary_expression.type) {
-               case UNARY_UNSIGNED_CONSTANT:
-               {
-                       struct ctf_field_class_array *array_decl = NULL;
-
-                       array_decl = ctf_field_class_array_create();
-                       BT_ASSERT(array_decl);
-                       array_decl->length =
-                               first->u.unary_expression.u.unsigned_constant;
-                       array_decl->base.elem_fc = nested_decl;
-                       nested_decl = NULL;
-                       decl = (void *) array_decl;
-                       break;
-               }
-               case UNARY_STRING:
-               {
-                       /* Lookup unsigned integer definition, create seq. */
-                       struct ctf_field_class_sequence *seq_decl = NULL;
-                       char *length_name = concatenate_unary_strings(length);
-
-                       if (!length_name) {
-                               _BT_LOGE_NODE(node_field_class_declarator,
-                                       "Cannot concatenate unary strings.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (strncmp(length_name, "env.", 4) == 0) {
-                               /* This is, in fact, an array */
-                               const char *env_entry_name = &length_name[4];
-                               struct ctf_trace_class_env_entry *env_entry =
-                                       ctf_trace_class_borrow_env_entry_by_name(
-                                               ctx->ctf_tc, env_entry_name);
-                               struct ctf_field_class_array *array_decl;
-
-                               if (!env_entry) {
-                                       _BT_LOGE_NODE(node_field_class_declarator,
-                                               "Cannot find environment entry: "
-                                               "name=\"%s\"", env_entry_name);
-                                       ret = -EINVAL;
-                                       goto error;
-                               }
-
-                               if (env_entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
-                                       _BT_LOGE_NODE(node_field_class_declarator,
-                                               "Wrong environment entry type "
-                                               "(expecting integer): "
-                                               "name=\"%s\"", env_entry_name);
-                                       ret = -EINVAL;
-                                       goto error;
-                               }
-
-                               if (env_entry->value.i < 0) {
-                                       _BT_LOGE_NODE(node_field_class_declarator,
-                                               "Invalid, negative array length: "
-                                               "env-entry-name=\"%s\", "
-                                               "value=%" PRId64,
-                                               env_entry_name,
-                                               env_entry->value.i);
-                                       ret = -EINVAL;
-                                       goto error;
-                               }
-
-                               array_decl = ctf_field_class_array_create();
-                               BT_ASSERT(array_decl);
-                               array_decl->length =
-                                       (uint64_t) env_entry->value.i;
-                               array_decl->base.elem_fc = nested_decl;
-                               nested_decl = NULL;
-                               decl = (void *) array_decl;
-                       } else {
-                               char *length_name_no_underscore =
-                                       remove_underscores_from_field_ref(
-                                               length_name);
-                               if (!length_name_no_underscore) {
-                                       /*
-                                        * remove_underscores_from_field_ref()
-                                        * logs errors
-                                        */
-                                       ret = -EINVAL;
-                                       goto error;
-                               }
-                               seq_decl = ctf_field_class_sequence_create();
-                               BT_ASSERT(seq_decl);
-                               seq_decl->base.elem_fc = nested_decl;
-                               nested_decl = NULL;
-                               g_string_assign(seq_decl->length_ref,
-                                       length_name_no_underscore);
-                               free(length_name_no_underscore);
-                               decl = (void *) seq_decl;
-                       }
-
-                       g_free(length_name);
-                       break;
-               }
-               default:
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               BT_ASSERT(!nested_decl);
-               BT_ASSERT(decl);
-               BT_ASSERT(!*field_decl);
-
-               /*
-                * At this point, we found the next nested declaration.
-                * We currently own this (and lost the ownership of
-                * nested_decl in the meantime). Pass this next
-                * nested declaration as the content of the outer
-                * container, MOVING its ownership.
-                */
-               ret = visit_field_class_declarator(ctx, cls_specifier_list,
-                       field_name,
-                       node_field_class_declarator->
-                               u.field_class_declarator.u.nested.field_class_declarator,
-                       &outer_field_decl, decl);
-               decl = NULL;
-               if (ret) {
-                       BT_ASSERT(!outer_field_decl);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               BT_ASSERT(outer_field_decl);
-               *field_decl = outer_field_decl;
-               outer_field_decl = NULL;
-       }
-
-       BT_ASSERT(*field_decl);
-       goto end;
-
-error:
-       ctf_field_class_destroy(*field_decl);
-       *field_decl = NULL;
-
-       if (ret >= 0) {
-               ret = -1;
-       }
-
-end:
-       ctf_field_class_destroy(nested_decl);
-       nested_decl = NULL;
-       return ret;
-}
-
-static
-int visit_struct_decl_field(struct ctx *ctx,
-               struct ctf_field_class_struct *struct_decl,
-               struct ctf_node *cls_specifier_list,
-               struct bt_list_head *field_class_declarators)
-{
-       int ret = 0;
-       struct ctf_node *iter;
-       struct ctf_field_class *field_decl = NULL;
-
-       bt_list_for_each_entry(iter, field_class_declarators, siblings) {
-               field_decl = NULL;
-               GQuark qfield_name;
-               const char *field_name;
-
-               ret = visit_field_class_declarator(ctx, cls_specifier_list,
-                       &qfield_name, iter, &field_decl, NULL);
-               if (ret) {
-                       BT_ASSERT(!field_decl);
-                       _BT_LOGE_NODE(cls_specifier_list,
-                               "Cannot visit field class declarator: ret=%d", ret);
-                       goto error;
-               }
-
-               BT_ASSERT(field_decl);
-               field_name = g_quark_to_string(qfield_name);
-
-               /* Check if field with same name already exists */
-               if (ctf_field_class_struct_borrow_member_by_name(
-                               struct_decl, field_name)) {
-                       _BT_LOGE_NODE(cls_specifier_list,
-                               "Duplicate field in structure field class: "
-                               "field-name=\"%s\"", field_name);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               /* Add field to structure */
-               ctf_field_class_struct_append_member(struct_decl,
-                       field_name, field_decl);
-               field_decl = NULL;
-       }
-
-       return 0;
-
-error:
-       ctf_field_class_destroy(field_decl);
-       field_decl = NULL;
-       return ret;
-}
-
-static
-int visit_variant_decl_field(struct ctx *ctx,
-               struct ctf_field_class_variant *variant_decl,
-               struct ctf_node *cls_specifier_list,
-               struct bt_list_head *field_class_declarators)
-{
-       int ret = 0;
-       struct ctf_node *iter;
-       struct ctf_field_class *field_decl = NULL;
-
-       bt_list_for_each_entry(iter, field_class_declarators, siblings) {
-               field_decl = NULL;
-               GQuark qfield_name;
-               const char *field_name;
-
-               ret = visit_field_class_declarator(ctx, cls_specifier_list,
-                       &qfield_name, iter, &field_decl, NULL);
-               if (ret) {
-                       BT_ASSERT(!field_decl);
-                       _BT_LOGE_NODE(cls_specifier_list,
-                               "Cannot visit field class declarator: ret=%d", ret);
-                       goto error;
-               }
-
-               BT_ASSERT(field_decl);
-               field_name = g_quark_to_string(qfield_name);
-
-               /* Check if field with same name already exists */
-               if (ctf_field_class_variant_borrow_option_by_name(
-                               variant_decl, field_name)) {
-                       _BT_LOGE_NODE(cls_specifier_list,
-                               "Duplicate field in variant field class: "
-                               "field-name=\"%s\"", field_name);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               /* Add field to structure */
-               ctf_field_class_variant_append_option(variant_decl,
-                       field_name, field_decl);
-               field_decl = NULL;
-       }
-
-       return 0;
-
-error:
-       ctf_field_class_destroy(field_decl);
-       field_decl = NULL;
-       return ret;
-}
-
-static
-int visit_field_class_def(struct ctx *ctx, struct ctf_node *cls_specifier_list,
-               struct bt_list_head *field_class_declarators)
-{
-       int ret = 0;
-       GQuark qidentifier;
-       struct ctf_node *iter;
-       struct ctf_field_class *class_decl = NULL;
-
-       bt_list_for_each_entry(iter, field_class_declarators, siblings) {
-               ret = visit_field_class_declarator(ctx, cls_specifier_list,
-                       &qidentifier, iter, &class_decl, NULL);
-               if (ret) {
-                       _BT_LOGE_NODE(iter,
-                               "Cannot visit field class declarator: ret=%d", ret);
-                       ret = -EINVAL;
-                       goto end;
-               }
-
-               /* Do not allow field class def and alias of untagged variants */
-               if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
-                       struct ctf_field_class_variant *var_fc =
-                               (void *) class_decl;
-
-                       if (var_fc->tag_path.path->len == 0) {
-                               _BT_LOGE_NODE(iter,
-                                       "Type definition of untagged variant field class is not allowed.");
-                               ret = -EPERM;
-                               goto end;
-                       }
-               }
-
-               ret = ctx_decl_scope_register_alias(ctx->current_scope,
-                       g_quark_to_string(qidentifier), class_decl);
-               if (ret) {
-                       _BT_LOGE_NODE(iter,
-                               "Cannot register field class alias: name=\"%s\"",
-                               g_quark_to_string(qidentifier));
-                       goto end;
-               }
-       }
-
-end:
-       ctf_field_class_destroy(class_decl);
-       class_decl = NULL;
-       return ret;
-}
-
-static
-int visit_field_class_alias(struct ctx *ctx, struct ctf_node *target,
-               struct ctf_node *alias)
-{
-       int ret = 0;
-       GQuark qalias;
-       struct ctf_node *node;
-       GQuark qdummy_field_name;
-       struct ctf_field_class *class_decl = NULL;
-
-       /* Create target field class */
-       if (bt_list_empty(&target->u.field_class_alias_target.field_class_declarators)) {
-               node = NULL;
-       } else {
-               node = _BT_LIST_FIRST_ENTRY(
-                       &target->u.field_class_alias_target.field_class_declarators,
-                       struct ctf_node, siblings);
-       }
-
-       ret = visit_field_class_declarator(ctx,
-               target->u.field_class_alias_target.field_class_specifier_list,
-               &qdummy_field_name, node, &class_decl, NULL);
-       if (ret) {
-               BT_ASSERT(!class_decl);
-               _BT_LOGE_NODE(node,
-                       "Cannot visit field class declarator: ret=%d", ret);
-               goto end;
-       }
-
-       /* Do not allow field class def and alias of untagged variants */
-       if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
-               struct ctf_field_class_variant *var_fc = (void *) class_decl;
-
-               if (var_fc->tag_path.path->len == 0) {
-                       _BT_LOGE_NODE(target,
-                               "Type definition of untagged variant field class is not allowed.");
-                       ret = -EPERM;
-                       goto end;
-               }
-       }
-
-       /*
-        * The semantic validator does not check whether the target is
-        * abstract or not (if it has an identifier). Check it here.
-        */
-       if (qdummy_field_name != 0) {
-               _BT_LOGE_NODE(target,
-                       "Expecting empty identifier: id=\"%s\"",
-                       g_quark_to_string(qdummy_field_name));
-               ret = -EINVAL;
-               goto end;
-       }
-
-       /* Create alias identifier */
-       node = _BT_LIST_FIRST_ENTRY(&alias->u.field_class_alias_name.field_class_declarators,
-               struct ctf_node, siblings);
-       qalias = create_class_alias_identifier(ctx,
-               alias->u.field_class_alias_name.field_class_specifier_list, node);
-       ret = ctx_decl_scope_register_alias(ctx->current_scope,
-               g_quark_to_string(qalias), class_decl);
-       if (ret) {
-               _BT_LOGE_NODE(node,
-                       "Cannot register class alias: name=\"%s\"",
-                       g_quark_to_string(qalias));
-               goto end;
-       }
-
-end:
-       ctf_field_class_destroy(class_decl);
-       class_decl = NULL;
-       return ret;
-}
-
-static
-int visit_struct_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
-               struct ctf_field_class_struct *struct_decl)
-{
-       int ret = 0;
-
-       switch (entry_node->type) {
-       case NODE_TYPEDEF:
-               ret = visit_field_class_def(ctx,
-                       entry_node->u.field_class_def.field_class_specifier_list,
-                       &entry_node->u.field_class_def.field_class_declarators);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Cannot add field class found in structure field class: ret=%d",
-                               ret);
-                       goto end;
-               }
-               break;
-       case NODE_TYPEALIAS:
-               ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target,
-                       entry_node->u.field_class_alias.alias);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Cannot add field class alias found in structure field class: ret=%d",
-                               ret);
-                       goto end;
-               }
-               break;
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               /* Field */
-               ret = visit_struct_decl_field(ctx, struct_decl,
-                       entry_node->u.struct_or_variant_declaration.
-                               field_class_specifier_list,
-                       &entry_node->u.struct_or_variant_declaration.
-                               field_class_declarators);
-               if (ret) {
-                       goto end;
-               }
-               break;
-       default:
-               _BT_LOGE_NODE(entry_node,
-                       "Unexpected node type: node-type=%d", entry_node->type);
-               ret = -EINVAL;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int visit_variant_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
-               struct ctf_field_class_variant *variant_decl)
-{
-       int ret = 0;
-
-       switch (entry_node->type) {
-       case NODE_TYPEDEF:
-               ret = visit_field_class_def(ctx,
-                       entry_node->u.field_class_def.field_class_specifier_list,
-                       &entry_node->u.field_class_def.field_class_declarators);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Cannot add field class found in variant field class: ret=%d",
-                               ret);
-                       goto end;
-               }
-               break;
-       case NODE_TYPEALIAS:
-               ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target,
-                       entry_node->u.field_class_alias.alias);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Cannot add field class alias found in variant field class: ret=%d",
-                               ret);
-                       goto end;
-               }
-               break;
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               /* Field */
-               ret = visit_variant_decl_field(ctx, variant_decl,
-                       entry_node->u.struct_or_variant_declaration.
-                               field_class_specifier_list,
-                       &entry_node->u.struct_or_variant_declaration.
-                               field_class_declarators);
-               if (ret) {
-                       goto end;
-               }
-               break;
-       default:
-               _BT_LOGE_NODE(entry_node,
-                       "Unexpected node type: node-type=%d",
-                       entry_node->type);
-               ret = -EINVAL;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int visit_struct_decl(struct ctx *ctx, const char *name,
-               struct bt_list_head *decl_list, int has_body,
-               struct bt_list_head *min_align,
-               struct ctf_field_class_struct **struct_decl)
-{
-       int ret = 0;
-
-       BT_ASSERT(struct_decl);
-       *struct_decl = NULL;
-
-       /* For named struct (without body), lookup in declaration scope */
-       if (!has_body) {
-               if (!name) {
-                       BT_LOGE_STR("Bodyless structure field class: missing name.");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               *struct_decl = ctx_decl_scope_lookup_struct(ctx->current_scope,
-                       name, -1, true);
-               if (!*struct_decl) {
-                       BT_LOGE("Cannot find structure field class: name=\"struct %s\"",
-                               name);
-                       ret = -EINVAL;
-                       goto error;
-               }
-       } else {
-               struct ctf_node *entry_node;
-               uint64_t min_align_value = 0;
-
-               if (name) {
-                       if (ctx_decl_scope_lookup_struct(
-                                       ctx->current_scope, name, 1, false)) {
-                               BT_LOGE("Structure field class already declared in local scope: "
-                                       "name=\"struct %s\"", name);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-               }
-
-               if (!bt_list_empty(min_align)) {
-                       ret = get_unary_unsigned(min_align, &min_align_value);
-                       if (ret) {
-                               BT_LOGE("Unexpected unary expression for structure field class's `align` attribute: "
-                                       "ret=%d", ret);
-                               goto error;
-                       }
-               }
-
-               *struct_decl = ctf_field_class_struct_create();
-               BT_ASSERT(*struct_decl);
-
-               if (min_align_value != 0) {
-                       (*struct_decl)->base.alignment = min_align_value;
-               }
-
-               _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
-
-               bt_list_for_each_entry(entry_node, decl_list, siblings) {
-                       ret = visit_struct_decl_entry(ctx, entry_node,
-                               *struct_decl);
-                       if (ret) {
-                               _BT_LOGE_NODE(entry_node,
-                                       "Cannot visit structure field class entry: "
-                                       "ret=%d", ret);
-                               ctx_pop_scope(ctx);
-                               goto error;
-                       }
-               }
-
-               ctx_pop_scope(ctx);
-
-               if (name) {
-                       ret = ctx_decl_scope_register_struct(ctx->current_scope,
-                               name, *struct_decl);
-                       if (ret) {
-                               BT_LOGE("Cannot register structure field class in declaration scope: "
-                                       "name=\"struct %s\", ret=%d", name, ret);
-                               goto error;
-                       }
-               }
-       }
-
-       return 0;
-
-error:
-       ctf_field_class_destroy((void *) *struct_decl);
-       *struct_decl = NULL;
-       return ret;
-}
-
-static
-int visit_variant_decl(struct ctx *ctx, const char *name,
-       const char *tag, struct bt_list_head *decl_list,
-       int has_body, struct ctf_field_class_variant **variant_decl)
-{
-       int ret = 0;
-       struct ctf_field_class_variant *untagged_variant_decl = NULL;
-
-       BT_ASSERT(variant_decl);
-       *variant_decl = NULL;
-
-       /* For named variant (without body), lookup in declaration scope */
-       if (!has_body) {
-               if (!name) {
-                       BT_LOGE_STR("Bodyless variant field class: missing name.");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               untagged_variant_decl =
-                       ctx_decl_scope_lookup_variant(ctx->current_scope,
-                               name, -1, true);
-               if (!untagged_variant_decl) {
-                       BT_LOGE("Cannot find variant field class: name=\"variant %s\"",
-                               name);
-                       ret = -EINVAL;
-                       goto error;
-               }
-       } else {
-               struct ctf_node *entry_node;
-
-               if (name) {
-                       if (ctx_decl_scope_lookup_variant(ctx->current_scope,
-                                       name, 1, false)) {
-                               BT_LOGE("Variant field class already declared in local scope: "
-                                       "name=\"variant %s\"", name);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-               }
-
-               untagged_variant_decl = ctf_field_class_variant_create();
-               BT_ASSERT(untagged_variant_decl);
-               _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
-
-               bt_list_for_each_entry(entry_node, decl_list, siblings) {
-                       ret = visit_variant_decl_entry(ctx, entry_node,
-                               untagged_variant_decl);
-                       if (ret) {
-                               _BT_LOGE_NODE(entry_node,
-                                       "Cannot visit variant field class entry: "
-                                       "ret=%d", ret);
-                               ctx_pop_scope(ctx);
-                               goto error;
-                       }
-               }
-
-               ctx_pop_scope(ctx);
-
-               if (name) {
-                       ret = ctx_decl_scope_register_variant(
-                               ctx->current_scope, name,
-                               untagged_variant_decl);
-                       if (ret) {
-                               BT_LOGE("Cannot register variant field class in declaration scope: "
-                                       "name=\"variant %s\", ret=%d", name, ret);
-                               goto error;
-                       }
-               }
-       }
-
-       /*
-        * If tagged, create tagged variant and return; otherwise
-        * return untagged variant.
-        */
-       if (!tag) {
-               *variant_decl = untagged_variant_decl;
-               untagged_variant_decl = NULL;
-       } else {
-               /*
-                * At this point, we have a fresh untagged variant; nobody
-                * else owns it. Set its tag now.
-                */
-               char *tag_no_underscore =
-                       remove_underscores_from_field_ref(tag);
-
-               if (!tag_no_underscore) {
-                       /* remove_underscores_from_field_ref() logs errors */
-                       goto error;
-               }
-
-               g_string_assign(untagged_variant_decl->tag_ref,
-                       tag_no_underscore);
-               free(tag_no_underscore);
-               *variant_decl = untagged_variant_decl;
-               untagged_variant_decl = NULL;
-       }
-
-       BT_ASSERT(!untagged_variant_decl);
-       BT_ASSERT(*variant_decl);
-       return 0;
-
-error:
-       ctf_field_class_destroy((void *) untagged_variant_decl);
-       untagged_variant_decl = NULL;
-       ctf_field_class_destroy((void *) *variant_decl);
-       *variant_decl = NULL;
-       return ret;
-}
-
-struct uori {
-       bool is_signed;
-       union {
-               uint64_t u;
-               uint64_t i;
-       } value;
-};
-
-static
-int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator,
-               struct ctf_field_class_enum *enum_decl, struct uori *last)
-{
-       int ret = 0;
-       int nr_vals = 0;
-       struct ctf_node *iter;
-       struct uori start = {
-               .is_signed = false,
-               .value.u = 0,
-       };
-       struct uori end = {
-               .is_signed = false,
-               .value.u = 0,
-       };
-       const char *label = enumerator->u.enumerator.id;
-       const char *effective_label = label;
-       struct bt_list_head *values = &enumerator->u.enumerator.values;
-
-       bt_list_for_each_entry(iter, values, siblings) {
-               struct uori *target;
-
-               if (iter->type != NODE_UNARY_EXPRESSION) {
-                       _BT_LOGE_NODE(iter,
-                               "Wrong expression for enumeration field class label: "
-                               "node-type=%d, label=\"%s\"", iter->type,
-                               label);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (nr_vals == 0) {
-                       target = &start;
-               } else {
-                       target = &end;
-               }
-
-               switch (iter->u.unary_expression.type) {
-               case UNARY_SIGNED_CONSTANT:
-                       target->is_signed = true;
-                       target->value.i =
-                               iter->u.unary_expression.u.signed_constant;
-                       break;
-               case UNARY_UNSIGNED_CONSTANT:
-                       target->is_signed = false;
-                       target->value.u =
-                               iter->u.unary_expression.u.unsigned_constant;
-                       break;
-               default:
-                       _BT_LOGE_NODE(iter,
-                               "Invalid enumeration field class entry: "
-                               "expecting constant signed or unsigned integer: "
-                               "node-type=%d, label=\"%s\"",
-                               iter->u.unary_expression.type, label);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (nr_vals > 1) {
-                       _BT_LOGE_NODE(iter,
-                               "Invalid enumeration field class entry: label=\"%s\"",
-                               label);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               nr_vals++;
-       }
-
-       if (nr_vals == 0) {
-               start = *last;
-       }
-
-       if (nr_vals <= 1) {
-               end = start;
-       }
-
-       if (end.is_signed) {
-               last->value.i = end.value.i + 1;
-       } else {
-               last->value.u = end.value.u + 1;
-       }
-
-       if (label[0] == '_') {
-               /*
-                * Strip the first underscore of any enumeration field
-                * class's label in case this enumeration FC is used as
-                * a variant FC tag later. The variant FC choice names
-                * could also start with `_`, in which case the prefix
-                * is removed, and it the resulting choice name needs to
-                * match tag labels.
-                */
-               effective_label = &label[1];
-       }
-
-       ctf_field_class_enum_append_mapping(enum_decl, effective_label,
-               start.value.u, end.value.u);
-       return 0;
-
-error:
-       return ret;
-}
-
-static
-int visit_enum_decl(struct ctx *ctx, const char *name,
-               struct ctf_node *container_cls,
-               struct bt_list_head *enumerator_list,
-               int has_body, struct ctf_field_class_enum **enum_decl)
-{
-       int ret = 0;
-       GQuark qdummy_id;
-       struct ctf_field_class_int *integer_decl = NULL;
-
-       BT_ASSERT(enum_decl);
-       *enum_decl = NULL;
-
-       /* For named enum (without body), lookup in declaration scope */
-       if (!has_body) {
-               if (!name) {
-                       BT_LOGE_STR("Bodyless enumeration field class: missing name.");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               *enum_decl = ctx_decl_scope_lookup_enum(ctx->current_scope,
-                       name, -1, true);
-               if (!*enum_decl) {
-                       BT_LOGE("Cannot find enumeration field class: "
-                               "name=\"enum %s\"", name);
-                       ret = -EINVAL;
-                       goto error;
-               }
-       } else {
-               struct ctf_node *iter;
-               struct uori last_value = {
-                       .is_signed = false,
-                       .value.u = 0,
-               };
-
-               if (name) {
-                       if (ctx_decl_scope_lookup_enum(ctx->current_scope,
-                                       name, 1, false)) {
-                               BT_LOGE("Enumeration field class already declared in local scope: "
-                                       "name=\"enum %s\"", name);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-               }
-
-               if (!container_cls) {
-                       integer_decl = (void *) ctx_decl_scope_lookup_alias(
-                               ctx->current_scope, "int", -1, true);
-                       if (!integer_decl) {
-                               BT_LOGE_STR("Cannot find implicit `int` field class alias for enumeration field class.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-               } else {
-                       ret = visit_field_class_declarator(ctx, container_cls,
-                               &qdummy_id, NULL, (void *) &integer_decl,
-                               NULL);
-                       if (ret) {
-                               BT_ASSERT(!integer_decl);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-               }
-
-               BT_ASSERT(integer_decl);
-
-               if (integer_decl->base.base.type != CTF_FIELD_CLASS_TYPE_INT) {
-                       BT_LOGE("Container field class for enumeration field class is not an integer field class: "
-                               "fc-type=%d", integer_decl->base.base.type);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               *enum_decl = ctf_field_class_enum_create();
-               BT_ASSERT(*enum_decl);
-               (*enum_decl)->base.base.base.alignment =
-                       integer_decl->base.base.alignment;
-               ctf_field_class_int_copy_content((void *) *enum_decl,
-                               (void *) integer_decl);
-               last_value.is_signed = (*enum_decl)->base.is_signed;
-
-               bt_list_for_each_entry(iter, enumerator_list, siblings) {
-                       ret = visit_enum_decl_entry(ctx, iter, *enum_decl,
-                               &last_value);
-                       if (ret) {
-                               _BT_LOGE_NODE(iter,
-                                       "Cannot visit enumeration field class entry: "
-                                       "ret=%d", ret);
-                               goto error;
-                       }
-               }
-
-               if (name) {
-                       ret = ctx_decl_scope_register_enum(ctx->current_scope,
-                               name, *enum_decl);
-                       if (ret) {
-                               BT_LOGE("Cannot register enumeration field class in declaration scope: "
-                                       "ret=%d", ret);
-                               goto error;
-                       }
-               }
-       }
-
-       goto end;
-
-error:
-       ctf_field_class_destroy((void *) *enum_decl);
-       *enum_decl = NULL;
-
-end:
-       ctf_field_class_destroy((void *) integer_decl);
-       integer_decl = NULL;
-       return ret;
-}
-
-static
-int visit_field_class_specifier(struct ctx *ctx,
-               struct ctf_node *cls_specifier_list,
-               struct ctf_field_class **decl)
-{
-       int ret = 0;
-       GString *str = NULL;
-
-       *decl = NULL;
-       str = g_string_new("");
-       ret = get_class_specifier_list_name(ctx, cls_specifier_list, str);
-       if (ret) {
-               _BT_LOGE_NODE(cls_specifier_list,
-                       "Cannot get field class specifier list's name: ret=%d", ret);
-               goto error;
-       }
-
-       *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1,
-               true);
-       if (!*decl) {
-               _BT_LOGE_NODE(cls_specifier_list,
-                       "Cannot find field class alias: name=\"%s\"", str->str);
-               ret = -EINVAL;
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ctf_field_class_destroy(*decl);
-       *decl = NULL;
-
-end:
-       if (str) {
-               g_string_free(str, TRUE);
-       }
-
-       return ret;
-}
-
-static
-int visit_integer_decl(struct ctx *ctx,
-               struct bt_list_head *expressions,
-               struct ctf_field_class_int **integer_decl)
-{
-       int set = 0;
-       int ret = 0;
-       int signedness = 0;
-       struct ctf_node *expression;
-       uint64_t alignment = 0, size = 0;
-       struct ctf_clock_class *mapped_clock_class = NULL;
-       enum ctf_encoding encoding = CTF_ENCODING_NONE;
-       bt_field_class_integer_preferred_display_base base =
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
-       enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order;
-
-       *integer_decl = NULL;
-
-       bt_list_for_each_entry(expression, expressions, siblings) {
-               struct ctf_node *left, *right;
-
-               left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left,
-                       struct ctf_node, siblings);
-               right = _BT_LIST_FIRST_ENTRY(
-                       &expression->u.ctf_expression.right, struct ctf_node,
-                       siblings);
-
-               if (left->u.unary_expression.type != UNARY_STRING) {
-                       _BT_LOGE_NODE(left,
-                               "Unexpected unary expression type: type=%d",
-                               left->u.unary_expression.type);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (!strcmp(left->u.unary_expression.u.string, "signed")) {
-                       if (_IS_SET(&set, _INTEGER_SIGNED_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "signed",
-                                       "integer field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       signedness = get_boolean(right);
-                       if (signedness < 0) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid boolean value for integer field class's `signed` attribute: "
-                                       "ret=%d", ret);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(&set, _INTEGER_SIGNED_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string,
-                               "byte_order")) {
-                       if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "byte_order",
-                                       "integer field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       byte_order = get_real_byte_order(ctx, right);
-                       if (byte_order == -1) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `byte_order` attribute in integer field class: "
-                                       "ret=%d", ret);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(&set, _INTEGER_BYTE_ORDER_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string, "size")) {
-                       if (_IS_SET(&set, _INTEGER_SIZE_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "size",
-                                       "integer field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       if (right->u.unary_expression.type !=
-                                       UNARY_UNSIGNED_CONSTANT) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `size` attribute in integer field class: "
-                                       "expecting unsigned constant integer: "
-                                       "node-type=%d",
-                                       right->u.unary_expression.type);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       size = right->u.unary_expression.u.unsigned_constant;
-                       if (size == 0) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `size` attribute in integer field class: "
-                                       "expecting positive constant integer: "
-                                       "size=%" PRIu64, size);
-                               ret = -EINVAL;
-                               goto error;
-                       } else if (size > 64) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `size` attribute in integer field class: "
-                                       "integer fields over 64 bits are not supported as of this version: "
-                                       "size=%" PRIu64, size);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(&set, _INTEGER_SIZE_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string,
-                               "align")) {
-                       if (_IS_SET(&set, _INTEGER_ALIGN_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "align",
-                                       "integer field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       if (right->u.unary_expression.type !=
-                                       UNARY_UNSIGNED_CONSTANT) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `align` attribute in integer field class: "
-                                       "expecting unsigned constant integer: "
-                                       "node-type=%d",
-                                       right->u.unary_expression.type);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       alignment =
-                               right->u.unary_expression.u.unsigned_constant;
-                       if (!is_align_valid(alignment)) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `align` attribute in integer field class: "
-                                       "expecting power of two: "
-                                       "align=%" PRIu64, alignment);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(&set, _INTEGER_ALIGN_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string, "base")) {
-                       if (_IS_SET(&set, _INTEGER_BASE_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "base",
-                                       "integer field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       switch (right->u.unary_expression.type) {
-                       case UNARY_UNSIGNED_CONSTANT:
-                       {
-                               uint64_t constant = right->u.unary_expression.
-                                       u.unsigned_constant;
-
-                               switch (constant) {
-                               case 2:
-                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
-                                       break;
-                               case 8:
-                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
-                                       break;
-                               case 10:
-                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
-                                       break;
-                               case 16:
-                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
-                                       break;
-                               default:
-                                       _BT_LOGE_NODE(right,
-                                               "Invalid `base` attribute in integer field class: "
-                                               "base=%" PRIu64,
-                                               right->u.unary_expression.u.unsigned_constant);
-                                       ret = -EINVAL;
-                                       goto error;
-                               }
-                               break;
-                       }
-                       case UNARY_STRING:
-                       {
-                               char *s_right = concatenate_unary_strings(
-                                       &expression->u.ctf_expression.right);
-                               if (!s_right) {
-                                       _BT_LOGE_NODE(right,
-                                               "Unexpected unary expression for integer field class's `base` attribute.");
-                                       ret = -EINVAL;
-                                       goto error;
-                               }
-
-                               if (!strcmp(s_right, "decimal") ||
-                                               !strcmp(s_right, "dec") ||
-                                               !strcmp(s_right, "d") ||
-                                               !strcmp(s_right, "i") ||
-                                               !strcmp(s_right, "u")) {
-                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
-                               } else if (!strcmp(s_right, "hexadecimal") ||
-                                               !strcmp(s_right, "hex") ||
-                                               !strcmp(s_right, "x") ||
-                                               !strcmp(s_right, "X") ||
-                                               !strcmp(s_right, "p")) {
-                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
-                               } else if (!strcmp(s_right, "octal") ||
-                                               !strcmp(s_right, "oct") ||
-                                               !strcmp(s_right, "o")) {
-                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
-                               } else if (!strcmp(s_right, "binary") ||
-                                               !strcmp(s_right, "b")) {
-                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
-                               } else {
-                                       _BT_LOGE_NODE(right,
-                                               "Unexpected unary expression for integer field class's `base` attribute: "
-                                               "base=\"%s\"", s_right);
-                                       g_free(s_right);
-                                       ret = -EINVAL;
-                                       goto error;
-                               }
-
-                               g_free(s_right);
-                               break;
-                       }
-                       default:
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `base` attribute in integer field class: "
-                                       "expecting unsigned constant integer or unary string.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(&set, _INTEGER_BASE_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string,
-                               "encoding")) {
-                       char *s_right;
-
-                       if (_IS_SET(&set, _INTEGER_ENCODING_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "encoding",
-                                       "integer field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       if (right->u.unary_expression.type != UNARY_STRING) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `encoding` attribute in integer field class: "
-                                       "expecting unary string.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       s_right = concatenate_unary_strings(
-                               &expression->u.ctf_expression.right);
-                       if (!s_right) {
-                               _BT_LOGE_NODE(right,
-                                       "Unexpected unary expression for integer field class's `encoding` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (!strcmp(s_right, "UTF8") ||
-                                       !strcmp(s_right, "utf8") ||
-                                       !strcmp(s_right, "utf-8") ||
-                                       !strcmp(s_right, "UTF-8") ||
-                                       !strcmp(s_right, "ASCII") ||
-                                       !strcmp(s_right, "ascii")) {
-                               encoding = CTF_ENCODING_UTF8;
-                       } else if (!strcmp(s_right, "none")) {
-                               encoding = CTF_ENCODING_NONE;
-                       } else {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `encoding` attribute in integer field class: "
-                                       "unknown encoding: encoding=\"%s\"",
-                                       s_right);
-                               g_free(s_right);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       g_free(s_right);
-                       _SET(&set, _INTEGER_ENCODING_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string, "map")) {
-                       const char *clock_name;
-
-                       if (_IS_SET(&set, _INTEGER_MAP_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "map",
-                                       "integer field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       if (right->u.unary_expression.type != UNARY_STRING) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `map` attribute in integer field class: "
-                                       "expecting unary string.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       clock_name =
-                               get_map_clock_name_value(
-                                       &expression->u.ctf_expression.right);
-                       if (!clock_name) {
-                               char *s_right = concatenate_unary_strings(
-                                       &expression->u.ctf_expression.right);
-
-                               if (!s_right) {
-                                       _BT_LOGE_NODE(right,
-                                               "Unexpected unary expression for integer field class's `map` attribute.");
-                                       ret = -EINVAL;
-                                       goto error;
-                               }
-
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `map` attribute in integer field class: "
-                                       "cannot find clock class at this point: name=\"%s\"",
-                                       s_right);
-                               _SET(&set, _INTEGER_MAP_SET);
-                               g_free(s_right);
-                               continue;
-                       }
-
-                       mapped_clock_class =
-                               ctf_trace_class_borrow_clock_class_by_name(
-                                       ctx->ctf_tc, clock_name);
-                       if (!mapped_clock_class) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `map` attribute in integer field class: "
-                                       "cannot find clock class at this point: name=\"%s\"",
-                                       clock_name);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(&set, _INTEGER_MAP_SET);
-               } else {
-                       _BT_LOGW_NODE(left,
-                               "Unknown attribute in integer field class: "
-                               "attr-name=\"%s\"",
-                               left->u.unary_expression.u.string);
-               }
-       }
-
-       if (!_IS_SET(&set, _INTEGER_SIZE_SET)) {
-               BT_LOGE_STR("Missing `size` attribute in integer field class.");
-               ret = -EPERM;
-               goto error;
-       }
-
-       if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) {
-               if (size % CHAR_BIT) {
-                       /* Bit-packed alignment */
-                       alignment = 1;
-               } else {
-                       /* Byte-packed alignment */
-                       alignment = CHAR_BIT;
-               }
-       }
-
-       *integer_decl = ctf_field_class_int_create();
-       BT_ASSERT(*integer_decl);
-       (*integer_decl)->base.base.alignment = alignment;
-       (*integer_decl)->base.byte_order = byte_order;
-       (*integer_decl)->base.size = size;
-       (*integer_decl)->is_signed = (signedness > 0);
-       (*integer_decl)->disp_base = base;
-       (*integer_decl)->encoding = encoding;
-       (*integer_decl)->mapped_clock_class = mapped_clock_class;
-       return 0;
-
-error:
-       ctf_field_class_destroy((void *) *integer_decl);
-       *integer_decl = NULL;
-       return ret;
-}
-
-static
-int visit_floating_point_number_decl(struct ctx *ctx,
-               struct bt_list_head *expressions,
-               struct ctf_field_class_float **float_decl)
-{
-       int set = 0;
-       int ret = 0;
-       struct ctf_node *expression;
-       uint64_t alignment = 1, exp_dig = 0, mant_dig = 0;
-       enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order;
-
-       *float_decl = NULL;
-
-       bt_list_for_each_entry(expression, expressions, siblings) {
-               struct ctf_node *left, *right;
-
-               left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left,
-                       struct ctf_node, siblings);
-               right = _BT_LIST_FIRST_ENTRY(
-                       &expression->u.ctf_expression.right, struct ctf_node,
-                       siblings);
-
-               if (left->u.unary_expression.type != UNARY_STRING) {
-                       _BT_LOGE_NODE(left,
-                               "Unexpected unary expression type: type=%d",
-                               left->u.unary_expression.type);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (!strcmp(left->u.unary_expression.u.string, "byte_order")) {
-                       if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "byte_order",
-                                       "floating point number field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       byte_order = get_real_byte_order(ctx, right);
-                       if (byte_order == -1) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `byte_order` attribute in floating point number field class: "
-                                       "ret=%d", ret);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(&set, _FLOAT_BYTE_ORDER_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string,
-                               "exp_dig")) {
-                       if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "exp_dig",
-                                       "floating point number field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       if (right->u.unary_expression.type !=
-                                       UNARY_UNSIGNED_CONSTANT) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `exp_dig` attribute in floating point number field class: "
-                                       "expecting unsigned constant integer: "
-                                       "node-type=%d",
-                                       right->u.unary_expression.type);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       exp_dig = right->u.unary_expression.u.unsigned_constant;
-                       _SET(&set, _FLOAT_EXP_DIG_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string,
-                               "mant_dig")) {
-                       if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "mant_dig",
-                                       "floating point number field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       if (right->u.unary_expression.type !=
-                                       UNARY_UNSIGNED_CONSTANT) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `mant_dig` attribute in floating point number field class: "
-                                       "expecting unsigned constant integer: "
-                                       "node-type=%d",
-                                       right->u.unary_expression.type);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       mant_dig = right->u.unary_expression.u.
-                               unsigned_constant;
-                       _SET(&set, _FLOAT_MANT_DIG_SET);
-               } else if (!strcmp(left->u.unary_expression.u.string,
-                               "align")) {
-                       if (_IS_SET(&set, _FLOAT_ALIGN_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "align",
-                                       "floating point number field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       if (right->u.unary_expression.type !=
-                                       UNARY_UNSIGNED_CONSTANT) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `align` attribute in floating point number field class: "
-                                       "expecting unsigned constant integer: "
-                                       "node-type=%d",
-                                       right->u.unary_expression.type);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       alignment = right->u.unary_expression.u.
-                               unsigned_constant;
-
-                       if (!is_align_valid(alignment)) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `align` attribute in floating point number field class: "
-                                       "expecting power of two: "
-                                       "align=%" PRIu64, alignment);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(&set, _FLOAT_ALIGN_SET);
-               } else {
-                       _BT_LOGW_NODE(left,
-                               "Unknown attribute in floating point number field class: "
-                               "attr-name=\"%s\"",
-                               left->u.unary_expression.u.string);
-               }
-       }
-
-       if (!_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
-               BT_LOGE_STR("Missing `mant_dig` attribute in floating point number field class.");
-               ret = -EPERM;
-               goto error;
-       }
-
-       if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
-               BT_LOGE_STR("Missing `exp_dig` attribute in floating point number field class.");
-               ret = -EPERM;
-               goto error;
-       }
-
-       if (mant_dig != 24 && mant_dig != 53) {
-               BT_LOGE_STR("`mant_dig` attribute: expecting 24 or 53.");
-               ret = -EPERM;
-               goto error;
-       }
-
-       if (mant_dig == 24 && exp_dig != 8) {
-               BT_LOGE_STR("`exp_dig` attribute: expecting 8 because `mant_dig` is 24.");
-               ret = -EPERM;
-               goto error;
-       }
-
-       if (mant_dig == 53 && exp_dig != 11) {
-               BT_LOGE_STR("`exp_dig` attribute: expecting 11 because `mant_dig` is 53.");
-               ret = -EPERM;
-               goto error;
-       }
-
-       if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) {
-               if ((mant_dig + exp_dig) % CHAR_BIT) {
-                       /* Bit-packed alignment */
-                       alignment = 1;
-               } else {
-                       /* Byte-packed alignment */
-                       alignment = CHAR_BIT;
-               }
-       }
-
-       *float_decl = ctf_field_class_float_create();
-       BT_ASSERT(*float_decl);
-       (*float_decl)->base.base.alignment = alignment;
-       (*float_decl)->base.byte_order = byte_order;
-       (*float_decl)->base.size = mant_dig + exp_dig;
-       return 0;
-
-error:
-       ctf_field_class_destroy((void *) *float_decl);
-       *float_decl = NULL;
-       return ret;
-}
-
-static
-int visit_string_decl(struct ctx *ctx,
-               struct bt_list_head *expressions,
-               struct ctf_field_class_string **string_decl)
-{
-       int set = 0;
-       int ret = 0;
-       struct ctf_node *expression;
-       enum ctf_encoding encoding = CTF_ENCODING_UTF8;
-
-       *string_decl = NULL;
-
-       bt_list_for_each_entry(expression, expressions, siblings) {
-               struct ctf_node *left, *right;
-
-               left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left,
-                       struct ctf_node, siblings);
-               right = _BT_LIST_FIRST_ENTRY(
-                       &expression->u.ctf_expression.right, struct ctf_node,
-                       siblings);
-
-               if (left->u.unary_expression.type != UNARY_STRING) {
-                       _BT_LOGE_NODE(left,
-                               "Unexpected unary expression type: type=%d",
-                               left->u.unary_expression.type);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (!strcmp(left->u.unary_expression.u.string, "encoding")) {
-                       char *s_right;
-
-                       if (_IS_SET(&set, _STRING_ENCODING_SET)) {
-                               _BT_LOGE_DUP_ATTR(left, "encoding",
-                                       "string field class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       if (right->u.unary_expression.type != UNARY_STRING) {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `encoding` attribute in string field class: "
-                                       "expecting unary string.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       s_right = concatenate_unary_strings(
-                               &expression->u.ctf_expression.right);
-                       if (!s_right) {
-                               _BT_LOGE_NODE(right,
-                                       "Unexpected unary expression for string field class's `encoding` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (!strcmp(s_right, "UTF8") ||
-                                       !strcmp(s_right, "utf8") ||
-                                       !strcmp(s_right, "utf-8") ||
-                                       !strcmp(s_right, "UTF-8") ||
-                                       !strcmp(s_right, "ASCII") ||
-                                       !strcmp(s_right, "ascii")) {
-                               encoding = CTF_ENCODING_UTF8;
-                       } else if (!strcmp(s_right, "none")) {
-                               encoding = CTF_ENCODING_NONE;
-                       } else {
-                               _BT_LOGE_NODE(right,
-                                       "Invalid `encoding` attribute in string field class: "
-                                       "unknown encoding: encoding=\"%s\"",
-                                       s_right);
-                               g_free(s_right);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       g_free(s_right);
-                       _SET(&set, _STRING_ENCODING_SET);
-               } else {
-                       _BT_LOGW_NODE(left,
-                               "Unknown attribute in string field class: "
-                               "attr-name=\"%s\"",
-                               left->u.unary_expression.u.string);
-               }
-       }
-
-       *string_decl = ctf_field_class_string_create();
-       BT_ASSERT(*string_decl);
-       (*string_decl)->encoding = encoding;
-       return 0;
-
-error:
-       ctf_field_class_destroy((void *) *string_decl);
-       *string_decl = NULL;
-       return ret;
-}
-
-static
-int visit_field_class_specifier_list(struct ctx *ctx,
-               struct ctf_node *ts_list, struct ctf_field_class **decl)
-{
-       int ret = 0;
-       struct ctf_node *first, *node;
-
-       *decl = NULL;
-
-       if (ts_list->type != NODE_TYPE_SPECIFIER_LIST) {
-               _BT_LOGE_NODE(ts_list,
-                       "Unexpected node type: node-type=%d", ts_list->type);
-               ret = -EINVAL;
-               goto error;
-       }
-
-       first = _BT_LIST_FIRST_ENTRY(&ts_list->u.field_class_specifier_list.head,
-               struct ctf_node, siblings);
-       if (first->type != NODE_TYPE_SPECIFIER) {
-               _BT_LOGE_NODE(first,
-                       "Unexpected node type: node-type=%d", first->type);
-               ret = -EINVAL;
-               goto error;
-       }
-
-       node = first->u.field_class_specifier.node;
-
-       switch (first->u.field_class_specifier.type) {
-       case TYPESPEC_INTEGER:
-               ret = visit_integer_decl(ctx, &node->u.integer.expressions,
-                       (void *) decl);
-               if (ret) {
-                       BT_ASSERT(!*decl);
-                       goto error;
-               }
-               break;
-       case TYPESPEC_FLOATING_POINT:
-               ret = visit_floating_point_number_decl(ctx,
-                       &node->u.floating_point.expressions, (void *) decl);
-               if (ret) {
-                       BT_ASSERT(!*decl);
-                       goto error;
-               }
-               break;
-       case TYPESPEC_STRING:
-               ret = visit_string_decl(ctx,
-                       &node->u.string.expressions, (void *) decl);
-               if (ret) {
-                       BT_ASSERT(!*decl);
-                       goto error;
-               }
-               break;
-       case TYPESPEC_STRUCT:
-               ret = visit_struct_decl(ctx, node->u._struct.name,
-                       &node->u._struct.declaration_list,
-                       node->u._struct.has_body,
-                       &node->u._struct.min_align, (void *) decl);
-               if (ret) {
-                       BT_ASSERT(!*decl);
-                       goto error;
-               }
-               break;
-       case TYPESPEC_VARIANT:
-               ret = visit_variant_decl(ctx, node->u.variant.name,
-                       node->u.variant.choice,
-                       &node->u.variant.declaration_list,
-                       node->u.variant.has_body, (void *) decl);
-               if (ret) {
-                       BT_ASSERT(!*decl);
-                       goto error;
-               }
-               break;
-       case TYPESPEC_ENUM:
-               ret = visit_enum_decl(ctx, node->u._enum.enum_id,
-                       node->u._enum.container_field_class,
-                       &node->u._enum.enumerator_list,
-                       node->u._enum.has_body, (void *) decl);
-               if (ret) {
-                       BT_ASSERT(!*decl);
-                       goto error;
-               }
-               break;
-       case TYPESPEC_VOID:
-       case TYPESPEC_CHAR:
-       case TYPESPEC_SHORT:
-       case TYPESPEC_INT:
-       case TYPESPEC_LONG:
-       case TYPESPEC_FLOAT:
-       case TYPESPEC_DOUBLE:
-       case TYPESPEC_SIGNED:
-       case TYPESPEC_UNSIGNED:
-       case TYPESPEC_BOOL:
-       case TYPESPEC_COMPLEX:
-       case TYPESPEC_IMAGINARY:
-       case TYPESPEC_CONST:
-       case TYPESPEC_ID_TYPE:
-               ret = visit_field_class_specifier(ctx, ts_list, decl);
-               if (ret) {
-                       _BT_LOGE_NODE(first,
-                               "Cannot visit field class specifier: ret=%d",
-                               ret);
-                       BT_ASSERT(!*decl);
-                       goto error;
-               }
-               break;
-       default:
-               _BT_LOGE_NODE(first,
-                       "Unexpected field class specifier type: node-type=%d",
-                       first->u.field_class_specifier.type);
-               ret = -EINVAL;
-               goto error;
-       }
-
-       BT_ASSERT(*decl);
-       return 0;
-
-error:
-       ctf_field_class_destroy((void *) *decl);
-       *decl = NULL;
-       return ret;
-}
-
-static
-int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
-               struct ctf_event_class *event_class, uint64_t *stream_id,
-               int *set)
-{
-       int ret = 0;
-       char *left = NULL;
-
-       switch (node->type) {
-       case NODE_TYPEDEF:
-               ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
-                       &node->u.field_class_def.field_class_declarators);
-               if (ret) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot add field class found in event class.");
-                       goto error;
-               }
-               break;
-       case NODE_TYPEALIAS:
-               ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
-                       node->u.field_class_alias.alias);
-               if (ret) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot add field class alias found in event class.");
-                       goto error;
-               }
-               break;
-       case NODE_CTF_EXPRESSION:
-       {
-               left = concatenate_unary_strings(&node->u.ctf_expression.left);
-               if (!left) {
-                       _BT_LOGE_NODE(node, "Cannot concatenate unary strings.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (!strcmp(left, "name")) {
-                       /* This is already known at this stage */
-                       if (_IS_SET(set, _EVENT_NAME_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "name", "event class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       _SET(set, _EVENT_NAME_SET);
-               } else if (!strcmp(left, "id")) {
-                       int64_t id = -1;
-
-                       if (_IS_SET(set, _EVENT_ID_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "id", "event class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               (uint64_t *) &id);
-                       /* Only read "id" if get_unary_unsigned() succeeded. */
-                       if (ret || (!ret && id < 0)) {
-                               _BT_LOGE_NODE(node,
-                                       "Unexpected unary expression for event class's `id` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       event_class->id = id;
-                       _SET(set, _EVENT_ID_SET);
-               } else if (!strcmp(left, "stream_id")) {
-                       if (_IS_SET(set, _EVENT_STREAM_ID_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "stream_id",
-                                       "event class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               stream_id);
-
-                       /*
-                        * Only read "stream_id" if get_unary_unsigned()
-                        * succeeded.
-                        */
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Unexpected unary expression for event class's `stream_id` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       _SET(set, _EVENT_STREAM_ID_SET);
-               } else if (!strcmp(left, "context")) {
-                       if (_IS_SET(set, _EVENT_CONTEXT_SET)) {
-                               _BT_LOGE_NODE(node,
-                                       "Duplicate `context` entry in event class.");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = visit_field_class_specifier_list(ctx,
-                               _BT_LIST_FIRST_ENTRY(
-                                       &node->u.ctf_expression.right,
-                                       struct ctf_node, siblings),
-                               &event_class->spec_context_fc);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot create event class's context field class.");
-                               goto error;
-                       }
-
-                       BT_ASSERT(event_class->spec_context_fc);
-                       _SET(set, _EVENT_CONTEXT_SET);
-               } else if (!strcmp(left, "fields")) {
-                       if (_IS_SET(set, _EVENT_FIELDS_SET)) {
-                               _BT_LOGE_NODE(node,
-                                       "Duplicate `fields` entry in event class.");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = visit_field_class_specifier_list(ctx,
-                               _BT_LIST_FIRST_ENTRY(
-                                       &node->u.ctf_expression.right,
-                                       struct ctf_node, siblings),
-                               &event_class->payload_fc);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot create event class's payload field class.");
-                               goto error;
-                       }
-
-                       BT_ASSERT(event_class->payload_fc);
-                       _SET(set, _EVENT_FIELDS_SET);
-               } else if (!strcmp(left, "loglevel")) {
-                       uint64_t loglevel_value;
-                       bt_event_class_log_level log_level = -1;
-
-                       if (_IS_SET(set, _EVENT_LOG_LEVEL_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "loglevel",
-                                       "event class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               &loglevel_value);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Unexpected unary expression for event class's `loglevel` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       switch (loglevel_value) {
-                       case 0:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY;
-                               break;
-                       case 1:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_ALERT;
-                               break;
-                       case 2:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_CRITICAL;
-                               break;
-                       case 3:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_ERROR;
-                               break;
-                       case 4:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_WARNING;
-                               break;
-                       case 5:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_NOTICE;
-                               break;
-                       case 6:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_INFO;
-                               break;
-                       case 7:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM;
-                               break;
-                       case 8:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM;
-                               break;
-                       case 9:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS;
-                               break;
-                       case 10:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE;
-                               break;
-                       case 11:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT;
-                               break;
-                       case 12:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION;
-                               break;
-                       case 13:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE;
-                               break;
-                       case 14:
-                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG;
-                               break;
-                       default:
-                               _BT_LOGW_NODE(node, "Not setting event class's log level because its value is unknown: "
-                                       "log-level=%" PRIu64, loglevel_value);
-                       }
-
-                       if (log_level != -1) {
-                               event_class->log_level = log_level;
-                       }
-
-                       _SET(set, _EVENT_LOG_LEVEL_SET);
-               } else if (!strcmp(left, "model.emf.uri")) {
-                       char *right;
-
-                       if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "model.emf.uri",
-                                       "event class");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       right = concatenate_unary_strings(
-                               &node->u.ctf_expression.right);
-                       if (!right) {
-                               _BT_LOGE_NODE(node,
-                                       "Unexpected unary expression for event class's `model.emf.uri` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (strlen(right) == 0) {
-                               _BT_LOGW_NODE(node,
-                                       "Not setting event class's EMF URI because it's empty.");
-                       } else {
-                               g_string_assign(event_class->emf_uri,
-                                       right);
-                       }
-
-                       g_free(right);
-                       _SET(set, _EVENT_MODEL_EMF_URI_SET);
-               } else {
-                       _BT_LOGW_NODE(node,
-                               "Unknown attribute in event class: "
-                               "attr-name=\"%s\"", left);
-               }
-
-               g_free(left);
-               left = NULL;
-               break;
-       }
-       default:
-               ret = -EPERM;
-               goto error;
-       }
-
-       goto end;
-
-error:
-       if (left) {
-               g_free(left);
-       }
-
-end:
-       return ret;
-}
-
-static
-char *get_event_decl_name(struct ctx *ctx, struct ctf_node *node)
-{
-       char *left = NULL;
-       char *name = NULL;
-       struct ctf_node *iter;
-       struct bt_list_head *decl_list = &node->u.event.declaration_list;
-
-       bt_list_for_each_entry(iter, decl_list, siblings) {
-               if (iter->type != NODE_CTF_EXPRESSION) {
-                       continue;
-               }
-
-               left = concatenate_unary_strings(&iter->u.ctf_expression.left);
-               if (!left) {
-                       _BT_LOGE_NODE(iter,
-                               "Cannot concatenate unary strings.");
-                       goto error;
-               }
-
-               if (!strcmp(left, "name")) {
-                       name = concatenate_unary_strings(
-                               &iter->u.ctf_expression.right);
-                       if (!name) {
-                               _BT_LOGE_NODE(iter,
-                                       "Unexpected unary expression for event class's `name` attribute.");
-                               goto error;
-                       }
-               }
-
-               g_free(left);
-               left = NULL;
-
-               if (name) {
-                       break;
-               }
-       }
-
-       return name;
-
-error:
-       g_free(left);
-       return NULL;
-}
-
-static
-int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
-{
-       int ret = 0;
-       int set = 0;
-       struct ctf_node *iter;
-       uint64_t stream_id = 0;
-       char *event_name = NULL;
-       struct ctf_event_class *event_class = NULL;
-       struct ctf_stream_class *stream_class = NULL;
-       struct bt_list_head *decl_list = &node->u.event.declaration_list;
-       bool pop_scope = false;
-
-       if (node->visited) {
-               goto end;
-       }
-
-       node->visited = TRUE;
-       event_name = get_event_decl_name(ctx, node);
-       if (!event_name) {
-               _BT_LOGE_NODE(node,
-                       "Missing `name` attribute in event class.");
-               ret = -EPERM;
-               goto error;
-       }
-
-       event_class = ctf_event_class_create();
-       BT_ASSERT(event_class);
-       g_string_assign(event_class->name, event_name);
-       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
-       pop_scope = true;
-
-       bt_list_for_each_entry(iter, decl_list, siblings) {
-               ret = visit_event_decl_entry(ctx, iter, event_class,
-                       &stream_id, &set);
-               if (ret) {
-                       _BT_LOGE_NODE(iter, "Cannot visit event class's entry: "
-                               "ret=%d", ret);
-                       goto error;
-               }
-       }
-
-       if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) {
-               /*
-                * Allow missing stream_id if there is only a single
-                * stream class.
-                */
-               switch (ctx->ctf_tc->stream_classes->len) {
-               case 0:
-                       /* Create implicit stream class if there's none */
-                       stream_id = 0;
-                       stream_class = ctf_stream_class_create();
-                       BT_ASSERT(stream_class);
-                       stream_class->id = stream_id;
-                       g_ptr_array_add(ctx->ctf_tc->stream_classes,
-                               stream_class);
-                       break;
-               case 1:
-                       /* Single stream class: get its ID */
-                       stream_class = ctx->ctf_tc->stream_classes->pdata[0];
-                       stream_id = stream_class->id;
-                       break;
-               default:
-                       _BT_LOGE_NODE(node,
-                               "Missing `stream_id` attribute in event class.");
-                       ret = -EPERM;
-                       goto error;
-               }
-       }
-
-       /* We have the stream ID now; get the stream class if found */
-       if (!stream_class) {
-               stream_class = ctf_trace_class_borrow_stream_class_by_id(
-                       ctx->ctf_tc, stream_id);
-               if (!stream_class) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot find stream class at this point: "
-                               "id=%" PRId64, stream_id);
-                       ret = -EINVAL;
-                       goto error;
-               }
-       }
-
-       BT_ASSERT(stream_class);
-
-       if (!_IS_SET(&set, _EVENT_ID_SET)) {
-               /* Allow only one event without ID per stream */
-               if (stream_class->event_classes->len != 0) {
-                       _BT_LOGE_NODE(node,
-                               "Missing `id` attribute in event class.");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               /* Automatic ID */
-               event_class->id = 0;
-       }
-
-       if (ctf_stream_class_borrow_event_class_by_id(stream_class,
-                       event_class->id)) {
-               _BT_LOGE_NODE(node,
-                       "Duplicate event class (same ID) in the same stream class: "
-                       "id=%" PRId64, event_class->id);
-               ret = -EEXIST;
-               goto error;
-       }
-
-       ctf_stream_class_append_event_class(stream_class, event_class);
-       event_class = NULL;
-       goto end;
-
-error:
-       ctf_event_class_destroy(event_class);
-       event_class = NULL;
-
-       if (ret >= 0) {
-               ret = -1;
-       }
-
-end:
-       if (pop_scope) {
-               ctx_pop_scope(ctx);
-       }
-
-       if (event_name) {
-               g_free(event_name);
-       }
-
-       return ret;
-}
-
-static
-int auto_map_field_to_trace_clock_class(struct ctx *ctx,
-               struct ctf_field_class *fc)
-{
-       struct ctf_clock_class *clock_class_to_map_to = NULL;
-       struct ctf_field_class_int *int_fc = (void *) fc;
-       int ret = 0;
-       uint64_t clock_class_count;
-
-       if (!fc) {
-               goto end;
-       }
-
-       if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                       fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-               goto end;
-       }
-
-       if (int_fc->mapped_clock_class) {
-               /* Already mapped */
-               goto end;
-       }
-
-       clock_class_count = ctx->ctf_tc->clock_classes->len;
-
-       switch (clock_class_count) {
-       case 0:
-               /*
-                * No clock class exists in the trace at this point. Create an
-                * implicit one at 1 GHz, named `default`, and use this clock
-                * class.
-                */
-               clock_class_to_map_to = ctf_clock_class_create();
-               BT_ASSERT(clock_class_to_map_to);
-               clock_class_to_map_to->frequency = UINT64_C(1000000000);
-               g_string_assign(clock_class_to_map_to->name, "default");
-               BT_ASSERT(ret == 0);
-               g_ptr_array_add(ctx->ctf_tc->clock_classes,
-                       clock_class_to_map_to);
-               break;
-       case 1:
-               /*
-                * Only one clock class exists in the trace at this point: use
-                * this one.
-                */
-               clock_class_to_map_to = ctx->ctf_tc->clock_classes->pdata[0];
-               break;
-       default:
-               /*
-                * Timestamp field not mapped to a clock class and there's more
-                * than one clock class in the trace: this is an error.
-                */
-               BT_LOGE_STR("Timestamp field found with no mapped clock class, "
-                       "but there's more than one clock class in the trace at this point.");
-               ret = -1;
-               goto end;
-       }
-
-       BT_ASSERT(clock_class_to_map_to);
-       int_fc->mapped_clock_class = clock_class_to_map_to;
-
-end:
-       return ret;
-}
-
-static
-int auto_map_fields_to_trace_clock_class(struct ctx *ctx,
-               struct ctf_field_class *root_fc, const char *field_name)
-{
-       int ret = 0;
-       uint64_t i, count;
-       struct ctf_field_class_struct *struct_fc = (void *) root_fc;
-       struct ctf_field_class_variant *var_fc = (void *) root_fc;
-
-       if (!root_fc) {
-               goto end;
-       }
-
-       if (root_fc->type != CTF_FIELD_CLASS_TYPE_STRUCT &&
-                       root_fc->type != CTF_FIELD_CLASS_TYPE_VARIANT) {
-               goto end;
-       }
-
-       if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) {
-               count = struct_fc->members->len;
-       } else {
-               count = var_fc->options->len;
-       }
-
-       for (i = 0; i < count; i++) {
-               struct ctf_named_field_class *named_fc = NULL;
-
-               if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) {
-                       named_fc = ctf_field_class_struct_borrow_member_by_index(
-                               struct_fc, i);
-               } else if (root_fc->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
-                       named_fc = ctf_field_class_variant_borrow_option_by_index(
-                               var_fc, i);
-               }
-
-               if (strcmp(named_fc->name->str, field_name) == 0) {
-                       ret = auto_map_field_to_trace_clock_class(ctx,
-                               named_fc->fc);
-                       if (ret) {
-                               BT_LOGE("Cannot automatically map field to trace's clock class: "
-                                       "field-name=\"%s\"", field_name);
-                               goto end;
-                       }
-               }
-
-               ret = auto_map_fields_to_trace_clock_class(ctx, named_fc->fc,
-                       field_name);
-               if (ret) {
-                       BT_LOGE("Cannot automatically map structure or variant field class's fields to trace's clock class: "
-                               "field-name=\"%s\", root-field-name=\"%s\"",
-                               field_name, named_fc->name->str);
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
-               struct ctf_stream_class *stream_class, int *set)
-{
-       int ret = 0;
-       char *left = NULL;
-
-       switch (node->type) {
-       case NODE_TYPEDEF:
-               ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
-                       &node->u.field_class_def.field_class_declarators);
-               if (ret) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot add field class found in stream class.");
-                       goto error;
-               }
-               break;
-       case NODE_TYPEALIAS:
-               ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
-                       node->u.field_class_alias.alias);
-               if (ret) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot add field class alias found in stream class.");
-                       goto error;
-               }
-               break;
-       case NODE_CTF_EXPRESSION:
-       {
-               left = concatenate_unary_strings(&node->u.ctf_expression.left);
-               if (!left) {
-                       _BT_LOGE_NODE(node, "Cannot concatenate unary strings.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (!strcmp(left, "id")) {
-                       int64_t id;
-
-                       if (_IS_SET(set, _STREAM_ID_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "id",
-                                       "stream declaration");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               (uint64_t *) &id);
-
-                       /* Only read "id" if get_unary_unsigned() succeeded. */
-                       if (ret || (!ret && id < 0)) {
-                               _BT_LOGE_NODE(node,
-                                       "Unexpected unary expression for stream class's `id` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (ctf_trace_class_borrow_stream_class_by_id(
-                                       ctx->ctf_tc, id)) {
-                               _BT_LOGE_NODE(node,
-                                       "Duplicate stream class (same ID): id=%" PRId64,
-                                       id);
-                               ret = -EEXIST;
-                               goto error;
-                       }
-
-                       stream_class->id = id;
-                       _SET(set, _STREAM_ID_SET);
-               } else if (!strcmp(left, "event.header")) {
-                       if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) {
-                               _BT_LOGE_NODE(node,
-                                       "Duplicate `event.header` entry in stream class.");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = visit_field_class_specifier_list(ctx,
-                               _BT_LIST_FIRST_ENTRY(
-                                       &node->u.ctf_expression.right,
-                                       struct ctf_node, siblings),
-                               &stream_class->event_header_fc);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot create stream class's event header field class.");
-                               goto error;
-                       }
-
-                       BT_ASSERT(stream_class->event_header_fc);
-                       ret = auto_map_fields_to_trace_clock_class(ctx,
-                               stream_class->event_header_fc, "timestamp");
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot automatically map specific event header field class fields named `timestamp` to trace's clock class.");
-                               goto error;
-                       }
-
-                       _SET(set, _STREAM_EVENT_HEADER_SET);
-               } else if (!strcmp(left, "event.context")) {
-                       if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) {
-                               _BT_LOGE_NODE(node,
-                                       "Duplicate `event.context` entry in stream class.");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = visit_field_class_specifier_list(ctx,
-                               _BT_LIST_FIRST_ENTRY(
-                                       &node->u.ctf_expression.right,
-                                       struct ctf_node, siblings),
-                               &stream_class->event_common_context_fc);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot create stream class's event context field class.");
-                               goto error;
-                       }
-
-                       BT_ASSERT(stream_class->event_common_context_fc);
-                       _SET(set, _STREAM_EVENT_CONTEXT_SET);
-               } else if (!strcmp(left, "packet.context")) {
-                       if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) {
-                               _BT_LOGE_NODE(node,
-                                       "Duplicate `packet.context` entry in stream class.");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = visit_field_class_specifier_list(ctx,
-                               _BT_LIST_FIRST_ENTRY(
-                                       &node->u.ctf_expression.right,
-                                       struct ctf_node, siblings),
-                               &stream_class->packet_context_fc);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot create stream class's packet context field class.");
-                               goto error;
-                       }
-
-                       BT_ASSERT(stream_class->packet_context_fc);
-                       ret = auto_map_fields_to_trace_clock_class(ctx,
-                               stream_class->packet_context_fc,
-                               "timestamp_begin");
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot automatically map specific packet context field class fields named `timestamp_begin` to trace's clock class.");
-                               goto error;
-                       }
-
-                       ret = auto_map_fields_to_trace_clock_class(ctx,
-                               stream_class->packet_context_fc,
-                               "timestamp_end");
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot automatically map specific packet context field class fields named `timestamp_end` to trace's clock class.");
-                               goto error;
-                       }
-
-                       _SET(set, _STREAM_PACKET_CONTEXT_SET);
-               } else {
-                       _BT_LOGW_NODE(node,
-                               "Unknown attribute in stream class: "
-                               "attr-name=\"%s\"", left);
-               }
-
-               g_free(left);
-               left = NULL;
-               break;
-       }
-
-       default:
-               ret = -EPERM;
-               goto error;
-       }
-
-       return 0;
-
-error:
-       g_free(left);
-       return ret;
-}
-
-static
-int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
-{
-       int set = 0;
-       int ret = 0;
-       struct ctf_node *iter;
-       struct ctf_stream_class *stream_class = NULL;
-       struct bt_list_head *decl_list = &node->u.stream.declaration_list;
-
-       if (node->visited) {
-               goto end;
-       }
-
-       node->visited = TRUE;
-       stream_class = ctf_stream_class_create();
-       BT_ASSERT(stream_class);
-       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
-
-       bt_list_for_each_entry(iter, decl_list, siblings) {
-               ret = visit_stream_decl_entry(ctx, iter, stream_class, &set);
-               if (ret) {
-                       _BT_LOGE_NODE(iter,
-                               "Cannot visit stream class's entry: "
-                               "ret=%d", ret);
-                       ctx_pop_scope(ctx);
-                       goto error;
-               }
-       }
-
-       ctx_pop_scope(ctx);
-
-       if (_IS_SET(&set, _STREAM_ID_SET)) {
-               /* Check that packet header has `stream_id` field */
-               struct ctf_named_field_class *named_fc = NULL;
-
-               if (!ctx->ctf_tc->packet_header_fc) {
-                       _BT_LOGE_NODE(node,
-                               "Stream class has a `id` attribute, "
-                               "but trace has no packet header field class.");
-                       goto error;
-               }
-
-               named_fc = ctf_field_class_struct_borrow_member_by_name(
-                       (void *) ctx->ctf_tc->packet_header_fc, "stream_id");
-               if (!named_fc) {
-                       _BT_LOGE_NODE(node,
-                               "Stream class has a `id` attribute, "
-                               "but trace's packet header field class has no `stream_id` field.");
-                       goto error;
-               }
-
-               if (named_fc->fc->type != CTF_FIELD_CLASS_TYPE_INT &&
-                               named_fc->fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
-                       _BT_LOGE_NODE(node,
-                               "Stream class has a `id` attribute, "
-                               "but trace's packet header field class's `stream_id` field is not an integer field class.");
-                       goto error;
-               }
-       } else {
-               /* Allow only _one_ ID-less stream */
-               if (ctx->ctf_tc->stream_classes->len != 0) {
-                       _BT_LOGE_NODE(node,
-                               "Missing `id` attribute in stream class as there's more than one stream class in the trace.");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               /* Automatic ID: 0 */
-               stream_class->id = 0;
-       }
-
-       /*
-        * Make sure that this stream class's ID is currently unique in
-        * the trace.
-        */
-       if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc,
-                       stream_class->id)) {
-               _BT_LOGE_NODE(node,
-                       "Duplicate stream class (same ID): id=%" PRId64,
-                       stream_class->id);
-               ret = -EINVAL;
-               goto error;
-       }
-
-       g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class);
-       stream_class = NULL;
-       goto end;
-
-error:
-       ctf_stream_class_destroy(stream_class);
-       stream_class = NULL;
-
-end:
-       return ret;
-}
-
-static
-int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
-{
-       int ret = 0;
-       char *left = NULL;
-       uint64_t val;
-
-       switch (node->type) {
-       case NODE_TYPEDEF:
-               ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
-                       &node->u.field_class_def.field_class_declarators);
-               if (ret) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot add field class found in trace (`trace` block).");
-                       goto error;
-               }
-               break;
-       case NODE_TYPEALIAS:
-               ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
-                       node->u.field_class_alias.alias);
-               if (ret) {
-                       _BT_LOGE_NODE(node,
-                               "Cannot add field class alias found in trace (`trace` block).");
-                       goto error;
-               }
-               break;
-       case NODE_CTF_EXPRESSION:
-       {
-               left = concatenate_unary_strings(&node->u.ctf_expression.left);
-               if (!left) {
-                       _BT_LOGE_NODE(node, "Cannot concatenate unary strings.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (!strcmp(left, "major")) {
-                       if (_IS_SET(set, _TRACE_MAJOR_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "major", "trace");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               &val);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Unexpected unary expression for trace's `major` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (val != 1) {
-                               _BT_LOGE_NODE(node,
-                                       "Invalid trace's `minor` attribute: expecting 1.");
-                               goto error;
-                       }
-
-                       ctx->ctf_tc->major = val;
-                       _SET(set, _TRACE_MAJOR_SET);
-               } else if (!strcmp(left, "minor")) {
-                       if (_IS_SET(set, _TRACE_MINOR_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "minor", "trace");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
-                               &val);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Unexpected unary expression for trace's `minor` attribute.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (val != 8) {
-                               _BT_LOGE_NODE(node,
-                                       "Invalid trace's `minor` attribute: expecting 8.");
-                               goto error;
-                       }
-
-                       ctx->ctf_tc->minor = val;
-                       _SET(set, _TRACE_MINOR_SET);
-               } else if (!strcmp(left, "uuid")) {
-                       if (_IS_SET(set, _TRACE_UUID_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "uuid", "trace");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = get_unary_uuid(&node->u.ctf_expression.right,
-                               ctx->ctf_tc->uuid);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Invalid trace's `uuid` attribute.");
-                               goto error;
-                       }
-
-                       ctx->ctf_tc->is_uuid_set = true;
-                       _SET(set, _TRACE_UUID_SET);
-               } else if (!strcmp(left, "byte_order")) {
-                       /* Default byte order is already known at this stage */
-                       if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) {
-                               _BT_LOGE_DUP_ATTR(node, "byte_order",
-                                       "trace");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       BT_ASSERT(ctx->ctf_tc->default_byte_order != -1);
-                       _SET(set, _TRACE_BYTE_ORDER_SET);
-               } else if (!strcmp(left, "packet.header")) {
-                       if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) {
-                               _BT_LOGE_NODE(node,
-                                       "Duplicate `packet.header` entry in trace.");
-                               ret = -EPERM;
-                               goto error;
-                       }
-
-                       ret = visit_field_class_specifier_list(ctx,
-                               _BT_LIST_FIRST_ENTRY(
-                                       &node->u.ctf_expression.right,
-                                       struct ctf_node, siblings),
-                               &ctx->ctf_tc->packet_header_fc);
-                       if (ret) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot create trace's packet header field class.");
-                               goto error;
-                       }
-
-                       BT_ASSERT(ctx->ctf_tc->packet_header_fc);
-                       _SET(set, _TRACE_PACKET_HEADER_SET);
-               } else {
-                       _BT_LOGW_NODE(node,
-                               "Unknown attribute in stream class: "
-                               "attr-name=\"%s\"", left);
-               }
-
-               g_free(left);
-               left = NULL;
-               break;
-       }
-       default:
-               _BT_LOGE_NODE(node, "Unknown expression in trace.");
-               ret = -EINVAL;
-               goto error;
-       }
-
-       return 0;
-
-error:
-       g_free(left);
-       return ret;
-}
-
-static
-int visit_trace_decl(struct ctx *ctx, struct ctf_node *node)
-{
-       int ret = 0;
-       int set = 0;
-       struct ctf_node *iter;
-       struct bt_list_head *decl_list = &node->u.trace.declaration_list;
-
-       if (node->visited) {
-               goto end;
-       }
-
-       node->visited = TRUE;
-
-       if (ctx->is_trace_visited) {
-               _BT_LOGE_NODE(node, "Duplicate trace (`trace` block).");
-               ret = -EEXIST;
-               goto error;
-       }
-
-       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
-
-       bt_list_for_each_entry(iter, decl_list, siblings) {
-               ret = visit_trace_decl_entry(ctx, iter, &set);
-               if (ret) {
-                       _BT_LOGE_NODE(iter, "Cannot visit trace's entry (`trace` block): "
-                               "ret=%d", ret);
-                       ctx_pop_scope(ctx);
-                       goto error;
-               }
-       }
-
-       ctx_pop_scope(ctx);
-
-       if (!_IS_SET(&set, _TRACE_MAJOR_SET)) {
-               _BT_LOGE_NODE(node,
-                       "Missing `major` attribute in trace (`trace` block).");
-               ret = -EPERM;
-               goto error;
-       }
-
-       if (!_IS_SET(&set, _TRACE_MINOR_SET)) {
-               _BT_LOGE_NODE(node,
-                       "Missing `minor` attribute in trace (`trace` block).");
-               ret = -EPERM;
-               goto error;
-       }
-
-       if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
-               _BT_LOGE_NODE(node,
-                       "Missing `byte_order` attribute in trace (`trace` block).");
-               ret = -EPERM;
-               goto error;
-       }
-
-       ctx->is_trace_visited = true;
-
-end:
-       return 0;
-
-error:
-       return ret;
-}
-
-static
-int visit_env(struct ctx *ctx, struct ctf_node *node)
-{
-       int ret = 0;
-       char *left = NULL;
-       struct ctf_node *entry_node;
-       struct bt_list_head *decl_list = &node->u.env.declaration_list;
-
-       if (node->visited) {
-               goto end;
-       }
-
-       node->visited = TRUE;
-
-       bt_list_for_each_entry(entry_node, decl_list, siblings) {
-               struct bt_list_head *right_head =
-                       &entry_node->u.ctf_expression.right;
-
-               if (entry_node->type != NODE_CTF_EXPRESSION) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Wrong expression in environment entry: "
-                               "node-type=%d", entry_node->type);
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               left = concatenate_unary_strings(
-                       &entry_node->u.ctf_expression.left);
-               if (!left) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Cannot get environment entry's name.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (is_unary_string(right_head)) {
-                       char *right = concatenate_unary_strings(right_head);
-
-                       if (!right) {
-                               _BT_LOGE_NODE(entry_node,
-                                       "Unexpected unary expression for environment entry's value: "
-                                       "name=\"%s\"", left);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (strcmp(left, "tracer_name") == 0) {
-                               if (strncmp(right, "lttng", 5) == 0) {
-                                       BT_LOGI("Detected LTTng trace from `%s` environment value: "
-                                               "tracer-name=\"%s\"",
-                                               left, right);
-                                       ctx->is_lttng = true;
-                               }
-                       }
-
-                       ctf_trace_class_append_env_entry(ctx->ctf_tc,
-                               left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR,
-                               right, 0);
-                       g_free(right);
-               } else if (is_unary_unsigned(right_head) ||
-                               is_unary_signed(right_head)) {
-                       int64_t v;
-
-                       if (is_unary_unsigned(right_head)) {
-                               ret = get_unary_unsigned(right_head,
-                                       (uint64_t *) &v);
-                       } else {
-                               ret = get_unary_signed(right_head, &v);
-                       }
-                       if (ret) {
-                               _BT_LOGE_NODE(entry_node,
-                                       "Unexpected unary expression for environment entry's value: "
-                                       "name=\"%s\"", left);
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       ctf_trace_class_append_env_entry(ctx->ctf_tc,
-                               left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT,
-                               NULL, v);
-               } else {
-                       _BT_LOGW_NODE(entry_node,
-                               "Environment entry has unknown type: "
-                               "name=\"%s\"", left);
-               }
-
-               g_free(left);
-               left = NULL;
-       }
-
-end:
-       return 0;
-
-error:
-       g_free(left);
-       return ret;
-}
-
-static
-int set_trace_byte_order(struct ctx *ctx, struct ctf_node *trace_node)
-{
-       int ret = 0;
-       int set = 0;
-       char *left = NULL;
-       struct ctf_node *node;
-       struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list;
-
-       bt_list_for_each_entry(node, decl_list, siblings) {
-               if (node->type == NODE_CTF_EXPRESSION) {
-                       struct ctf_node *right_node;
-
-                       left = concatenate_unary_strings(
-                               &node->u.ctf_expression.left);
-                       if (!left) {
-                               _BT_LOGE_NODE(node,
-                                       "Cannot concatenate unary strings.");
-                               ret = -EINVAL;
-                               goto error;
-                       }
-
-                       if (!strcmp(left, "byte_order")) {
-                               enum ctf_byte_order bo;
-
-                               if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
-                                       _BT_LOGE_DUP_ATTR(node, "byte_order",
-                                               "trace");
-                                       ret = -EPERM;
-                                       goto error;
-                               }
-
-                               _SET(&set, _TRACE_BYTE_ORDER_SET);
-                               right_node = _BT_LIST_FIRST_ENTRY(
-                                       &node->u.ctf_expression.right,
-                                       struct ctf_node, siblings);
-                               bo = byte_order_from_unary_expr(right_node);
-                               if (bo == -1) {
-                                       _BT_LOGE_NODE(node,
-                                               "Invalid `byte_order` attribute in trace (`trace` block): "
-                                               "expecting `le`, `be`, or `network`.");
-                                       ret = -EINVAL;
-                                       goto error;
-                               } else if (bo == CTF_BYTE_ORDER_DEFAULT) {
-                                       _BT_LOGE_NODE(node,
-                                               "Invalid `byte_order` attribute in trace (`trace` block): "
-                                               "cannot be set to `native` here.");
-                                       ret = -EPERM;
-                                       goto error;
-                               }
-
-                               ctx->ctf_tc->default_byte_order = bo;
-                       }
-
-                       g_free(left);
-                       left = NULL;
-               }
-       }
-
-       if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
-               _BT_LOGE_NODE(trace_node,
-                       "Missing `byte_order` attribute in trace (`trace` block).");
-               ret = -EINVAL;
-               goto error;
-       }
-
-       return 0;
-
-error:
-       g_free(left);
-       return ret;
-}
-
-static
-int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
-       struct ctf_clock_class *clock, int *set, int64_t *offset_seconds,
-       uint64_t *offset_cycles)
-{
-       int ret = 0;
-       char *left = NULL;
-
-       if (entry_node->type != NODE_CTF_EXPRESSION) {
-               _BT_LOGE_NODE(entry_node,
-                       "Unexpected node type: node-type=%d",
-                       entry_node->type);
-               ret = -EPERM;
-               goto error;
-       }
-
-       left = concatenate_unary_strings(&entry_node->u.ctf_expression.left);
-       if (!left) {
-               _BT_LOGE_NODE(entry_node, "Cannot concatenate unary strings.");
-               ret = -EINVAL;
-               goto error;
-       }
-
-       if (!strcmp(left, "name")) {
-               char *right;
-
-               if (_IS_SET(set, _CLOCK_NAME_SET)) {
-                       _BT_LOGE_DUP_ATTR(entry_node, "name", "clock class");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               right = concatenate_unary_strings(
-                       &entry_node->u.ctf_expression.right);
-               if (!right) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Unexpected unary expression for clock class's `name` attribute.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               g_string_assign(clock->name, right);
-               g_free(right);
-               _SET(set, _CLOCK_NAME_SET);
-       } else if (!strcmp(left, "uuid")) {
-               uint8_t uuid[BABELTRACE_UUID_LEN];
-
-               if (_IS_SET(set, _CLOCK_UUID_SET)) {
-                       _BT_LOGE_DUP_ATTR(entry_node, "uuid", "clock class");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               ret = get_unary_uuid(&entry_node->u.ctf_expression.right, uuid);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Invalid clock class's `uuid` attribute.");
-                       goto error;
-               }
-
-               clock->has_uuid = true;
-               memcpy(&clock->uuid[0], uuid, 16);
-               _SET(set, _CLOCK_UUID_SET);
-       } else if (!strcmp(left, "description")) {
-               char *right;
-
-               if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) {
-                       _BT_LOGE_DUP_ATTR(entry_node, "description",
-                               "clock class");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               right = concatenate_unary_strings(
-                       &entry_node->u.ctf_expression.right);
-               if (!right) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Unexpected unary expression for clock class's `description` attribute.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               g_string_assign(clock->description, right);
-               g_free(right);
-               _SET(set, _CLOCK_DESCRIPTION_SET);
-       } else if (!strcmp(left, "freq")) {
-               uint64_t freq = UINT64_C(-1);
-
-               if (_IS_SET(set, _CLOCK_FREQ_SET)) {
-                       _BT_LOGE_DUP_ATTR(entry_node, "freq", "clock class");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               ret = get_unary_unsigned(
-                       &entry_node->u.ctf_expression.right, &freq);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Unexpected unary expression for clock class's `freq` attribute.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               if (freq == UINT64_C(-1) || freq == 0) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Invalid clock class frequency: freq=%" PRIu64,
-                               freq);
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               clock->frequency = freq;
-               _SET(set, _CLOCK_FREQ_SET);
-       } else if (!strcmp(left, "precision")) {
-               uint64_t precision;
-
-               if (_IS_SET(set, _CLOCK_PRECISION_SET)) {
-                       _BT_LOGE_DUP_ATTR(entry_node, "precision",
-                               "clock class");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               ret = get_unary_unsigned(
-                       &entry_node->u.ctf_expression.right, &precision);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Unexpected unary expression for clock class's `precision` attribute.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               clock->precision = precision;
-               _SET(set, _CLOCK_PRECISION_SET);
-       } else if (!strcmp(left, "offset_s")) {
-               if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
-                       _BT_LOGE_DUP_ATTR(entry_node, "offset_s",
-                               "clock class");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               ret = get_unary_signed(
-                       &entry_node->u.ctf_expression.right, offset_seconds);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Unexpected unary expression for clock class's `offset_s` attribute.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               _SET(set, _CLOCK_OFFSET_S_SET);
-       } else if (!strcmp(left, "offset")) {
-               if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
-                       _BT_LOGE_DUP_ATTR(entry_node, "offset", "clock class");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               ret = get_unary_unsigned(
-                       &entry_node->u.ctf_expression.right, offset_cycles);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Unexpected unary expression for clock class's `offset` attribute.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               _SET(set, _CLOCK_OFFSET_SET);
-       } else if (!strcmp(left, "absolute")) {
-               struct ctf_node *right;
-
-               if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) {
-                       _BT_LOGE_DUP_ATTR(entry_node, "absolute",
-                               "clock class");
-                       ret = -EPERM;
-                       goto error;
-               }
-
-               right = _BT_LIST_FIRST_ENTRY(
-                       &entry_node->u.ctf_expression.right,
-                       struct ctf_node, siblings);
-               ret = get_boolean(right);
-               if (ret < 0) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Unexpected unary expression for clock class's `absolute` attribute.");
-                       ret = -EINVAL;
-                       goto error;
-               }
-
-               clock->is_absolute = ret;
-               _SET(set, _CLOCK_ABSOLUTE_SET);
-       } else {
-               _BT_LOGW_NODE(entry_node,
-                       "Unknown attribute in clock class: attr-name=\"%s\"",
-                       left);
-       }
-
-       g_free(left);
-       left = NULL;
-       return 0;
-
-error:
-       g_free(left);
-       return ret;
-}
-
-static inline
-uint64_t cycles_from_ns(uint64_t frequency, uint64_t ns)
-{
-       uint64_t cycles;
-
-       /* 1GHz */
-       if (frequency == UINT64_C(1000000000)) {
-               cycles = ns;
-       } else {
-               cycles = (uint64_t) (((double) ns * (double) frequency) / 1e9);
-       }
-
-       return cycles;
-}
-
-static
-void calibrate_clock_class_offsets(int64_t *offset_seconds,
-               uint64_t *offset_cycles, uint64_t freq)
-{
-       if (*offset_cycles >= freq) {
-               const uint64_t s_in_offset_cycles = *offset_cycles / freq;
-
-               *offset_seconds += (int64_t) s_in_offset_cycles;
-               *offset_cycles -= (s_in_offset_cycles * freq);
-       }
-}
-
-static
-void apply_clock_class_offset(struct ctx *ctx,
-               struct ctf_clock_class *clock)
-{
-       uint64_t freq;
-       int64_t offset_s_to_apply = ctx->decoder_config.clock_class_offset_s;
-       uint64_t offset_ns_to_apply;
-       int64_t cur_offset_s;
-       uint64_t cur_offset_cycles;
-
-       if (ctx->decoder_config.clock_class_offset_s == 0 &&
-                       ctx->decoder_config.clock_class_offset_ns == 0) {
-               goto end;
-       }
-
-       /* Transfer nanoseconds to seconds as much as possible */
-       if (ctx->decoder_config.clock_class_offset_ns < 0) {
-               const int64_t abs_ns = -ctx->decoder_config.clock_class_offset_ns;
-               const int64_t abs_extra_s = abs_ns / INT64_C(1000000000) + 1;
-               const int64_t extra_s = -abs_extra_s;
-               const int64_t offset_ns = ctx->decoder_config.clock_class_offset_ns -
-                       (extra_s * INT64_C(1000000000));
-
-               BT_ASSERT(offset_ns > 0);
-               offset_ns_to_apply = (uint64_t) offset_ns;
-               offset_s_to_apply += extra_s;
-       } else {
-               const int64_t extra_s = ctx->decoder_config.clock_class_offset_ns /
-                       INT64_C(1000000000);
-               const int64_t offset_ns = ctx->decoder_config.clock_class_offset_ns -
-                       (extra_s * INT64_C(1000000000));
-
-               BT_ASSERT(offset_ns >= 0);
-               offset_ns_to_apply = (uint64_t) offset_ns;
-               offset_s_to_apply += extra_s;
-       }
-
-       freq = clock->frequency;
-       cur_offset_s = clock->offset_seconds;
-       cur_offset_cycles = clock->offset_cycles;
-
-       /* Apply offsets */
-       cur_offset_s += offset_s_to_apply;
-       cur_offset_cycles += cycles_from_ns(freq, offset_ns_to_apply);
-
-       /*
-        * Recalibrate offsets because the part in cycles can be greater
-        * than the frequency at this point.
-        */
-       calibrate_clock_class_offsets(&cur_offset_s, &cur_offset_cycles, freq);
-
-       /* Set final offsets */
-       clock->offset_seconds = cur_offset_s;
-       clock->offset_cycles = cur_offset_cycles;
-
-end:
-       return;
-}
-
-static
-int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
-{
-       int ret = 0;
-       int set = 0;
-       struct ctf_clock_class *clock;
-       struct ctf_node *entry_node;
-       struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list;
-       const char *clock_class_name;
-       int64_t offset_seconds = 0;
-       uint64_t offset_cycles = 0;
-       uint64_t freq;
-
-       if (clock_node->visited) {
-               return 0;
-       }
-
-       clock_node->visited = TRUE;
-
-       /* CTF 1.8's default frequency for a clock class is 1 GHz */
-       clock = ctf_clock_class_create();
-       if (!clock) {
-               _BT_LOGE_NODE(clock_node,
-                       "Cannot create default clock class.");
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       bt_list_for_each_entry(entry_node, decl_list, siblings) {
-               ret = visit_clock_decl_entry(ctx, entry_node, clock, &set,
-                       &offset_seconds, &offset_cycles);
-               if (ret) {
-                       _BT_LOGE_NODE(entry_node,
-                               "Cannot visit clock class's entry: ret=%d",
-                               ret);
-                       goto end;
-               }
-       }
-
-       if (!_IS_SET(&set, _CLOCK_NAME_SET)) {
-               _BT_LOGE_NODE(clock_node,
-                       "Missing `name` attribute in clock class.");
-               ret = -EPERM;
-               goto end;
-       }
-
-       clock_class_name = clock->name->str;
-       BT_ASSERT(clock_class_name);
-       if (ctx->is_lttng && strcmp(clock_class_name, "monotonic") == 0) {
-               /*
-                * Old versions of LTTng forgot to set its clock class
-                * as absolute, even if it is. This is important because
-                * it's a condition to be able to sort messages
-                * from different sources.
-                */
-               clock->is_absolute = true;
-       }
-
-       /*
-        * Adjust offsets so that the part in cycles is less than the
-        * frequency (move to the part in seconds).
-        */
-       freq = clock->frequency;
-       calibrate_clock_class_offsets(&offset_seconds, &offset_cycles, freq);
-       BT_ASSERT(offset_cycles < clock->frequency);
-       clock->offset_seconds = offset_seconds;
-       clock->offset_cycles = offset_cycles;
-       apply_clock_class_offset(ctx, clock);
-       g_ptr_array_add(ctx->ctf_tc->clock_classes, clock);
-       clock = NULL;
-
-end:
-       if (clock) {
-               ctf_clock_class_destroy(clock);
-       }
-
-       return ret;
-}
-
-static
-int visit_root_decl(struct ctx *ctx, struct ctf_node *root_decl_node)
-{
-       int ret = 0;
-
-       if (root_decl_node->visited) {
-               goto end;
-       }
-
-       root_decl_node->visited = TRUE;
-
-       switch (root_decl_node->type) {
-       case NODE_TYPEDEF:
-               ret = visit_field_class_def(ctx,
-                       root_decl_node->u.field_class_def.field_class_specifier_list,
-                       &root_decl_node->u.field_class_def.field_class_declarators);
-               if (ret) {
-                       _BT_LOGE_NODE(root_decl_node,
-                               "Cannot add field class found in root scope.");
-                       goto end;
-               }
-               break;
-       case NODE_TYPEALIAS:
-               ret = visit_field_class_alias(ctx, root_decl_node->u.field_class_alias.target,
-                       root_decl_node->u.field_class_alias.alias);
-               if (ret) {
-                       _BT_LOGE_NODE(root_decl_node,
-                               "Cannot add field class alias found in root scope.");
-                       goto end;
-               }
-               break;
-       case NODE_TYPE_SPECIFIER_LIST:
-       {
-               struct ctf_field_class *decl = NULL;
-
-               /*
-                * Just add the field class specifier to the root
-                * declaration scope. Put local reference.
-                */
-               ret = visit_field_class_specifier_list(ctx, root_decl_node, &decl);
-               if (ret) {
-                       _BT_LOGE_NODE(root_decl_node,
-                               "Cannot visit root scope's field class: "
-                               "ret=%d", ret);
-                       BT_ASSERT(!decl);
-                       goto end;
-               }
-
-               ctf_field_class_destroy(decl);
-               decl = NULL;
-               break;
-       }
-       default:
-               _BT_LOGE_NODE(root_decl_node,
-                       "Unexpected node type: node-type=%d",
-                       root_decl_node->type);
-               ret = -EPERM;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(
-               bt_self_component_source *self_comp,
-               const struct ctf_metadata_decoder_config *decoder_config)
-{
-       struct ctx *ctx = NULL;
-
-       /* Create visitor's context */
-       ctx = ctx_create(self_comp, decoder_config);
-       if (!ctx) {
-               BT_LOGE_STR("Cannot create visitor's context.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ctx_destroy(ctx);
-       ctx = NULL;
-
-end:
-       return (void *) ctx;
-}
-
-BT_HIDDEN
-void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor)
-{
-       ctx_destroy((void *) visitor);
-}
-
-BT_HIDDEN
-bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(
-               struct ctf_visitor_generate_ir *visitor)
-{
-       struct ctx *ctx = (void *) visitor;
-
-       BT_ASSERT(ctx);
-
-       if (ctx->trace_class) {
-               bt_trace_class_get_ref(ctx->trace_class);
-       }
-
-       return ctx->trace_class;
-}
-
-BT_HIDDEN
-struct ctf_trace_class *ctf_visitor_generate_ir_borrow_ctf_trace_class(
-               struct ctf_visitor_generate_ir *visitor)
-{
-       struct ctx *ctx = (void *) visitor;
-
-       BT_ASSERT(ctx);
-       BT_ASSERT(ctx->ctf_tc);
-       return ctx->ctf_tc;
-}
-
-BT_HIDDEN
-int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
-               struct ctf_node *node)
-{
-       int ret = 0;
-       struct ctx *ctx = (void *) visitor;
-
-       BT_LOGI_STR("Visiting metadata's AST to generate CTF IR objects.");
-
-       switch (node->type) {
-       case NODE_ROOT:
-       {
-               struct ctf_node *iter;
-               bool got_trace_decl = false;
-
-               /*
-                * The first thing we need is the native byte order of
-                * the trace block, because early class aliases can have
-                * a `byte_order` attribute set to `native`. If we don't
-                * have the native byte order yet, and we don't have any
-                * trace block yet, then fail with EINCOMPLETE.
-                */
-               if (ctx->ctf_tc->default_byte_order == -1) {
-                       bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
-                               if (got_trace_decl) {
-                                       _BT_LOGE_NODE(node,
-                                               "Duplicate trace (`trace` block).");
-                                       ret = -1;
-                                       goto end;
-                               }
-
-                               ret = set_trace_byte_order(ctx, iter);
-                               if (ret) {
-                                       _BT_LOGE_NODE(node,
-                                               "Cannot set trace's native byte order: "
-                                               "ret=%d", ret);
-                                       goto end;
-                               }
-
-                               got_trace_decl = true;
-                       }
-
-                       if (!got_trace_decl) {
-                               BT_LOGD_STR("Incomplete AST: need trace (`trace` block).");
-                               ret = -EINCOMPLETE;
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_LITTLE ||
-                       ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_BIG);
-               BT_ASSERT(ctx->current_scope &&
-                               ctx->current_scope->parent_scope == NULL);
-
-               /* Environment */
-               bt_list_for_each_entry(iter, &node->u.root.env, siblings) {
-                       ret = visit_env(ctx, iter);
-                       if (ret) {
-                               _BT_LOGE_NODE(iter,
-                                       "Cannot visit trace's environment (`env` block) entry: "
-                                       "ret=%d", ret);
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(ctx->current_scope &&
-                       ctx->current_scope->parent_scope == NULL);
-
-               /*
-                * Visit clock blocks.
-                */
-               bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
-                       ret = visit_clock_decl(ctx, iter);
-                       if (ret) {
-                               _BT_LOGE_NODE(iter,
-                                       "Cannot visit clock class: ret=%d",
-                                       ret);
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(ctx->current_scope &&
-                       ctx->current_scope->parent_scope == NULL);
-
-               /*
-                * Visit root declarations next, as they can be used by any
-                * following entity.
-                */
-               bt_list_for_each_entry(iter, &node->u.root.declaration_list,
-                               siblings) {
-                       ret = visit_root_decl(ctx, iter);
-                       if (ret) {
-                               _BT_LOGE_NODE(iter,
-                                       "Cannot visit root entry: ret=%d",
-                                       ret);
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(ctx->current_scope &&
-                       ctx->current_scope->parent_scope == NULL);
-
-               /* Callsite blocks are not supported */
-               bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
-                       _BT_LOGW_NODE(iter,
-                               "\"callsite\" blocks are not supported as of this version.");
-               }
-
-               BT_ASSERT(ctx->current_scope &&
-                       ctx->current_scope->parent_scope == NULL);
-
-               /* Trace */
-               bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
-                       ret = visit_trace_decl(ctx, iter);
-                       if (ret) {
-                               _BT_LOGE_NODE(iter,
-                                       "Cannot visit trace (`trace` block): "
-                                       "ret=%d", ret);
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(ctx->current_scope &&
-                       ctx->current_scope->parent_scope == NULL);
-
-               /* Streams */
-               bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
-                       ret = visit_stream_decl(ctx, iter);
-                       if (ret) {
-                               _BT_LOGE_NODE(iter,
-                                       "Cannot visit stream class: ret=%d",
-                                       ret);
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(ctx->current_scope &&
-                       ctx->current_scope->parent_scope == NULL);
-
-               /* Events */
-               bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
-                       ret = visit_event_decl(ctx, iter);
-                       if (ret) {
-                               _BT_LOGE_NODE(iter,
-                                       "Cannot visit event class: ret=%d",
-                                       ret);
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(ctx->current_scope &&
-                       ctx->current_scope->parent_scope == NULL);
-               break;
-       }
-       default:
-               _BT_LOGE_NODE(node,
-                       "Unexpected node type: node-type=%d",
-                       node->type);
-               ret = -EINVAL;
-               goto end;
-       }
-
-       /* Update default clock classes */
-       ret = ctf_trace_class_update_default_clock_classes(ctx->ctf_tc);
-       if (ret) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       /* Update trace class meanings */
-       ret = ctf_trace_class_update_meanings(ctx->ctf_tc);
-       if (ret) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       /* Update stream class configuration */
-       ret = ctf_trace_class_update_stream_class_config(ctx->ctf_tc);
-       if (ret) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       /* Update text arrays and sequences */
-       ret = ctf_trace_class_update_text_array_sequence(ctx->ctf_tc);
-       if (ret) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       /* Resolve sequence lengths and variant tags */
-       ret = ctf_trace_class_resolve_field_classes(ctx->ctf_tc);
-       if (ret) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       if (ctx->trace_class) {
-               /*
-                * Update "in IR" for field classes.
-                *
-                * If we have no IR trace class, then we'll have no way
-                * to create IR fields anyway, so we leave all the
-                * `in_ir` members false.
-                */
-               ret = ctf_trace_class_update_in_ir(ctx->ctf_tc);
-               if (ret) {
-                       ret = -EINVAL;
-                       goto end;
-               }
-       }
-
-       /* Update saved value indexes */
-       ret = ctf_trace_class_update_value_storing_indexes(ctx->ctf_tc);
-       if (ret) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       /* Validate what we have so far */
-       ret = ctf_trace_class_validate(ctx->ctf_tc);
-       if (ret) {
-               ret = -EINVAL;
-               goto end;
-       }
-
-       /*
-        * If there are fields which are not related to the CTF format
-        * itself in the packet header and in event header field
-        * classes, warn about it because they are never translated.
-        */
-       ctf_trace_class_warn_meaningless_header_fields(ctx->ctf_tc);
-
-       if (ctx->trace_class) {
-               /* Copy new CTF metadata -> new IR metadata */
-               ret = ctf_trace_class_translate(ctx->self_comp,
-                               ctx->trace_class, ctx->ctf_tc);
-               if (ret) {
-                       ret = -EINVAL;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/visitor-parent-links.c b/plugins/ctf/common/metadata/visitor-parent-links.c
deleted file mode 100644 (file)
index c163dc1..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * ctf-visitor-parent-links.c
- *
- * Common Trace Format Metadata Parent Link Creator.
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-PARENT-LINKS-VISITOR"
-#include "logging.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/list-internal.h>
-#include "scanner.h"
-#include "parser.h"
-#include "ast.h"
-
-static
-int ctf_visitor_unary_expression(int depth, struct ctf_node *node)
-{
-       int ret = 0;
-
-       switch (node->u.unary_expression.link) {
-       case UNARY_LINK_UNKNOWN:
-       case UNARY_DOTLINK:
-       case UNARY_ARROWLINK:
-       case UNARY_DOTDOTDOT:
-               break;
-       default:
-               _BT_LOGE_LINENO(node->lineno,
-                       "Unknown expression link type: type=%d\n",
-                       node->u.unary_expression.link);
-               return -EINVAL;
-       }
-
-       switch (node->u.unary_expression.type) {
-       case UNARY_STRING:
-       case UNARY_SIGNED_CONSTANT:
-       case UNARY_UNSIGNED_CONSTANT:
-               break;
-       case UNARY_SBRAC:
-               node->u.unary_expression.u.sbrac_exp->parent = node;
-               ret = ctf_visitor_unary_expression(depth + 1,
-                       node->u.unary_expression.u.sbrac_exp);
-               if (ret)
-                       return ret;
-               break;
-
-       case UNARY_UNKNOWN:
-       default:
-               _BT_LOGE_LINENO(node->lineno,
-                       "Unknown expression link type: type=%d\n",
-                       node->u.unary_expression.link);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static
-int ctf_visitor_type_specifier(int depth, struct ctf_node *node)
-{
-       int ret;
-
-       switch (node->u.field_class_specifier.type) {
-       case TYPESPEC_VOID:
-       case TYPESPEC_CHAR:
-       case TYPESPEC_SHORT:
-       case TYPESPEC_INT:
-       case TYPESPEC_LONG:
-       case TYPESPEC_FLOAT:
-       case TYPESPEC_DOUBLE:
-       case TYPESPEC_SIGNED:
-       case TYPESPEC_UNSIGNED:
-       case TYPESPEC_BOOL:
-       case TYPESPEC_COMPLEX:
-       case TYPESPEC_IMAGINARY:
-       case TYPESPEC_CONST:
-       case TYPESPEC_ID_TYPE:
-               break;
-       case TYPESPEC_FLOATING_POINT:
-       case TYPESPEC_INTEGER:
-       case TYPESPEC_STRING:
-       case TYPESPEC_STRUCT:
-       case TYPESPEC_VARIANT:
-       case TYPESPEC_ENUM:
-               node->u.field_class_specifier.node->parent = node;
-               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_specifier.node);
-               if (ret)
-                       return ret;
-               break;
-
-       case TYPESPEC_UNKNOWN:
-       default:
-               _BT_LOGE_LINENO(node->lineno,
-                       "Unknown type specifier: type=%d\n",
-                       node->u.field_class_specifier.type);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static
-int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node)
-{
-       int ret = 0;
-       struct ctf_node *iter;
-
-       depth++;
-
-       bt_list_for_each_entry(iter, &node->u.field_class_declarator.pointers,
-                               siblings) {
-               iter->parent = node;
-               ret = ctf_visitor_parent_links(depth + 1, iter);
-               if (ret)
-                       return ret;
-       }
-
-       switch (node->u.field_class_declarator.type) {
-       case TYPEDEC_ID:
-               break;
-       case TYPEDEC_NESTED:
-               if (node->u.field_class_declarator.u.nested.field_class_declarator) {
-                       node->u.field_class_declarator.u.nested.field_class_declarator->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1,
-                               node->u.field_class_declarator.u.nested.field_class_declarator);
-                       if (ret)
-                               return ret;
-               }
-               if (!node->u.field_class_declarator.u.nested.abstract_array) {
-                       bt_list_for_each_entry(iter, &node->u.field_class_declarator.u.nested.length,
-                                               siblings) {
-                               iter->parent = node;
-                               ret = ctf_visitor_parent_links(depth + 1, iter);
-                               if (ret)
-                                       return ret;
-                       }
-               }
-               if (node->u.field_class_declarator.bitfield_len) {
-                       node->u.field_class_declarator.bitfield_len = node;
-                       ret = ctf_visitor_parent_links(depth + 1,
-                               node->u.field_class_declarator.bitfield_len);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case TYPEDEC_UNKNOWN:
-       default:
-               _BT_LOGE_LINENO(node->lineno,
-                       "Unknown type declarator: type=%d\n",
-                       node->u.field_class_declarator.type);
-               return -EINVAL;
-       }
-       depth--;
-       return 0;
-}
-
-int ctf_visitor_parent_links(int depth, struct ctf_node *node)
-{
-       int ret = 0;
-       struct ctf_node *iter;
-
-       if (node->visited)
-               return 0;
-
-       switch (node->type) {
-       case NODE_ROOT:
-               bt_list_for_each_entry(iter, &node->u.root.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-
-       case NODE_EVENT:
-               bt_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_STREAM:
-               bt_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_ENV:
-               bt_list_for_each_entry(iter, &node->u.env.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_TRACE:
-               bt_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_CLOCK:
-               bt_list_for_each_entry(iter, &node->u.clock.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_CALLSITE:
-               bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-
-       case NODE_CTF_EXPRESSION:
-               depth++;
-               bt_list_for_each_entry(iter, &node->u.ctf_expression.left, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               depth--;
-               break;
-       case NODE_UNARY_EXPRESSION:
-               return ctf_visitor_unary_expression(depth, node);
-
-       case NODE_TYPEDEF:
-               depth++;
-               node->u.field_class_def.field_class_specifier_list->parent = node;
-               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_def.field_class_specifier_list);
-               if (ret)
-                       return ret;
-               bt_list_for_each_entry(iter, &node->u.field_class_def.field_class_declarators, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               depth--;
-               break;
-       case NODE_TYPEALIAS_TARGET:
-               depth++;
-               node->u.field_class_alias_target.field_class_specifier_list->parent = node;
-               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias_target.field_class_specifier_list);
-               if (ret)
-                       return ret;
-               bt_list_for_each_entry(iter, &node->u.field_class_alias_target.field_class_declarators, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               depth--;
-               break;
-       case NODE_TYPEALIAS_ALIAS:
-               depth++;
-               node->u.field_class_alias_name.field_class_specifier_list->parent = node;
-               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias_name.field_class_specifier_list);
-               if (ret)
-                       return ret;
-               bt_list_for_each_entry(iter, &node->u.field_class_alias_name.field_class_declarators, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               depth--;
-               break;
-       case NODE_TYPEALIAS:
-               node->u.field_class_alias.target->parent = node;
-               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias.target);
-               if (ret)
-                       return ret;
-               node->u.field_class_alias.alias->parent = node;
-               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias.alias);
-               if (ret)
-                       return ret;
-               break;
-
-       case NODE_TYPE_SPECIFIER_LIST:
-               bt_list_for_each_entry(iter, &node->u.field_class_specifier_list.head, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-
-       case NODE_TYPE_SPECIFIER:
-               ret = ctf_visitor_type_specifier(depth, node);
-               if (ret)
-                       return ret;
-               break;
-       case NODE_POINTER:
-               break;
-       case NODE_TYPE_DECLARATOR:
-               ret = ctf_visitor_field_class_declarator(depth, node);
-               if (ret)
-                       return ret;
-               break;
-
-       case NODE_FLOATING_POINT:
-               bt_list_for_each_entry(iter, &node->u.floating_point.expressions, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_INTEGER:
-               bt_list_for_each_entry(iter, &node->u.integer.expressions, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_STRING:
-               bt_list_for_each_entry(iter, &node->u.string.expressions, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_ENUMERATOR:
-               bt_list_for_each_entry(iter, &node->u.enumerator.values, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_ENUM:
-               depth++;
-               if (node->u._enum.container_field_class) {
-                       ret = ctf_visitor_parent_links(depth + 1, node->u._enum.container_field_class);
-                       if (ret)
-                               return ret;
-               }
-
-               bt_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               depth--;
-               break;
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               node->u.struct_or_variant_declaration.field_class_specifier_list->parent = node;
-               ret = ctf_visitor_parent_links(depth + 1,
-                       node->u.struct_or_variant_declaration.field_class_specifier_list);
-               if (ret)
-                       return ret;
-               bt_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_VARIANT:
-               bt_list_for_each_entry(iter, &node->u.variant.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_STRUCT:
-               bt_list_for_each_entry(iter, &node->u._struct.declaration_list, siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u._struct.min_align,
-                                       siblings) {
-                       iter->parent = node;
-                       ret = ctf_visitor_parent_links(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-
-       case NODE_UNKNOWN:
-       default:
-               _BT_LOGE_LINENO(node->lineno,
-                       "Unknown node type: type=%d\n", node->type);
-               return -EINVAL;
-       }
-       return ret;
-}
diff --git a/plugins/ctf/common/metadata/visitor-semantic-validator.c b/plugins/ctf/common/metadata/visitor-semantic-validator.c
deleted file mode 100644 (file)
index 0149d61..0000000
+++ /dev/null
@@ -1,1012 +0,0 @@
-/*
- * ctf-visitor-semantic-validator.c
- *
- * Common Trace Format Metadata Semantic Validator.
- *
- * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-METADATA-SEMANTIC-VALIDATOR-VISITOR"
-#include "logging.h"
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <babeltrace2/list-internal.h>
-#include "scanner.h"
-#include "parser.h"
-#include "ast.h"
-
-#define _bt_list_first_entry(ptr, type, member)        \
-       bt_list_entry((ptr)->next, type, member)
-
-static
-int _ctf_visitor_semantic_check(int depth, struct ctf_node *node);
-
-static
-int ctf_visitor_unary_expression(int depth, struct ctf_node *node)
-{
-       struct ctf_node *iter;
-       int is_ctf_exp = 0, is_ctf_exp_left = 0;
-
-       switch (node->parent->type) {
-       case NODE_CTF_EXPRESSION:
-               is_ctf_exp = 1;
-               bt_list_for_each_entry(iter, &node->parent->u.ctf_expression.left,
-                                       siblings) {
-                       if (iter == node) {
-                               is_ctf_exp_left = 1;
-                               /*
-                                * We are a left child of a ctf expression.
-                                * We are only allowed to be a string.
-                                */
-                               if (node->u.unary_expression.type != UNARY_STRING) {
-                                       _BT_LOGE_LINENO(node->lineno,
-                                               "Left child of a CTF expression is only allowed to be a string.");
-                                       goto errperm;
-                               }
-                               break;
-                       }
-               }
-               /* Right child of a ctf expression can be any type of unary exp. */
-               break;                  /* OK */
-       case NODE_TYPE_DECLARATOR:
-               /*
-                * We are the length of a type declarator.
-                */
-               switch (node->u.unary_expression.type) {
-               case UNARY_UNSIGNED_CONSTANT:
-               case UNARY_STRING:
-                       break;
-               default:
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Children of field class declarator and `enum` can only be unsigned numeric constants or references to fields (e.g., `a.b.c`).");
-                       goto errperm;
-               }
-               break;                  /* OK */
-
-       case NODE_STRUCT:
-               /*
-                * We are the size of a struct align attribute.
-                */
-               switch (node->u.unary_expression.type) {
-               case UNARY_UNSIGNED_CONSTANT:
-                       break;
-               default:
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Structure alignment attribute can only be an unsigned numeric constant.");
-                       goto errperm;
-               }
-               break;
-
-       case NODE_ENUMERATOR:
-               /* The enumerator's parent has validated its validity already. */
-               break;                  /* OK */
-
-       case NODE_UNARY_EXPRESSION:
-               /*
-                * We disallow nested unary expressions and "sbrac" unary
-                * expressions.
-                */
-               _BT_LOGE_LINENO(node->lineno,
-                       "Nested unary expressions not allowed (`()` and `[]`).");
-               goto errperm;
-
-       case NODE_ROOT:
-       case NODE_EVENT:
-       case NODE_STREAM:
-       case NODE_ENV:
-       case NODE_TRACE:
-       case NODE_CLOCK:
-       case NODE_CALLSITE:
-       case NODE_TYPEDEF:
-       case NODE_TYPEALIAS_TARGET:
-       case NODE_TYPEALIAS_ALIAS:
-       case NODE_TYPEALIAS:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_POINTER:
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_ENUM:
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-       case NODE_VARIANT:
-       default:
-               goto errinval;
-       }
-
-       switch (node->u.unary_expression.link) {
-       case UNARY_LINK_UNKNOWN:
-               /* We don't allow empty link except on the first node of the list */
-               if (is_ctf_exp && _bt_list_first_entry(is_ctf_exp_left ?
-                                         &node->parent->u.ctf_expression.left :
-                                         &node->parent->u.ctf_expression.right,
-                                         struct ctf_node,
-                                         siblings) != node) {
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Empty link is not allowed except on first node of unary expression (need to separate nodes with `.` or `->`).");
-                       goto errperm;
-               }
-               break;                  /* OK */
-       case UNARY_DOTLINK:
-       case UNARY_ARROWLINK:
-               /* We only allow -> and . links between children of ctf_expression. */
-               if (node->parent->type != NODE_CTF_EXPRESSION) {
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Links `.` and `->` are only allowed as children of CTF expression.");
-                       goto errperm;
-               }
-               /*
-                * Only strings can be separated linked by . or ->.
-                * This includes "", '' and non-quoted identifiers.
-                */
-               if (node->u.unary_expression.type != UNARY_STRING) {
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Links `.` and `->` are only allowed to separate strings and identifiers.");
-                       goto errperm;
-               }
-               /* We don't allow link on the first node of the list */
-               if (is_ctf_exp && _bt_list_first_entry(is_ctf_exp_left ?
-                                         &node->parent->u.ctf_expression.left :
-                                         &node->parent->u.ctf_expression.right,
-                                         struct ctf_node,
-                                         siblings) == node) {
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Links `.` and `->` are not allowed before first node of the unary expression list.");
-                       goto errperm;
-               }
-               break;
-       case UNARY_DOTDOTDOT:
-               /* We only allow ... link between children of enumerator. */
-               if (node->parent->type != NODE_ENUMERATOR) {
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Link `...` is only allowed within enumerator.");
-                       goto errperm;
-               }
-               /* We don't allow link on the first node of the list */
-               if (_bt_list_first_entry(&node->parent->u.enumerator.values,
-                                         struct ctf_node,
-                                         siblings) == node) {
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Link `...` is not allowed on the first node of the unary expression list.");
-                       goto errperm;
-               }
-               break;
-       default:
-               _BT_LOGE_LINENO(node->lineno,
-                       "Unknown expression link type: type=%d",
-                       node->u.unary_expression.link);
-               return -EINVAL;
-       }
-       return 0;
-
-errinval:
-       _BT_LOGE_LINENO(node->lineno,
-               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
-               node_type(node), node_type(node->parent));
-       return -EINVAL;         /* Incoherent structure */
-
-errperm:
-       _BT_LOGE_LINENO(node->lineno,
-               "Semantic error: node-type=%s, parent-node-type=%s",
-               node_type(node), node_type(node->parent));
-       return -EPERM;          /* Structure not allowed */
-}
-
-static
-int ctf_visitor_field_class_specifier_list(int depth, struct ctf_node *node)
-{
-       switch (node->parent->type) {
-       case NODE_CTF_EXPRESSION:
-       case NODE_TYPE_DECLARATOR:
-       case NODE_TYPEDEF:
-       case NODE_TYPEALIAS_TARGET:
-       case NODE_TYPEALIAS_ALIAS:
-       case NODE_ENUM:
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-       case NODE_ROOT:
-               break;                  /* OK */
-
-       case NODE_EVENT:
-       case NODE_STREAM:
-       case NODE_ENV:
-       case NODE_TRACE:
-       case NODE_CLOCK:
-       case NODE_CALLSITE:
-       case NODE_UNARY_EXPRESSION:
-       case NODE_TYPEALIAS:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_TYPE_SPECIFIER_LIST:
-       case NODE_POINTER:
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_ENUMERATOR:
-       case NODE_VARIANT:
-       case NODE_STRUCT:
-       default:
-               goto errinval;
-       }
-       return 0;
-errinval:
-       _BT_LOGE_LINENO(node->lineno,
-               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
-               node_type(node), node_type(node->parent));
-       return -EINVAL;         /* Incoherent structure */
-}
-
-static
-int ctf_visitor_field_class_specifier(int depth, struct ctf_node *node)
-{
-       switch (node->parent->type) {
-       case NODE_TYPE_SPECIFIER_LIST:
-               break;                  /* OK */
-
-       case NODE_CTF_EXPRESSION:
-       case NODE_TYPE_DECLARATOR:
-       case NODE_TYPEDEF:
-       case NODE_TYPEALIAS_TARGET:
-       case NODE_TYPEALIAS_ALIAS:
-       case NODE_ENUM:
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-       case NODE_ROOT:
-       case NODE_EVENT:
-       case NODE_STREAM:
-       case NODE_ENV:
-       case NODE_TRACE:
-       case NODE_CLOCK:
-       case NODE_CALLSITE:
-       case NODE_UNARY_EXPRESSION:
-       case NODE_TYPEALIAS:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_POINTER:
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_ENUMERATOR:
-       case NODE_VARIANT:
-       case NODE_STRUCT:
-       default:
-               goto errinval;
-       }
-       return 0;
-errinval:
-       _BT_LOGE_LINENO(node->lineno,
-               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
-               node_type(node), node_type(node->parent));
-       return -EINVAL;         /* Incoherent structure */
-}
-
-static
-int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node)
-{
-       int ret = 0;
-       struct ctf_node *iter;
-
-       depth++;
-
-       switch (node->parent->type) {
-       case NODE_TYPE_DECLARATOR:
-               /*
-                * A nested field class declarator is not allowed to
-                * contain pointers.
-                */
-               if (!bt_list_empty(&node->u.field_class_declarator.pointers))
-                       goto errperm;
-               break;                  /* OK */
-       case NODE_TYPEALIAS_TARGET:
-               break;                  /* OK */
-       case NODE_TYPEALIAS_ALIAS:
-               /*
-                * Only accept alias name containing:
-                * - identifier
-                * - identifier *   (any number of pointers)
-                * NOT accepting alias names containing [] (would otherwise
-                * cause semantic clash for later declarations of
-                * arrays/sequences of elements, where elements could be
-                * arrays/sequences themselves (if allowed in field class alias).
-                * NOT accepting alias with identifier. The declarator should
-                * be either empty or contain pointer(s).
-                */
-               if (node->u.field_class_declarator.type == TYPEDEC_NESTED)
-                       goto errperm;
-               bt_list_for_each_entry(iter, &node->parent->u.field_class_alias_name.field_class_specifier_list->u.field_class_specifier_list.head,
-                                       siblings) {
-                       switch (iter->u.field_class_specifier.type) {
-                       case TYPESPEC_FLOATING_POINT:
-                       case TYPESPEC_INTEGER:
-                       case TYPESPEC_STRING:
-                       case TYPESPEC_STRUCT:
-                       case TYPESPEC_VARIANT:
-                       case TYPESPEC_ENUM:
-                               if (bt_list_empty(&node->u.field_class_declarator.pointers))
-                                       goto errperm;
-                               break;
-                       default:
-                               break;
-                       }
-               }
-               if (node->u.field_class_declarator.type == TYPEDEC_ID &&
-                   node->u.field_class_declarator.u.id != NULL)
-                       goto errperm;
-               break;                  /* OK */
-       case NODE_TYPEDEF:
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               break;                  /* OK */
-
-       case NODE_ROOT:
-       case NODE_EVENT:
-       case NODE_STREAM:
-       case NODE_ENV:
-       case NODE_TRACE:
-       case NODE_CLOCK:
-       case NODE_CALLSITE:
-       case NODE_CTF_EXPRESSION:
-       case NODE_UNARY_EXPRESSION:
-       case NODE_TYPEALIAS:
-       case NODE_TYPE_SPECIFIER:
-       case NODE_POINTER:
-       case NODE_FLOATING_POINT:
-       case NODE_INTEGER:
-       case NODE_STRING:
-       case NODE_ENUMERATOR:
-       case NODE_ENUM:
-       case NODE_VARIANT:
-       case NODE_STRUCT:
-       default:
-               goto errinval;
-       }
-
-       bt_list_for_each_entry(iter, &node->u.field_class_declarator.pointers,
-                               siblings) {
-               ret = _ctf_visitor_semantic_check(depth + 1, iter);
-               if (ret)
-                       return ret;
-       }
-
-       switch (node->u.field_class_declarator.type) {
-       case TYPEDEC_ID:
-               break;
-       case TYPEDEC_NESTED:
-       {
-               if (node->u.field_class_declarator.u.nested.field_class_declarator) {
-                       ret = _ctf_visitor_semantic_check(depth + 1,
-                               node->u.field_class_declarator.u.nested.field_class_declarator);
-                       if (ret)
-                               return ret;
-               }
-               if (!node->u.field_class_declarator.u.nested.abstract_array) {
-                       bt_list_for_each_entry(iter, &node->u.field_class_declarator.u.nested.length,
-                                               siblings) {
-                               if (iter->type != NODE_UNARY_EXPRESSION) {
-                                       _BT_LOGE_LINENO(node->lineno,
-                                               "Expecting unary expression as length: node-type=%s",
-                                               node_type(iter));
-                                       return -EINVAL;
-                               }
-                               ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                               if (ret)
-                                       return ret;
-                       }
-               } else {
-                       if (node->parent->type == NODE_TYPEALIAS_TARGET) {
-                               _BT_LOGE_LINENO(node->lineno,
-                                       "Abstract array declarator not permitted as target of field class alias.");
-                               return -EINVAL;
-                       }
-               }
-               if (node->u.field_class_declarator.bitfield_len) {
-                       ret = _ctf_visitor_semantic_check(depth + 1,
-                               node->u.field_class_declarator.bitfield_len);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       }
-       case TYPEDEC_UNKNOWN:
-       default:
-               _BT_LOGE_LINENO(node->lineno,
-                       "Unknown field class declarator: type=%d",
-                       node->u.field_class_declarator.type);
-               return -EINVAL;
-       }
-       depth--;
-       return 0;
-
-errinval:
-       _BT_LOGE_LINENO(node->lineno,
-               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
-               node_type(node), node_type(node->parent));
-       return -EINVAL;         /* Incoherent structure */
-
-errperm:
-       _BT_LOGE_LINENO(node->lineno,
-               "Semantic error: node-type=%s, parent-node-type=%s",
-               node_type(node), node_type(node->parent));
-       return -EPERM;          /* Structure not allowed */
-}
-
-static
-int _ctf_visitor_semantic_check(int depth, struct ctf_node *node)
-{
-       int ret = 0;
-       struct ctf_node *iter;
-
-       if (node->visited)
-               return 0;
-
-       switch (node->type) {
-       case NODE_ROOT:
-               bt_list_for_each_entry(iter, &node->u.root.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-
-       case NODE_EVENT:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-
-               bt_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_STREAM:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-
-               bt_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_ENV:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-
-               bt_list_for_each_entry(iter, &node->u.env.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_TRACE:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-
-               bt_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_CLOCK:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-
-               bt_list_for_each_entry(iter, &node->u.clock.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_CALLSITE:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-
-               bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-
-       case NODE_CTF_EXPRESSION:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-               case NODE_EVENT:
-               case NODE_STREAM:
-               case NODE_ENV:
-               case NODE_TRACE:
-               case NODE_CLOCK:
-               case NODE_CALLSITE:
-               case NODE_FLOATING_POINT:
-               case NODE_INTEGER:
-               case NODE_STRING:
-                       break;                  /* OK */
-
-               case NODE_CTF_EXPRESSION:
-               case NODE_UNARY_EXPRESSION:
-               case NODE_TYPEDEF:
-               case NODE_TYPEALIAS_TARGET:
-               case NODE_TYPEALIAS_ALIAS:
-               case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               case NODE_TYPEALIAS:
-               case NODE_TYPE_SPECIFIER:
-               case NODE_TYPE_SPECIFIER_LIST:
-               case NODE_POINTER:
-               case NODE_TYPE_DECLARATOR:
-               case NODE_ENUMERATOR:
-               case NODE_ENUM:
-               case NODE_VARIANT:
-               case NODE_STRUCT:
-               default:
-                       goto errinval;
-               }
-
-               depth++;
-               bt_list_for_each_entry(iter, &node->u.ctf_expression.left, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               bt_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               depth--;
-               break;
-       case NODE_UNARY_EXPRESSION:
-               return ctf_visitor_unary_expression(depth, node);
-
-       case NODE_TYPEDEF:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-               case NODE_EVENT:
-               case NODE_STREAM:
-               case NODE_TRACE:
-               case NODE_VARIANT:
-               case NODE_STRUCT:
-                       break;                  /* OK */
-
-               case NODE_CTF_EXPRESSION:
-               case NODE_UNARY_EXPRESSION:
-               case NODE_TYPEDEF:
-               case NODE_TYPEALIAS_TARGET:
-               case NODE_TYPEALIAS_ALIAS:
-               case NODE_TYPEALIAS:
-               case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               case NODE_TYPE_SPECIFIER:
-               case NODE_TYPE_SPECIFIER_LIST:
-               case NODE_POINTER:
-               case NODE_TYPE_DECLARATOR:
-               case NODE_FLOATING_POINT:
-               case NODE_INTEGER:
-               case NODE_STRING:
-               case NODE_ENUMERATOR:
-               case NODE_ENUM:
-               case NODE_CLOCK:
-               case NODE_CALLSITE:
-               case NODE_ENV:
-               default:
-                       goto errinval;
-               }
-
-               depth++;
-               ret = _ctf_visitor_semantic_check(depth + 1,
-                       node->u.field_class_def.field_class_specifier_list);
-               if (ret)
-                       return ret;
-               bt_list_for_each_entry(iter, &node->u.field_class_def.field_class_declarators, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               depth--;
-               break;
-       case NODE_TYPEALIAS_TARGET:
-       {
-               int nr_declarators;
-
-               switch (node->parent->type) {
-               case NODE_TYPEALIAS:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-
-               depth++;
-               ret = _ctf_visitor_semantic_check(depth + 1,
-                       node->u.field_class_alias_target.field_class_specifier_list);
-               if (ret)
-                       return ret;
-               nr_declarators = 0;
-               bt_list_for_each_entry(iter, &node->u.field_class_alias_target.field_class_declarators, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-                       nr_declarators++;
-               }
-               if (nr_declarators > 1) {
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Too many declarators in field class alias's name (maximum is 1): count=%d",
-                               nr_declarators);
-                       return -EINVAL;
-               }
-               depth--;
-               break;
-       }
-       case NODE_TYPEALIAS_ALIAS:
-       {
-               int nr_declarators;
-
-               switch (node->parent->type) {
-               case NODE_TYPEALIAS:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-
-               depth++;
-               ret = _ctf_visitor_semantic_check(depth + 1,
-                       node->u.field_class_alias_name.field_class_specifier_list);
-               if (ret)
-                       return ret;
-               nr_declarators = 0;
-               bt_list_for_each_entry(iter, &node->u.field_class_alias_name.field_class_declarators, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-                       nr_declarators++;
-               }
-               if (nr_declarators > 1) {
-                       _BT_LOGE_LINENO(node->lineno,
-                               "Too many declarators in field class alias's name (maximum is 1): count=%d",
-                               nr_declarators);
-                       return -EINVAL;
-               }
-               depth--;
-               break;
-       }
-       case NODE_TYPEALIAS:
-               switch (node->parent->type) {
-               case NODE_ROOT:
-               case NODE_EVENT:
-               case NODE_STREAM:
-               case NODE_TRACE:
-               case NODE_VARIANT:
-               case NODE_STRUCT:
-                       break;                  /* OK */
-
-               case NODE_CTF_EXPRESSION:
-               case NODE_UNARY_EXPRESSION:
-               case NODE_TYPEDEF:
-               case NODE_TYPEALIAS_TARGET:
-               case NODE_TYPEALIAS_ALIAS:
-               case NODE_TYPEALIAS:
-               case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               case NODE_TYPE_SPECIFIER:
-               case NODE_TYPE_SPECIFIER_LIST:
-               case NODE_POINTER:
-               case NODE_TYPE_DECLARATOR:
-               case NODE_FLOATING_POINT:
-               case NODE_INTEGER:
-               case NODE_STRING:
-               case NODE_ENUMERATOR:
-               case NODE_ENUM:
-               case NODE_CLOCK:
-               case NODE_CALLSITE:
-               case NODE_ENV:
-               default:
-                       goto errinval;
-               }
-
-               ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.target);
-               if (ret)
-                       return ret;
-               ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.alias);
-               if (ret)
-                       return ret;
-               break;
-
-       case NODE_TYPE_SPECIFIER_LIST:
-               ret = ctf_visitor_field_class_specifier_list(depth, node);
-               if (ret)
-                       return ret;
-               break;
-       case NODE_TYPE_SPECIFIER:
-               ret = ctf_visitor_field_class_specifier(depth, node);
-               if (ret)
-                       return ret;
-               break;
-       case NODE_POINTER:
-               switch (node->parent->type) {
-               case NODE_TYPE_DECLARATOR:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-               }
-               break;
-       case NODE_TYPE_DECLARATOR:
-               ret = ctf_visitor_field_class_declarator(depth, node);
-               if (ret)
-                       return ret;
-               break;
-
-       case NODE_FLOATING_POINT:
-               switch (node->parent->type) {
-               case NODE_TYPE_SPECIFIER:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-
-               case NODE_UNARY_EXPRESSION:
-                       goto errperm;
-               }
-               bt_list_for_each_entry(iter, &node->u.floating_point.expressions, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_INTEGER:
-               switch (node->parent->type) {
-               case NODE_TYPE_SPECIFIER:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-
-               }
-
-               bt_list_for_each_entry(iter, &node->u.integer.expressions, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_STRING:
-               switch (node->parent->type) {
-               case NODE_TYPE_SPECIFIER:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-
-               case NODE_UNARY_EXPRESSION:
-                       goto errperm;
-               }
-
-               bt_list_for_each_entry(iter, &node->u.string.expressions, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_ENUMERATOR:
-               switch (node->parent->type) {
-               case NODE_ENUM:
-                       break;
-               default:
-                       goto errinval;
-               }
-               /*
-                * Enumerators are only allows to contain:
-                *    numeric unary expression
-                * or num. unary exp. ... num. unary exp
-                */
-               {
-                       int count = 0;
-
-                       bt_list_for_each_entry(iter, &node->u.enumerator.values,
-                                               siblings) {
-                               switch (count++) {
-                               case 0: if (iter->type != NODE_UNARY_EXPRESSION
-                                           || (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT
-                                               && iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT)
-                                           || iter->u.unary_expression.link != UNARY_LINK_UNKNOWN) {
-                                               _BT_LOGE_LINENO(iter->lineno,
-                                                       "First unary expression of enumerator is unexpected.");
-                                               goto errperm;
-                                       }
-                                       break;
-                               case 1: if (iter->type != NODE_UNARY_EXPRESSION
-                                           || (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT
-                                               && iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT)
-                                           || iter->u.unary_expression.link != UNARY_DOTDOTDOT) {
-                                               _BT_LOGE_LINENO(iter->lineno,
-                                                       "Second unary expression of enumerator is unexpected.");
-                                               goto errperm;
-                                       }
-                                       break;
-                               default:
-                                       goto errperm;
-                               }
-                       }
-               }
-
-               bt_list_for_each_entry(iter, &node->u.enumerator.values, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_ENUM:
-               switch (node->parent->type) {
-               case NODE_TYPE_SPECIFIER:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-
-               case NODE_UNARY_EXPRESSION:
-                       goto errperm;
-               }
-
-               depth++;
-               ret = _ctf_visitor_semantic_check(depth + 1, node->u._enum.container_field_class);
-               if (ret)
-                       return ret;
-
-               bt_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               depth--;
-               break;
-       case NODE_STRUCT_OR_VARIANT_DECLARATION:
-               switch (node->parent->type) {
-               case NODE_STRUCT:
-               case NODE_VARIANT:
-                       break;
-               default:
-                       goto errinval;
-               }
-               ret = _ctf_visitor_semantic_check(depth + 1,
-                       node->u.struct_or_variant_declaration.field_class_specifier_list);
-               if (ret)
-                       return ret;
-               bt_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NODE_VARIANT:
-               switch (node->parent->type) {
-               case NODE_TYPE_SPECIFIER:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-
-               case NODE_UNARY_EXPRESSION:
-                       goto errperm;
-               }
-               bt_list_for_each_entry(iter, &node->u.variant.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-
-       case NODE_STRUCT:
-               switch (node->parent->type) {
-               case NODE_TYPE_SPECIFIER:
-                       break;                  /* OK */
-               default:
-                       goto errinval;
-
-               case NODE_UNARY_EXPRESSION:
-                       goto errperm;
-               }
-               bt_list_for_each_entry(iter, &node->u._struct.declaration_list, siblings) {
-                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
-                       if (ret)
-                               return ret;
-               }
-               break;
-
-       case NODE_UNKNOWN:
-       default:
-               _BT_LOGE_LINENO(node->lineno,
-                       "Unknown node type: type=%d", node->type);
-               return -EINVAL;
-       }
-       return ret;
-
-errinval:
-       _BT_LOGE_LINENO(node->lineno,
-               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
-               node_type(node), node_type(node->parent));
-       return -EINVAL;         /* Incoherent structure */
-
-errperm:
-       _BT_LOGE_LINENO(node->lineno,
-               "Semantic error: node-type=%s, parent-node-type=%s",
-               node_type(node), node_type(node->parent));
-       return -EPERM;          /* Structure not allowed */
-}
-
-int ctf_visitor_semantic_check(int depth, struct ctf_node *node)
-{
-       int ret = 0;
-
-       /*
-        * First make sure we create the parent links for all children. Let's
-        * take the safe route and recreate them at each validation, just in
-        * case the structure has changed.
-        */
-       ret = ctf_visitor_parent_links(depth, node);
-       if (ret) {
-               _BT_LOGE_LINENO(node->lineno,
-                       "Cannot create parent links in metadata's AST: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-       ret = _ctf_visitor_semantic_check(depth, node);
-       if (ret) {
-               _BT_LOGE_LINENO(node->lineno,
-                       "Cannot check metadata's AST semantics: "
-                       "ret=%d", ret);
-               goto end;
-       }
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/common/msg-iter/Makefile.am b/plugins/ctf/common/msg-iter/Makefile.am
deleted file mode 100644 (file)
index 7c3c208..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-noinst_LTLIBRARIES = libctf-msg-iter.la
-
-libctf_msg_iter_la_SOURCES = \
-       msg-iter.c \
-       msg-iter.h \
-       logging.c \
-       logging.h
diff --git a/plugins/ctf/common/msg-iter/logging.c b/plugins/ctf/common/msg-iter/logging.c
deleted file mode 100644 (file)
index 3b9b285..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL ctf_msg_iter_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(ctf_msg_iter_log_level,
-       "BABELTRACE_PLUGIN_CTF_MSG_ITER_LOG_LEVEL");
diff --git a/plugins/ctf/common/msg-iter/logging.h b/plugins/ctf/common/msg-iter/logging.h
deleted file mode 100644 (file)
index 7e41dd9..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef CTF_MSG_ITER_LOGGING_H
-#define CTF_MSG_ITER_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL ctf_msg_iter_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(ctf_msg_iter_log_level);
-
-#endif /* CTF_MSG_ITER_LOGGING_H */
diff --git a/plugins/ctf/common/msg-iter/msg-iter.c b/plugins/ctf/common/msg-iter/msg-iter.c
deleted file mode 100644 (file)
index 0671d9c..0000000
+++ /dev/null
@@ -1,3046 +0,0 @@
-/*
- * Babeltrace - CTF message iterator
- *
- * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-MSG-ITER"
-#include "logging.h"
-
-#include <stdint.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <babeltrace2/assert-internal.h>
-#include <string.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/common-internal.h>
-#include <glib.h>
-#include <stdlib.h>
-
-#include "msg-iter.h"
-#include "../bfcr/bfcr.h"
-
-struct bt_msg_iter;
-
-/* A visit stack entry */
-struct stack_entry {
-       /*
-        * Current base field, one of:
-        *
-        *   * string
-        *   * structure
-        *   * array
-        *   * sequence
-        *   * variant
-        *
-        * Field is borrowed.
-        */
-       bt_field *base;
-
-       /* Index of next field to set */
-       size_t index;
-};
-
-/* Visit stack */
-struct stack {
-       /* Entries (struct stack_entry) */
-       GArray *entries;
-
-       /* Number of active entries */
-       size_t size;
-};
-
-/* State */
-enum state {
-       STATE_INIT,
-       STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN,
-       STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
-       STATE_AFTER_TRACE_PACKET_HEADER,
-       STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN,
-       STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
-       STATE_AFTER_STREAM_PACKET_CONTEXT,
-       STATE_CHECK_EMIT_MSG_STREAM_BEGINNING,
-       STATE_EMIT_MSG_STREAM_BEGINNING,
-       STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING,
-       STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS,
-       STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS,
-       STATE_EMIT_MSG_DISCARDED_EVENTS,
-       STATE_EMIT_MSG_DISCARDED_PACKETS,
-       STATE_EMIT_MSG_PACKET_BEGINNING,
-       STATE_DSCOPE_EVENT_HEADER_BEGIN,
-       STATE_DSCOPE_EVENT_HEADER_CONTINUE,
-       STATE_AFTER_EVENT_HEADER,
-       STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN,
-       STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE,
-       STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
-       STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE,
-       STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
-       STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
-       STATE_EMIT_MSG_EVENT,
-       STATE_SKIP_PACKET_PADDING,
-       STATE_EMIT_MSG_PACKET_END_MULTI,
-       STATE_EMIT_MSG_PACKET_END_SINGLE,
-       STATE_CHECK_EMIT_MSG_STREAM_ACTIVITY_END,
-       STATE_EMIT_MSG_STREAM_ACTIVITY_END,
-       STATE_EMIT_MSG_STREAM_END,
-       STATE_DONE,
-};
-
-struct end_of_packet_snapshots {
-       uint64_t discarded_events;
-       uint64_t packets;
-       uint64_t beginning_clock;
-       uint64_t end_clock;
-};
-
-/* CTF message iterator */
-struct bt_msg_iter {
-       /* Visit stack */
-       struct stack *stack;
-
-       /* Current message iterator to create messages (weak) */
-       bt_self_message_iterator *msg_iter;
-
-       /*
-        * True to emit stream beginning and stream activity beginning
-        * messages.
-        */
-       bool emit_stream_begin_msg;
-
-       /* True to emit stream end and stream activity end messages */
-       bool emit_stream_end_msg;
-
-       /* True to set the stream */
-       bool set_stream;
-
-       /*
-        * Current dynamic scope field pointer.
-        *
-        * This is set by read_dscope_begin_state() and contains the
-        * value of one of the pointers in `dscopes` below.
-        */
-       bt_field *cur_dscope_field;
-
-       /*
-        * True if we're done filling a string field from a text
-        * array/sequence payload.
-        */
-       bool done_filling_string;
-
-       /* Trace and classes */
-       /* True to set IR fields */
-       bool set_ir_fields;
-
-       struct {
-               struct ctf_trace_class *tc;
-               struct ctf_stream_class *sc;
-               struct ctf_event_class *ec;
-       } meta;
-
-       /* Current packet context field wrapper (NULL if not created yet) */
-       bt_packet_context_field *packet_context_field;
-
-       /* Current packet (NULL if not created yet) */
-       bt_packet *packet;
-
-       /* Current stream (NULL if not set yet) */
-       bt_stream *stream;
-
-       /* Current event (NULL if not created yet) */
-       bt_event *event;
-
-       /* Current event message (NULL if not created yet) */
-       bt_message *event_msg;
-
-       /* Database of current dynamic scopes */
-       struct {
-               bt_field *stream_packet_context;
-               bt_field *event_common_context;
-               bt_field *event_spec_context;
-               bt_field *event_payload;
-       } dscopes;
-
-       /* Current state */
-       enum state state;
-
-       /* Current medium buffer data */
-       struct {
-               /* Last address provided by medium */
-               const uint8_t *addr;
-
-               /* Buffer size provided by medium (bytes) */
-               size_t sz;
-
-               /* Offset within whole packet of addr (bits) */
-               size_t packet_offset;
-
-               /* Current position from addr (bits) */
-               size_t at;
-
-               /* Position of the last event header from addr (bits) */
-               size_t last_eh_at;
-       } buf;
-
-       /* Binary type reader */
-       struct bt_bfcr *bfcr;
-
-       /* Current medium data */
-       struct {
-               struct bt_msg_iter_medium_ops medops;
-               size_t max_request_sz;
-               void *data;
-       } medium;
-
-       /* Current packet size (bits) (-1 if unknown) */
-       int64_t cur_exp_packet_total_size;
-
-       /* Current content size (bits) (-1 if unknown) */
-       int64_t cur_exp_packet_content_size;
-
-       /* Current stream class ID */
-       int64_t cur_stream_class_id;
-
-       /* Current event class ID */
-       int64_t cur_event_class_id;
-
-       /* Current data stream ID */
-       int64_t cur_data_stream_id;
-
-       /*
-        * Offset, in the underlying media, of the current packet's
-        * start (-1 if unknown).
-        */
-       off_t cur_packet_offset;
-
-       /* Default clock's current value */
-       uint64_t default_clock_snapshot;
-
-       /* End of current packet snapshots */
-       struct end_of_packet_snapshots snapshots;
-
-       /* End of previous packet snapshots */
-       struct end_of_packet_snapshots prev_packet_snapshots;
-
-       /* Stored values (for sequence lengths, variant tags) */
-       GArray *stored_values;
-};
-
-static inline
-const char *state_string(enum state state)
-{
-       switch (state) {
-       case STATE_INIT:
-               return "STATE_INIT";
-       case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
-               return "STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN";
-       case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
-               return "STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE";
-       case STATE_AFTER_TRACE_PACKET_HEADER:
-               return "STATE_AFTER_TRACE_PACKET_HEADER";
-       case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
-               return "STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN";
-       case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
-               return "STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE";
-       case STATE_AFTER_STREAM_PACKET_CONTEXT:
-               return "STATE_AFTER_STREAM_PACKET_CONTEXT";
-       case STATE_EMIT_MSG_STREAM_BEGINNING:
-               return "STATE_EMIT_MSG_STREAM_BEGINNING";
-       case STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING:
-               return "STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING";
-       case STATE_EMIT_MSG_PACKET_BEGINNING:
-               return "STATE_EMIT_MSG_PACKET_BEGINNING";
-       case STATE_EMIT_MSG_DISCARDED_EVENTS:
-               return "STATE_EMIT_MSG_DISCARDED_EVENTS";
-       case STATE_EMIT_MSG_DISCARDED_PACKETS:
-               return "STATE_EMIT_MSG_DISCARDED_PACKETS";
-       case STATE_DSCOPE_EVENT_HEADER_BEGIN:
-               return "STATE_DSCOPE_EVENT_HEADER_BEGIN";
-       case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
-               return "STATE_DSCOPE_EVENT_HEADER_CONTINUE";
-       case STATE_AFTER_EVENT_HEADER:
-               return "STATE_AFTER_EVENT_HEADER";
-       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
-               return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN";
-       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
-               return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE";
-       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
-               return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN";
-       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
-               return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE";
-       case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
-               return "STATE_DSCOPE_EVENT_PAYLOAD_BEGIN";
-       case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
-               return "STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE";
-       case STATE_EMIT_MSG_EVENT:
-               return "STATE_EMIT_MSG_EVENT";
-       case STATE_SKIP_PACKET_PADDING:
-               return "STATE_SKIP_PACKET_PADDING";
-       case STATE_EMIT_MSG_PACKET_END_MULTI:
-               return "STATE_EMIT_MSG_PACKET_END_MULTI";
-       case STATE_EMIT_MSG_PACKET_END_SINGLE:
-               return "STATE_EMIT_MSG_PACKET_END_SINGLE";
-       case STATE_EMIT_MSG_STREAM_ACTIVITY_END:
-               return "STATE_EMIT_MSG_STREAM_ACTIVITY_END";
-       case STATE_EMIT_MSG_STREAM_END:
-               return "STATE_EMIT_MSG_STREAM_END";
-       case STATE_DONE:
-               return "STATE_DONE";
-       default:
-               return "(unknown)";
-       }
-}
-
-static
-int bt_msg_iter_switch_packet(struct bt_msg_iter *notit);
-
-static
-struct stack *stack_new(struct bt_msg_iter *notit)
-{
-       struct stack *stack = NULL;
-
-       stack = g_new0(struct stack, 1);
-       if (!stack) {
-               BT_LOGE_STR("Failed to allocate one stack.");
-               goto error;
-       }
-
-       stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
-       if (!stack->entries) {
-               BT_LOGE_STR("Failed to allocate a GArray.");
-               goto error;
-       }
-
-       BT_LOGD("Created stack: notit-addr=%p, stack-addr=%p", notit, stack);
-       goto end;
-
-error:
-       g_free(stack);
-       stack = NULL;
-
-end:
-       return stack;
-}
-
-static
-void stack_destroy(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       BT_LOGD("Destroying stack: addr=%p", stack);
-
-       if (stack->entries) {
-               g_array_free(stack->entries, TRUE);
-       }
-
-       g_free(stack);
-}
-
-static
-void stack_push(struct stack *stack, bt_field *base)
-{
-       struct stack_entry *entry;
-
-       BT_ASSERT(stack);
-       BT_ASSERT(base);
-       BT_LOGV("Pushing base field on stack: stack-addr=%p, "
-               "stack-size-before=%zu, stack-size-after=%zu",
-               stack, stack->size, stack->size + 1);
-
-       if (stack->entries->len == stack->size) {
-               g_array_set_size(stack->entries, stack->size + 1);
-       }
-
-       entry = &g_array_index(stack->entries, struct stack_entry, stack->size);
-       entry->base = base;
-       entry->index = 0;
-       stack->size++;
-}
-
-static inline
-unsigned int stack_size(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       return stack->size;
-}
-
-static
-void stack_pop(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       BT_ASSERT(stack_size(stack));
-       BT_LOGV("Popping from stack: "
-               "stack-addr=%p, stack-size-before=%zu, stack-size-after=%zu",
-               stack, stack->size, stack->size - 1);
-       stack->size--;
-}
-
-static inline
-struct stack_entry *stack_top(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       BT_ASSERT(stack_size(stack));
-       return &g_array_index(stack->entries, struct stack_entry,
-               stack->size - 1);
-}
-
-static inline
-bool stack_empty(struct stack *stack)
-{
-       return stack_size(stack) == 0;
-}
-
-static
-void stack_clear(struct stack *stack)
-{
-       BT_ASSERT(stack);
-       stack->size = 0;
-}
-
-static inline
-enum bt_msg_iter_status msg_iter_status_from_m_status(
-               enum bt_msg_iter_medium_status m_status)
-{
-       /* They are the same */
-       return (int) m_status;
-}
-
-static inline
-size_t buf_size_bits(struct bt_msg_iter *notit)
-{
-       return notit->buf.sz * 8;
-}
-
-static inline
-size_t buf_available_bits(struct bt_msg_iter *notit)
-{
-       return buf_size_bits(notit) - notit->buf.at;
-}
-
-static inline
-size_t packet_at(struct bt_msg_iter *notit)
-{
-       return notit->buf.packet_offset + notit->buf.at;
-}
-
-static inline
-void buf_consume_bits(struct bt_msg_iter *notit, size_t incr)
-{
-       BT_LOGV("Advancing cursor: notit-addr=%p, cur-before=%zu, cur-after=%zu",
-               notit, notit->buf.at, notit->buf.at + incr);
-       notit->buf.at += incr;
-}
-
-static
-enum bt_msg_iter_status request_medium_bytes(
-               struct bt_msg_iter *notit)
-{
-       uint8_t *buffer_addr = NULL;
-       size_t buffer_sz = 0;
-       enum bt_msg_iter_medium_status m_status;
-
-       BT_LOGV("Calling user function (request bytes): notit-addr=%p, "
-               "request-size=%zu", notit, notit->medium.max_request_sz);
-       m_status = notit->medium.medops.request_bytes(
-               notit->medium.max_request_sz, &buffer_addr,
-               &buffer_sz, notit->medium.data);
-       BT_LOGV("User function returned: status=%s, buf-addr=%p, buf-size=%zu",
-               bt_msg_iter_medium_status_string(m_status),
-               buffer_addr, buffer_sz);
-       if (m_status == BT_MSG_ITER_MEDIUM_STATUS_OK) {
-               BT_ASSERT(buffer_sz != 0);
-
-               /* New packet offset is old one + old size (in bits) */
-               notit->buf.packet_offset += buf_size_bits(notit);
-
-               /* Restart at the beginning of the new medium buffer */
-               notit->buf.at = 0;
-               notit->buf.last_eh_at = SIZE_MAX;
-
-               /* New medium buffer size */
-               notit->buf.sz = buffer_sz;
-
-               /* New medium buffer address */
-               notit->buf.addr = buffer_addr;
-
-               BT_LOGV("User function returned new bytes: "
-                       "packet-offset=%zu, cur=%zu, size=%zu, addr=%p",
-                       notit->buf.packet_offset, notit->buf.at,
-                       notit->buf.sz, notit->buf.addr);
-               BT_LOGV_MEM(buffer_addr, buffer_sz, "Returned bytes at %p:",
-                       buffer_addr);
-       } else if (m_status == BT_MSG_ITER_MEDIUM_STATUS_EOF) {
-               /*
-                * User returned end of stream: validate that we're not
-                * in the middle of a packet header, packet context, or
-                * event.
-                */
-               if (notit->cur_exp_packet_total_size >= 0) {
-                       if (packet_at(notit) ==
-                                       notit->cur_exp_packet_total_size) {
-                               goto end;
-                       }
-               } else {
-                       if (packet_at(notit) == 0) {
-                               goto end;
-                       }
-
-                       if (notit->buf.last_eh_at != SIZE_MAX &&
-                                       notit->buf.at == notit->buf.last_eh_at) {
-                               goto end;
-                       }
-               }
-
-               /* All other states are invalid */
-               BT_LOGW("User function returned %s, but message iterator is in an unexpected state: "
-                       "state=%s, cur-packet-size=%" PRId64 ", cur=%zu, "
-                       "packet-cur=%zu, last-eh-at=%zu",
-                       bt_msg_iter_medium_status_string(m_status),
-                       state_string(notit->state),
-                       notit->cur_exp_packet_total_size,
-                       notit->buf.at, packet_at(notit),
-                       notit->buf.last_eh_at);
-               m_status = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
-       } else if (m_status < 0) {
-               BT_LOGW("User function failed: status=%s",
-                       bt_msg_iter_medium_status_string(m_status));
-       }
-
-end:
-       return msg_iter_status_from_m_status(m_status);
-}
-
-static inline
-enum bt_msg_iter_status buf_ensure_available_bits(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-
-       if (unlikely(buf_available_bits(notit) == 0)) {
-               /*
-                * This _cannot_ return BT_MSG_ITER_STATUS_OK
-                * _and_ no bits.
-                */
-               status = request_medium_bytes(notit);
-       }
-
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_dscope_begin_state(
-               struct bt_msg_iter *notit,
-               struct ctf_field_class *dscope_fc,
-               enum state done_state, enum state continue_state,
-               bt_field *dscope_field)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       enum bt_bfcr_status bfcr_status;
-       size_t consumed_bits;
-
-       notit->cur_dscope_field = dscope_field;
-       BT_LOGV("Starting BFCR: notit-addr=%p, bfcr-addr=%p, fc-addr=%p",
-               notit, notit->bfcr, dscope_fc);
-       consumed_bits = bt_bfcr_start(notit->bfcr, dscope_fc,
-               notit->buf.addr, notit->buf.at, packet_at(notit),
-               notit->buf.sz, &bfcr_status);
-       BT_LOGV("BFCR consumed bits: size=%zu", consumed_bits);
-
-       switch (bfcr_status) {
-       case BT_BFCR_STATUS_OK:
-               /* Field class was read completely */
-               BT_LOGV_STR("Field was completely decoded.");
-               notit->state = done_state;
-               break;
-       case BT_BFCR_STATUS_EOF:
-               BT_LOGV_STR("BFCR needs more data to decode field completely.");
-               notit->state = continue_state;
-               break;
-       default:
-               BT_LOGW("BFCR failed to start: notit-addr=%p, bfcr-addr=%p, "
-                       "status=%s", notit, notit->bfcr,
-                       bt_bfcr_status_string(bfcr_status));
-               status = BT_MSG_ITER_STATUS_ERROR;
-               goto end;
-       }
-
-       /* Consume bits now since we know we're not in an error state */
-       buf_consume_bits(notit, consumed_bits);
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_dscope_continue_state(
-               struct bt_msg_iter *notit, enum state done_state)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       enum bt_bfcr_status bfcr_status;
-       size_t consumed_bits;
-
-       BT_LOGV("Continuing BFCR: notit-addr=%p, bfcr-addr=%p",
-               notit, notit->bfcr);
-
-       status = buf_ensure_available_bits(notit);
-       if (status != BT_MSG_ITER_STATUS_OK) {
-               if (status < 0) {
-                       BT_LOGW("Cannot ensure that buffer has at least one byte: "
-                               "msg-addr=%p, status=%s",
-                               notit, bt_msg_iter_status_string(status));
-               } else {
-                       BT_LOGV("Cannot ensure that buffer has at least one byte: "
-                               "msg-addr=%p, status=%s",
-                               notit, bt_msg_iter_status_string(status));
-               }
-
-               goto end;
-       }
-
-       consumed_bits = bt_bfcr_continue(notit->bfcr, notit->buf.addr,
-               notit->buf.sz, &bfcr_status);
-       BT_LOGV("BFCR consumed bits: size=%zu", consumed_bits);
-
-       switch (bfcr_status) {
-       case BT_BFCR_STATUS_OK:
-               /* Type was read completely. */
-               BT_LOGV_STR("Field was completely decoded.");
-               notit->state = done_state;
-               break;
-       case BT_BFCR_STATUS_EOF:
-               /* Stay in this continue state. */
-               BT_LOGV_STR("BFCR needs more data to decode field completely.");
-               break;
-       default:
-               BT_LOGW("BFCR failed to continue: notit-addr=%p, bfcr-addr=%p, "
-                       "status=%s", notit, notit->bfcr,
-                       bt_bfcr_status_string(bfcr_status));
-               status = BT_MSG_ITER_STATUS_ERROR;
-               goto end;
-       }
-
-       /* Consume bits now since we know we're not in an error state. */
-       buf_consume_bits(notit, consumed_bits);
-end:
-       return status;
-}
-
-static
-void release_event_dscopes(struct bt_msg_iter *notit)
-{
-       notit->dscopes.event_common_context = NULL;
-       notit->dscopes.event_spec_context = NULL;
-       notit->dscopes.event_payload = NULL;
-}
-
-static
-void release_all_dscopes(struct bt_msg_iter *notit)
-{
-       notit->dscopes.stream_packet_context = NULL;
-
-       if (notit->packet_context_field) {
-               bt_packet_context_field_release(notit->packet_context_field);
-               notit->packet_context_field = NULL;
-       }
-
-       release_event_dscopes(notit);
-}
-
-static
-enum bt_msg_iter_status read_packet_header_begin_state(
-               struct bt_msg_iter *notit)
-{
-       struct ctf_field_class *packet_header_fc = NULL;
-       enum bt_msg_iter_status ret = BT_MSG_ITER_STATUS_OK;
-
-       if (bt_msg_iter_switch_packet(notit)) {
-               BT_LOGW("Cannot switch packet: notit-addr=%p", notit);
-               ret = BT_MSG_ITER_STATUS_ERROR;
-               goto end;
-       }
-
-       /*
-        * Make sure at least one bit is available for this packet. An
-        * empty packet is impossible. If we reach the end of the medium
-        * at this point, then it's considered the end of the stream.
-        */
-       ret = buf_ensure_available_bits(notit);
-       switch (ret) {
-       case BT_MSG_ITER_STATUS_OK:
-               break;
-       case BT_MSG_ITER_STATUS_EOF:
-               ret = BT_MSG_ITER_STATUS_OK;
-               notit->state = STATE_CHECK_EMIT_MSG_STREAM_ACTIVITY_END;
-               goto end;
-       default:
-               goto end;
-       }
-
-       /* Packet header class is common to the whole trace class. */
-       packet_header_fc = notit->meta.tc->packet_header_fc;
-       if (!packet_header_fc) {
-               notit->state = STATE_AFTER_TRACE_PACKET_HEADER;
-               goto end;
-       }
-
-       notit->cur_stream_class_id = -1;
-       notit->cur_event_class_id = -1;
-       notit->cur_data_stream_id = -1;
-       BT_LOGV("Decoding packet header field:"
-               "notit-addr=%p, trace-class-addr=%p, fc-addr=%p",
-               notit, notit->meta.tc, packet_header_fc);
-       ret = read_dscope_begin_state(notit, packet_header_fc,
-               STATE_AFTER_TRACE_PACKET_HEADER,
-               STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, NULL);
-       if (ret < 0) {
-               BT_LOGW("Cannot decode packet header field: "
-                       "notit-addr=%p, trace-class-addr=%p, "
-                       "fc-addr=%p",
-                       notit, notit->meta.tc, packet_header_fc);
-       }
-
-end:
-       return ret;
-}
-
-static
-enum bt_msg_iter_status read_packet_header_continue_state(
-               struct bt_msg_iter *notit)
-{
-       return read_dscope_continue_state(notit,
-               STATE_AFTER_TRACE_PACKET_HEADER);
-}
-
-static inline
-enum bt_msg_iter_status set_current_stream_class(struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       struct ctf_stream_class *new_stream_class = NULL;
-
-       if (notit->cur_stream_class_id == -1) {
-               /*
-                * No current stream class ID field, therefore only one
-                * stream class.
-                */
-               if (notit->meta.tc->stream_classes->len != 1) {
-                       BT_LOGW("Need exactly one stream class since there's "
-                               "no stream class ID field: "
-                               "notit-addr=%p", notit);
-                       status = BT_MSG_ITER_STATUS_ERROR;
-                       goto end;
-               }
-
-               new_stream_class = notit->meta.tc->stream_classes->pdata[0];
-               notit->cur_stream_class_id = new_stream_class->id;
-       }
-
-       new_stream_class = ctf_trace_class_borrow_stream_class_by_id(
-               notit->meta.tc, notit->cur_stream_class_id);
-       if (!new_stream_class) {
-               BT_LOGW("No stream class with ID of stream class ID to use in trace class: "
-                       "notit-addr=%p, stream-class-id=%" PRIu64 ", "
-                       "trace-class-addr=%p",
-                       notit, notit->cur_stream_class_id, notit->meta.tc);
-               status = BT_MSG_ITER_STATUS_ERROR;
-               goto end;
-       }
-
-       if (notit->meta.sc) {
-               if (new_stream_class != notit->meta.sc) {
-                       BT_LOGW("Two packets refer to two different stream classes within the same packet sequence: "
-                               "notit-addr=%p, prev-stream-class-addr=%p, "
-                               "prev-stream-class-id=%" PRId64 ", "
-                               "next-stream-class-addr=%p, "
-                               "next-stream-class-id=%" PRId64 ", "
-                               "trace-addr=%p",
-                               notit, notit->meta.sc,
-                               notit->meta.sc->id,
-                               new_stream_class,
-                               new_stream_class->id,
-                               notit->meta.tc);
-                       status = BT_MSG_ITER_STATUS_ERROR;
-                       goto end;
-               }
-       } else {
-               notit->meta.sc = new_stream_class;
-       }
-
-       BT_LOGV("Set current stream class: "
-               "notit-addr=%p, stream-class-addr=%p, "
-               "stream-class-id=%" PRId64,
-               notit, notit->meta.sc, notit->meta.sc->id);
-
-end:
-       return status;
-}
-
-static inline
-enum bt_msg_iter_status set_current_stream(struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       bt_stream *stream = NULL;
-
-       BT_LOGV("Calling user function (get stream): notit-addr=%p, "
-               "stream-class-addr=%p, stream-class-id=%" PRId64,
-               notit, notit->meta.sc,
-               notit->meta.sc->id);
-       stream = notit->medium.medops.borrow_stream(
-               notit->meta.sc->ir_sc, notit->cur_data_stream_id,
-               notit->medium.data);
-       bt_stream_get_ref(stream);
-       BT_LOGV("User function returned: stream-addr=%p", stream);
-       if (!stream) {
-               BT_LOGW_STR("User function failed to return a stream object "
-                       "for the given stream class.");
-               status = BT_MSG_ITER_STATUS_ERROR;
-               goto end;
-       }
-
-       if (notit->stream && stream != notit->stream) {
-               BT_LOGW("User function returned a different stream than the "
-                       "previous one for the same sequence of packets.");
-               status = BT_MSG_ITER_STATUS_ERROR;
-               goto end;
-       }
-
-       BT_STREAM_MOVE_REF(notit->stream, stream);
-
-end:
-       bt_stream_put_ref(stream);
-       return status;
-}
-
-static inline
-enum bt_msg_iter_status set_current_packet(struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       bt_packet *packet = NULL;
-
-       BT_LOGV("Creating packet for packet message: "
-               "notit-addr=%p", notit);
-       BT_LOGV("Creating packet from stream: "
-               "notit-addr=%p, stream-addr=%p, "
-               "stream-class-addr=%p, "
-               "stream-class-id=%" PRId64,
-               notit, notit->stream, notit->meta.sc,
-               notit->meta.sc->id);
-
-       /* Create packet */
-       BT_ASSERT(notit->stream);
-       packet = bt_packet_create(notit->stream);
-       if (!packet) {
-               BT_LOGE("Cannot create packet from stream: "
-                       "notit-addr=%p, stream-addr=%p, "
-                       "stream-class-addr=%p, "
-                       "stream-class-id=%" PRId64,
-                       notit, notit->stream, notit->meta.sc,
-                       notit->meta.sc->id);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_PACKET_PUT_REF_AND_RESET(packet);
-       status = BT_MSG_ITER_STATUS_ERROR;
-
-end:
-       BT_PACKET_MOVE_REF(notit->packet, packet);
-       return status;
-}
-
-static
-enum bt_msg_iter_status after_packet_header_state(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status;
-
-       status = set_current_stream_class(notit);
-       if (status != BT_MSG_ITER_STATUS_OK) {
-               goto end;
-       }
-
-       notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_packet_context_begin_state(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       struct ctf_field_class *packet_context_fc;
-
-       BT_ASSERT(notit->meta.sc);
-       packet_context_fc = notit->meta.sc->packet_context_fc;
-       if (!packet_context_fc) {
-               BT_LOGV("No packet packet context field class in stream class: continuing: "
-                       "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-id=%" PRId64,
-                       notit, notit->meta.sc,
-                       notit->meta.sc->id);
-               notit->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
-               goto end;
-       }
-
-       BT_ASSERT(!notit->packet_context_field);
-
-       if (packet_context_fc->in_ir) {
-               /*
-                * Create free packet context field from stream class.
-                * This field is going to be moved to the packet once we
-                * create it. We cannot create the packet now because a
-                * packet is created from a stream, and this API must be
-                * able to return the packet context properties without
-                * creating a stream
-                * (bt_msg_iter_get_packet_properties()).
-                */
-               notit->packet_context_field =
-                       bt_packet_context_field_create(
-                               notit->meta.sc->ir_sc);
-               if (!notit->packet_context_field) {
-                       BT_LOGE_STR("Cannot create packet context field wrapper from stream class.");
-                       status = BT_MSG_ITER_STATUS_ERROR;
-                       goto end;
-               }
-
-               notit->dscopes.stream_packet_context =
-                       bt_packet_context_field_borrow_field(
-                               notit->packet_context_field);
-               BT_ASSERT(notit->dscopes.stream_packet_context);
-       }
-
-       BT_LOGV("Decoding packet context field: "
-               "notit-addr=%p, stream-class-addr=%p, "
-               "stream-class-id=%" PRId64 ", fc-addr=%p",
-               notit, notit->meta.sc,
-               notit->meta.sc->id, packet_context_fc);
-       status = read_dscope_begin_state(notit, packet_context_fc,
-               STATE_AFTER_STREAM_PACKET_CONTEXT,
-               STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
-               notit->dscopes.stream_packet_context);
-       if (status < 0) {
-               BT_LOGW("Cannot decode packet context field: "
-                       "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-id=%" PRId64 ", fc-addr=%p",
-                       notit, notit->meta.sc,
-                       notit->meta.sc->id,
-                       packet_context_fc);
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_packet_context_continue_state(
-               struct bt_msg_iter *notit)
-{
-       return read_dscope_continue_state(notit,
-                       STATE_AFTER_STREAM_PACKET_CONTEXT);
-}
-
-static
-enum bt_msg_iter_status set_current_packet_content_sizes(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-
-       if (notit->cur_exp_packet_total_size == -1) {
-               if (notit->cur_exp_packet_content_size != -1) {
-                       notit->cur_exp_packet_total_size =
-                               notit->cur_exp_packet_content_size;
-               }
-       } else {
-               if (notit->cur_exp_packet_content_size == -1) {
-                       notit->cur_exp_packet_content_size =
-                               notit->cur_exp_packet_total_size;
-               }
-       }
-
-       BT_ASSERT((notit->cur_exp_packet_total_size >= 0 &&
-               notit->cur_exp_packet_content_size >= 0) ||
-               (notit->cur_exp_packet_total_size < 0 &&
-               notit->cur_exp_packet_content_size < 0));
-
-       if (notit->cur_exp_packet_content_size >
-                       notit->cur_exp_packet_total_size) {
-               BT_LOGW("Invalid packet or content size: "
-                       "content size is greater than packet size: "
-                       "notit-addr=%p, packet-context-field-addr=%p, "
-                       "packet-size=%" PRId64 ", content-size=%" PRId64,
-                       notit, notit->dscopes.stream_packet_context,
-                       notit->cur_exp_packet_total_size,
-                       notit->cur_exp_packet_content_size);
-               status = BT_MSG_ITER_STATUS_ERROR;
-               goto end;
-       }
-
-       BT_LOGV("Set current packet and content sizes: "
-               "notit-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64,
-               notit, notit->cur_exp_packet_total_size,
-               notit->cur_exp_packet_content_size);
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status after_packet_context_state(struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status;
-
-       status = set_current_packet_content_sizes(notit);
-       if (status != BT_MSG_ITER_STATUS_OK) {
-               goto end;
-       }
-
-       if (notit->stream) {
-               /*
-                * Stream exists, which means we already emitted at
-                * least one packet beginning message, so the initial
-                * stream beginning message was also emitted.
-                */
-               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
-       } else {
-               notit->state = STATE_CHECK_EMIT_MSG_STREAM_BEGINNING;
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_event_header_begin_state(struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       struct ctf_field_class *event_header_fc = NULL;
-
-       /* Reset the position of the last event header */
-       notit->buf.last_eh_at = notit->buf.at;
-       notit->cur_event_class_id = -1;
-
-       /* Check if we have some content left */
-       if (notit->cur_exp_packet_content_size >= 0) {
-               if (unlikely(packet_at(notit) ==
-                               notit->cur_exp_packet_content_size)) {
-                       /* No more events! */
-                       BT_LOGV("Reached end of packet: notit-addr=%p, "
-                               "cur=%zu", notit, packet_at(notit));
-                       notit->state = STATE_EMIT_MSG_PACKET_END_MULTI;
-                       goto end;
-               } else if (unlikely(packet_at(notit) >
-                               notit->cur_exp_packet_content_size)) {
-                       /* That's not supposed to happen */
-                       BT_LOGV("Before decoding event header field: cursor is passed the packet's content: "
-                               "notit-addr=%p, content-size=%" PRId64 ", "
-                               "cur=%zu", notit,
-                               notit->cur_exp_packet_content_size,
-                               packet_at(notit));
-                       status = BT_MSG_ITER_STATUS_ERROR;
-                       goto end;
-               }
-       } else {
-               /*
-                * "Infinite" content: we're done when the medium has
-                * nothing else for us.
-                */
-               status = buf_ensure_available_bits(notit);
-               switch (status) {
-               case BT_MSG_ITER_STATUS_OK:
-                       break;
-               case BT_MSG_ITER_STATUS_EOF:
-                       status = BT_MSG_ITER_STATUS_OK;
-                       notit->state = STATE_EMIT_MSG_PACKET_END_SINGLE;
-                       goto end;
-               default:
-                       goto end;
-               }
-       }
-
-       release_event_dscopes(notit);
-       BT_ASSERT(notit->meta.sc);
-       event_header_fc = notit->meta.sc->event_header_fc;
-       if (!event_header_fc) {
-               notit->state = STATE_AFTER_EVENT_HEADER;
-               goto end;
-       }
-
-       BT_LOGV("Decoding event header field: "
-               "notit-addr=%p, stream-class-addr=%p, "
-               "stream-class-id=%" PRId64 ", "
-               "fc-addr=%p",
-               notit, notit->meta.sc,
-               notit->meta.sc->id,
-               event_header_fc);
-       status = read_dscope_begin_state(notit, event_header_fc,
-               STATE_AFTER_EVENT_HEADER,
-               STATE_DSCOPE_EVENT_HEADER_CONTINUE, NULL);
-       if (status < 0) {
-               BT_LOGW("Cannot decode event header field: "
-                       "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-id=%" PRId64 ", fc-addr=%p",
-                       notit, notit->meta.sc,
-                       notit->meta.sc->id,
-                       event_header_fc);
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_event_header_continue_state(
-               struct bt_msg_iter *notit)
-{
-       return read_dscope_continue_state(notit,
-               STATE_AFTER_EVENT_HEADER);
-}
-
-static inline
-enum bt_msg_iter_status set_current_event_class(struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-
-       struct ctf_event_class *new_event_class = NULL;
-
-       if (notit->cur_event_class_id == -1) {
-               /*
-                * No current event class ID field, therefore only one
-                * event class.
-                */
-               if (notit->meta.sc->event_classes->len != 1) {
-                       BT_LOGW("Need exactly one event class since there's "
-                               "no event class ID field: "
-                               "notit-addr=%p", notit);
-                       status = BT_MSG_ITER_STATUS_ERROR;
-                       goto end;
-               }
-
-               new_event_class = notit->meta.sc->event_classes->pdata[0];
-               notit->cur_event_class_id = new_event_class->id;
-       }
-
-       new_event_class = ctf_stream_class_borrow_event_class_by_id(
-               notit->meta.sc, notit->cur_event_class_id);
-       if (!new_event_class) {
-               BT_LOGW("No event class with ID of event class ID to use in stream class: "
-                       "notit-addr=%p, stream-class-id=%" PRIu64 ", "
-                       "event-class-id=%" PRIu64 ", "
-                       "trace-class-addr=%p",
-                       notit, notit->meta.sc->id, notit->cur_event_class_id,
-                       notit->meta.tc);
-               status = BT_MSG_ITER_STATUS_ERROR;
-               goto end;
-       }
-
-       notit->meta.ec = new_event_class;
-       BT_LOGV("Set current event class: "
-               "notit-addr=%p, event-class-addr=%p, "
-               "event-class-id=%" PRId64 ", "
-               "event-class-name=\"%s\"",
-               notit, notit->meta.ec, notit->meta.ec->id,
-               notit->meta.ec->name->str);
-
-end:
-       return status;
-}
-
-static inline
-enum bt_msg_iter_status set_current_event_message(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       bt_message *msg = NULL;
-
-       BT_ASSERT(notit->meta.ec);
-       BT_ASSERT(notit->packet);
-       BT_LOGV("Creating event message from event class and packet: "
-               "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", packet-addr=%p",
-               notit, notit->meta.ec,
-               notit->meta.ec->name->str,
-               notit->packet);
-       BT_ASSERT(notit->msg_iter);
-       BT_ASSERT(notit->meta.sc);
-
-       if (bt_stream_class_borrow_default_clock_class(notit->meta.sc->ir_sc)) {
-               msg = bt_message_event_create_with_default_clock_snapshot(
-                       notit->msg_iter, notit->meta.ec->ir_ec,
-                       notit->packet, notit->default_clock_snapshot);
-       } else {
-               msg = bt_message_event_create(notit->msg_iter,
-                       notit->meta.ec->ir_ec, notit->packet);
-       }
-
-       if (!msg) {
-               BT_LOGE("Cannot create event message: "
-                       "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", "
-                       "packet-addr=%p",
-                       notit, notit->meta.ec,
-                       notit->meta.ec->name->str,
-                       notit->packet);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_MESSAGE_PUT_REF_AND_RESET(msg);
-       status = BT_MSG_ITER_STATUS_ERROR;
-
-end:
-       BT_MESSAGE_MOVE_REF(notit->event_msg, msg);
-       return status;
-}
-
-static
-enum bt_msg_iter_status after_event_header_state(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status;
-
-       status = set_current_event_class(notit);
-       if (status != BT_MSG_ITER_STATUS_OK) {
-               goto end;
-       }
-
-       status = set_current_event_message(notit);
-       if (status != BT_MSG_ITER_STATUS_OK) {
-               goto end;
-       }
-
-       notit->event = bt_message_event_borrow_event(
-               notit->event_msg);
-       BT_ASSERT(notit->event);
-       notit->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN;
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_event_common_context_begin_state(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       struct ctf_field_class *event_common_context_fc;
-
-       event_common_context_fc = notit->meta.sc->event_common_context_fc;
-       if (!event_common_context_fc) {
-               notit->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN;
-               goto end;
-       }
-
-       if (event_common_context_fc->in_ir) {
-               BT_ASSERT(!notit->dscopes.event_common_context);
-               notit->dscopes.event_common_context =
-                       bt_event_borrow_common_context_field(
-                               notit->event);
-               BT_ASSERT(notit->dscopes.event_common_context);
-       }
-
-       BT_LOGV("Decoding event common context field: "
-               "notit-addr=%p, stream-class-addr=%p, "
-               "stream-class-id=%" PRId64 ", "
-               "fc-addr=%p",
-               notit, notit->meta.sc,
-               notit->meta.sc->id,
-               event_common_context_fc);
-       status = read_dscope_begin_state(notit, event_common_context_fc,
-               STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
-               STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE,
-               notit->dscopes.event_common_context);
-       if (status < 0) {
-               BT_LOGW("Cannot decode event common context field: "
-                       "notit-addr=%p, stream-class-addr=%p, "
-                       "stream-class-id=%" PRId64 ", fc-addr=%p",
-                       notit, notit->meta.sc,
-                       notit->meta.sc->id,
-                       event_common_context_fc);
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_event_common_context_continue_state(
-               struct bt_msg_iter *notit)
-{
-       return read_dscope_continue_state(notit,
-               STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN);
-}
-
-static
-enum bt_msg_iter_status read_event_spec_context_begin_state(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       struct ctf_field_class *event_spec_context_fc;
-
-       event_spec_context_fc = notit->meta.ec->spec_context_fc;
-       if (!event_spec_context_fc) {
-               notit->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
-               goto end;
-       }
-
-       if (event_spec_context_fc->in_ir) {
-               BT_ASSERT(!notit->dscopes.event_spec_context);
-               notit->dscopes.event_spec_context =
-                       bt_event_borrow_specific_context_field(
-                               notit->event);
-               BT_ASSERT(notit->dscopes.event_spec_context);
-       }
-
-       BT_LOGV("Decoding event specific context field: "
-               "notit-addr=%p, event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "fc-addr=%p",
-               notit, notit->meta.ec,
-               notit->meta.ec->name->str,
-               notit->meta.ec->id,
-               event_spec_context_fc);
-       status = read_dscope_begin_state(notit, event_spec_context_fc,
-               STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
-               STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE,
-               notit->dscopes.event_spec_context);
-       if (status < 0) {
-               BT_LOGW("Cannot decode event specific context field: "
-                       "notit-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", fc-addr=%p",
-                       notit, notit->meta.ec,
-                       notit->meta.ec->name->str,
-                       notit->meta.ec->id,
-                       event_spec_context_fc);
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_event_spec_context_continue_state(
-               struct bt_msg_iter *notit)
-{
-       return read_dscope_continue_state(notit,
-               STATE_DSCOPE_EVENT_PAYLOAD_BEGIN);
-}
-
-static
-enum bt_msg_iter_status read_event_payload_begin_state(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       struct ctf_field_class *event_payload_fc;
-
-       event_payload_fc = notit->meta.ec->payload_fc;
-       if (!event_payload_fc) {
-               notit->state = STATE_EMIT_MSG_EVENT;
-               goto end;
-       }
-
-       if (event_payload_fc->in_ir) {
-               BT_ASSERT(!notit->dscopes.event_payload);
-               notit->dscopes.event_payload =
-                       bt_event_borrow_payload_field(
-                               notit->event);
-               BT_ASSERT(notit->dscopes.event_payload);
-       }
-
-       BT_LOGV("Decoding event payload field: "
-               "notit-addr=%p, event-class-addr=%p, "
-               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
-               "fc-addr=%p",
-               notit, notit->meta.ec,
-               notit->meta.ec->name->str,
-               notit->meta.ec->id,
-               event_payload_fc);
-       status = read_dscope_begin_state(notit, event_payload_fc,
-               STATE_EMIT_MSG_EVENT,
-               STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
-               notit->dscopes.event_payload);
-       if (status < 0) {
-               BT_LOGW("Cannot decode event payload field: "
-                       "notit-addr=%p, event-class-addr=%p, "
-                       "event-class-name=\"%s\", "
-                       "event-class-id=%" PRId64 ", fc-addr=%p",
-                       notit, notit->meta.ec,
-                       notit->meta.ec->name->str,
-                       notit->meta.ec->id,
-                       event_payload_fc);
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_event_payload_continue_state(
-               struct bt_msg_iter *notit)
-{
-       return read_dscope_continue_state(notit, STATE_EMIT_MSG_EVENT);
-}
-
-static
-enum bt_msg_iter_status skip_packet_padding_state(struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       size_t bits_to_skip;
-
-       BT_ASSERT(notit->cur_exp_packet_total_size > 0);
-       bits_to_skip = notit->cur_exp_packet_total_size - packet_at(notit);
-       if (bits_to_skip == 0) {
-               notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
-               goto end;
-       } else {
-               size_t bits_to_consume;
-
-               BT_LOGV("Trying to skip %zu bits of padding: notit-addr=%p, size=%zu",
-                       bits_to_skip, notit, bits_to_skip);
-               status = buf_ensure_available_bits(notit);
-               if (status != BT_MSG_ITER_STATUS_OK) {
-                       goto end;
-               }
-
-               bits_to_consume = MIN(buf_available_bits(notit), bits_to_skip);
-               BT_LOGV("Skipping %zu bits of padding: notit-addr=%p, size=%zu",
-                       bits_to_consume, notit, bits_to_consume);
-               buf_consume_bits(notit, bits_to_consume);
-               bits_to_skip = notit->cur_exp_packet_total_size -
-                       packet_at(notit);
-               if (bits_to_skip == 0) {
-                       notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
-                       goto end;
-               }
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status check_emit_msg_stream_beginning_state(
-               struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-
-       if (notit->set_stream) {
-               status = set_current_stream(notit);
-               if (status != BT_MSG_ITER_STATUS_OK) {
-                       goto end;
-               }
-       }
-
-       if (notit->emit_stream_begin_msg) {
-               notit->state = STATE_EMIT_MSG_STREAM_BEGINNING;
-       } else {
-               /* Stream's first packet */
-               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status check_emit_msg_discarded_events(
-               struct bt_msg_iter *notit)
-{
-       notit->state = STATE_EMIT_MSG_DISCARDED_EVENTS;
-
-       if (!notit->meta.sc->has_discarded_events) {
-               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
-               goto end;
-       }
-
-       if (notit->prev_packet_snapshots.discarded_events == UINT64_C(-1)) {
-               if (notit->snapshots.discarded_events == 0 ||
-                               notit->snapshots.discarded_events == UINT64_C(-1)) {
-                       /*
-                        * Stream's first packet with no discarded
-                        * events or no information about discarded
-                        * events: do not emit.
-                        */
-                       notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
-               }
-       } else {
-               /*
-                * If the previous packet has a value for this counter,
-                * then this counter is defined for the whole stream.
-                */
-               BT_ASSERT(notit->snapshots.discarded_events != UINT64_C(-1));
-
-               if (notit->snapshots.discarded_events -
-                               notit->prev_packet_snapshots.discarded_events == 0) {
-                       /*
-                        * No discarded events since previous packet: do
-                        * not emit.
-                        */
-                       notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
-               }
-       }
-
-end:
-       return BT_MSG_ITER_STATUS_OK;
-}
-
-static
-enum bt_msg_iter_status check_emit_msg_discarded_packets(
-               struct bt_msg_iter *notit)
-{
-       notit->state = STATE_EMIT_MSG_DISCARDED_PACKETS;
-
-       if (!notit->meta.sc->has_discarded_packets) {
-               notit->state = STATE_EMIT_MSG_PACKET_BEGINNING;
-               goto end;
-       }
-
-       if (notit->prev_packet_snapshots.packets == UINT64_C(-1)) {
-               /*
-                * Stream's first packet or no information about
-                * discarded packets: do not emit. In other words, if
-                * this is the first packet and its sequence number is
-                * not 0, do not consider that packets were previously
-                * lost: we might be reading a partial stream (LTTng
-                * snapshot for example).
-                */
-               notit->state = STATE_EMIT_MSG_PACKET_BEGINNING;
-       } else {
-               /*
-                * If the previous packet has a value for this counter,
-                * then this counter is defined for the whole stream.
-                */
-               BT_ASSERT(notit->snapshots.packets != UINT64_C(-1));
-
-               if (notit->snapshots.packets -
-                               notit->prev_packet_snapshots.packets <= 1) {
-                       /*
-                        * No discarded packets since previous packet:
-                        * do not emit.
-                        */
-                       notit->state = STATE_EMIT_MSG_PACKET_BEGINNING;
-               }
-       }
-
-end:
-       return BT_MSG_ITER_STATUS_OK;
-}
-
-static
-enum bt_msg_iter_status check_emit_msg_stream_activity_end(
-               struct bt_msg_iter *notit)
-{
-       if (notit->emit_stream_end_msg) {
-               notit->state = STATE_EMIT_MSG_STREAM_ACTIVITY_END;
-       } else {
-               notit->state = STATE_DONE;
-       }
-
-       return BT_MSG_ITER_STATUS_OK;
-}
-
-static inline
-enum bt_msg_iter_status handle_state(struct bt_msg_iter *notit)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-       const enum state state = notit->state;
-
-       BT_LOGV("Handling state: notit-addr=%p, state=%s",
-               notit, state_string(state));
-
-       // TODO: optimalize!
-       switch (state) {
-       case STATE_INIT:
-               notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
-               break;
-       case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
-               status = read_packet_header_begin_state(notit);
-               break;
-       case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
-               status = read_packet_header_continue_state(notit);
-               break;
-       case STATE_AFTER_TRACE_PACKET_HEADER:
-               status = after_packet_header_state(notit);
-               break;
-       case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
-               status = read_packet_context_begin_state(notit);
-               break;
-       case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
-               status = read_packet_context_continue_state(notit);
-               break;
-       case STATE_AFTER_STREAM_PACKET_CONTEXT:
-               status = after_packet_context_state(notit);
-               break;
-       case STATE_CHECK_EMIT_MSG_STREAM_BEGINNING:
-               status = check_emit_msg_stream_beginning_state(notit);
-               break;
-       case STATE_EMIT_MSG_STREAM_BEGINNING:
-               notit->state = STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING;
-               break;
-       case STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING:
-               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
-               break;
-       case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
-               status = check_emit_msg_discarded_events(notit);
-               break;
-       case STATE_EMIT_MSG_DISCARDED_EVENTS:
-               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
-               break;
-       case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
-               status = check_emit_msg_discarded_packets(notit);
-               break;
-       case STATE_EMIT_MSG_DISCARDED_PACKETS:
-               notit->state = STATE_EMIT_MSG_PACKET_BEGINNING;
-               break;
-       case STATE_EMIT_MSG_PACKET_BEGINNING:
-               notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
-               break;
-       case STATE_DSCOPE_EVENT_HEADER_BEGIN:
-               status = read_event_header_begin_state(notit);
-               break;
-       case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
-               status = read_event_header_continue_state(notit);
-               break;
-       case STATE_AFTER_EVENT_HEADER:
-               status = after_event_header_state(notit);
-               break;
-       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
-               status = read_event_common_context_begin_state(notit);
-               break;
-       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
-               status = read_event_common_context_continue_state(notit);
-               break;
-       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
-               status = read_event_spec_context_begin_state(notit);
-               break;
-       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
-               status = read_event_spec_context_continue_state(notit);
-               break;
-       case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
-               status = read_event_payload_begin_state(notit);
-               break;
-       case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
-               status = read_event_payload_continue_state(notit);
-               break;
-       case STATE_EMIT_MSG_EVENT:
-               notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
-               break;
-       case STATE_SKIP_PACKET_PADDING:
-               status = skip_packet_padding_state(notit);
-               break;
-       case STATE_EMIT_MSG_PACKET_END_MULTI:
-               notit->state = STATE_SKIP_PACKET_PADDING;
-               break;
-       case STATE_EMIT_MSG_PACKET_END_SINGLE:
-               notit->state = STATE_CHECK_EMIT_MSG_STREAM_ACTIVITY_END;
-               break;
-       case STATE_CHECK_EMIT_MSG_STREAM_ACTIVITY_END:
-               status = check_emit_msg_stream_activity_end(notit);
-               break;
-       case STATE_EMIT_MSG_STREAM_ACTIVITY_END:
-               notit->state = STATE_EMIT_MSG_STREAM_END;
-               break;
-       case STATE_EMIT_MSG_STREAM_END:
-               notit->state = STATE_DONE;
-               break;
-       case STATE_DONE:
-               break;
-       default:
-               BT_LOGD("Unknown CTF plugin message iterator state: "
-                       "notit-addr=%p, state=%d", notit, notit->state);
-               abort();
-       }
-
-       BT_LOGV("Handled state: notit-addr=%p, status=%s, "
-               "prev-state=%s, cur-state=%s",
-               notit, bt_msg_iter_status_string(status),
-               state_string(state), state_string(notit->state));
-       return status;
-}
-
-BT_HIDDEN
-void bt_msg_iter_reset_for_next_stream_file(struct bt_msg_iter *notit)
-{
-       BT_ASSERT(notit);
-       BT_LOGD("Resetting message iterator: addr=%p", notit);
-       stack_clear(notit->stack);
-       notit->meta.sc = NULL;
-       notit->meta.ec = NULL;
-       BT_PACKET_PUT_REF_AND_RESET(notit->packet);
-       BT_STREAM_PUT_REF_AND_RESET(notit->stream);
-       BT_MESSAGE_PUT_REF_AND_RESET(notit->event_msg);
-       release_all_dscopes(notit);
-       notit->cur_dscope_field = NULL;
-
-       if (notit->packet_context_field) {
-               bt_packet_context_field_release(notit->packet_context_field);
-               notit->packet_context_field = NULL;
-       }
-
-       notit->buf.addr = NULL;
-       notit->buf.sz = 0;
-       notit->buf.at = 0;
-       notit->buf.last_eh_at = SIZE_MAX;
-       notit->buf.packet_offset = 0;
-       notit->state = STATE_INIT;
-       notit->cur_exp_packet_content_size = -1;
-       notit->cur_exp_packet_total_size = -1;
-       notit->cur_packet_offset = -1;
-       notit->cur_event_class_id = -1;
-       notit->snapshots.beginning_clock = UINT64_C(-1);
-       notit->snapshots.end_clock = UINT64_C(-1);
-}
-
-/**
- * Resets the internal state of a CTF message iterator.
- */
-BT_HIDDEN
-void bt_msg_iter_reset(struct bt_msg_iter *notit)
-{
-       bt_msg_iter_reset_for_next_stream_file(notit);
-       notit->cur_stream_class_id = -1;
-       notit->cur_data_stream_id = -1;
-       notit->emit_stream_begin_msg = true;
-       notit->emit_stream_end_msg = true;
-       notit->snapshots.discarded_events = UINT64_C(-1);
-       notit->snapshots.packets = UINT64_C(-1);
-       notit->prev_packet_snapshots.discarded_events = UINT64_C(-1);
-       notit->prev_packet_snapshots.packets = UINT64_C(-1);
-       notit->prev_packet_snapshots.beginning_clock = UINT64_C(-1);
-       notit->prev_packet_snapshots.end_clock = UINT64_C(-1);
-}
-
-static
-int bt_msg_iter_switch_packet(struct bt_msg_iter *notit)
-{
-       int ret = 0;
-
-       /*
-        * We don't put the stream class here because we need to make
-        * sure that all the packets processed by the same message
-        * iterator refer to the same stream class (the first one).
-        */
-       BT_ASSERT(notit);
-
-       if (notit->cur_exp_packet_total_size != -1) {
-               notit->cur_packet_offset += notit->cur_exp_packet_total_size;
-       }
-
-       BT_LOGV("Switching packet: notit-addr=%p, cur=%zu, "
-               "packet-offset=%" PRId64, notit, notit->buf.at,
-               notit->cur_packet_offset);
-       stack_clear(notit->stack);
-       notit->meta.ec = NULL;
-       BT_PACKET_PUT_REF_AND_RESET(notit->packet);
-       BT_MESSAGE_PUT_REF_AND_RESET(notit->event_msg);
-       release_all_dscopes(notit);
-       notit->cur_dscope_field = NULL;
-
-       /*
-        * Adjust current buffer so that addr points to the beginning of the new
-        * packet.
-        */
-       if (notit->buf.addr) {
-               size_t consumed_bytes = (size_t) (notit->buf.at / CHAR_BIT);
-
-               /* Packets are assumed to start on a byte frontier. */
-               if (notit->buf.at % CHAR_BIT) {
-                       BT_LOGW("Cannot switch packet: current position is not a multiple of 8: "
-                               "notit-addr=%p, cur=%zu", notit, notit->buf.at);
-                       ret = -1;
-                       goto end;
-               }
-
-               notit->buf.addr += consumed_bytes;
-               notit->buf.sz -= consumed_bytes;
-               notit->buf.at = 0;
-               notit->buf.packet_offset = 0;
-               BT_LOGV("Adjusted buffer: addr=%p, size=%zu",
-                       notit->buf.addr, notit->buf.sz);
-       }
-
-       notit->cur_exp_packet_content_size = -1;
-       notit->cur_exp_packet_total_size = -1;
-       notit->cur_stream_class_id = -1;
-       notit->cur_event_class_id = -1;
-       notit->cur_data_stream_id = -1;
-       notit->prev_packet_snapshots = notit->snapshots;
-       notit->snapshots.discarded_events = UINT64_C(-1);
-       notit->snapshots.packets = UINT64_C(-1);
-       notit->snapshots.beginning_clock = UINT64_C(-1);
-       notit->snapshots.end_clock = UINT64_C(-1);
-
-end:
-       return ret;
-}
-
-static
-bt_field *borrow_next_field(struct bt_msg_iter *notit)
-{
-       bt_field *next_field = NULL;
-       bt_field *base_field;
-       const bt_field_class *base_fc;
-       size_t index;
-
-       BT_ASSERT(!stack_empty(notit->stack));
-       index = stack_top(notit->stack)->index;
-       base_field = stack_top(notit->stack)->base;
-       BT_ASSERT(base_field);
-       base_fc = bt_field_borrow_class_const(base_field);
-       BT_ASSERT(base_fc);
-
-       switch (bt_field_class_get_type(base_fc)) {
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-       {
-               BT_ASSERT(index <
-                       bt_field_class_structure_get_member_count(
-                               bt_field_borrow_class_const(
-                                               base_field)));
-               next_field =
-                       bt_field_structure_borrow_member_field_by_index(
-                               base_field, index);
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-               BT_ASSERT(index < bt_field_array_get_length(base_field));
-               next_field = bt_field_array_borrow_element_field_by_index(
-                       base_field, index);
-               break;
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-               BT_ASSERT(index == 0);
-               next_field = bt_field_variant_borrow_selected_option_field(
-                       base_field);
-               break;
-       default:
-               abort();
-       }
-
-       BT_ASSERT(next_field);
-       return next_field;
-}
-
-static
-void update_default_clock(struct bt_msg_iter *notit, uint64_t new_val,
-               uint64_t new_val_size)
-{
-       uint64_t new_val_mask;
-       uint64_t cur_value_masked;
-
-       BT_ASSERT(new_val_size > 0);
-
-       /*
-        * Special case for a 64-bit new value, which is the limit
-        * of a clock value as of this version: overwrite the
-        * current value directly.
-        */
-       if (new_val_size == 64) {
-               notit->default_clock_snapshot = new_val;
-               goto end;
-       }
-
-       new_val_mask = (1ULL << new_val_size) - 1;
-       cur_value_masked = notit->default_clock_snapshot & new_val_mask;
-
-       if (new_val < cur_value_masked) {
-               /*
-                * It looks like a wrap happened on the number of bits
-                * of the requested new value. Assume that the clock
-                * value wrapped only one time.
-                */
-               notit->default_clock_snapshot += new_val_mask + 1;
-       }
-
-       /* Clear the low bits of the current clock value. */
-       notit->default_clock_snapshot &= ~new_val_mask;
-
-       /* Set the low bits of the current clock value. */
-       notit->default_clock_snapshot |= new_val;
-
-end:
-       BT_LOGV("Updated default clock's value from integer field's value: "
-               "value=%" PRIu64, notit->default_clock_snapshot);
-}
-
-static
-enum bt_bfcr_status bfcr_unsigned_int_cb(uint64_t value,
-               struct ctf_field_class *fc, void *data)
-{
-       struct bt_msg_iter *notit = data;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       bt_field *field = NULL;
-       struct ctf_field_class_int *int_fc = (void *) fc;
-
-       BT_LOGV("Unsigned integer function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d, value=%" PRIu64,
-               notit, notit->bfcr, fc, fc->type, fc->in_ir, value);
-
-       if (likely(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE)) {
-               goto update_def_clock;
-       }
-
-       switch (int_fc->meaning) {
-       case CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID:
-               notit->cur_event_class_id = value;
-               break;
-       case CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID:
-               notit->cur_data_stream_id = value;
-               break;
-       case CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME:
-               notit->snapshots.beginning_clock = value;
-               break;
-       case CTF_FIELD_CLASS_MEANING_PACKET_END_TIME:
-               notit->snapshots.end_clock = value;
-               break;
-       case CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID:
-               notit->cur_stream_class_id = value;
-               break;
-       case CTF_FIELD_CLASS_MEANING_MAGIC:
-               if (value != 0xc1fc1fc1) {
-                       BT_LOGW("Invalid CTF magic number: notit-addr=%p, "
-                               "magic=%" PRIx64, notit, value);
-                       status = BT_BFCR_STATUS_ERROR;
-                       goto end;
-               }
-
-               break;
-       case CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT:
-               notit->snapshots.packets = value;
-               break;
-       case CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT:
-               notit->snapshots.discarded_events = value;
-               break;
-       case CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE:
-               notit->cur_exp_packet_total_size = value;
-               break;
-       case CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE:
-               notit->cur_exp_packet_content_size = value;
-               break;
-       default:
-               abort();
-       }
-
-update_def_clock:
-       if (unlikely(int_fc->mapped_clock_class)) {
-               update_default_clock(notit, value, int_fc->base.size);
-       }
-
-       if (unlikely(int_fc->storing_index >= 0)) {
-               g_array_index(notit->stored_values, uint64_t,
-                       (uint64_t) int_fc->storing_index) = value;
-       }
-
-       if (unlikely(!fc->in_ir)) {
-               goto end;
-       }
-
-       field = borrow_next_field(notit);
-       BT_ASSERT(field);
-       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
-       BT_ASSERT(bt_field_get_class_type(field) ==
-                 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
-                 bt_field_get_class_type(field) ==
-                 BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION);
-       bt_field_unsigned_integer_set_value(field, value);
-       stack_top(notit->stack)->index++;
-
-end:
-       return status;
-}
-
-static
-enum bt_bfcr_status bfcr_unsigned_int_char_cb(uint64_t value,
-               struct ctf_field_class *fc, void *data)
-{
-       int ret;
-       struct bt_msg_iter *notit = data;
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       bt_field *string_field = NULL;
-       struct ctf_field_class_int *int_fc = (void *) fc;
-       char str[2] = {'\0', '\0'};
-
-       BT_LOGV("Unsigned integer character function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d, value=%" PRIu64,
-               notit, notit->bfcr, fc, fc->type, fc->in_ir, value);
-       BT_ASSERT(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
-       BT_ASSERT(!int_fc->mapped_clock_class);
-       BT_ASSERT(int_fc->storing_index < 0);
-
-       if (unlikely(!fc->in_ir)) {
-               goto end;
-       }
-
-       if (notit->done_filling_string) {
-               goto end;
-       }
-
-       if (value == 0) {
-               notit->done_filling_string = true;
-               goto end;
-       }
-
-       string_field = stack_top(notit->stack)->base;
-       BT_ASSERT(bt_field_get_class_type(string_field) ==
-                 BT_FIELD_CLASS_TYPE_STRING);
-
-       /* Append character */
-       str[0] = (char) value;
-       ret = bt_field_string_append_with_length(string_field, str, 1);
-       if (ret) {
-               BT_LOGE("Cannot append character to string field's value: "
-                       "notit-addr=%p, field-addr=%p, ret=%d",
-                       notit, string_field, ret);
-               status = BT_BFCR_STATUS_ERROR;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_bfcr_status bfcr_signed_int_cb(int64_t value,
-               struct ctf_field_class *fc, void *data)
-{
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       bt_field *field = NULL;
-       struct bt_msg_iter *notit = data;
-       struct ctf_field_class_int *int_fc = (void *) fc;
-
-       BT_LOGV("Signed integer function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d, value=%" PRId64,
-               notit, notit->bfcr, fc, fc->type, fc->in_ir, value);
-       BT_ASSERT(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
-
-       if (unlikely(int_fc->storing_index >= 0)) {
-               g_array_index(notit->stored_values, uint64_t,
-                       (uint64_t) int_fc->storing_index) = (uint64_t) value;
-       }
-
-       if (unlikely(!fc->in_ir)) {
-               goto end;
-       }
-
-       field = borrow_next_field(notit);
-       BT_ASSERT(field);
-       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
-       BT_ASSERT(bt_field_get_class_type(field) ==
-                 BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
-                 bt_field_get_class_type(field) ==
-                 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION);
-       bt_field_signed_integer_set_value(field, value);
-       stack_top(notit->stack)->index++;
-
-end:
-       return status;
-}
-
-static
-enum bt_bfcr_status bfcr_floating_point_cb(double value,
-               struct ctf_field_class *fc, void *data)
-{
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       bt_field *field = NULL;
-       struct bt_msg_iter *notit = data;
-
-       BT_LOGV("Floating point number function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d, value=%f",
-               notit, notit->bfcr, fc, fc->type, fc->in_ir, value);
-
-       if (unlikely(!fc->in_ir)) {
-               goto end;
-       }
-
-       field = borrow_next_field(notit);
-       BT_ASSERT(field);
-       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
-       BT_ASSERT(bt_field_get_class_type(field) ==
-                 BT_FIELD_CLASS_TYPE_REAL);
-       bt_field_real_set_value(field, value);
-       stack_top(notit->stack)->index++;
-
-end:
-       return status;
-}
-
-static
-enum bt_bfcr_status bfcr_string_begin_cb(
-               struct ctf_field_class *fc, void *data)
-{
-       bt_field *field = NULL;
-       struct bt_msg_iter *notit = data;
-       int ret;
-
-       BT_LOGV("String (beginning) function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d",
-               notit, notit->bfcr, fc, fc->type, fc->in_ir);
-
-       if (unlikely(!fc->in_ir)) {
-               goto end;
-       }
-
-       field = borrow_next_field(notit);
-       BT_ASSERT(field);
-       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
-       BT_ASSERT(bt_field_get_class_type(field) ==
-                 BT_FIELD_CLASS_TYPE_STRING);
-       ret = bt_field_string_clear(field);
-       BT_ASSERT(ret == 0);
-
-       /*
-        * Push on stack. Not a compound class per se, but we know that
-        * only bfcr_string_cb() may be called between this call and a
-        * subsequent call to bfcr_string_end_cb().
-        */
-       stack_push(notit->stack, field);
-
-end:
-       return BT_BFCR_STATUS_OK;
-}
-
-static
-enum bt_bfcr_status bfcr_string_cb(const char *value,
-               size_t len, struct ctf_field_class *fc, void *data)
-{
-       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
-       bt_field *field = NULL;
-       struct bt_msg_iter *notit = data;
-       int ret;
-
-       BT_LOGV("String (substring) function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d, string-length=%zu",
-               notit, notit->bfcr, fc, fc->type, fc->in_ir,
-               len);
-
-       if (unlikely(!fc->in_ir)) {
-               goto end;
-       }
-
-       field = stack_top(notit->stack)->base;
-       BT_ASSERT(field);
-
-       /* Append current substring */
-       ret = bt_field_string_append_with_length(field, value, len);
-       if (ret) {
-               BT_LOGE("Cannot append substring to string field's value: "
-                       "notit-addr=%p, field-addr=%p, string-length=%zu, "
-                       "ret=%d", notit, field, len, ret);
-               status = BT_BFCR_STATUS_ERROR;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_bfcr_status bfcr_string_end_cb(
-               struct ctf_field_class *fc, void *data)
-{
-       struct bt_msg_iter *notit = data;
-
-       BT_LOGV("String (end) function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d",
-               notit, notit->bfcr, fc, fc->type, fc->in_ir);
-
-       if (unlikely(!fc->in_ir)) {
-               goto end;
-       }
-
-       /* Pop string field */
-       stack_pop(notit->stack);
-
-       /* Go to next field */
-       stack_top(notit->stack)->index++;
-
-end:
-       return BT_BFCR_STATUS_OK;
-}
-
-enum bt_bfcr_status bfcr_compound_begin_cb(
-               struct ctf_field_class *fc, void *data)
-{
-       struct bt_msg_iter *notit = data;
-       bt_field *field;
-
-       BT_LOGV("Compound (beginning) function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d",
-               notit, notit->bfcr, fc, fc->type, fc->in_ir);
-
-       if (!fc->in_ir) {
-               goto end;
-       }
-
-       /* Borrow field */
-       if (stack_empty(notit->stack)) {
-               /* Root: already set by read_dscope_begin_state() */
-               field = notit->cur_dscope_field;
-       } else {
-               field = borrow_next_field(notit);
-               BT_ASSERT(field);
-       }
-
-       /* Push field */
-       BT_ASSERT(field);
-       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
-       stack_push(notit->stack, field);
-
-       /*
-        * Change BFCR "unsigned int" callback if it's a text
-        * array/sequence.
-        */
-       if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY ||
-                       fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               if (array_fc->is_text) {
-                       int ret;
-
-                       BT_ASSERT(bt_field_get_class_type(field) ==
-                                 BT_FIELD_CLASS_TYPE_STRING);
-                       notit->done_filling_string = false;
-                       ret = bt_field_string_clear(field);
-                       BT_ASSERT(ret == 0);
-                       bt_bfcr_set_unsigned_int_cb(notit->bfcr,
-                               bfcr_unsigned_int_char_cb);
-               }
-       }
-
-end:
-       return BT_BFCR_STATUS_OK;
-}
-
-enum bt_bfcr_status bfcr_compound_end_cb(
-               struct ctf_field_class *fc, void *data)
-{
-       struct bt_msg_iter *notit = data;
-
-       BT_LOGV("Compound (end) function called from BFCR: "
-               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
-               "fc-type=%d, fc-in-ir=%d",
-               notit, notit->bfcr, fc, fc->type, fc->in_ir);
-
-       if (!fc->in_ir) {
-               goto end;
-       }
-
-       BT_ASSERT(!stack_empty(notit->stack));
-       BT_ASSERT(bt_field_borrow_class_const(stack_top(notit->stack)->base) ==
-               fc->ir_fc);
-
-       /*
-        * Reset BFCR "unsigned int" callback if it's a text
-        * array/sequence.
-        */
-       if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY ||
-                       fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
-               struct ctf_field_class_array_base *array_fc = (void *) fc;
-
-               if (array_fc->is_text) {
-                       BT_ASSERT(bt_field_get_class_type(
-                               stack_top(notit->stack)->base) ==
-                               BT_FIELD_CLASS_TYPE_STRING);
-                       bt_bfcr_set_unsigned_int_cb(notit->bfcr,
-                               bfcr_unsigned_int_cb);
-               }
-       }
-
-       /* Pop stack */
-       stack_pop(notit->stack);
-
-       /* If the stack is not empty, increment the base's index */
-       if (!stack_empty(notit->stack)) {
-               stack_top(notit->stack)->index++;
-       }
-
-end:
-       return BT_BFCR_STATUS_OK;
-}
-
-static
-int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data)
-{
-       bt_field *seq_field;
-       struct bt_msg_iter *notit = data;
-       struct ctf_field_class_sequence *seq_fc = (void *) fc;
-       int64_t length = -1;
-       int ret;
-
-       length = (uint64_t) g_array_index(notit->stored_values, uint64_t,
-               seq_fc->stored_length_index);
-       seq_field = stack_top(notit->stack)->base;
-       BT_ASSERT(seq_field);
-
-       /*
-        * bfcr_get_sequence_length_cb() also gets called back for a
-        * text sequence, but the destination field is a string field.
-        * Only set the field's sequence length if the destination field
-        * is a sequence field.
-        */
-       if (!seq_fc->base.is_text) {
-               BT_ASSERT(bt_field_get_class_type(seq_field) ==
-                       BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY);
-               ret = bt_field_dynamic_array_set_length(seq_field,
-                       (uint64_t) length);
-               if (ret) {
-                       BT_LOGE("Cannot set dynamic array field's length field: "
-                               "notit-addr=%p, field-addr=%p, "
-                               "length=%" PRIu64, notit, seq_field, length);
-               }
-       }
-
-       return length;
-}
-
-static
-struct ctf_field_class *bfcr_borrow_variant_selected_field_class_cb(
-               struct ctf_field_class *fc, void *data)
-{
-       int ret;
-       uint64_t i;
-       int64_t option_index = -1;
-       struct bt_msg_iter *notit = data;
-       struct ctf_field_class_variant *var_fc = (void *) fc;
-       struct ctf_named_field_class *selected_option = NULL;
-       struct ctf_field_class *ret_fc = NULL;
-       union {
-               uint64_t u;
-               int64_t i;
-       } tag;
-
-       /* Get variant's tag */
-       tag.u = g_array_index(notit->stored_values, uint64_t,
-               var_fc->stored_tag_index);
-
-       /*
-        * Check each range to find the selected option's index.
-        */
-       if (var_fc->tag_fc->base.is_signed) {
-               for (i = 0; i < var_fc->ranges->len; i++) {
-                       struct ctf_field_class_variant_range *range =
-                               ctf_field_class_variant_borrow_range_by_index(
-                                       var_fc, i);
-
-                       if (tag.i >= range->range.lower.i &&
-                                       tag.i <= range->range.upper.i) {
-                               option_index = (int64_t) range->option_index;
-                               break;
-                       }
-               }
-       } else {
-               for (i = 0; i < var_fc->ranges->len; i++) {
-                       struct ctf_field_class_variant_range *range =
-                               ctf_field_class_variant_borrow_range_by_index(
-                                       var_fc, i);
-
-                       if (tag.u >= range->range.lower.u &&
-                                       tag.u <= range->range.upper.u) {
-                               option_index = (int64_t) range->option_index;
-                               break;
-                       }
-               }
-       }
-
-       if (option_index < 0) {
-               BT_LOGW("Cannot find variant field class's option: "
-                       "notit-addr=%p, var-fc-addr=%p, u-tag=%" PRIu64 ", "
-                       "i-tag=%" PRId64, notit, var_fc, tag.u, tag.i);
-               goto end;
-       }
-
-       selected_option = ctf_field_class_variant_borrow_option_by_index(
-               var_fc, (uint64_t) option_index);
-
-       if (selected_option->fc->in_ir) {
-               bt_field *var_field = stack_top(notit->stack)->base;
-
-               ret = bt_field_variant_select_option_field(
-                       var_field, option_index);
-               if (ret) {
-                       BT_LOGW("Cannot select variant field's option field: "
-                               "notit-addr=%p, var-field-addr=%p, "
-                               "opt-index=%" PRId64, notit, var_field,
-                               option_index);
-                       goto end;
-               }
-       }
-
-       ret_fc = selected_option->fc;
-
-end:
-       return ret_fc;
-}
-
-static
-void create_msg_stream_beginning(struct bt_msg_iter *notit,
-               bt_message **message)
-{
-       bt_message *ret = NULL;
-
-       BT_ASSERT(notit->stream);
-       BT_ASSERT(notit->msg_iter);
-       ret = bt_message_stream_beginning_create(notit->msg_iter,
-               notit->stream);
-       if (!ret) {
-               BT_LOGE("Cannot create stream beginning message: "
-                       "notit-addr=%p, stream-addr=%p",
-                       notit, notit->stream);
-               return;
-       }
-
-       *message = ret;
-}
-
-static
-void create_msg_stream_activity_beginning(struct bt_msg_iter *notit,
-               bt_message **message)
-{
-       bt_message *ret = NULL;
-
-       BT_ASSERT(notit->stream);
-       BT_ASSERT(notit->msg_iter);
-       ret = bt_message_stream_activity_beginning_create(notit->msg_iter,
-               notit->stream);
-       if (!ret) {
-               BT_LOGE("Cannot create stream activity beginning message: "
-                       "notit-addr=%p, stream-addr=%p",
-                       notit, notit->stream);
-               return;
-       }
-
-       *message = ret;
-}
-
-static
-void create_msg_stream_activity_end(struct bt_msg_iter *notit,
-               bt_message **message)
-{
-       bt_message *ret = NULL;
-
-       if (!notit->stream) {
-               BT_LOGE("Cannot create stream for stream message: "
-                       "notit-addr=%p", notit);
-               return;
-       }
-
-       BT_ASSERT(notit->stream);
-       BT_ASSERT(notit->msg_iter);
-       ret = bt_message_stream_activity_end_create(notit->msg_iter,
-               notit->stream);
-       if (!ret) {
-               BT_LOGE("Cannot create stream activity end message: "
-                       "notit-addr=%p, stream-addr=%p",
-                       notit, notit->stream);
-               return;
-       }
-
-       *message = ret;
-}
-
-static
-void create_msg_stream_end(struct bt_msg_iter *notit, bt_message **message)
-{
-       bt_message *ret;
-
-       if (!notit->stream) {
-               BT_LOGE("Cannot create stream for stream message: "
-                       "notit-addr=%p", notit);
-               return;
-       }
-
-       BT_ASSERT(notit->msg_iter);
-       ret = bt_message_stream_end_create(notit->msg_iter,
-               notit->stream);
-       if (!ret) {
-               BT_LOGE("Cannot create stream end message: "
-                       "notit-addr=%p, stream-addr=%p",
-                       notit, notit->stream);
-               return;
-       }
-
-       *message = ret;
-}
-
-static
-void create_msg_packet_beginning(struct bt_msg_iter *notit,
-               bt_message **message)
-{
-       int ret;
-       enum bt_msg_iter_status status;
-       bt_message *msg = NULL;
-       const bt_stream_class *sc;
-
-       status = set_current_packet(notit);
-       if (status != BT_MSG_ITER_STATUS_OK) {
-               goto end;
-       }
-
-       BT_ASSERT(notit->packet);
-       sc = notit->meta.sc->ir_sc;
-       BT_ASSERT(sc);
-
-       if (notit->packet_context_field) {
-               ret = bt_packet_move_context_field(
-                       notit->packet, notit->packet_context_field);
-               if (ret) {
-                       goto end;
-               }
-
-               notit->packet_context_field = NULL;
-
-               /*
-                * At this point notit->dscopes.stream_packet_context
-                * has the same value as the packet context field within
-                * notit->packet.
-                */
-               BT_ASSERT(bt_packet_borrow_context_field(
-                       notit->packet) ==
-                       notit->dscopes.stream_packet_context);
-       }
-
-       BT_ASSERT(notit->msg_iter);
-
-       if (notit->meta.sc->packets_have_ts_begin) {
-               BT_ASSERT(notit->snapshots.beginning_clock != UINT64_C(-1));
-               msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
-                       notit->msg_iter, notit->packet,
-                       notit->snapshots.beginning_clock);
-       } else {
-               msg = bt_message_packet_beginning_create(notit->msg_iter,
-                       notit->packet);
-       }
-
-       if (!msg) {
-               BT_LOGE("Cannot create packet beginning message: "
-                       "notit-addr=%p, packet-addr=%p",
-                       notit, notit->packet);
-               goto end;
-       }
-
-       *message = msg;
-
-end:
-       return;
-}
-
-static
-void create_msg_packet_end(struct bt_msg_iter *notit, bt_message **message)
-{
-       bt_message *msg;
-
-       if (!notit->packet) {
-               return;
-       }
-
-       /* Update default clock from packet's end time */
-       if (notit->snapshots.end_clock != UINT64_C(-1)) {
-               notit->default_clock_snapshot = notit->snapshots.end_clock;
-       }
-
-       BT_ASSERT(notit->msg_iter);
-
-       if (notit->meta.sc->packets_have_ts_end) {
-               BT_ASSERT(notit->snapshots.end_clock != UINT64_C(-1));
-               msg = bt_message_packet_end_create_with_default_clock_snapshot(
-                       notit->msg_iter, notit->packet,
-                       notit->snapshots.end_clock);
-       } else {
-               msg = bt_message_packet_end_create(notit->msg_iter,
-                       notit->packet);
-       }
-
-       if (!msg) {
-               BT_LOGE("Cannot create packet end message: "
-                       "notit-addr=%p, packet-addr=%p",
-                       notit, notit->packet);
-               return;
-
-       }
-
-       BT_PACKET_PUT_REF_AND_RESET(notit->packet);
-       *message = msg;
-}
-
-static
-void create_msg_discarded_events(struct bt_msg_iter *notit,
-               bt_message **message)
-{
-       bt_message *msg;
-       uint64_t beginning_raw_value = UINT64_C(-1);
-       uint64_t end_raw_value = UINT64_C(-1);
-
-       BT_ASSERT(notit->msg_iter);
-       BT_ASSERT(notit->stream);
-       BT_ASSERT(notit->meta.sc->has_discarded_events);
-
-       if (notit->meta.sc->discarded_events_have_default_cs) {
-               if (notit->prev_packet_snapshots.discarded_events == UINT64_C(-1)) {
-                       /*
-                        * We discarded events, but before (and possibly
-                        * including) the current packet: use this packet's time
-                        * range, and do not have a specific count.
-                        */
-                       beginning_raw_value = notit->snapshots.beginning_clock;
-                       end_raw_value = notit->snapshots.end_clock;
-               } else {
-                       beginning_raw_value = notit->prev_packet_snapshots.end_clock;
-                       end_raw_value = notit->snapshots.end_clock;
-               }
-
-               BT_ASSERT(beginning_raw_value != UINT64_C(-1));
-               BT_ASSERT(end_raw_value != UINT64_C(-1));
-               msg = bt_message_discarded_events_create_with_default_clock_snapshots(
-                       notit->msg_iter, notit->stream, beginning_raw_value,
-                       end_raw_value);
-       } else {
-               msg = bt_message_discarded_events_create(notit->msg_iter,
-                       notit->stream);
-       }
-
-       if (!msg) {
-               BT_LOGE("Cannot create discarded events message: "
-                       "notit-addr=%p, stream-addr=%p",
-                       notit, notit->stream);
-               return;
-       }
-
-       if (notit->prev_packet_snapshots.discarded_events != UINT64_C(-1)) {
-               bt_message_discarded_events_set_count(msg,
-                       notit->snapshots.discarded_events -
-                       notit->prev_packet_snapshots.discarded_events);
-       }
-
-       *message = msg;
-}
-
-static
-void create_msg_discarded_packets(struct bt_msg_iter *notit,
-               bt_message **message)
-{
-       bt_message *msg;
-
-       BT_ASSERT(notit->msg_iter);
-       BT_ASSERT(notit->stream);
-       BT_ASSERT(notit->meta.sc->has_discarded_packets);
-       BT_ASSERT(notit->prev_packet_snapshots.packets !=
-               UINT64_C(-1));
-
-       if (notit->meta.sc->discarded_packets_have_default_cs) {
-               BT_ASSERT(notit->prev_packet_snapshots.end_clock != UINT64_C(-1));
-               BT_ASSERT(notit->snapshots.beginning_clock != UINT64_C(-1));
-               msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
-                       notit->msg_iter, notit->stream,
-                       notit->prev_packet_snapshots.end_clock,
-                       notit->snapshots.beginning_clock);
-       } else {
-               msg = bt_message_discarded_packets_create(notit->msg_iter,
-                       notit->stream);
-       }
-
-       if (!msg) {
-               BT_LOGE("Cannot create discarded packets message: "
-                       "notit-addr=%p, stream-addr=%p",
-                       notit, notit->stream);
-               return;
-       }
-
-       bt_message_discarded_packets_set_count(msg,
-               notit->snapshots.packets -
-                       notit->prev_packet_snapshots.packets - 1);
-       *message = msg;
-}
-
-BT_HIDDEN
-struct bt_msg_iter *bt_msg_iter_create(struct ctf_trace_class *tc,
-               size_t max_request_sz,
-               struct bt_msg_iter_medium_ops medops, void *data)
-{
-       struct bt_msg_iter *notit = NULL;
-       struct bt_bfcr_cbs cbs = {
-               .classes = {
-                       .signed_int = bfcr_signed_int_cb,
-                       .unsigned_int = bfcr_unsigned_int_cb,
-                       .floating_point = bfcr_floating_point_cb,
-                       .string_begin = bfcr_string_begin_cb,
-                       .string = bfcr_string_cb,
-                       .string_end = bfcr_string_end_cb,
-                       .compound_begin = bfcr_compound_begin_cb,
-                       .compound_end = bfcr_compound_end_cb,
-               },
-               .query = {
-                       .get_sequence_length = bfcr_get_sequence_length_cb,
-                       .borrow_variant_selected_field_class = bfcr_borrow_variant_selected_field_class_cb,
-               },
-       };
-
-       BT_ASSERT(tc);
-       BT_ASSERT(medops.request_bytes);
-       BT_ASSERT(medops.borrow_stream);
-       BT_LOGD("Creating CTF plugin message iterator: "
-               "trace-addr=%p, max-request-size=%zu, "
-               "data=%p", tc, max_request_sz, data);
-       notit = g_new0(struct bt_msg_iter, 1);
-       if (!notit) {
-               BT_LOGE_STR("Failed to allocate one CTF plugin message iterator.");
-               goto end;
-       }
-       notit->meta.tc = tc;
-       notit->medium.medops = medops;
-       notit->medium.max_request_sz = max_request_sz;
-       notit->medium.data = data;
-       notit->stack = stack_new(notit);
-       notit->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t));
-       g_array_set_size(notit->stored_values, tc->stored_value_count);
-
-       if (!notit->stack) {
-               BT_LOGE_STR("Failed to create field stack.");
-               goto error;
-       }
-
-       notit->bfcr = bt_bfcr_create(cbs, notit);
-       if (!notit->bfcr) {
-               BT_LOGE_STR("Failed to create binary class reader (BFCR).");
-               goto error;
-       }
-
-       bt_msg_iter_reset(notit);
-       BT_LOGD("Created CTF plugin message iterator: "
-               "trace-addr=%p, max-request-size=%zu, "
-               "data=%p, notit-addr=%p",
-               tc, max_request_sz, data, notit);
-       notit->cur_packet_offset = 0;
-
-end:
-       return notit;
-
-error:
-       bt_msg_iter_destroy(notit);
-       notit = NULL;
-       goto end;
-}
-
-void bt_msg_iter_destroy(struct bt_msg_iter *notit)
-{
-       BT_PACKET_PUT_REF_AND_RESET(notit->packet);
-       BT_STREAM_PUT_REF_AND_RESET(notit->stream);
-       release_all_dscopes(notit);
-
-       BT_LOGD("Destroying CTF plugin message iterator: addr=%p", notit);
-
-       if (notit->stack) {
-               BT_LOGD_STR("Destroying field stack.");
-               stack_destroy(notit->stack);
-       }
-
-       if (notit->bfcr) {
-               BT_LOGD("Destroying BFCR: bfcr-addr=%p", notit->bfcr);
-               bt_bfcr_destroy(notit->bfcr);
-       }
-
-       if (notit->stored_values) {
-               g_array_free(notit->stored_values, TRUE);
-       }
-
-       g_free(notit);
-}
-
-enum bt_msg_iter_status bt_msg_iter_get_next_message(
-               struct bt_msg_iter *notit,
-               bt_self_message_iterator *msg_iter, bt_message **message)
-{
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-
-       BT_ASSERT(notit);
-       BT_ASSERT(message);
-       notit->msg_iter = msg_iter;
-       notit->set_stream = true;
-       BT_LOGV("Getting next message: notit-addr=%p", notit);
-
-       while (true) {
-               status = handle_state(notit);
-               if (unlikely(status == BT_MSG_ITER_STATUS_AGAIN)) {
-                       BT_LOGV_STR("Medium returned BT_MSG_ITER_STATUS_AGAIN.");
-                       goto end;
-               } else if (unlikely(status != BT_MSG_ITER_STATUS_OK)) {
-                       BT_LOGW("Cannot handle state: notit-addr=%p, state=%s",
-                               notit, state_string(notit->state));
-                       goto end;
-               }
-
-               switch (notit->state) {
-               case STATE_EMIT_MSG_EVENT:
-                       BT_ASSERT(notit->event_msg);
-                       *message = notit->event_msg;
-                       notit->event_msg = NULL;
-                       goto end;
-               case STATE_EMIT_MSG_DISCARDED_EVENTS:
-                       /* create_msg_discared_events() logs errors */
-                       create_msg_discarded_events(notit, message);
-
-                       if (!*message) {
-                               status = BT_MSG_ITER_STATUS_ERROR;
-                       }
-
-                       goto end;
-               case STATE_EMIT_MSG_DISCARDED_PACKETS:
-                       /* create_msg_discared_packets() logs errors */
-                       create_msg_discarded_packets(notit, message);
-
-                       if (!*message) {
-                               status = BT_MSG_ITER_STATUS_ERROR;
-                       }
-
-                       goto end;
-               case STATE_EMIT_MSG_PACKET_BEGINNING:
-                       /* create_msg_packet_beginning() logs errors */
-                       create_msg_packet_beginning(notit, message);
-
-                       if (!*message) {
-                               status = BT_MSG_ITER_STATUS_ERROR;
-                       }
-
-                       goto end;
-               case STATE_EMIT_MSG_PACKET_END_SINGLE:
-               case STATE_EMIT_MSG_PACKET_END_MULTI:
-                       /* create_msg_packet_end() logs errors */
-                       create_msg_packet_end(notit, message);
-
-                       if (!*message) {
-                               status = BT_MSG_ITER_STATUS_ERROR;
-                       }
-
-                       goto end;
-               case STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING:
-                       /* create_msg_stream_activity_beginning() logs errors */
-                       create_msg_stream_activity_beginning(notit, message);
-
-                       if (!*message) {
-                               status = BT_MSG_ITER_STATUS_ERROR;
-                       }
-
-                       goto end;
-               case STATE_EMIT_MSG_STREAM_ACTIVITY_END:
-                       /* create_msg_stream_activity_end() logs errors */
-                       create_msg_stream_activity_end(notit, message);
-
-                       if (!*message) {
-                               status = BT_MSG_ITER_STATUS_ERROR;
-                       }
-
-                       goto end;
-               case STATE_EMIT_MSG_STREAM_BEGINNING:
-                       /* create_msg_stream_beginning() logs errors */
-                       create_msg_stream_beginning(notit, message);
-
-                       if (!*message) {
-                               status = BT_MSG_ITER_STATUS_ERROR;
-                       }
-
-                       goto end;
-               case STATE_EMIT_MSG_STREAM_END:
-                       /* create_msg_stream_end() logs errors */
-                       create_msg_stream_end(notit, message);
-
-                       if (!*message) {
-                               status = BT_MSG_ITER_STATUS_ERROR;
-                       }
-
-                       goto end;
-               case STATE_DONE:
-                       status = BT_MSG_ITER_STATUS_EOF;
-                       goto end;
-               default:
-                       /* Non-emitting state: continue */
-                       break;
-               }
-       }
-
-end:
-       return status;
-}
-
-static
-enum bt_msg_iter_status read_packet_header_context_fields(
-               struct bt_msg_iter *notit)
-{
-       int ret;
-       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
-
-       BT_ASSERT(notit);
-       notit->set_stream = false;
-
-       if (notit->state == STATE_EMIT_MSG_PACKET_BEGINNING) {
-               /* We're already there */
-               goto end;
-       }
-
-       while (true) {
-               status = handle_state(notit);
-               if (unlikely(status == BT_MSG_ITER_STATUS_AGAIN)) {
-                       BT_LOGV_STR("Medium returned BT_MSG_ITER_STATUS_AGAIN.");
-                       goto end;
-               } else if (unlikely(status != BT_MSG_ITER_STATUS_OK)) {
-                       BT_LOGW("Cannot handle state: notit-addr=%p, state=%s",
-                               notit, state_string(notit->state));
-                       goto end;
-               }
-
-               switch (notit->state) {
-               case STATE_EMIT_MSG_PACKET_BEGINNING:
-                       /*
-                        * Packet header and context fields are
-                        * potentially decoded (or they don't exist).
-                        */
-                       goto end;
-               case STATE_INIT:
-               case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
-               case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
-               case STATE_AFTER_TRACE_PACKET_HEADER:
-               case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
-               case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
-               case STATE_AFTER_STREAM_PACKET_CONTEXT:
-               case STATE_CHECK_EMIT_MSG_STREAM_BEGINNING:
-               case STATE_EMIT_MSG_STREAM_BEGINNING:
-               case STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING:
-               case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
-               case STATE_EMIT_MSG_DISCARDED_EVENTS:
-               case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
-               case STATE_EMIT_MSG_DISCARDED_PACKETS:
-                       /* Non-emitting state: continue */
-                       break;
-               default:
-                       /*
-                        * We should never get past the
-                        * STATE_EMIT_MSG_PACKET_BEGINNING state.
-                        */
-                       BT_LOGF("Unexpected state: notit-addr=%p, state=%s",
-                               notit, state_string(notit->state));
-                       abort();
-               }
-       }
-
-end:
-       ret = set_current_packet_content_sizes(notit);
-       if (ret) {
-               status = BT_MSG_ITER_STATUS_ERROR;
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-void bt_msg_iter_set_medops_data(struct bt_msg_iter *notit,
-               void *medops_data)
-{
-       BT_ASSERT(notit);
-       notit->medium.data = medops_data;
-}
-
-BT_HIDDEN
-enum bt_msg_iter_status bt_msg_iter_seek(struct bt_msg_iter *notit,
-               off_t offset)
-{
-       enum bt_msg_iter_status ret = BT_MSG_ITER_STATUS_OK;
-       enum bt_msg_iter_medium_status medium_status;
-
-       BT_ASSERT(notit);
-       if (offset < 0) {
-               BT_LOGE("Cannot seek to negative offset: offset=%jd", offset);
-               ret = BT_MSG_ITER_STATUS_INVAL;
-               goto end;
-       }
-
-       if (!notit->medium.medops.seek) {
-               ret = BT_MSG_ITER_STATUS_UNSUPPORTED;
-               BT_LOGD("Aborting seek as the iterator's underlying media does not implement seek support.");
-               goto end;
-       }
-
-       medium_status = notit->medium.medops.seek(
-               BT_MSG_ITER_SEEK_WHENCE_SET, offset, notit->medium.data);
-       if (medium_status != BT_MSG_ITER_MEDIUM_STATUS_OK) {
-               if (medium_status == BT_MSG_ITER_MEDIUM_STATUS_EOF) {
-                       ret = BT_MSG_ITER_STATUS_EOF;
-               } else {
-                       ret = BT_MSG_ITER_STATUS_ERROR;
-                       goto end;
-               }
-       }
-
-       bt_msg_iter_reset(notit);
-       notit->cur_packet_offset = offset;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-enum bt_msg_iter_status bt_msg_iter_get_packet_properties(
-               struct bt_msg_iter *notit,
-               struct bt_msg_iter_packet_properties *props)
-{
-       enum bt_msg_iter_status status;
-
-       BT_ASSERT(notit);
-       BT_ASSERT(props);
-       status = read_packet_header_context_fields(notit);
-       if (status != BT_MSG_ITER_STATUS_OK) {
-               goto end;
-       }
-
-       props->exp_packet_total_size = notit->cur_exp_packet_total_size;
-       props->exp_packet_content_size = notit->cur_exp_packet_content_size;
-       props->stream_class_id = (uint64_t) notit->cur_stream_class_id;
-       props->data_stream_id = notit->cur_data_stream_id;
-       props->snapshots.discarded_events = notit->snapshots.discarded_events;
-       props->snapshots.packets = notit->snapshots.packets;
-       props->snapshots.beginning_clock = notit->snapshots.beginning_clock;
-       props->snapshots.end_clock = notit->snapshots.end_clock;
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-void bt_msg_iter_set_emit_stream_beginning_message(struct bt_msg_iter *notit,
-               bool val)
-{
-       notit->emit_stream_begin_msg = val;
-}
-
-BT_HIDDEN
-void bt_msg_iter_set_emit_stream_end_message(struct bt_msg_iter *notit,
-               bool val)
-{
-       notit->emit_stream_end_msg = val;
-}
diff --git a/plugins/ctf/common/msg-iter/msg-iter.h b/plugins/ctf/common/msg-iter/msg-iter.h
deleted file mode 100644 (file)
index c893fda..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-#ifndef CTF_MSG_ITER_H
-#define CTF_MSG_ITER_H
-
-/*
- * Babeltrace - CTF message iterator
- *
- * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#include "../metadata/ctf-meta.h"
-
-/**
- * @file ctf-msg-iter.h
- *
- * CTF message iterator
- *
- * This is a common internal API used by CTF source plugins. It allows
- * one to get messages from a user-provided medium.
- */
-
-/**
- * Medium operations status codes.
- */
-enum bt_msg_iter_medium_status {
-       /**
-        * End of file.
-        *
-        * The medium function called by the message iterator
-        * function reached the end of the file.
-        */
-       BT_MSG_ITER_MEDIUM_STATUS_EOF = 1,
-
-       /**
-        * There is no data available right now, try again later.
-        */
-       BT_MSG_ITER_MEDIUM_STATUS_AGAIN = 11,
-
-       /** Unsupported operation. */
-       BT_MSG_ITER_MEDIUM_STATUS_UNSUPPORTED = -3,
-
-       /** Invalid argument. */
-       BT_MSG_ITER_MEDIUM_STATUS_INVAL = -2,
-
-       /** General error. */
-       BT_MSG_ITER_MEDIUM_STATUS_ERROR = -1,
-
-       /** Everything okay. */
-       BT_MSG_ITER_MEDIUM_STATUS_OK = 0,
-};
-
-/**
- * CTF message iterator API status code.
- */
-enum bt_msg_iter_status {
-       /**
-        * End of file.
-        *
-        * The medium function called by the message iterator
-        * function reached the end of the file.
-        */
-       BT_MSG_ITER_STATUS_EOF = BT_MSG_ITER_MEDIUM_STATUS_EOF,
-
-       /**
-        * There is no data available right now, try again later.
-        *
-        * Some condition resulted in the
-        * bt_msg_iter_medium_ops::request_bytes() user function not
-        * having access to any data now. You should retry calling the
-        * last called message iterator function once the situation
-        * is resolved.
-        */
-       BT_MSG_ITER_STATUS_AGAIN = BT_MSG_ITER_MEDIUM_STATUS_AGAIN,
-
-       /** Invalid argument. */
-       BT_MSG_ITER_STATUS_INVAL = BT_MSG_ITER_MEDIUM_STATUS_INVAL,
-
-       /** Unsupported operation. */
-       BT_MSG_ITER_STATUS_UNSUPPORTED = BT_MSG_ITER_MEDIUM_STATUS_UNSUPPORTED,
-
-       /** General error. */
-       BT_MSG_ITER_STATUS_ERROR = BT_MSG_ITER_MEDIUM_STATUS_ERROR,
-
-       /** Everything okay. */
-       BT_MSG_ITER_STATUS_OK = 0,
-};
-
-/**
- * CTF message iterator seek operation directives.
- */
-enum bt_msg_iter_seek_whence {
-       /**
-        * Set the iterator's position to an absolute offset in the underlying
-        * medium.
-        */
-       BT_MSG_ITER_SEEK_WHENCE_SET,
-};
-
-/**
- * Medium operations.
- *
- * Those user functions are called by the message iterator
- * functions to request medium actions.
- */
-struct bt_msg_iter_medium_ops {
-       /**
-        * Returns the next byte buffer to be used by the binary file
-        * reader to deserialize binary data.
-        *
-        * This function \em must be defined.
-        *
-        * The purpose of this function is to return a buffer of bytes
-        * to the message iterator, of a maximum of \p request_sz
-        * bytes. If this function cannot return a buffer of at least
-        * \p request_sz bytes, it may return a smaller buffer. In
-        * either cases, \p buffer_sz must be set to the returned buffer
-        * size (in bytes).
-        *
-        * The returned buffer's ownership remains the medium, in that
-        * it won't be freed by the message iterator functions. The
-        * returned buffer won't be modified by the message
-        * iterator functions either.
-        *
-        * When this function is called for the first time for a given
-        * file, the offset within the file is considered to be 0. The
-        * next times this function is called, the returned buffer's
-        * byte offset within the complete file must be the previous
-        * offset plus the last returned value of \p buffer_sz by this
-        * medium.
-        *
-        * This function must return one of the following statuses:
-        *
-        *   - <b>#BT_MSG_ITER_MEDIUM_STATUS_OK</b>: Everything
-        *     is okay, i.e. \p buffer_sz is set to a positive value
-        *     reflecting the number of available bytes in the buffer
-        *     starting at the address written in \p buffer_addr.
-        *   - <b>#BT_MSG_ITER_MEDIUM_STATUS_AGAIN</b>: No data is
-        *     available right now. In this case, the message
-        *     iterator function called by the user returns
-        *     #BT_MSG_ITER_STATUS_AGAIN, and it is the user's
-        *     responsibility to make sure enough data becomes available
-        *     before calling the \em same message iterator
-        *     function again to continue the decoding process.
-        *   - <b>#BT_MSG_ITER_MEDIUM_STATUS_EOF</b>: The end of
-        *     the file was reached, and no more data will ever be
-        *     available for this file. In this case, the message
-        *     iterator function called by the user returns
-        *     #BT_MSG_ITER_STATUS_EOF. This must \em not be
-        *     returned when returning at least one byte of data to the
-        *     caller, i.e. this must be returned when there's
-        *     absolutely nothing left; should the request size be
-        *     larger than what's left in the file, this function must
-        *     return what's left, setting \p buffer_sz to the number of
-        *     remaining bytes, and return
-        *     #BT_MSG_ITER_MEDIUM_STATUS_EOF on the \em following
-        *     call.
-        *   - <b>#BT_MSG_ITER_MEDIUM_STATUS_ERROR</b>: A fatal
-        *     error occured during this operation. In this case, the
-        *     message iterator function called by the user returns
-        *     #BT_MSG_ITER_STATUS_ERROR.
-        *
-        * If #BT_MSG_ITER_MEDIUM_STATUS_OK is not returned, the
-        * values of \p buffer_sz and \p buffer_addr are \em ignored by
-        * the caller.
-        *
-        * @param request_sz    Requested buffer size (bytes)
-        * @param buffer_addr   Returned buffer address
-        * @param buffer_sz     Returned buffer's size (bytes)
-        * @param data          User data
-        * @returns             Status code (see description above)
-        */
-       enum bt_msg_iter_medium_status (* request_bytes)(size_t request_sz,
-                       uint8_t **buffer_addr, size_t *buffer_sz, void *data);
-
-       /**
-        * Repositions the underlying stream's position.
-        *
-        * This *optional* method repositions the underlying stream
-        * to a given absolute or relative position, as indicated by
-        * the whence directive.
-        *
-        * @param whence        One of #bt_msg_iter_seek_whence values
-        * @param offset        Offset to use for the given directive
-        * @param data          User data
-        * @returns             One of #bt_msg_iter_medium_status values
-        */
-       enum bt_msg_iter_medium_status (* seek)(
-                       enum bt_msg_iter_seek_whence whence,
-                       off_t offset, void *data);
-
-       /**
-        * Returns a stream instance (weak reference) for the given
-        * stream class.
-        *
-        * This is called after a packet header is read, and the
-        * corresponding stream class is found by the message
-        * iterator.
-        *
-        * @param stream_class  Stream class of the stream to get
-        * @param stream_id     Stream (instance) ID of the stream
-        *                      to get (-1ULL if not available)
-        * @param data          User data
-        * @returns             Stream instance (weak reference) or
-        *                      \c NULL on error
-        */
-       bt_stream * (* borrow_stream)(bt_stream_class *stream_class,
-                       int64_t stream_id, void *data);
-};
-
-/** CTF message iterator. */
-struct bt_msg_iter;
-
-/**
- * Creates a CTF message iterator.
- *
- * Upon successful completion, the reference count of \p trace is
- * incremented.
- *
- * @param trace                        Trace to read
- * @param max_request_sz       Maximum buffer size, in bytes, to
- *                             request to
- *                             bt_msg_iter_medium_ops::request_bytes()
- *                             at a time
- * @param medops               Medium operations
- * @param medops_data          User data (passed to medium operations)
- * @returns                    New CTF message iterator on
- *                             success, or \c NULL on error
- */
-BT_HIDDEN
-struct bt_msg_iter *bt_msg_iter_create(struct ctf_trace_class *tc,
-       size_t max_request_sz, struct bt_msg_iter_medium_ops medops,
-       void *medops_data);
-
-/**
- * Destroys a CTF message iterator, freeing all internal resources.
- *
- * The registered trace's reference count is decremented.
- *
- * @param msg_iter             CTF message iterator
- */
-BT_HIDDEN
-void bt_msg_iter_destroy(struct bt_msg_iter *msg_iter);
-
-/**
- * Returns the next message from a CTF message iterator.
- *
- * Upon successful completion, #BT_MSG_ITER_STATUS_OK is
- * returned, and the next message is written to \p msg.
- * In this case, the caller is responsible for calling
- * bt_message_put() on the returned message.
- *
- * If this function returns #BT_MSG_ITER_STATUS_AGAIN, the caller
- * should make sure that data becomes available to its medium, and
- * call this function again, until another status is returned.
- *
- * @param msg_iter             CTF message iterator
- * @param message              Returned message if the function's
- *                             return value is #BT_MSG_ITER_STATUS_OK
- * @returns                    One of #bt_msg_iter_status values
- */
-BT_HIDDEN
-enum bt_msg_iter_status bt_msg_iter_get_next_message(
-               struct bt_msg_iter *notit,
-               bt_self_message_iterator *msg_iter,
-               bt_message **message);
-
-struct bt_msg_iter_packet_properties {
-       int64_t exp_packet_total_size;
-       int64_t exp_packet_content_size;
-       uint64_t stream_class_id;
-       int64_t data_stream_id;
-
-       struct {
-               uint64_t discarded_events;
-               uint64_t packets;
-               uint64_t beginning_clock;
-               uint64_t end_clock;
-       } snapshots;
-};
-
-BT_HIDDEN
-enum bt_msg_iter_status bt_msg_iter_get_packet_properties(
-               struct bt_msg_iter *notit,
-               struct bt_msg_iter_packet_properties *props);
-
-BT_HIDDEN
-void bt_msg_iter_set_medops_data(struct bt_msg_iter *notit,
-               void *medops_data);
-
-BT_HIDDEN
-enum bt_msg_iter_status bt_msg_iter_seek(
-               struct bt_msg_iter *notit, off_t offset);
-
-/*
- * Resets the iterator so that the next requested medium bytes are
- * assumed to be the first bytes of a new stream. Depending on
- * bt_msg_iter_set_emit_stream_beginning_message(), the first message
- * which this iterator emits after calling bt_msg_iter_reset() is of
- * type `BT_MESSAGE_TYPE_STREAM_BEGINNING`.
- */
-BT_HIDDEN
-void bt_msg_iter_reset(struct bt_msg_iter *notit);
-
-/*
- * Like bt_msg_iter_reset(), but preserves stream-dependent state.
- */
-BT_HIDDEN
-void bt_msg_iter_reset_for_next_stream_file(struct bt_msg_iter *notit);
-
-BT_HIDDEN
-void bt_msg_iter_set_emit_stream_beginning_message(struct bt_msg_iter *notit,
-               bool val);
-
-BT_HIDDEN
-void bt_msg_iter_set_emit_stream_end_message(struct bt_msg_iter *notit,
-               bool val);
-
-static inline
-const char *bt_msg_iter_medium_status_string(
-               enum bt_msg_iter_medium_status status)
-{
-       switch (status) {
-       case BT_MSG_ITER_MEDIUM_STATUS_EOF:
-               return "BT_MSG_ITER_MEDIUM_STATUS_EOF";
-       case BT_MSG_ITER_MEDIUM_STATUS_AGAIN:
-               return "BT_MSG_ITER_MEDIUM_STATUS_AGAIN";
-       case BT_MSG_ITER_MEDIUM_STATUS_INVAL:
-               return "BT_MSG_ITER_MEDIUM_STATUS_INVAL";
-       case BT_MSG_ITER_MEDIUM_STATUS_ERROR:
-               return "BT_MSG_ITER_MEDIUM_STATUS_ERROR";
-       case BT_MSG_ITER_MEDIUM_STATUS_OK:
-               return "BT_MSG_ITER_MEDIUM_STATUS_OK";
-       default:
-               return "(unknown)";
-       }
-}
-
-static inline
-const char *bt_msg_iter_status_string(
-               enum bt_msg_iter_status status)
-{
-       switch (status) {
-       case BT_MSG_ITER_STATUS_EOF:
-               return "BT_MSG_ITER_STATUS_EOF";
-       case BT_MSG_ITER_STATUS_AGAIN:
-               return "BT_MSG_ITER_STATUS_AGAIN";
-       case BT_MSG_ITER_STATUS_INVAL:
-               return "BT_MSG_ITER_STATUS_INVAL";
-       case BT_MSG_ITER_STATUS_ERROR:
-               return "BT_MSG_ITER_STATUS_ERROR";
-       case BT_MSG_ITER_STATUS_OK:
-               return "BT_MSG_ITER_STATUS_OK";
-       default:
-               return "(unknown)";
-       }
-}
-
-#endif /* CTF_MSG_ITER_H */
diff --git a/plugins/ctf/common/print.h b/plugins/ctf/common/print.h
deleted file mode 100644 (file)
index a19dbff..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef CTF_BTR_PRINT_H
-#define CTF_BTR_PRINT_H
-
-/*
- * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#define PERR(fmt, ...)                                                 \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "Error: " PRINT_PREFIX ": " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PWARN(fmt, ...)                                                        \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "Warning: " PRINT_PREFIX ": " fmt,      \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PDBG(fmt, ...)                                                 \
-       do {                                                            \
-               if (babeltrace_debug) {                                 \
-                       fprintf(stderr,                                 \
-                               "Debug: " PRINT_PREFIX ": " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#endif /* CTF_BTR_PRINT_H */
diff --git a/plugins/ctf/common/utils/Makefile.am b/plugins/ctf/common/utils/Makefile.am
deleted file mode 100644 (file)
index c4b62ff..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-noinst_LTLIBRARIES = libctf-utils.la
-libctf_utils_la_SOURCES = \
-       logging.c \
-       logging.h \
-       utils.c \
-       utils.h
diff --git a/plugins/ctf/common/utils/logging.c b/plugins/ctf/common/utils/logging.c
deleted file mode 100644 (file)
index 9a5e1e5..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
- /*
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL utils_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(utils_log_level, "BABELTRACE_PLUGIN_CTF_UTILS_LOG_LEVEL");
diff --git a/plugins/ctf/common/utils/logging.h b/plugins/ctf/common/utils/logging.h
deleted file mode 100644 (file)
index a5f5167..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef CTF_UTILS_LOGGING_H
-#define CTF_UTILS_LOGGING_H
-
-/*
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL utils_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(utils_log_level);
-
-#endif /* CTF_UTILS_LOGGING_H */
diff --git a/plugins/ctf/common/utils/utils.c b/plugins/ctf/common/utils/utils.c
deleted file mode 100644 (file)
index dd65f94..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Babeltrace - CTF Utils
- *
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-UTILS"
-#include "logging.h"
-
-#include "utils.h"
diff --git a/plugins/ctf/common/utils/utils.h b/plugins/ctf/common/utils/utils.h
deleted file mode 100644 (file)
index 266ae7c..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef CTF_UTILS_H
-#define CTF_UTILS_H
-
-/*
- * Babeltrace - CTF Utilities
- *
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#endif /* CTF_UTILS_H */
diff --git a/plugins/ctf/fs-sink/Makefile.am b/plugins/ctf/fs-sink/Makefile.am
deleted file mode 100644 (file)
index 6035b1a..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-noinst_LTLIBRARIES = libbabeltrace2-plugin-ctf-fs-sink.la
-
-libbabeltrace2_plugin_ctf_fs_sink_la_LIBADD =
-libbabeltrace2_plugin_ctf_fs_sink_la_SOURCES = \
-       fs-sink.c \
-       fs-sink.h \
-       logging.c \
-       logging.h \
-       fs-sink-ctf-meta.h \
-       translate-trace-ir-to-ctf-ir.c \
-       translate-trace-ir-to-ctf-ir.h \
-       translate-ctf-ir-to-tsdl.c \
-       translate-ctf-ir-to-tsdl.h \
-       fs-sink-stream.c \
-       fs-sink-stream.h \
-       fs-sink-trace.c \
-       fs-sink-trace.h
diff --git a/plugins/ctf/fs-sink/fs-sink-ctf-meta.h b/plugins/ctf/fs-sink/fs-sink-ctf-meta.h
deleted file mode 100644 (file)
index 2070c39..0000000
+++ /dev/null
@@ -1,926 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_CTF_META_H
-#define BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_CTF_META_H
-
-/*
- * Copyright 2018-2019 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <glib.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdbool.h>
-#include <ctype.h>
-
-enum fs_sink_ctf_field_class_type {
-       FS_SINK_CTF_FIELD_CLASS_TYPE_INT,
-       FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT,
-       FS_SINK_CTF_FIELD_CLASS_TYPE_STRING,
-       FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT,
-       FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY,
-       FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE,
-       FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT,
-};
-
-struct fs_sink_ctf_field_class {
-       enum fs_sink_ctf_field_class_type type;
-
-       /* Weak */
-       const bt_field_class *ir_fc;
-
-       unsigned int alignment;
-
-       /* Index of the field class within its own parent */
-       uint64_t index_in_parent;
-};
-
-struct fs_sink_ctf_field_class_bit_array {
-       struct fs_sink_ctf_field_class base;
-       unsigned int size;
-};
-
-struct fs_sink_ctf_field_class_int {
-       struct fs_sink_ctf_field_class_bit_array base;
-       bool is_signed;
-};
-
-struct fs_sink_ctf_field_class_float {
-       struct fs_sink_ctf_field_class_bit_array base;
-};
-
-struct fs_sink_ctf_field_class_string {
-       struct fs_sink_ctf_field_class base;
-};
-
-struct fs_sink_ctf_named_field_class {
-       GString *name;
-
-       /* Owned by this */
-       struct fs_sink_ctf_field_class *fc;
-};
-
-struct fs_sink_ctf_field_class_struct {
-       struct fs_sink_ctf_field_class base;
-
-       /* Array of `struct fs_sink_ctf_named_field_class` */
-       GArray *members;
-};
-
-struct fs_sink_ctf_field_class_variant {
-       struct fs_sink_ctf_field_class base;
-       GString *tag_ref;
-       bool tag_is_before;
-
-       /* Array of `struct fs_sink_ctf_named_field_class` */
-       GArray *options;
-};
-
-struct fs_sink_ctf_field_class_array_base {
-       struct fs_sink_ctf_field_class base;
-       struct fs_sink_ctf_field_class *elem_fc;
-};
-
-struct fs_sink_ctf_field_class_array {
-       struct fs_sink_ctf_field_class_array_base base;
-       uint64_t length;
-};
-
-struct fs_sink_ctf_field_class_sequence {
-       struct fs_sink_ctf_field_class_array_base base;
-       GString *length_ref;
-       bool length_is_before;
-};
-
-struct fs_sink_ctf_stream_class;
-
-struct fs_sink_ctf_event_class {
-       /* Weak */
-       const bt_event_class *ir_ec;
-
-       /* Weak */
-       struct fs_sink_ctf_stream_class *sc;
-
-       /* Owned by this */
-       struct fs_sink_ctf_field_class *spec_context_fc;
-
-       /* Owned by this */
-       struct fs_sink_ctf_field_class *payload_fc;
-};
-
-struct fs_sink_ctf_trace_class;
-
-struct fs_sink_ctf_stream_class {
-       /* Weak */
-       struct fs_sink_ctf_trace_class *tc;
-
-       /* Weak */
-       const bt_stream_class *ir_sc;
-
-       /* Weak */
-       const bt_clock_class *default_clock_class;
-
-       GString *default_clock_class_name;
-       bool packets_have_ts_begin;
-       bool packets_have_ts_end;
-       bool has_discarded_events;
-       bool discarded_events_has_ts;
-       bool discarded_packets_has_ts;
-
-       /* Owned by this */
-       struct fs_sink_ctf_field_class *packet_context_fc;
-
-       /* Owned by this */
-       struct fs_sink_ctf_field_class *event_common_context_fc;
-
-       /* Array of `struct fs_sink_ctf_event_class *` (owned by this) */
-       GPtrArray *event_classes;
-
-       /*
-        * `const bt_event_class *` (weak) ->
-        * `struct fs_sink_ctf_event_class *` (weak)
-        */
-       GHashTable *event_classes_from_ir;
-};
-
-struct fs_sink_ctf_trace_class {
-       /* Weak */
-       const bt_trace_class *ir_tc;
-
-       unsigned char uuid[BABELTRACE_UUID_LEN];
-
-       /* Array of `struct fs_sink_ctf_stream_class *` (owned by this) */
-       GPtrArray *stream_classes;
-};
-
-static inline
-void fs_sink_ctf_field_class_destroy(struct fs_sink_ctf_field_class *fc);
-
-static inline
-void _fs_sink_ctf_field_class_init(struct fs_sink_ctf_field_class *fc,
-               enum fs_sink_ctf_field_class_type type,
-               const bt_field_class *ir_fc, unsigned int alignment,
-               uint64_t index_in_parent)
-{
-       BT_ASSERT(fc);
-       fc->type = type;
-       fc->ir_fc = ir_fc;
-       fc->alignment = alignment;
-       fc->index_in_parent = index_in_parent;
-}
-
-static inline
-void _fs_sink_ctf_field_class_bit_array_init(
-               struct fs_sink_ctf_field_class_bit_array *fc,
-               enum fs_sink_ctf_field_class_type type,
-               const bt_field_class *ir_fc, unsigned int size,
-               uint64_t index_in_parent)
-{
-       _fs_sink_ctf_field_class_init((void *) fc, type, ir_fc,
-               size % 8 == 0 ? 8 : 1, index_in_parent);
-       fc->size = size;
-}
-
-static inline
-void _fs_sink_ctf_field_class_int_init(struct fs_sink_ctf_field_class_int *fc,
-               enum fs_sink_ctf_field_class_type type,
-               const bt_field_class *ir_fc, uint64_t index_in_parent)
-{
-       bt_field_class_type ir_fc_type = bt_field_class_get_type(ir_fc);
-
-       _fs_sink_ctf_field_class_bit_array_init((void *) fc, type, ir_fc,
-               (unsigned int) bt_field_class_integer_get_field_value_range(
-                       ir_fc),
-               index_in_parent);
-       fc->is_signed = (ir_fc_type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
-               ir_fc_type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION);
-}
-
-static inline
-void _fs_sink_ctf_named_field_class_init(
-               struct fs_sink_ctf_named_field_class *named_fc)
-{
-       BT_ASSERT(named_fc);
-       named_fc->name = g_string_new(NULL);
-       BT_ASSERT(named_fc->name);
-}
-
-static inline
-void _fs_sink_ctf_named_field_class_fini(
-               struct fs_sink_ctf_named_field_class *named_fc)
-{
-       BT_ASSERT(named_fc);
-
-       if (named_fc->name) {
-               g_string_free(named_fc->name, TRUE);
-               named_fc->name = NULL;
-       }
-
-       fs_sink_ctf_field_class_destroy(named_fc->fc);
-       named_fc->fc = NULL;
-}
-
-static inline
-struct fs_sink_ctf_field_class_int *fs_sink_ctf_field_class_int_create(
-               const bt_field_class *ir_fc, uint64_t index_in_parent)
-{
-       struct fs_sink_ctf_field_class_int *fc =
-               g_new0(struct fs_sink_ctf_field_class_int, 1);
-
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_int_init(fc, FS_SINK_CTF_FIELD_CLASS_TYPE_INT,
-               ir_fc, index_in_parent);
-       return fc;
-}
-
-static inline
-struct fs_sink_ctf_field_class_float *fs_sink_ctf_field_class_float_create(
-               const bt_field_class *ir_fc, uint64_t index_in_parent)
-{
-       struct fs_sink_ctf_field_class_float *fc =
-               g_new0(struct fs_sink_ctf_field_class_float, 1);
-
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_bit_array_init((void *) fc,
-               FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT,
-               ir_fc, bt_field_class_real_is_single_precision(ir_fc) ? 32 : 64,
-               index_in_parent);
-       return fc;
-}
-
-static inline
-struct fs_sink_ctf_field_class_string *fs_sink_ctf_field_class_string_create(
-               const bt_field_class *ir_fc, uint64_t index_in_parent)
-{
-       struct fs_sink_ctf_field_class_string *fc =
-               g_new0(struct fs_sink_ctf_field_class_string, 1);
-
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_init((void *) fc,
-               FS_SINK_CTF_FIELD_CLASS_TYPE_STRING, ir_fc,
-               8, index_in_parent);
-       return fc;
-}
-
-static inline
-struct fs_sink_ctf_field_class_struct *fs_sink_ctf_field_class_struct_create_empty(
-               const bt_field_class *ir_fc, uint64_t index_in_parent)
-{
-       struct fs_sink_ctf_field_class_struct *fc =
-               g_new0(struct fs_sink_ctf_field_class_struct, 1);
-
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_init((void *) fc,
-               FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT, ir_fc, 1, index_in_parent);
-       fc->members = g_array_new(FALSE, TRUE,
-               sizeof(struct fs_sink_ctf_named_field_class));
-       BT_ASSERT(fc->members);
-       return fc;
-}
-
-static inline
-struct fs_sink_ctf_field_class_variant *fs_sink_ctf_field_class_variant_create_empty(
-               const bt_field_class *ir_fc, uint64_t index_in_parent)
-{
-       struct fs_sink_ctf_field_class_variant *fc =
-               g_new0(struct fs_sink_ctf_field_class_variant, 1);
-
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_init((void *) fc,
-               FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT, ir_fc,
-               1, index_in_parent);
-       fc->options = g_array_new(FALSE, TRUE,
-               sizeof(struct fs_sink_ctf_named_field_class));
-       BT_ASSERT(fc->options);
-       fc->tag_ref = g_string_new(NULL);
-       BT_ASSERT(fc->tag_ref);
-       fc->tag_is_before =
-               bt_field_class_variant_borrow_selector_field_path_const(ir_fc) ==
-               NULL;
-       return fc;
-}
-
-static inline
-struct fs_sink_ctf_field_class_array *fs_sink_ctf_field_class_array_create_empty(
-               const bt_field_class *ir_fc, uint64_t index_in_parent)
-{
-       struct fs_sink_ctf_field_class_array *fc =
-               g_new0(struct fs_sink_ctf_field_class_array, 1);
-
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_init((void *) fc,
-               FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY, ir_fc,
-               1, index_in_parent);
-       fc->length = bt_field_class_static_array_get_length(ir_fc);
-       return fc;
-}
-
-static inline
-struct fs_sink_ctf_field_class_sequence *fs_sink_ctf_field_class_sequence_create_empty(
-               const bt_field_class *ir_fc, uint64_t index_in_parent)
-{
-       struct fs_sink_ctf_field_class_sequence *fc =
-               g_new0(struct fs_sink_ctf_field_class_sequence, 1);
-
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_init((void *) fc,
-               FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE,
-               ir_fc, 1, index_in_parent);
-       fc->length_ref = g_string_new(NULL);
-       BT_ASSERT(fc->length_ref);
-       fc->length_is_before =
-               bt_field_class_dynamic_array_borrow_length_field_path_const(ir_fc) ==
-               NULL;
-       return fc;
-}
-
-static inline
-struct fs_sink_ctf_named_field_class *
-fs_sink_ctf_field_class_struct_borrow_member_by_index(
-               struct fs_sink_ctf_field_class_struct *fc, uint64_t index);
-
-static inline
-struct fs_sink_ctf_named_field_class *
-fs_sink_ctf_field_class_variant_borrow_option_by_index(
-               struct fs_sink_ctf_field_class_variant *fc, uint64_t index);
-
-static inline
-void _fs_sink_ctf_field_class_fini(struct fs_sink_ctf_field_class *fc)
-{
-       BT_ASSERT(fc);
-}
-
-static inline
-void _fs_sink_ctf_field_class_int_destroy(
-               struct fs_sink_ctf_field_class_int *fc)
-{
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_fini((void *) fc);
-       g_free(fc);
-}
-
-static inline
-void _fs_sink_ctf_field_class_float_destroy(
-               struct fs_sink_ctf_field_class_float *fc)
-{
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_fini((void *) fc);
-       g_free(fc);
-}
-
-static inline
-void _fs_sink_ctf_field_class_string_destroy(
-               struct fs_sink_ctf_field_class_string *fc)
-{
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_fini((void *) fc);
-       g_free(fc);
-}
-
-static inline
-void _fs_sink_ctf_field_class_struct_destroy(
-               struct fs_sink_ctf_field_class_struct *fc)
-{
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_fini((void *) fc);
-
-       if (fc->members) {
-               uint64_t i;
-
-               for (i = 0; i < fc->members->len; i++) {
-                       struct fs_sink_ctf_named_field_class *named_fc =
-                               fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                                       fc, i);
-
-                       _fs_sink_ctf_named_field_class_fini(named_fc);
-               }
-
-               g_array_free(fc->members, TRUE);
-               fc->members = NULL;
-       }
-
-       g_free(fc);
-}
-
-static inline
-void _fs_sink_ctf_field_class_array_base_fini(
-               struct fs_sink_ctf_field_class_array_base *fc)
-{
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_fini((void *) fc);
-       fs_sink_ctf_field_class_destroy(fc->elem_fc);
-       fc->elem_fc = NULL;
-}
-
-static inline
-void _fs_sink_ctf_field_class_array_destroy(
-               struct fs_sink_ctf_field_class_array *fc)
-{
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_array_base_fini((void *) fc);
-       g_free(fc);
-}
-
-static inline
-void _fs_sink_ctf_field_class_sequence_destroy(
-               struct fs_sink_ctf_field_class_sequence *fc)
-{
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_array_base_fini((void *) fc);
-
-       if (fc->length_ref) {
-               g_string_free(fc->length_ref, TRUE);
-               fc->length_ref = NULL;
-       }
-
-       g_free(fc);
-}
-
-static inline
-void _fs_sink_ctf_field_class_variant_destroy(
-               struct fs_sink_ctf_field_class_variant *fc)
-{
-       BT_ASSERT(fc);
-       _fs_sink_ctf_field_class_fini((void *) fc);
-
-       if (fc->options) {
-               uint64_t i;
-
-               for (i = 0; i < fc->options->len; i++) {
-                       struct fs_sink_ctf_named_field_class *named_fc =
-                               fs_sink_ctf_field_class_variant_borrow_option_by_index(
-                                       fc, i);
-
-                       _fs_sink_ctf_named_field_class_fini(named_fc);
-               }
-
-               g_array_free(fc->options, TRUE);
-               fc->options = NULL;
-       }
-
-       if (fc->tag_ref) {
-               g_string_free(fc->tag_ref, TRUE);
-               fc->tag_ref = NULL;
-       }
-
-       g_free(fc);
-}
-
-static inline
-void fs_sink_ctf_field_class_destroy(struct fs_sink_ctf_field_class *fc)
-{
-       if (!fc) {
-               return;
-       }
-
-       switch (fc->type) {
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_INT:
-               _fs_sink_ctf_field_class_int_destroy((void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT:
-               _fs_sink_ctf_field_class_float_destroy((void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRING:
-               _fs_sink_ctf_field_class_string_destroy((void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-               _fs_sink_ctf_field_class_struct_destroy((void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
-               _fs_sink_ctf_field_class_array_destroy((void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
-               _fs_sink_ctf_field_class_sequence_destroy((void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-               _fs_sink_ctf_field_class_variant_destroy((void *) fc);
-               break;
-       default:
-               abort();
-       }
-}
-
-static inline
-struct fs_sink_ctf_named_field_class *
-fs_sink_ctf_field_class_struct_borrow_member_by_index(
-               struct fs_sink_ctf_field_class_struct *fc, uint64_t index)
-{
-       BT_ASSERT(fc);
-       BT_ASSERT(index < fc->members->len);
-       return &g_array_index(fc->members, struct fs_sink_ctf_named_field_class,
-               index);
-}
-
-static inline
-struct fs_sink_ctf_named_field_class *
-fs_sink_ctf_field_class_struct_borrow_member_by_name(
-               struct fs_sink_ctf_field_class_struct *fc, const char *name)
-{
-       uint64_t i;
-       struct fs_sink_ctf_named_field_class *ret_named_fc = NULL;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(name);
-
-       for (i = 0; i < fc->members->len; i++) {
-               struct fs_sink_ctf_named_field_class *named_fc =
-                       fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                               fc, i);
-
-               if (strcmp(name, named_fc->name->str) == 0) {
-                       ret_named_fc = named_fc;
-                       goto end;
-               }
-       }
-
-end:
-       return ret_named_fc;
-}
-
-static inline
-struct fs_sink_ctf_field_class *
-fs_sink_ctf_field_class_struct_borrow_member_field_class_by_name(
-               struct fs_sink_ctf_field_class_struct *struct_fc, const char *name)
-{
-       struct fs_sink_ctf_named_field_class *named_fc = NULL;
-       struct fs_sink_ctf_field_class *fc = NULL;
-
-       if (!struct_fc) {
-               goto end;
-       }
-
-       named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_name(
-               struct_fc, name);
-       if (!named_fc) {
-               goto end;
-       }
-
-       fc = named_fc->fc;
-
-end:
-       return fc;
-}
-
-static inline
-struct fs_sink_ctf_field_class_int *
-fs_sink_ctf_field_class_struct_borrow_member_int_field_class_by_name(
-               struct fs_sink_ctf_field_class_struct *struct_fc,
-               const char *name)
-{
-       struct fs_sink_ctf_field_class_int *int_fc = NULL;
-
-       int_fc = (void *)
-               fs_sink_ctf_field_class_struct_borrow_member_field_class_by_name(
-                       struct_fc, name);
-       if (!int_fc) {
-               goto end;
-       }
-
-       if (int_fc->base.base.type != FS_SINK_CTF_FIELD_CLASS_TYPE_INT) {
-               int_fc = NULL;
-               goto end;
-       }
-
-end:
-       return int_fc;
-}
-
-static inline
-void fs_sink_ctf_field_class_struct_align_at_least(
-               struct fs_sink_ctf_field_class_struct *fc,
-               unsigned int alignment)
-{
-       if (alignment > fc->base.alignment) {
-               fc->base.alignment = alignment;
-       }
-}
-
-static inline
-void fs_sink_ctf_field_class_struct_append_member(
-               struct fs_sink_ctf_field_class_struct *fc,
-               const char *name, struct fs_sink_ctf_field_class *member_fc)
-{
-       struct fs_sink_ctf_named_field_class *named_fc;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(name);
-       g_array_set_size(fc->members, fc->members->len + 1);
-
-       named_fc = &g_array_index(fc->members,
-               struct fs_sink_ctf_named_field_class, fc->members->len - 1);
-       _fs_sink_ctf_named_field_class_init(named_fc);
-       g_string_assign(named_fc->name, name);
-       named_fc->fc = member_fc;
-       fs_sink_ctf_field_class_struct_align_at_least(fc, member_fc->alignment);
-}
-
-static inline
-struct fs_sink_ctf_named_field_class *
-fs_sink_ctf_field_class_variant_borrow_option_by_index(
-               struct fs_sink_ctf_field_class_variant *fc, uint64_t index)
-{
-       BT_ASSERT(fc);
-       BT_ASSERT(index < fc->options->len);
-       return &g_array_index(fc->options, struct fs_sink_ctf_named_field_class,
-               index);
-}
-
-static inline
-struct fs_sink_ctf_named_field_class *
-fs_sink_ctf_field_class_variant_borrow_option_by_name(
-               struct fs_sink_ctf_field_class_variant *fc, const char *name)
-{
-       uint64_t i;
-       struct fs_sink_ctf_named_field_class *ret_named_fc = NULL;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(name);
-
-       for (i = 0; i < fc->options->len; i++) {
-               struct fs_sink_ctf_named_field_class *named_fc =
-                       fs_sink_ctf_field_class_variant_borrow_option_by_index(
-                               fc, i);
-
-               if (strcmp(name, named_fc->name->str) == 0) {
-                       ret_named_fc = named_fc;
-                       goto end;
-               }
-       }
-
-end:
-       return ret_named_fc;
-}
-
-static inline
-void fs_sink_ctf_field_class_variant_append_option(
-               struct fs_sink_ctf_field_class_variant *fc,
-               const char *name, struct fs_sink_ctf_field_class *option_fc)
-{
-       struct fs_sink_ctf_named_field_class *named_fc;
-
-       BT_ASSERT(fc);
-       BT_ASSERT(name);
-       g_array_set_size(fc->options, fc->options->len + 1);
-
-       named_fc = &g_array_index(fc->options,
-               struct fs_sink_ctf_named_field_class, fc->options->len - 1);
-       _fs_sink_ctf_named_field_class_init(named_fc);
-       g_string_assign(named_fc->name, name);
-       named_fc->fc = option_fc;
-}
-
-static inline
-struct fs_sink_ctf_event_class *fs_sink_ctf_event_class_create(
-               struct fs_sink_ctf_stream_class *sc,
-               const bt_event_class *ir_ec)
-{
-       struct fs_sink_ctf_event_class *ec =
-               g_new0(struct fs_sink_ctf_event_class, 1);
-
-       BT_ASSERT(sc);
-       BT_ASSERT(ir_ec);
-       BT_ASSERT(ec);
-       ec->ir_ec = ir_ec;
-       ec->sc = sc;
-       g_ptr_array_add(sc->event_classes, ec);
-       g_hash_table_insert(sc->event_classes_from_ir, (gpointer) ir_ec, ec);
-       return ec;
-}
-
-static inline
-void fs_sink_ctf_event_class_destroy(struct fs_sink_ctf_event_class *ec)
-{
-       if (!ec) {
-               return;
-       }
-
-       fs_sink_ctf_field_class_destroy(ec->spec_context_fc);
-       ec->spec_context_fc = NULL;
-       fs_sink_ctf_field_class_destroy(ec->payload_fc);
-       ec->payload_fc = NULL;
-       g_free(ec);
-}
-
-static inline
-struct fs_sink_ctf_stream_class *fs_sink_ctf_stream_class_create(
-               struct fs_sink_ctf_trace_class *tc,
-               const bt_stream_class *ir_sc)
-{
-       struct fs_sink_ctf_stream_class *sc =
-               g_new0(struct fs_sink_ctf_stream_class, 1);
-
-       BT_ASSERT(tc);
-       BT_ASSERT(ir_sc);
-       BT_ASSERT(sc);
-       sc->tc = tc;
-       sc->ir_sc = ir_sc;
-       sc->default_clock_class =
-               bt_stream_class_borrow_default_clock_class_const(ir_sc);
-       sc->default_clock_class_name = g_string_new(NULL);
-       BT_ASSERT(sc->default_clock_class_name);
-       sc->event_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) fs_sink_ctf_event_class_destroy);
-       BT_ASSERT(sc->event_classes);
-       sc->event_classes_from_ir = g_hash_table_new(g_direct_hash,
-               g_direct_equal);
-       BT_ASSERT(sc->event_classes_from_ir);
-       sc->packets_have_ts_begin =
-               bt_stream_class_packets_have_beginning_default_clock_snapshot(
-                       ir_sc);
-       sc->packets_have_ts_end =
-               bt_stream_class_packets_have_end_default_clock_snapshot(ir_sc);
-       sc->has_discarded_events =
-               bt_stream_class_supports_discarded_events(ir_sc);
-
-       if (sc->has_discarded_events) {
-               sc->discarded_events_has_ts =
-                       bt_stream_class_discarded_events_have_default_clock_snapshots(
-                               ir_sc);
-       }
-
-       if (bt_stream_class_supports_discarded_packets(ir_sc)) {
-               sc->discarded_packets_has_ts =
-                       bt_stream_class_discarded_packets_have_default_clock_snapshots(
-                               ir_sc);
-       }
-
-       g_ptr_array_add(tc->stream_classes, sc);
-       return sc;
-}
-
-static inline
-void fs_sink_ctf_stream_class_destroy(struct fs_sink_ctf_stream_class *sc)
-{
-       if (!sc) {
-               return;
-       }
-
-       if (sc->default_clock_class_name) {
-               g_string_free(sc->default_clock_class_name, TRUE);
-               sc->default_clock_class_name = NULL;
-       }
-
-       if (sc->event_classes) {
-               g_ptr_array_free(sc->event_classes, TRUE);
-               sc->event_classes = NULL;
-       }
-
-       if (sc->event_classes_from_ir) {
-               g_hash_table_destroy(sc->event_classes_from_ir);
-               sc->event_classes_from_ir = NULL;
-       }
-
-       fs_sink_ctf_field_class_destroy(sc->packet_context_fc);
-       sc->packet_context_fc = NULL;
-       fs_sink_ctf_field_class_destroy(sc->event_common_context_fc);
-       sc->event_common_context_fc = NULL;
-       g_free(sc);
-}
-
-static inline
-void fs_sink_ctf_stream_class_append_event_class(
-               struct fs_sink_ctf_stream_class *sc,
-               struct fs_sink_ctf_event_class *ec)
-{
-       g_ptr_array_add(sc->event_classes, ec);
-}
-
-static inline
-void fs_sink_ctf_trace_class_destroy(struct fs_sink_ctf_trace_class *tc)
-{
-       if (!tc) {
-               return;
-       }
-
-       if (tc->stream_classes) {
-               g_ptr_array_free(tc->stream_classes, TRUE);
-               tc->stream_classes = NULL;
-       }
-
-       g_free(tc);
-}
-
-static inline
-struct fs_sink_ctf_trace_class *fs_sink_ctf_trace_class_create(
-               const bt_trace_class *ir_tc)
-{
-       struct fs_sink_ctf_trace_class *tc =
-               g_new0(struct fs_sink_ctf_trace_class, 1);
-
-       BT_ASSERT(tc);
-
-       if (bt_uuid_generate(tc->uuid)) {
-               fs_sink_ctf_trace_class_destroy(tc);
-               tc = NULL;
-               goto end;
-       }
-
-       tc->ir_tc = ir_tc;
-       tc->stream_classes = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) fs_sink_ctf_stream_class_destroy);
-       BT_ASSERT(tc->stream_classes);
-
-end:
-       return tc;
-}
-
-static inline
-bool fs_sink_ctf_ist_valid_identifier(const char *name)
-{
-       const char *at;
-       uint64_t i;
-       bool ist_valid = true;
-       static const char *reserved_keywords[] = {
-               "align",
-               "callsite",
-               "const",
-               "char",
-               "clock",
-               "double",
-               "enum",
-               "env",
-               "event",
-               "floating_point",
-               "float",
-               "integer",
-               "int",
-               "long",
-               "short",
-               "signed",
-               "stream",
-               "string",
-               "struct",
-               "trace",
-               "typealias",
-               "typedef",
-               "unsigned",
-               "variant",
-               "void",
-               "_Bool",
-               "_Complex",
-               "_Imaginary",
-       };
-
-       /* Make sure the name is not a reserved keyword */
-       for (i = 0; i < sizeof(reserved_keywords) / sizeof(*reserved_keywords);
-                       i++) {
-               if (strcmp(name, reserved_keywords[i]) == 0) {
-                       ist_valid = false;
-                       goto end;
-               }
-       }
-
-       /* Make sure the name is not an empty string */
-       if (strlen(name) == 0) {
-               ist_valid = false;
-               goto end;
-       }
-
-       /* Make sure the name starts with a letter or `_` */
-       if (!isalpha(name[0]) && name[0] != '_') {
-               ist_valid = false;
-               goto end;
-       }
-
-       /* Make sure the name only contains letters, digits, and `_` */
-       for (at = name; *at != '\0'; at++) {
-               if (!isalnum(*at) && *at != '_') {
-                       ist_valid = false;
-                       goto end;
-               }
-       }
-
-end:
-       return ist_valid;
-}
-
-static inline
-int fs_sink_ctf_protect_name(GString *name)
-{
-       int ret = 0;
-
-       if (!fs_sink_ctf_ist_valid_identifier(name->str)) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Prepend `_` to protect it */
-       g_string_prepend_c(name, '_');
-
-end:
-       return ret;
-}
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_CTF_META_H */
diff --git a/plugins/ctf/fs-sink/fs-sink-stream.c b/plugins/ctf/fs-sink/fs-sink-stream.c
deleted file mode 100644 (file)
index edf8dd0..0000000
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-STREAM"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <babeltrace2/endian-internal.h>
-
-#include "fs-sink-trace.h"
-#include "fs-sink-stream.h"
-#include "translate-trace-ir-to-ctf-ir.h"
-
-BT_HIDDEN
-void fs_sink_stream_destroy(struct fs_sink_stream *stream)
-{
-       if (!stream) {
-               goto end;
-       }
-
-       bt_ctfser_fini(&stream->ctfser);
-
-       if (stream->file_name) {
-               g_string_free(stream->file_name, TRUE);
-               stream->file_name = NULL;
-       }
-
-       bt_packet_put_ref(stream->packet_state.packet);
-       g_free(stream);
-
-end:
-       return;
-}
-
-static
-bool stream_file_name_exists(struct fs_sink_trace *trace, const char *name)
-{
-       bool exists = false;
-       GHashTableIter iter;
-       gpointer key, value;
-
-       g_hash_table_iter_init(&iter, trace->streams);
-
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               struct fs_sink_stream *stream = value;
-
-               if (strcmp(name, stream->file_name->str) == 0) {
-                       exists = true;
-                       goto end;
-               }
-       }
-
-end:
-       return exists;
-}
-
-static
-GString *sanitize_stream_file_name(const char *file_name)
-{
-       GString *san_file_name = g_string_new(NULL);
-       const char *ch;
-       gchar *basename;
-
-       BT_ASSERT(san_file_name);
-       BT_ASSERT(file_name);
-       basename = g_path_get_basename(file_name);
-
-       for (ch = basename; *ch != '\0'; ch++) {
-               if (*ch == '/') {
-                       g_string_append_c(san_file_name, '_');
-               } else {
-                       g_string_append_c(san_file_name, *ch);
-               }
-       }
-
-       /* Do not allow `.` and `..` either */
-       if (strcmp(san_file_name->str, ".") == 0 ||
-                       strcmp(san_file_name->str, "..") == 0) {
-               g_string_assign(san_file_name, "stream");
-       }
-
-       g_free(basename);
-       return san_file_name;
-}
-
-static
-GString *make_unique_stream_file_name(struct fs_sink_trace *trace,
-               const char *base)
-{
-       GString *san_base = sanitize_stream_file_name(base);
-       GString *name = g_string_new(san_base->str);
-       unsigned int suffix = 0;
-
-       BT_ASSERT(name);
-
-       while (stream_file_name_exists(trace, name->str) &&
-                       strcmp(name->str, "metadata") == 0) {
-               g_string_printf(name, "%s-%u", san_base->str, suffix);
-               suffix++;
-       }
-
-       g_string_free(san_base, TRUE);
-       return name;
-}
-
-static
-void set_stream_file_name(struct fs_sink_stream *stream)
-{
-       const char *base_name = bt_stream_get_name(stream->ir_stream);
-
-       if (!base_name) {
-               base_name = "stream";
-       }
-
-       BT_ASSERT(!stream->file_name);
-       stream->file_name = make_unique_stream_file_name(stream->trace,
-               base_name);
-}
-
-BT_HIDDEN
-struct fs_sink_stream *fs_sink_stream_create(struct fs_sink_trace *trace,
-               const bt_stream *ir_stream)
-{
-       struct fs_sink_stream *stream = g_new0(struct fs_sink_stream, 1);
-       int ret;
-       GString *path = g_string_new(trace->path->str);
-
-       if (!stream) {
-               goto end;
-       }
-
-       stream->trace = trace;
-       stream->ir_stream = ir_stream;
-       stream->packet_state.beginning_cs = UINT64_C(-1);
-       stream->packet_state.end_cs = UINT64_C(-1);
-       stream->prev_packet_state.end_cs = UINT64_C(-1);
-       stream->prev_packet_state.discarded_events_counter = UINT64_C(-1);
-       stream->prev_packet_state.seq_num = UINT64_C(-1);
-       ret = try_translate_stream_class_trace_ir_to_ctf_ir(trace->tc,
-               bt_stream_borrow_class_const(ir_stream), &stream->sc);
-       if (ret) {
-               goto error;
-       }
-
-       set_stream_file_name(stream);
-       g_string_append_printf(path, "/%s", stream->file_name->str);
-       ret = bt_ctfser_init(&stream->ctfser, path->str);
-       if (ret) {
-               goto error;
-       }
-
-       g_hash_table_insert(trace->streams, (gpointer) ir_stream, stream);
-       goto end;
-
-error:
-       fs_sink_stream_destroy(stream);
-       stream = NULL;
-
-end:
-       if (path) {
-               g_string_free(path, TRUE);
-       }
-
-       return stream;
-}
-
-static
-int write_field(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class *fc, const bt_field *field);
-
-static inline
-int write_int_field(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class_int *fc, const bt_field *field)
-{
-       int ret;
-
-       if (fc->is_signed) {
-               ret = bt_ctfser_write_signed_int(&stream->ctfser,
-                       bt_field_signed_integer_get_value(field),
-                       fc->base.base.alignment, fc->base.size, BYTE_ORDER);
-       } else {
-               ret = bt_ctfser_write_unsigned_int(&stream->ctfser,
-                       bt_field_unsigned_integer_get_value(field),
-                       fc->base.base.alignment, fc->base.size, BYTE_ORDER);
-       }
-
-       return ret;
-}
-
-static inline
-int write_float_field(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class_float *fc, const bt_field *field)
-{
-       int ret;
-       double val = bt_field_real_get_value(field);
-
-       if (fc->base.size == 32) {
-               ret = bt_ctfser_write_float32(&stream->ctfser, val,
-                       fc->base.base.alignment, BYTE_ORDER);
-       } else {
-               ret = bt_ctfser_write_float64(&stream->ctfser, val,
-                       fc->base.base.alignment, BYTE_ORDER);
-       }
-
-       return ret;
-}
-
-static inline
-int write_string_field(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class_string *fc, const bt_field *field)
-{
-       return bt_ctfser_write_string(&stream->ctfser,
-               bt_field_string_get_value(field));
-}
-
-static inline
-int write_array_field_elements(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class_array_base *fc,
-               const bt_field *field)
-{
-       uint64_t i;
-       uint64_t len = bt_field_array_get_length(field);
-       int ret = 0;
-
-       for (i = 0; i < len; i++) {
-               const bt_field *elem_field =
-                       bt_field_array_borrow_element_field_by_index_const(
-                               field, i);
-               ret = write_field(stream, fc->elem_fc, elem_field);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int write_sequence_field(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class_sequence *fc,
-               const bt_field *field)
-{
-       int ret;
-
-       if (fc->length_is_before) {
-               ret = bt_ctfser_write_unsigned_int(&stream->ctfser,
-                       bt_field_array_get_length(field), 8, 32, BYTE_ORDER);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       ret = write_array_field_elements(stream, (void *) fc, field);
-
-end:
-       return ret;
-}
-
-static inline
-int write_struct_field(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class_struct *fc,
-               const bt_field *field, bool align_struct)
-{
-       int ret = 0;
-       uint64_t i;
-
-       if (likely(align_struct)) {
-               ret = bt_ctfser_align_offset_in_current_packet(&stream->ctfser,
-                       fc->base.alignment);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < fc->members->len; i++) {
-               const bt_field *memb_field =
-                       bt_field_structure_borrow_member_field_by_index_const(
-                               field, i);
-               struct fs_sink_ctf_field_class *member_fc =
-                       fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                               fc, i)->fc;
-
-               ret = write_field(stream, member_fc, memb_field);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int write_variant_field(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class_variant *fc,
-               const bt_field *field)
-{
-       uint64_t opt_index =
-               bt_field_variant_get_selected_option_field_index(field);
-       int ret;
-
-       if (fc->tag_is_before) {
-               ret = bt_ctfser_write_unsigned_int(&stream->ctfser,
-                       opt_index, 8, 16, BYTE_ORDER);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       ret = write_field(stream,
-               fs_sink_ctf_field_class_variant_borrow_option_by_index(fc,
-                       opt_index)->fc,
-               bt_field_variant_borrow_selected_option_field_const(field));
-
-end:
-       return ret;
-}
-
-static
-int write_field(struct fs_sink_stream *stream,
-               struct fs_sink_ctf_field_class *fc, const bt_field *field)
-{
-       int ret;
-
-       switch (fc->type) {
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_INT:
-               ret = write_int_field(stream, (void *) fc, field);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT:
-               ret = write_float_field(stream, (void *) fc, field);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRING:
-               ret = write_string_field(stream, (void *) fc, field);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-               ret = write_struct_field(stream, (void *) fc, field, true);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
-               ret = write_array_field_elements(stream, (void *) fc, field);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
-               ret = write_sequence_field(stream, (void *) fc, field);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-               ret = write_variant_field(stream, (void *) fc, field);
-               break;
-       default:
-               abort();
-       }
-
-       return ret;
-}
-
-static inline
-int write_event_header(struct fs_sink_stream *stream,
-               const bt_clock_snapshot *cs, struct fs_sink_ctf_event_class *ec)
-{
-       int ret;
-
-       /* Event class ID */
-       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-               bt_event_class_get_id(ec->ir_ec), 8, 64, BYTE_ORDER);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-       /* Time */
-       if (stream->sc->default_clock_class) {
-               BT_ASSERT(cs);
-               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-                       bt_clock_snapshot_get_value(cs), 8, 64, BYTE_ORDER);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int fs_sink_stream_write_event(struct fs_sink_stream *stream,
-               const bt_clock_snapshot *cs, const bt_event *event,
-               struct fs_sink_ctf_event_class *ec)
-{
-       int ret;
-       const bt_field *field;
-
-       /* Header */
-       ret = write_event_header(stream, cs, ec);
-       if (unlikely(ret)) {
-               goto end;
-       }
-
-       /* Common context */
-       if (stream->sc->event_common_context_fc) {
-               field = bt_event_borrow_common_context_field_const(event);
-               BT_ASSERT(field);
-               ret = write_struct_field(stream,
-                       (void *) stream->sc->event_common_context_fc,
-                       field, true);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       /* Specific context */
-       if (ec->spec_context_fc) {
-               field = bt_event_borrow_specific_context_field_const(event);
-               BT_ASSERT(field);
-               ret = write_struct_field(stream, (void *) ec->spec_context_fc,
-                       field, true);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-       /* Specific context */
-       if (ec->payload_fc) {
-               field = bt_event_borrow_payload_field_const(event);
-               BT_ASSERT(field);
-               ret = write_struct_field(stream, (void *) ec->payload_fc,
-                       field, true);
-               if (unlikely(ret)) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static
-int write_packet_context(struct fs_sink_stream *stream)
-{
-       int ret;
-
-       /* Packet total size */
-       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-               stream->packet_state.total_size, 8, 64, BYTE_ORDER);
-       if (ret) {
-               goto end;
-       }
-
-       /* Packet content size */
-       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-               stream->packet_state.content_size, 8, 64, BYTE_ORDER);
-       if (ret) {
-               goto end;
-       }
-
-       if (stream->sc->packets_have_ts_begin) {
-               /* Beginning time */
-               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-                       stream->packet_state.beginning_cs, 8, 64, BYTE_ORDER);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       if (stream->sc->packets_have_ts_end) {
-               /* End time */
-               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-                       stream->packet_state.end_cs, 8, 64, BYTE_ORDER);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       if (stream->sc->has_discarded_events) {
-               /* Discarded event counter */
-               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-                       stream->packet_state.discarded_events_counter, 8, 64,
-                       BYTE_ORDER);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Sequence number */
-       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-               stream->packet_state.seq_num, 8, 64, BYTE_ORDER);
-       if (ret) {
-               goto end;
-       }
-
-       /* Other members */
-       if (stream->sc->packet_context_fc) {
-               const bt_field *packet_context_field =
-                       bt_packet_borrow_context_field_const(
-                               stream->packet_state.packet);
-
-               BT_ASSERT(packet_context_field);
-               ret = write_struct_field(stream,
-                       (void *) stream->sc->packet_context_fc,
-                       packet_context_field, false);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int fs_sink_stream_open_packet(struct fs_sink_stream *stream,
-               const bt_clock_snapshot *cs, const bt_packet *packet)
-{
-       int ret;
-       uint64_t i;
-
-       BT_ASSERT(!stream->packet_state.is_open);
-       bt_packet_put_ref(stream->packet_state.packet);
-       stream->packet_state.packet = packet;
-       bt_packet_get_ref(stream->packet_state.packet);
-       if (cs) {
-               stream->packet_state.beginning_cs =
-                       bt_clock_snapshot_get_value(cs);
-       }
-
-       /* Open packet */
-       ret = bt_ctfser_open_packet(&stream->ctfser);
-       if (ret) {
-               /* bt_ctfser_open_packet() logs errors */
-               goto end;
-       }
-
-       /* Packet header: magic */
-       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-               UINT64_C(0xc1fc1fc1), 8, 32, BYTE_ORDER);
-       if (ret) {
-               BT_LOGE("Error writing packet header magic: stream-file-name=%s",
-                       stream->file_name->str);
-               goto end;
-       }
-
-       /* Packet header: UUID */
-       for (i = 0; i < BABELTRACE_UUID_LEN; i++) {
-               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-                       (uint64_t) stream->sc->tc->uuid[i], 8, 8, BYTE_ORDER);
-               if (ret) {
-                       BT_LOGE("Error writing packet header UUID: stream-file-name=%s",
-                               stream->file_name->str);
-                       goto end;
-               }
-       }
-
-       /* Packet header: stream class ID */
-       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-               bt_stream_class_get_id(stream->sc->ir_sc), 8, 64, BYTE_ORDER);
-       if (ret) {
-               BT_LOGE("Error writing packet header stream class id: "
-                       "stream-file-name=%s, stream-class-id=%"PRIu64,
-                       stream->file_name->str,
-                       bt_stream_class_get_id(stream->sc->ir_sc));
-               goto end;
-       }
-
-       /* Packet header: stream ID */
-       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
-               bt_stream_get_id(stream->ir_stream), 8, 64, BYTE_ORDER);
-       if (ret) {
-               BT_LOGE("Error writing packet header stream id: "
-                       "stream-file-name=%s, stream-id=%"PRIu64,
-                       stream->file_name->str,
-                       bt_stream_get_id(stream->ir_stream));
-               goto end;
-       }
-
-       /* Save packet context's offset to rewrite it later */
-       stream->packet_state.context_offset_bits =
-               bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser);
-
-       /* Write packet context just to advance to content (first event) */
-       ret = write_packet_context(stream);
-       if (ret) {
-               goto end;
-       }
-
-       stream->packet_state.is_open = true;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int fs_sink_stream_close_packet(struct fs_sink_stream *stream,
-               const bt_clock_snapshot *cs)
-{
-       int ret;
-
-       BT_ASSERT(stream->packet_state.is_open);
-
-       if (cs) {
-               stream->packet_state.end_cs = bt_clock_snapshot_get_value(cs);
-       }
-
-       stream->packet_state.content_size =
-               bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser);
-       stream->packet_state.total_size =
-               (stream->packet_state.content_size + 7) & ~UINT64_C(7);
-
-       /* Rewrite packet context */
-       bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser,
-               stream->packet_state.context_offset_bits);
-       ret = write_packet_context(stream);
-       if (ret) {
-               goto end;
-       }
-
-       /* Close packet */
-       bt_ctfser_close_current_packet(&stream->ctfser,
-               stream->packet_state.total_size / 8);
-
-       /* Partially copy current packet state to previous packet state */
-       stream->prev_packet_state.end_cs = stream->packet_state.end_cs;
-       stream->prev_packet_state.discarded_events_counter =
-               stream->packet_state.discarded_events_counter;
-       stream->prev_packet_state.seq_num =
-               stream->packet_state.seq_num;
-
-       /* Reset current packet state */
-       stream->packet_state.beginning_cs = UINT64_C(-1);
-       stream->packet_state.end_cs = UINT64_C(-1);
-       stream->packet_state.content_size = 0;
-       stream->packet_state.total_size = 0;
-       stream->packet_state.seq_num += 1;
-       stream->packet_state.context_offset_bits = 0;
-       stream->packet_state.is_open = false;
-       BT_PACKET_PUT_REF_AND_RESET(stream->packet_state.packet);
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/fs-sink/fs-sink-stream.h b/plugins/ctf/fs-sink/fs-sink-stream.h
deleted file mode 100644 (file)
index 959d01a..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_STREAM_H
-#define BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_STREAM_H
-
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <glib.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#include "fs-sink-ctf-meta.h"
-
-struct fs_sink_trace;
-
-struct fs_sink_stream {
-       struct fs_sink_trace *trace;
-       struct bt_ctfser ctfser;
-
-       /* Stream's file name */
-       GString *file_name;
-
-       /* Weak */
-       const bt_stream *ir_stream;
-
-       struct fs_sink_ctf_stream_class *sc;
-
-       /* Current packet's state */
-       struct {
-               /*
-                * True if we're, for this stream, within an opened
-                * packet (got a packet beginning message, but no
-                * packet end message yet).
-                */
-               bool is_open;
-
-               /*
-                * Current beginning default clock snapshot for the
-                * current packet (`UINT64_C(-1)` if not set).
-                */
-               uint64_t beginning_cs;
-
-               /*
-                * Current end default clock snapshot for the current
-                * packet (`UINT64_C(-1)` if not set).
-                */
-               uint64_t end_cs;
-
-               /*
-                * Current packet's content size (bits) for the current
-                * packet.
-                */
-               uint64_t content_size;
-
-               /*
-                * Current packet's total size (bits) for the current
-                * packet.
-                */
-               uint64_t total_size;
-
-               /*
-                * Discarded events (free running) counter for the
-                * current packet.
-                */
-               uint64_t discarded_events_counter;
-
-               /* Sequence number (free running) of the current packet */
-               uint64_t seq_num;
-
-               /*
-                * Offset of the packet context structure within the
-                * current packet (bits).
-                */
-               uint64_t context_offset_bits;
-
-               /* Owned by this */
-               const bt_packet *packet;
-       } packet_state;
-
-       /* Previous packet's state */
-       struct {
-               /* End default clock snapshot (`UINT64_C(-1)` if not set) */
-               uint64_t end_cs;
-
-               /* Discarded events (free running) counter */
-               uint64_t discarded_events_counter;
-
-               /* Sequence number (free running) */
-               uint64_t seq_num;
-       } prev_packet_state;
-
-       /* State to handle discarded events */
-       struct {
-               /*
-                * True if we're in the time range given by a previously
-                * received discarded events message. In this case,
-                * `beginning_cs` and `end_cs` below contain the
-                * beginning and end clock snapshots for this range.
-                *
-                * This is used to validate that, when receiving a
-                * packet end message, the current discarded events time
-                * range matches what's expected for CTF 1.8, that is:
-                *
-                * * Its beginning time is the previous packet's end
-                *   time (or the current packet's beginning time if
-                *   this is the first packet).
-                *
-                * * Its end time is the current packet's end time.
-                */
-               bool in_range;
-
-               /*
-                * Beginning and end times of the time range given by a
-                * previously received discarded events message.
-                */
-               uint64_t beginning_cs;
-               uint64_t end_cs;
-       } discarded_events_state;
-
-       /* State to handle discarded packets */
-       struct {
-               /*
-                * True if we're in the time range given by a previously
-                * received discarded packets message. In this case,
-                * `beginning_cs` and `end_cs` below contain the
-                * beginning and end clock snapshots for this range.
-                *
-                * This is used to validate that, when receiving a
-                * packet beginning message, the current discarded
-                * packets time range matches what's expected for CTF
-                * 1.8, that is:
-                *
-                * * Its beginning time is the previous packet's end
-                *   time.
-                *
-                * * Its end time is the current packet's beginning
-                *   time.
-                */
-               bool in_range;
-
-               /*
-                * Beginning and end times of the time range given by a
-                * previously received discarded packets message.
-                */
-               uint64_t beginning_cs;
-               uint64_t end_cs;
-       } discarded_packets_state;
-};
-
-BT_HIDDEN
-struct fs_sink_stream *fs_sink_stream_create(struct fs_sink_trace *trace,
-               const bt_stream *ir_stream);
-
-BT_HIDDEN
-void fs_sink_stream_destroy(struct fs_sink_stream *stream);
-
-BT_HIDDEN
-int fs_sink_stream_write_event(struct fs_sink_stream *stream,
-               const bt_clock_snapshot *cs, const bt_event *event,
-               struct fs_sink_ctf_event_class *ec);
-
-BT_HIDDEN
-int fs_sink_stream_open_packet(struct fs_sink_stream *stream,
-               const bt_clock_snapshot *cs, const bt_packet *packet);
-
-BT_HIDDEN
-int fs_sink_stream_close_packet(struct fs_sink_stream *stream,
-               const bt_clock_snapshot *cs);
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_STREAM_H */
diff --git a/plugins/ctf/fs-sink/fs-sink-trace.c b/plugins/ctf/fs-sink/fs-sink-trace.c
deleted file mode 100644 (file)
index 400b21d..0000000
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRACE"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctfser-internal.h>
-
-#include "translate-trace-ir-to-ctf-ir.h"
-#include "translate-ctf-ir-to-tsdl.h"
-#include "fs-sink.h"
-#include "fs-sink-trace.h"
-#include "fs-sink-stream.h"
-
-/*
- * Sanitizes `path` so as to:
- *
- * * Replace `.` subdirectories with `_`.
- * * Replace `..` subdirectories with `__`.
- * * Remove trailing slashes.
- */
-static
-GString *sanitize_trace_path(const char *path)
-{
-       GString *san_path = g_string_new(NULL);
-       const char *ch = path;
-       bool dir_start = true;
-
-       BT_ASSERT(san_path);
-       BT_ASSERT(path);
-
-       while (*ch != '\0') {
-               switch (*ch) {
-               case '/':
-                       /* Start of directory */
-                       dir_start = true;
-                       g_string_append_c(san_path, *ch);
-                       ch++;
-                       continue;
-               case '.':
-                       if (dir_start) {
-                               switch (ch[1]) {
-                               case '\0':
-                               case '/':
-                                       /* `.` -> `_` */
-                                       g_string_append_c(san_path, '_');
-                                       ch++;
-                                       continue;
-                               case '.':
-                                       switch (ch[2]) {
-                                       case '\0':
-                                       case '/':
-                                               /* `..` -> `__` */
-                                               g_string_append(san_path, "__");
-                                               ch += 2;
-                                               continue;
-                                       default:
-                                               break;
-                                       }
-                               default:
-                                       break;
-                               }
-                       }
-               default:
-                       break;
-               }
-
-               /* Not a special character */
-               g_string_append_c(san_path, *ch);
-               ch++;
-               dir_start = false;
-       }
-
-       /* Remove trailing slashes */
-       while (san_path->len > 0 &&
-                       san_path->str[san_path->len - 1] == '/') {
-               /* Remove trailing slash */
-               g_string_set_size(san_path, san_path->len - 1);
-       }
-
-       if (san_path->len == 0) {
-               /* Looks like there's nothing left: just use `trace` */
-               g_string_assign(san_path, "trace");
-       }
-
-       return san_path;
-}
-
-/*
- * Find a path based on `path` that doesn't exist yet.  First, try `path`
- * itself, then try with incrementing suffixes.
- */
-
-static
-GString *make_unique_trace_path(const char *path)
-{
-       GString *unique_path;
-       unsigned int suffix = 0;
-
-       unique_path = g_string_new(path);
-
-       while (g_file_test(unique_path->str, G_FILE_TEST_EXISTS)) {
-               g_string_printf(unique_path, "%s-%u", path, suffix);
-               suffix++;
-       }
-
-       return unique_path;
-}
-
-/*
- * Validate that the input string `datetime` is an ISO8601-compliant string (the
- * format used by LTTng in the metadata).
- */
-
-static
-int lttng_validate_datetime(const char *datetime)
-{
-       GTimeVal tv;
-       int ret = -1;
-
-       /*
-        * We are using g_time_val_from_iso8601, as the safer/more modern
-        * alternative, g_date_time_new_from_iso8601, is only available in
-        * glib >= 2.56, and this is sufficient for our use case of validating
-        * the format.
-        */
-       if (!g_time_val_from_iso8601(datetime, &tv)) {
-               BT_LOGD("Couldn't parse datetime as iso8601: date=\"%s\"", datetime);
-               goto end;
-       }
-
-       ret = 0;
-
-end:
-       return ret;
-}
-
-static
-int append_lttng_trace_path_ust_uid(GString *path, const bt_trace_class *tc)
-{
-       const bt_value *v;
-       int ret;
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_buffering_id");
-       if (!v || !bt_value_is_signed_integer(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_buffering_id\"");
-               goto error;
-       }
-
-       g_string_append_printf(path, G_DIR_SEPARATOR_S "%" PRId64,
-               bt_value_signed_integer_get(v));
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "isa_length");
-       if (!v || !bt_value_is_signed_integer(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"isa_length\"");
-               goto error;
-       }
-
-       g_string_append_printf(path, G_DIR_SEPARATOR_S "%" PRIu64 "-bit",
-               bt_value_signed_integer_get(v));
-
-       ret = 0;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int append_lttng_trace_path_ust_pid(GString *path, const bt_trace_class *tc)
-{
-       const bt_value *v;
-       const char *datetime;
-       int ret;
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "procname");
-       if (!v || !bt_value_is_string(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"procname\"");
-               goto error;
-       }
-
-       g_string_append_printf(path, G_DIR_SEPARATOR_S "%s", bt_value_string_get(v));
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "vpid");
-       if (!v || !bt_value_is_signed_integer(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"vpid\"");
-               goto error;
-       }
-
-       g_string_append_printf(path, "-%" PRId64, bt_value_signed_integer_get(v));
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "vpid_datetime");
-       if (!v || !bt_value_is_string(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"vpid_datetime\"");
-               goto error;
-       }
-
-       datetime = bt_value_string_get(v);
-
-       if (lttng_validate_datetime(datetime)) {
-               goto error;
-       }
-
-       g_string_append_printf(path, "-%s", datetime);
-
-       ret = 0;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-/*
- * Try to build a trace path based on environment values put in the trace
- * environment by the LTTng tracer, starting with version 2.11.
- */
-static
-GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
-{
-       const bt_trace_class *tc;
-       const bt_value *v;
-       const char *tracer_name, *domain, *datetime;
-       int64_t tracer_major, tracer_minor;
-       GString *path;
-
-       path = g_string_new(NULL);
-       if (!path) {
-               goto error;
-       }
-
-       tc = bt_trace_borrow_class_const(trace->ir_trace);
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_name");
-       if (!v || !bt_value_is_string(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_name\"");
-               goto error;
-       }
-
-       tracer_name = bt_value_string_get(v);
-
-       if (!g_str_equal(tracer_name, "lttng-ust")
-                       && !g_str_equal(tracer_name, "lttng-modules")) {
-               BT_LOGD("Unrecognized tracer name: name=\"%s\"", tracer_name);
-               goto error;
-       }
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_major");
-       if (!v || !bt_value_is_signed_integer(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_major\"");
-               goto error;
-       }
-
-       tracer_major = bt_value_signed_integer_get(v);
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_minor");
-       if (!v || !bt_value_is_signed_integer(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_minor\"");
-               goto error;
-       }
-
-       tracer_minor = bt_value_signed_integer_get(v);
-
-       if (!(tracer_major >= 3 || (tracer_major == 2 && tracer_minor >= 11))) {
-               BT_LOGD("Unsupported LTTng version for automatic trace path: major=%" PRId64 ", minor=%" PRId64,
-                       tracer_major, tracer_minor);
-               goto error;
-       }
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "hostname");
-       if (!v || !bt_value_is_string(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_hostname\"");
-               goto error;
-       }
-
-       g_string_assign(path, bt_value_string_get(v));
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "trace_name");
-       if (!v || !bt_value_is_string(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"trace_name\"");
-               goto error;
-       }
-
-       g_string_append_printf(path, G_DIR_SEPARATOR_S "%s", bt_value_string_get(v));
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "trace_creation_datetime");
-       if (!v || !bt_value_is_string(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"trace_creation_datetime\"");
-               goto error;
-       }
-
-       datetime = bt_value_string_get(v);
-
-       if (lttng_validate_datetime(datetime)) {
-               goto error;
-       }
-
-       g_string_append_printf(path, "-%s", datetime);
-
-       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "domain");
-       if (!v || !bt_value_is_string(v)) {
-               BT_LOGD_STR("Couldn't get environment value: name=\"domain\"");
-               goto error;
-       }
-
-       domain = bt_value_string_get(v);
-       g_string_append_printf(path, G_DIR_SEPARATOR_S "%s", domain);
-
-       if (g_str_equal(domain, "ust")) {
-               const char *tracer_buffering_scheme;
-
-               v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_buffering_scheme");
-               if (!v || !bt_value_is_string(v)) {
-                       BT_LOGD_STR("Couldn't get environment value: name=\"tracer_buffering_scheme\"");
-                       goto error;
-               }
-
-               tracer_buffering_scheme = bt_value_string_get(v);
-               g_string_append_printf(path, G_DIR_SEPARATOR_S "%s", tracer_buffering_scheme);
-
-               if (g_str_equal(tracer_buffering_scheme, "uid")) {
-                       if (append_lttng_trace_path_ust_uid(path, tc)) {
-                               goto error;
-                       }
-               } else if (g_str_equal(tracer_buffering_scheme, "pid")){
-                       if (append_lttng_trace_path_ust_pid(path, tc)) {
-                               goto error;
-                       }
-               } else {
-                       /* Unknown buffering scheme. */
-                       BT_LOGD("Unknown buffering scheme: tracer_buffering_scheme=\"%s\"", tracer_buffering_scheme);
-                       goto error;
-               }
-       } else if (!g_str_equal(domain, "kernel")) {
-               /* Unknown domain. */
-               BT_LOGD("Unknown domain: domain=\"%s\"", domain);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       if (path) {
-               g_string_free(path, TRUE);
-               path = NULL;
-       }
-
-end:
-       return path;
-}
-
-/* Build the relative output path for `trace`. */
-
-static
-GString *make_trace_path_rel(const struct fs_sink_trace *trace)
-{
-       GString *path = NULL;
-
-       if (trace->fs_sink->assume_single_trace) {
-               /* Use output directory directly */
-               path = g_string_new("");
-               goto end;
-       }
-
-       /* First, try to build a path using environment fields written by LTTng. */
-       path = make_lttng_trace_path_rel(trace);
-       if (path) {
-               goto end;
-       }
-
-       /* Otherwise, use the trace name, if available. */
-       const char *trace_name = bt_trace_get_name(trace->ir_trace);
-       if (trace_name) {
-               path = g_string_new(trace_name);
-               goto end;
-       }
-
-       /* Otherwise, use "trace". */
-       path = g_string_new("trace");
-
-end:
-       return path;
-}
-
-/*
- * Compute the trace output path for `trace`, rooted at `output_base_directory`.
- */
-
-static
-GString *make_trace_path(const struct fs_sink_trace *trace, const char *output_base_directory)
-{
-       GString *rel_path = NULL;
-       GString *rel_path_san = NULL;
-       GString *full_path = NULL;
-       GString *unique_full_path = NULL;
-
-       rel_path = make_trace_path_rel(trace);
-       if (!rel_path) {
-               goto end;
-       }
-
-       rel_path_san = sanitize_trace_path(rel_path->str);
-       if (!rel_path_san) {
-               goto end;
-       }
-
-       full_path = g_string_new(NULL);
-       if (!full_path) {
-               goto end;
-       }
-
-       g_string_printf(full_path, "%s" G_DIR_SEPARATOR_S "%s",
-               output_base_directory, rel_path_san->str);
-
-       unique_full_path = make_unique_trace_path(full_path->str);
-
-end:
-       if (rel_path) {
-               g_string_free(rel_path, TRUE);
-       }
-
-       if (rel_path_san) {
-               g_string_free(rel_path_san, TRUE);
-       }
-
-       if (full_path) {
-               g_string_free(full_path, TRUE);
-       }
-
-       return unique_full_path;
-}
-
-BT_HIDDEN
-void fs_sink_trace_destroy(struct fs_sink_trace *trace)
-{
-       GString *tsdl = NULL;
-       FILE *fh = NULL;
-       size_t len;
-
-       if (!trace) {
-               goto end;
-       }
-
-       if (trace->ir_trace_destruction_listener_id != UINT64_C(-1)) {
-               /*
-                * Remove the destruction listener, otherwise it could
-                * be called in the future, and its private data is this
-                * CTF FS sink trace object which won't exist anymore.
-                */
-               (void) bt_trace_remove_destruction_listener(trace->ir_trace,
-                       trace->ir_trace_destruction_listener_id);
-               trace->ir_trace_destruction_listener_id = UINT64_C(-1);
-       }
-
-       if (trace->streams) {
-               g_hash_table_destroy(trace->streams);
-               trace->streams = NULL;
-       }
-
-       tsdl = g_string_new(NULL);
-       BT_ASSERT(tsdl);
-       translate_trace_class_ctf_ir_to_tsdl(trace->tc, tsdl);
-
-       BT_ASSERT(trace->metadata_path);
-       fh = fopen(trace->metadata_path->str, "wb");
-       if (!fh) {
-               BT_LOGF_ERRNO("In trace destruction listener: "
-                       "cannot open metadata file for writing: ",
-                       ": path=\"%s\"", trace->metadata_path->str);
-               abort();
-       }
-
-       len = fwrite(tsdl->str, sizeof(*tsdl->str), tsdl->len, fh);
-       if (len != tsdl->len) {
-               BT_LOGF_ERRNO("In trace destruction listener: "
-                       "cannot write metadata file: ",
-                       ": path=\"%s\"", trace->metadata_path->str);
-               abort();
-       }
-
-       if (!trace->fs_sink->quiet) {
-               printf("Created CTF trace `%s`.\n", trace->path->str);
-       }
-
-       if (trace->path) {
-               g_string_free(trace->path, TRUE);
-               trace->path = NULL;
-       }
-
-       g_string_free(trace->metadata_path, TRUE);
-       trace->metadata_path = NULL;
-
-       fs_sink_ctf_trace_class_destroy(trace->tc);
-       trace->tc = NULL;
-       g_free(trace);
-
-end:
-       if (fh) {
-               int ret = fclose(fh);
-
-               if (ret != 0) {
-                       BT_LOGW_ERRNO("In trace destruction listener: "
-                               "cannot close metadata file: ",
-                               ": path=\"%s\"", trace->metadata_path->str);
-               }
-       }
-
-       if (tsdl) {
-               g_string_free(tsdl, TRUE);
-       }
-
-       return;
-}
-
-static
-void ir_trace_destruction_listener(const bt_trace *ir_trace, void *data)
-{
-       struct fs_sink_trace *trace = data;
-
-       /*
-        * Prevent bt_trace_remove_destruction_listener() from being
-        * called in fs_sink_trace_destroy(), which is called by
-        * g_hash_table_remove() below.
-        */
-       trace->ir_trace_destruction_listener_id = UINT64_C(-1);
-       g_hash_table_remove(trace->fs_sink->traces, ir_trace);
-}
-
-BT_HIDDEN
-struct fs_sink_trace *fs_sink_trace_create(struct fs_sink_comp *fs_sink,
-               const bt_trace *ir_trace)
-{
-       int ret;
-       struct fs_sink_trace *trace = g_new0(struct fs_sink_trace, 1);
-       bt_trace_status trace_status;
-
-       if (!trace) {
-               goto end;
-       }
-
-       trace->fs_sink = fs_sink;
-       trace->ir_trace = ir_trace;
-       trace->ir_trace_destruction_listener_id = UINT64_C(-1);
-       trace->tc = translate_trace_class_trace_ir_to_ctf_ir(
-               bt_trace_borrow_class_const(ir_trace));
-       if (!trace->tc) {
-               goto error;
-       }
-
-       trace->path = make_trace_path(trace, fs_sink->output_dir_path->str);
-       BT_ASSERT(trace->path);
-       ret = g_mkdir_with_parents(trace->path->str, 0755);
-       if (ret) {
-               BT_LOGE_ERRNO("Cannot create directories for trace directory",
-                       ": path=\"%s\"", trace->path->str);
-               goto error;
-       }
-
-       trace->metadata_path = g_string_new(trace->path->str);
-       BT_ASSERT(trace->metadata_path);
-       g_string_append(trace->metadata_path, "/metadata");
-       trace->streams = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-               NULL, (GDestroyNotify) fs_sink_stream_destroy);
-       BT_ASSERT(trace->streams);
-       trace_status = bt_trace_add_destruction_listener(ir_trace,
-               ir_trace_destruction_listener, trace,
-               &trace->ir_trace_destruction_listener_id);
-       if (trace_status) {
-               goto error;
-       }
-
-       g_hash_table_insert(fs_sink->traces, (gpointer) ir_trace, trace);
-       goto end;
-
-error:
-       fs_sink_trace_destroy(trace);
-       trace = NULL;
-
-end:
-       return trace;
-}
diff --git a/plugins/ctf/fs-sink/fs-sink-trace.h b/plugins/ctf/fs-sink/fs-sink-trace.h
deleted file mode 100644 (file)
index e135ffa..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_TRACE_H
-#define BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_TRACE_H
-
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/ctfser-internal.h>
-#include <glib.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#include "fs-sink-ctf-meta.h"
-
-struct fs_sink_comp;
-
-struct fs_sink_trace {
-       struct fs_sink_comp *fs_sink;
-
-       /* Owned by this */
-       struct fs_sink_ctf_trace_class *tc;
-
-       /*
-        * Weak reference: this object does not own it, and `tc` above
-        * does not own its trace IR trace class either. Instead, we add
-        * a "trace destruction" listener (in create_trace()) so that
-        * this object gets destroyed when the trace object is
-        * destroyed.
-        *
-        * Otherwise (with a strong reference), we would keep this trace
-        * object alive until the upstream message iterator ends. This
-        * could "leak" resources (memory, file descriptors) associated
-        * to traces and streams which otherwise would not exist.
-        */
-       const bt_trace *ir_trace;
-
-       uint64_t ir_trace_destruction_listener_id;
-
-       /* Trace's directory */
-       GString *path;
-
-       /* `metadata` file path */
-       GString *metadata_path;
-
-       /*
-        * Hash table of `const bt_stream *` (weak) to
-        * `struct fs_sink_stream *` (owned by hash table).
-        */
-       GHashTable *streams;
-};
-
-BT_HIDDEN
-struct fs_sink_trace *fs_sink_trace_create(struct fs_sink_comp *fs_sink,
-               const bt_trace *ir_trace);
-
-BT_HIDDEN
-void fs_sink_trace_destroy(struct fs_sink_trace *trace);
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_TRACE_H */
diff --git a/plugins/ctf/fs-sink/fs-sink.c b/plugins/ctf/fs-sink/fs-sink.c
deleted file mode 100644 (file)
index 021066f..0000000
+++ /dev/null
@@ -1,1031 +0,0 @@
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/ctfser-internal.h>
-
-#include "fs-sink.h"
-#include "fs-sink-trace.h"
-#include "fs-sink-stream.h"
-#include "fs-sink-ctf-meta.h"
-#include "translate-trace-ir-to-ctf-ir.h"
-#include "translate-ctf-ir-to-tsdl.h"
-
-static
-const char * const in_port_name = "in";
-
-static
-bt_self_component_status ensure_output_dir_exists(
-               struct fs_sink_comp *fs_sink)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       int ret;
-
-       ret = g_mkdir_with_parents(fs_sink->output_dir_path->str, 0755);
-       if (ret) {
-               BT_LOGE_ERRNO("Cannot create directories for output directory",
-                       ": output-dir-path=\"%s\"",
-                       fs_sink->output_dir_path->str);
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-static
-bt_self_component_status configure_component(struct fs_sink_comp *fs_sink,
-               const bt_value *params)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       const bt_value *value;
-
-       value = bt_value_map_borrow_entry_value_const(params, "path");
-       if (!value) {
-               BT_LOGE_STR("Missing mandatory `path` parameter.");
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       if (!bt_value_is_string(value)) {
-               BT_LOGE_STR("`path` parameter: expecting a string.");
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       g_string_assign(fs_sink->output_dir_path,
-               bt_value_string_get(value));
-       value = bt_value_map_borrow_entry_value_const(params,
-               "assume-single-trace");
-       if (value) {
-               if (!bt_value_is_bool(value)) {
-                       BT_LOGE_STR("`assume-single-trace` parameter: expecting a boolean.");
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-
-               fs_sink->assume_single_trace = (bool) bt_value_bool_get(value);
-       }
-
-       value = bt_value_map_borrow_entry_value_const(params,
-               "ignore-discarded-events");
-       if (value) {
-               if (!bt_value_is_bool(value)) {
-                       BT_LOGE_STR("`ignore-discarded-events` parameter: expecting a boolean.");
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-
-               fs_sink->ignore_discarded_events =
-                       (bool) bt_value_bool_get(value);
-       }
-
-       value = bt_value_map_borrow_entry_value_const(params,
-               "ignore-discarded-packets");
-       if (value) {
-               if (!bt_value_is_bool(value)) {
-                       BT_LOGE_STR("`ignore-discarded-packets` parameter: expecting a boolean.");
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-
-               fs_sink->ignore_discarded_packets =
-                       (bool) bt_value_bool_get(value);
-       }
-
-       value = bt_value_map_borrow_entry_value_const(params,
-               "quiet");
-       if (value) {
-               if (!bt_value_is_bool(value)) {
-                       BT_LOGE_STR("`quiet` parameter: expecting a boolean.");
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-
-               fs_sink->quiet = (bool) bt_value_bool_get(value);
-       }
-
-end:
-       return status;
-}
-
-static
-void destroy_fs_sink_comp(struct fs_sink_comp *fs_sink)
-{
-       if (!fs_sink) {
-               goto end;
-       }
-
-       if (fs_sink->output_dir_path) {
-               g_string_free(fs_sink->output_dir_path, TRUE);
-               fs_sink->output_dir_path = NULL;
-       }
-
-       if (fs_sink->traces) {
-               g_hash_table_destroy(fs_sink->traces);
-               fs_sink->traces = NULL;
-       }
-
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
-               fs_sink->upstream_iter);
-       g_free(fs_sink);
-
-end:
-       return;
-}
-
-BT_HIDDEN
-bt_self_component_status ctf_fs_sink_init(
-               bt_self_component_sink *self_comp, const bt_value *params,
-               void *init_method_data)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct fs_sink_comp *fs_sink = NULL;
-
-       fs_sink = g_new0(struct fs_sink_comp, 1);
-       if (!fs_sink) {
-               BT_LOGE_STR("Failed to allocate one CTF FS sink structure.");
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       fs_sink->output_dir_path = g_string_new(NULL);
-       fs_sink->self_comp = self_comp;
-       status = configure_component(fs_sink, params);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               /* configure_component() logs errors */
-               goto end;
-       }
-
-       if (fs_sink->assume_single_trace &&
-                       g_file_test(fs_sink->output_dir_path->str,
-                               G_FILE_TEST_EXISTS)) {
-               BT_LOGE("Single trace mode, but output path exists: "
-                       "output-path=\"%s\"", fs_sink->output_dir_path->str);
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       status = ensure_output_dir_exists(fs_sink);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               /* ensure_output_dir_exists() logs errors */
-               goto end;
-       }
-
-       fs_sink->traces = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-               NULL, (GDestroyNotify) fs_sink_trace_destroy);
-       if (!fs_sink->traces) {
-               BT_LOGE_STR("Failed to allocate one GHashTable.");
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       status = bt_self_component_sink_add_input_port(self_comp, in_port_name,
-               NULL, NULL);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto end;
-       }
-
-       bt_self_component_set_data(
-               bt_self_component_sink_as_self_component(self_comp), fs_sink);
-
-end:
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               destroy_fs_sink_comp(fs_sink);
-       }
-
-       return status;
-}
-
-static inline
-struct fs_sink_stream *borrow_stream(struct fs_sink_comp *fs_sink,
-               const bt_stream *ir_stream)
-{
-       const bt_trace *ir_trace = bt_stream_borrow_trace_const(ir_stream);
-       struct fs_sink_trace *trace;
-       struct fs_sink_stream *stream = NULL;
-
-       trace = g_hash_table_lookup(fs_sink->traces, ir_trace);
-       if (unlikely(!trace)) {
-               if (fs_sink->assume_single_trace &&
-                               g_hash_table_size(fs_sink->traces) > 0) {
-                       BT_LOGE("Single trace mode, but getting more than one trace: "
-                               "stream-name=\"%s\"",
-                               bt_stream_get_name(ir_stream));
-                       goto end;
-               }
-
-               trace = fs_sink_trace_create(fs_sink, ir_trace);
-               if (!trace) {
-                       goto end;
-               }
-       }
-
-       stream = g_hash_table_lookup(trace->streams, ir_stream);
-       if (unlikely(!stream)) {
-               stream = fs_sink_stream_create(trace, ir_stream);
-               if (!stream) {
-                       goto end;
-               }
-       }
-
-end:
-       return stream;
-}
-
-static inline
-bt_self_component_status handle_event_msg(struct fs_sink_comp *fs_sink,
-               const bt_message *msg)
-{
-       int ret;
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       const bt_event *ir_event = bt_message_event_borrow_event_const(msg);
-       const bt_stream *ir_stream = bt_event_borrow_stream_const(ir_event);
-       struct fs_sink_stream *stream;
-       struct fs_sink_ctf_event_class *ec = NULL;
-       const bt_clock_snapshot *cs = NULL;
-
-       stream = borrow_stream(fs_sink, ir_stream);
-       if (unlikely(!stream)) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       ret = try_translate_event_class_trace_ir_to_ctf_ir(stream->sc,
-               bt_event_borrow_class_const(ir_event), &ec);
-       if (ret) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       BT_ASSERT(ec);
-
-       if (stream->sc->default_clock_class) {
-               cs = bt_message_event_borrow_default_clock_snapshot_const(
-                       msg);
-       }
-
-       ret = fs_sink_stream_write_event(stream, cs, ir_event, ec);
-       if (unlikely(ret)) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-static inline
-bt_self_component_status handle_packet_beginning_msg(
-               struct fs_sink_comp *fs_sink, const bt_message *msg)
-{
-       int ret;
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       const bt_packet *ir_packet =
-               bt_message_packet_beginning_borrow_packet_const(msg);
-       const bt_stream *ir_stream = bt_packet_borrow_stream_const(ir_packet);
-       struct fs_sink_stream *stream;
-       const bt_clock_snapshot *cs = NULL;
-
-       stream = borrow_stream(fs_sink, ir_stream);
-       if (unlikely(!stream)) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       if (stream->sc->packets_have_ts_begin) {
-               cs = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
-                       msg);
-               BT_ASSERT(cs);
-       }
-
-       /*
-        * If we previously received a discarded events message with
-        * a time range, make sure that its beginning time matches what's
-        * expected for CTF 1.8, that is:
-        *
-        * * Its beginning time is the previous packet's end
-        *   time (or the current packet's beginning time if
-        *   this is the first packet).
-        *
-        * We check this here instead of in handle_packet_end_msg()
-        * because we want to catch any incompatible message as early as
-        * possible to report the error.
-        *
-        * Validation of the discarded events message's end time is
-        * performed in handle_packet_end_msg().
-        */
-       if (stream->discarded_events_state.in_range) {
-               uint64_t expected_cs;
-
-               /*
-                * `stream->discarded_events_state.in_range` is only set
-                * when the stream class's discarded events have a time
-                * range.
-                *
-                * It is required that the packet beginning and end
-                * messages for this stream class have times when
-                * discarded events have a time range.
-                */
-               BT_ASSERT(stream->sc->discarded_events_has_ts);
-               BT_ASSERT(stream->sc->packets_have_ts_begin);
-               BT_ASSERT(stream->sc->packets_have_ts_end);
-
-               if (stream->prev_packet_state.end_cs == UINT64_C(-1)) {
-                       /* We're opening the first packet */
-                       expected_cs = bt_clock_snapshot_get_value(cs);
-               } else {
-                       expected_cs = stream->prev_packet_state.end_cs;
-               }
-
-               if (stream->discarded_events_state.beginning_cs !=
-                               expected_cs) {
-                       BT_LOGE("Incompatible discarded events message: "
-                               "unexpected beginning time: "
-                               "beginning-cs-val=%" PRIu64 ", "
-                               "expected-beginning-cs-val=%" PRIu64 ", "
-                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                               "trace-name=\"%s\", path=\"%s/%s\"",
-                               stream->discarded_events_state.beginning_cs,
-                               expected_cs,
-                               bt_stream_get_id(ir_stream),
-                               bt_stream_get_name(ir_stream),
-                               bt_trace_get_name(
-                                       bt_stream_borrow_trace_const(ir_stream)),
-                               stream->trace->path->str, stream->file_name->str);
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-       }
-
-       /*
-        * If we previously received a discarded packets message with a
-        * time range, make sure that its beginning and end times match
-        * what's expected for CTF 1.8, that is:
-        *
-        * * Its beginning time is the previous packet's end time.
-        *
-        * * Its end time is the current packet's beginning time.
-        */
-       if (stream->discarded_packets_state.in_range) {
-               uint64_t expected_end_cs;
-
-               /*
-                * `stream->discarded_packets_state.in_range` is only
-                * set when the stream class's discarded packets have a
-                * time range.
-                *
-                * It is required that the packet beginning and end
-                * messages for this stream class have times when
-                * discarded packets have a time range.
-                */
-               BT_ASSERT(stream->sc->discarded_packets_has_ts);
-               BT_ASSERT(stream->sc->packets_have_ts_begin);
-               BT_ASSERT(stream->sc->packets_have_ts_end);
-
-               /*
-                * It is not supported to have a discarded packets
-                * message _before_ the first packet: we cannot validate
-                * that its beginning time is compatible with CTF 1.8 in
-                * this case.
-                */
-               if (stream->prev_packet_state.end_cs == UINT64_C(-1)) {
-                       BT_LOGE("Incompatible discarded packets message "
-                               "occuring before the stream's first packet: "
-                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                               "trace-name=\"%s\", path=\"%s/%s\"",
-                               bt_stream_get_id(ir_stream),
-                               bt_stream_get_name(ir_stream),
-                               bt_trace_get_name(
-                                       bt_stream_borrow_trace_const(ir_stream)),
-                               stream->trace->path->str, stream->file_name->str);
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-
-               if (stream->discarded_packets_state.beginning_cs !=
-                               stream->prev_packet_state.end_cs) {
-                       BT_LOGE("Incompatible discarded packets message: "
-                               "unexpected beginning time: "
-                               "beginning-cs-val=%" PRIu64 ", "
-                               "expected-beginning-cs-val=%" PRIu64 ", "
-                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                               "trace-name=\"%s\", path=\"%s/%s\"",
-                               stream->discarded_packets_state.beginning_cs,
-                               stream->prev_packet_state.end_cs,
-                               bt_stream_get_id(ir_stream),
-                               bt_stream_get_name(ir_stream),
-                               bt_trace_get_name(
-                                       bt_stream_borrow_trace_const(ir_stream)),
-                               stream->trace->path->str, stream->file_name->str);
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-
-               expected_end_cs = bt_clock_snapshot_get_value(cs);
-
-               if (stream->discarded_packets_state.end_cs !=
-                               expected_end_cs) {
-                       BT_LOGE("Incompatible discarded packets message: "
-                               "unexpected end time: "
-                               "end-cs-val=%" PRIu64 ", "
-                               "expected-end-cs-val=%" PRIu64 ", "
-                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                               "trace-name=\"%s\", path=\"%s/%s\"",
-                               stream->discarded_packets_state.end_cs,
-                               expected_end_cs,
-                               bt_stream_get_id(ir_stream),
-                               bt_stream_get_name(ir_stream),
-                               bt_trace_get_name(
-                                       bt_stream_borrow_trace_const(ir_stream)),
-                               stream->trace->path->str, stream->file_name->str);
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-       }
-
-       /*
-        * We're not in a discarded packets time range anymore since we
-        * require that the discarded packets time ranges go from one
-        * packet's end time to the next packet's beginning time, and
-        * we're handling a packet beginning message here.
-        */
-       stream->discarded_packets_state.in_range = false;
-
-       ret = fs_sink_stream_open_packet(stream, cs, ir_packet);
-       if (ret) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-static inline
-bt_self_component_status handle_packet_end_msg(
-               struct fs_sink_comp *fs_sink, const bt_message *msg)
-{
-       int ret;
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       const bt_packet *ir_packet =
-               bt_message_packet_end_borrow_packet_const(msg);
-       const bt_stream *ir_stream = bt_packet_borrow_stream_const(ir_packet);
-       struct fs_sink_stream *stream;
-       const bt_clock_snapshot *cs = NULL;
-
-       stream = borrow_stream(fs_sink, ir_stream);
-       if (unlikely(!stream)) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       if (stream->sc->packets_have_ts_end) {
-               cs = bt_message_packet_end_borrow_default_clock_snapshot_const(
-                       msg);
-               BT_ASSERT(cs);
-       }
-
-       /*
-        * If we previously received a discarded events message with
-        * a time range, make sure that its end time matches what's
-        * expected for CTF 1.8, that is:
-        *
-        * * Its end time is the current packet's end time.
-        *
-        * Validation of the discarded events message's beginning time
-        * is performed in handle_packet_beginning_msg().
-        */
-       if (stream->discarded_events_state.in_range) {
-               uint64_t expected_cs;
-
-               /*
-                * `stream->discarded_events_state.in_range` is only set
-                * when the stream class's discarded events have a time
-                * range.
-                *
-                * It is required that the packet beginning and end
-                * messages for this stream class have times when
-                * discarded events have a time range.
-                */
-               BT_ASSERT(stream->sc->discarded_events_has_ts);
-               BT_ASSERT(stream->sc->packets_have_ts_begin);
-               BT_ASSERT(stream->sc->packets_have_ts_end);
-
-               expected_cs = bt_clock_snapshot_get_value(cs);
-
-               if (stream->discarded_events_state.end_cs != expected_cs) {
-                       BT_LOGE("Incompatible discarded events message: "
-                               "unexpected end time: "
-                               "end-cs-val=%" PRIu64 ", "
-                               "expected-end-cs-val=%" PRIu64 ", "
-                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                               "trace-name=\"%s\", path=\"%s/%s\"",
-                               stream->discarded_events_state.end_cs,
-                               expected_cs,
-                               bt_stream_get_id(ir_stream),
-                               bt_stream_get_name(ir_stream),
-                               bt_trace_get_name(
-                                       bt_stream_borrow_trace_const(ir_stream)),
-                               stream->trace->path->str, stream->file_name->str);
-                       status = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-       }
-
-       ret = fs_sink_stream_close_packet(stream, cs);
-       if (ret) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       /*
-        * We're not in a discarded events time range anymore since we
-        * require that the discarded events time ranges go from one
-        * packet's end time to the next packet's end time, and we're
-        * handling a packet end message here.
-        */
-       stream->discarded_events_state.in_range = false;
-
-end:
-       return status;
-}
-
-static inline
-bt_self_component_status handle_stream_beginning_msg(
-               struct fs_sink_comp *fs_sink, const bt_message *msg)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       const bt_stream *ir_stream =
-               bt_message_stream_beginning_borrow_stream_const(msg);
-       const bt_stream_class *ir_sc =
-               bt_stream_borrow_class_const(ir_stream);
-       struct fs_sink_stream *stream;
-       bool packets_have_beginning_end_cs =
-               bt_stream_class_packets_have_beginning_default_clock_snapshot(ir_sc) &&
-               bt_stream_class_packets_have_end_default_clock_snapshot(ir_sc);
-
-       /*
-        * Not supported: discarded events with default clock snapshots,
-        * but packet beginning/end without default clock snapshot.
-        */
-       if (!fs_sink->ignore_discarded_events &&
-                       bt_stream_class_discarded_events_have_default_clock_snapshots(ir_sc) &&
-                       !packets_have_beginning_end_cs) {
-               BT_LOGE("Unsupported stream: discarded events have "
-                       "default clock snapshots, but packets have no "
-                       "beginning and/or end default clock snapshots: "
-                       "stream-addr=%p, "
-                       "stream-id=%" PRIu64 ", "
-                       "stream-name=\"%s\"",
-                       ir_stream, bt_stream_get_id(ir_stream),
-                       bt_stream_get_name(ir_stream));
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       /*
-        * Not supported: discarded packets with default clock
-        * snapshots, but packet beginning/end without default clock
-        * snapshot.
-        */
-       if (!fs_sink->ignore_discarded_packets &&
-                       bt_stream_class_discarded_packets_have_default_clock_snapshots(ir_sc) &&
-                       !packets_have_beginning_end_cs) {
-               BT_LOGE("Unsupported stream: discarded packets have "
-                       "default clock snapshots, but packets have no "
-                       "beginning and/or end default clock snapshots: "
-                       "stream-addr=%p, "
-                       "stream-id=%" PRIu64 ", "
-                       "stream-name=\"%s\"",
-                       ir_stream, bt_stream_get_id(ir_stream),
-                       bt_stream_get_name(ir_stream));
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       stream = borrow_stream(fs_sink, ir_stream);
-       if (!stream) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       BT_LOGI("Created new, empty stream file: "
-               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-               "trace-name=\"%s\", path=\"%s/%s\"",
-               bt_stream_get_id(ir_stream), bt_stream_get_name(ir_stream),
-               bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream)),
-               stream->trace->path->str, stream->file_name->str);
-
-end:
-       return status;
-}
-
-static inline
-bt_self_component_status handle_stream_end_msg(struct fs_sink_comp *fs_sink,
-               const bt_message *msg)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       const bt_stream *ir_stream =
-               bt_message_stream_end_borrow_stream_const(msg);
-       struct fs_sink_stream *stream;
-
-       stream = borrow_stream(fs_sink, ir_stream);
-       if (!stream) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       BT_LOGI("Closing stream file: "
-               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-               "trace-name=\"%s\", path=\"%s/%s\"",
-               bt_stream_get_id(ir_stream), bt_stream_get_name(ir_stream),
-               bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream)),
-               stream->trace->path->str, stream->file_name->str);
-
-       /*
-        * This destroys the stream object and frees all its resources,
-        * closing the stream file.
-        */
-       g_hash_table_remove(stream->trace->streams, ir_stream);
-
-end:
-       return status;
-}
-
-static inline
-bt_self_component_status handle_discarded_events_msg(
-               struct fs_sink_comp *fs_sink, const bt_message *msg)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       const bt_stream *ir_stream =
-               bt_message_discarded_events_borrow_stream_const(msg);
-       struct fs_sink_stream *stream;
-       const bt_clock_snapshot *cs = NULL;
-       bt_property_availability avail;
-       uint64_t count;
-
-       stream = borrow_stream(fs_sink, ir_stream);
-       if (!stream) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       if (fs_sink->ignore_discarded_events) {
-               BT_LOGI("Ignoring discarded events message: "
-                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                       "trace-name=\"%s\", path=\"%s/%s\"",
-                       bt_stream_get_id(ir_stream),
-                       bt_stream_get_name(ir_stream),
-                       bt_trace_get_name(
-                               bt_stream_borrow_trace_const(ir_stream)),
-                       stream->trace->path->str, stream->file_name->str);
-               goto end;
-       }
-
-       if (stream->discarded_events_state.in_range) {
-               BT_LOGE("Unsupported contiguous discarded events message: "
-                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                       "trace-name=\"%s\", path=\"%s/%s\"",
-                       bt_stream_get_id(ir_stream),
-                       bt_stream_get_name(ir_stream),
-                       bt_trace_get_name(
-                               bt_stream_borrow_trace_const(ir_stream)),
-                       stream->trace->path->str, stream->file_name->str);
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       /*
-        * If we're currently in an opened packet (got a packet
-        * beginning message, but no packet end message yet), we do not
-        * support having a discarded events message with a time range
-        * because we require that the discarded events message's time
-        * range go from a packet's end time to the next packet's end
-        * time.
-        */
-       if (stream->packet_state.is_open &&
-                       stream->sc->discarded_events_has_ts) {
-               BT_LOGE("Unsupported discarded events message with "
-                       "default clock snapshots occuring within a packet: "
-                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                       "trace-name=\"%s\", path=\"%s/%s\"",
-                       bt_stream_get_id(ir_stream),
-                       bt_stream_get_name(ir_stream),
-                       bt_trace_get_name(
-                               bt_stream_borrow_trace_const(ir_stream)),
-                       stream->trace->path->str, stream->file_name->str);
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       if (stream->sc->discarded_events_has_ts) {
-               /*
-                * Make the stream's state be in the time range of a
-                * discarded events message since we have the message's
-                * time range (`stream->sc->discarded_events_has_ts`).
-                */
-               stream->discarded_events_state.in_range = true;
-
-               /*
-                * The clock snapshot values will be validated when
-                * handling the next packet beginning and end messages
-                * (next calls to handle_packet_beginning_msg() and
-                * handle_packet_end_msg()).
-                */
-               cs = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-                       msg);
-               BT_ASSERT(cs);
-               stream->discarded_events_state.beginning_cs =
-                       bt_clock_snapshot_get_value(cs);
-               cs = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
-                       msg);
-               BT_ASSERT(cs);
-               stream->discarded_events_state.end_cs = bt_clock_snapshot_get_value(cs);
-       }
-
-       avail = bt_message_discarded_events_get_count(msg, &count);
-       if (avail != BT_PROPERTY_AVAILABILITY_AVAILABLE) {
-               /*
-                * There's no specific count of discarded events: set it
-                * to 1 so that we know that we at least discarded
-                * something.
-                */
-               count = 1;
-       }
-
-       stream->packet_state.discarded_events_counter += count;
-
-end:
-       return status;
-}
-
-static inline
-bt_self_component_status handle_discarded_packets_msg(
-               struct fs_sink_comp *fs_sink, const bt_message *msg)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       const bt_stream *ir_stream =
-               bt_message_discarded_packets_borrow_stream_const(msg);
-       struct fs_sink_stream *stream;
-       const bt_clock_snapshot *cs = NULL;
-       bt_property_availability avail;
-       uint64_t count;
-
-       stream = borrow_stream(fs_sink, ir_stream);
-       if (!stream) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       if (fs_sink->ignore_discarded_packets) {
-               BT_LOGI("Ignoring discarded packets message: "
-                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                       "trace-name=\"%s\", path=\"%s/%s\"",
-                       bt_stream_get_id(ir_stream),
-                       bt_stream_get_name(ir_stream),
-                       bt_trace_get_name(
-                               bt_stream_borrow_trace_const(ir_stream)),
-                       stream->trace->path->str, stream->file_name->str);
-               goto end;
-       }
-
-       if (stream->discarded_packets_state.in_range) {
-               BT_LOGE("Unsupported contiguous discarded packets message: "
-                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
-                       "trace-name=\"%s\", path=\"%s/%s\"",
-                       bt_stream_get_id(ir_stream),
-                       bt_stream_get_name(ir_stream),
-                       bt_trace_get_name(
-                               bt_stream_borrow_trace_const(ir_stream)),
-                       stream->trace->path->str, stream->file_name->str);
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       /*
-        * Discarded packets messages are guaranteed to occur between
-        * packets.
-        */
-       BT_ASSERT(!stream->packet_state.is_open);
-
-       if (stream->sc->discarded_packets_has_ts) {
-               /*
-                * Make the stream's state be in the time range of a
-                * discarded packets message since we have the message's
-                * time range (`stream->sc->discarded_packets_has_ts`).
-                */
-               stream->discarded_packets_state.in_range = true;
-
-               /*
-                * The clock snapshot values will be validated when
-                * handling the next packet beginning message (next call
-                * to handle_packet_beginning_msg()).
-                */
-               cs = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-                       msg);
-               BT_ASSERT(cs);
-               stream->discarded_packets_state.beginning_cs =
-                       bt_clock_snapshot_get_value(cs);
-               cs = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
-                       msg);
-               BT_ASSERT(cs);
-               stream->discarded_packets_state.end_cs =
-                       bt_clock_snapshot_get_value(cs);
-       }
-
-       avail = bt_message_discarded_packets_get_count(msg, &count);
-       if (avail != BT_PROPERTY_AVAILABILITY_AVAILABLE) {
-               /*
-                * There's no specific count of discarded packets: set
-                * it to 1 so that we know that we at least discarded
-                * something.
-                */
-               count = 1;
-       }
-
-       stream->packet_state.seq_num += count;
-
-end:
-       return status;
-}
-
-static inline
-void put_messages(bt_message_array_const msgs, uint64_t count)
-{
-       uint64_t i;
-
-       for (i = 0; i < count; i++) {
-               BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
-       }
-}
-
-BT_HIDDEN
-bt_self_component_status ctf_fs_sink_consume(bt_self_component_sink *self_comp)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct fs_sink_comp *fs_sink;
-       bt_message_iterator_status it_status;
-       uint64_t msg_count = 0;
-       bt_message_array_const msgs;
-
-       fs_sink = bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(self_comp));
-       BT_ASSERT(fs_sink);
-       BT_ASSERT(fs_sink->upstream_iter);
-
-       /* Consume messages */
-       it_status = bt_self_component_port_input_message_iterator_next(
-               fs_sink->upstream_iter, &msgs, &msg_count);
-       if (it_status < 0) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       switch (it_status) {
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-       {
-               uint64_t i;
-
-               for (i = 0; i < msg_count; i++) {
-                       const bt_message *msg = msgs[i];
-
-                       BT_ASSERT(msg);
-
-                       switch (bt_message_get_type(msg)) {
-                       case BT_MESSAGE_TYPE_EVENT:
-                               status = handle_event_msg(fs_sink, msg);
-                               break;
-                       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-                               status = handle_packet_beginning_msg(
-                                       fs_sink, msg);
-                               break;
-                       case BT_MESSAGE_TYPE_PACKET_END:
-                               status = handle_packet_end_msg(
-                                       fs_sink, msg);
-                               break;
-                       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-                               /* Ignore */
-                               BT_LOGD_STR("Ignoring message iterator inactivity message.");
-                               break;
-                       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
-                               status = handle_stream_beginning_msg(
-                                       fs_sink, msg);
-                               break;
-                       case BT_MESSAGE_TYPE_STREAM_END:
-                               status = handle_stream_end_msg(
-                                       fs_sink, msg);
-                               break;
-                       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-                       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-                               /* Not supported by CTF 1.8 */
-                               BT_LOGD_STR("Ignoring stream activity message.");
-                               break;
-                       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-                               status = handle_discarded_events_msg(
-                                       fs_sink, msg);
-                               break;
-                       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-                               status = handle_discarded_packets_msg(
-                                       fs_sink, msg);
-                               break;
-                       default:
-                               abort();
-                       }
-
-                       BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
-
-                       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-                               BT_LOGE("Failed to handle message: "
-                                       "generated CTF traces could be incomplete: "
-                                       "output-dir-path=\"%s\"",
-                                       fs_sink->output_dir_path->str);
-                               goto error;
-                       }
-               }
-
-               break;
-       }
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               status = BT_SELF_COMPONENT_STATUS_AGAIN;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_END:
-               /* TODO: Finalize all traces (should already be done?) */
-               status = BT_SELF_COMPONENT_STATUS_END;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_ERROR:
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               break;
-       default:
-               break;
-       }
-
-       goto end;
-
-error:
-       BT_ASSERT(status != BT_SELF_COMPONENT_STATUS_OK);
-       put_messages(msgs, msg_count);
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-bt_self_component_status ctf_fs_sink_graph_is_configured(
-               bt_self_component_sink *self_comp)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct fs_sink_comp *fs_sink = bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(self_comp));
-
-       fs_sink->upstream_iter =
-               bt_self_component_port_input_message_iterator_create(
-                       bt_self_component_sink_borrow_input_port_by_name(
-                               self_comp, in_port_name));
-       if (!fs_sink->upstream_iter) {
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-void ctf_fs_sink_finalize(bt_self_component_sink *self_comp)
-{
-       struct fs_sink_comp *fs_sink = bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(self_comp));
-
-       destroy_fs_sink_comp(fs_sink);
-}
diff --git a/plugins/ctf/fs-sink/fs-sink.h b/plugins/ctf/fs-sink/fs-sink.h
deleted file mode 100644 (file)
index 278bdbe..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_H
-#define BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_H
-
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <stdbool.h>
-#include <glib.h>
-
-struct fs_sink_comp {
-       bt_self_component_sink *self_comp;
-
-       /* Owned by this */
-       bt_self_component_port_input_message_iterator *upstream_iter;
-
-       /* Base output directory path */
-       GString *output_dir_path;
-
-       /*
-        * True if the component assumes that it will only write a
-        * single CTF trace (which can contain one or more data
-        * streams). This makes the component write the stream files
-        * directly in the output directory (`output_dir_path` above).
-        */
-       bool assume_single_trace;
-
-       /* True to completely ignore discarded events messages */
-       bool ignore_discarded_events;
-
-       /* True to completely ignore discarded packets messages */
-       bool ignore_discarded_packets;
-
-       /*
-        * True to make the component quiet (nothing printed to the
-        * standard output).
-        */
-       bool quiet;
-
-       /*
-        * Hash table of `const bt_trace *` (weak) to
-        * `struct fs_sink_trace *` (owned by hash table).
-        */
-       GHashTable *traces;
-};
-
-BT_HIDDEN
-bt_self_component_status ctf_fs_sink_init(
-               bt_self_component_sink *component,
-               const bt_value *params,
-               void *init_method_data);
-
-BT_HIDDEN
-bt_self_component_status ctf_fs_sink_consume(
-               bt_self_component_sink *component);
-
-BT_HIDDEN
-bt_self_component_status ctf_fs_sink_graph_is_configured(
-               bt_self_component_sink *component);
-
-BT_HIDDEN
-void ctf_fs_sink_finalize(bt_self_component_sink *component);
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_H */
diff --git a/plugins/ctf/fs-sink/logging.c b/plugins/ctf/fs-sink/logging.c
deleted file mode 100644 (file)
index e53d744..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_fs_sink_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_plugin_fs_sink_log_level,
-       "BABELTRACE_SINK_CTF_FS_LOG_LEVEL");
diff --git a/plugins/ctf/fs-sink/logging.h b/plugins/ctf/fs-sink/logging.h
deleted file mode 100644 (file)
index 3ae6320..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef PLUGINS_FS_SINK_LOGGING_H
-#define PLUGINS_FS_SINK_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_fs_sink_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_fs_sink_log_level);
-
-#endif /* PLUGINS_FS_SINK_LOGGING_H */
diff --git a/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c b/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c
deleted file mode 100644 (file)
index 5715995..0000000
+++ /dev/null
@@ -1,907 +0,0 @@
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRANSLATE-CTF-IR-TO-TSDL"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-#include <glib.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/endian-internal.h>
-
-#include "fs-sink-ctf-meta.h"
-
-struct ctx {
-       unsigned int indent_level;
-       GString *tsdl;
-};
-
-static inline
-void append_indent(struct ctx *ctx)
-{
-       unsigned int i;
-
-       for (i = 0; i < ctx->indent_level; i++) {
-               g_string_append_c(ctx->tsdl, '\t');
-       }
-}
-
-static
-void append_uuid(struct ctx *ctx, bt_uuid uuid)
-{
-       g_string_append_printf(ctx->tsdl,
-               "\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-               (unsigned int) uuid[0],
-               (unsigned int) uuid[1],
-               (unsigned int) uuid[2],
-               (unsigned int) uuid[3],
-               (unsigned int) uuid[4],
-               (unsigned int) uuid[5],
-               (unsigned int) uuid[6],
-               (unsigned int) uuid[7],
-               (unsigned int) uuid[8],
-               (unsigned int) uuid[9],
-               (unsigned int) uuid[10],
-               (unsigned int) uuid[11],
-               (unsigned int) uuid[12],
-               (unsigned int) uuid[13],
-               (unsigned int) uuid[14],
-               (unsigned int) uuid[15]);
-}
-
-static
-void append_quoted_string_content(struct ctx *ctx, const char *str)
-{
-       const char *ch;
-
-       for (ch = str; *ch != '\0'; ch++) {
-               unsigned char uch = (unsigned char) *ch;
-
-               if (uch < 32 || uch >= 127) {
-                       switch (*ch) {
-                       case '\a':
-                               g_string_append(ctx->tsdl, "\\a");
-                               break;
-                       case '\b':
-                               g_string_append(ctx->tsdl, "\\b");
-                               break;
-                       case '\f':
-                               g_string_append(ctx->tsdl, "\\f");
-                               break;
-                       case '\n':
-                               g_string_append(ctx->tsdl, "\\n");
-                               break;
-                       case '\r':
-                               g_string_append(ctx->tsdl, "\\r");
-                               break;
-                       case '\t':
-                               g_string_append(ctx->tsdl, "\\t");
-                               break;
-                       case '\v':
-                               g_string_append(ctx->tsdl, "\\v");
-                               break;
-                       default:
-                               g_string_append_printf(ctx->tsdl, "\\x%02x",
-                                       (unsigned int) uch);
-                               break;
-                       }
-               } else if (*ch == '"' || *ch == '\\') {
-                       g_string_append_c(ctx->tsdl, '\\');
-                       g_string_append_c(ctx->tsdl, *ch);
-               } else {
-                       g_string_append_c(ctx->tsdl, *ch);
-               }
-       }
-}
-
-static
-void append_quoted_string(struct ctx *ctx, const char *str)
-{
-       g_string_append_c(ctx->tsdl, '"');
-       append_quoted_string_content(ctx, str);
-       g_string_append_c(ctx->tsdl, '"');
-}
-
-static
-void append_integer_field_class_from_props(struct ctx *ctx, unsigned int size,
-               unsigned int alignment, bool is_signed,
-               bt_field_class_integer_preferred_display_base disp_base,
-               const char *mapped_clock_class_name, const char *field_name,
-               bool end)
-{
-       g_string_append_printf(ctx->tsdl,
-               "integer { size = %u; align = %u;",
-               size, alignment);
-
-       if (is_signed) {
-               g_string_append(ctx->tsdl, " signed = true;");
-       }
-
-       if (disp_base != BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL) {
-               g_string_append(ctx->tsdl, " base = ");
-
-               switch (disp_base) {
-               case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
-                       g_string_append(ctx->tsdl, "b");
-                       break;
-               case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
-                       g_string_append(ctx->tsdl, "o");
-                       break;
-               case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
-                       g_string_append(ctx->tsdl, "x");
-                       break;
-               default:
-                       abort();
-               }
-
-               g_string_append_c(ctx->tsdl, ';');
-       }
-
-       if (mapped_clock_class_name) {
-               g_string_append_printf(ctx->tsdl, " map = clock.%s.value;",
-                       mapped_clock_class_name);
-       }
-
-       g_string_append(ctx->tsdl, " }");
-
-       if (field_name) {
-               g_string_append_printf(ctx->tsdl, " %s", field_name);
-       }
-
-       if (end) {
-               g_string_append(ctx->tsdl, ";\n");
-       }
-}
-
-static
-void append_end_block(struct ctx *ctx)
-{
-       ctx->indent_level--;
-       append_indent(ctx);
-       g_string_append(ctx->tsdl, "}");
-}
-
-static
-void append_end_block_semi_nl(struct ctx *ctx)
-{
-       ctx->indent_level--;
-       append_indent(ctx);
-       g_string_append(ctx->tsdl, "};\n");
-}
-
-static
-void append_end_block_semi_nl_nl(struct ctx *ctx)
-{
-       append_end_block_semi_nl(ctx);
-       g_string_append_c(ctx->tsdl, '\n');
-}
-
-static
-void append_integer_field_class(struct ctx *ctx,
-               struct fs_sink_ctf_field_class_int *fc)
-{
-       const bt_field_class *ir_fc = fc->base.base.ir_fc;
-       bt_field_class_type type = bt_field_class_get_type(ir_fc);
-       bool is_signed = type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION ||
-               type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER;
-
-       if (type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION ||
-                       type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
-               g_string_append(ctx->tsdl, "enum : ");
-       }
-
-       append_integer_field_class_from_props(ctx, fc->base.size,
-               fc->base.base.alignment, is_signed,
-               bt_field_class_integer_get_preferred_display_base(ir_fc),
-               NULL, NULL, false);
-
-       if (type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION ||
-                       type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
-               uint64_t i;
-
-               g_string_append(ctx->tsdl, " {\n");
-               ctx->indent_level++;
-
-               for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_fc); i++) {
-                       const char *label;
-                       const bt_field_class_enumeration_mapping *mapping;
-                       const bt_field_class_unsigned_enumeration_mapping *u_mapping;
-                       const bt_field_class_signed_enumeration_mapping *i_mapping;
-                       uint64_t range_count;
-                       uint64_t range_i;
-
-                       if (is_signed) {
-                               i_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
-                                       ir_fc, i);
-                               mapping = bt_field_class_signed_enumeration_mapping_as_mapping_const(
-                                       i_mapping);
-                       } else {
-                               u_mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
-                                       ir_fc, i);
-                               mapping = bt_field_class_unsigned_enumeration_mapping_as_mapping_const(
-                                       u_mapping);
-                       }
-
-                       label = bt_field_class_enumeration_mapping_get_label(
-                               mapping);
-                       range_count =
-                               bt_field_class_enumeration_mapping_get_range_count(
-                                       mapping);
-
-                       for (range_i = 0; range_i < range_count; range_i++) {
-                               append_indent(ctx);
-
-                               /*
-                                * Systematically prepend `_` to the
-                                * mapping's label as this could be used
-                                * as the tag of a subsequent variant
-                                * field class and variant FC option
-                                * names are systematically protected
-                                * with a leading `_`.
-                                *
-                                * FIXME: This is temporary as the
-                                * library's API should change to
-                                * decouple variant FC option names from
-                                * selector FC labels. The current
-                                * drawback is that an original label
-                                * `HELLO` becomes `_HELLO` in the
-                                * generated metadata, therefore tools
-                                * expecting `HELLO` could fail.
-                                */
-                               g_string_append(ctx->tsdl, "\"_");
-                               append_quoted_string_content(ctx, label);
-                               g_string_append(ctx->tsdl, "\" = ");
-
-                               if (is_signed) {
-                                       int64_t lower, upper;
-
-                                       bt_field_class_signed_enumeration_mapping_get_range_by_index(
-                                               i_mapping, range_i,
-                                               &lower, &upper);
-
-                                       if (lower == upper) {
-                                               g_string_append_printf(
-                                                       ctx->tsdl, "%" PRId64,
-                                                       lower);
-                                       } else {
-                                               g_string_append_printf(
-                                                       ctx->tsdl, "%" PRId64 " ... %" PRId64,
-                                                       lower, upper);
-                                       }
-                               } else {
-                                       uint64_t lower, upper;
-
-                                       bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
-                                               u_mapping, range_i,
-                                               &lower, &upper);
-
-                                       if (lower == upper) {
-                                               g_string_append_printf(
-                                                       ctx->tsdl, "%" PRIu64,
-                                                       lower);
-                                       } else {
-                                               g_string_append_printf(
-                                                       ctx->tsdl, "%" PRIu64 " ... %" PRIu64,
-                                                       lower, upper);
-                                       }
-                               }
-
-                               g_string_append(ctx->tsdl, ",\n");
-                       }
-               }
-
-               append_end_block(ctx);
-       }
-}
-
-static
-void append_float_field_class(struct ctx *ctx,
-               struct fs_sink_ctf_field_class_float *fc)
-{
-       unsigned int mant_dig, exp_dig;
-
-       if (bt_field_class_real_is_single_precision(fc->base.base.ir_fc)) {
-               mant_dig = 24;
-               exp_dig = 8;
-       } else {
-               mant_dig = 53;
-               exp_dig = 11;
-       }
-
-       g_string_append_printf(ctx->tsdl,
-               "floating_point { mant_dig = %u; exp_dig = %u; align = %u; }",
-               mant_dig, exp_dig, fc->base.base.alignment);
-}
-
-static
-void append_string_field_class(struct ctx *ctx,
-               struct fs_sink_ctf_field_class_float *fc)
-{
-       g_string_append(ctx->tsdl, "string { encoding = UTF8; }");
-}
-
-static
-void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc);
-
-static
-void append_member(struct ctx *ctx, const char *name,
-               struct fs_sink_ctf_field_class *fc)
-{
-       GString *lengths = NULL;
-       const char *lengths_str = "";
-
-       while (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY ||
-                       fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
-               if (!lengths) {
-                       lengths = g_string_new(NULL);
-                       BT_ASSERT(lengths);
-               }
-
-               if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY) {
-                       struct fs_sink_ctf_field_class_array *array_fc =
-                               (void *) fc;
-
-                       g_string_append_printf(lengths, "[%" PRIu64 "]",
-                               array_fc->length);
-                       fc = array_fc->base.elem_fc;
-               } else {
-                       struct fs_sink_ctf_field_class_sequence *seq_fc =
-                               (void *) fc;
-
-                       g_string_append_printf(lengths, "[%s]",
-                               seq_fc->length_ref->str);
-                       fc = seq_fc->base.elem_fc;
-               }
-       }
-
-       append_field_class(ctx, fc);
-
-       if (lengths) {
-               lengths_str = lengths->str;
-       }
-
-       g_string_append_printf(ctx->tsdl, " %s%s;\n", name, lengths_str);
-
-       if (lengths) {
-               g_string_free(lengths, TRUE);
-       }
-}
-
-static
-void append_struct_field_class_members(struct ctx *ctx,
-               struct fs_sink_ctf_field_class_struct *struct_fc)
-{
-       uint64_t i;
-
-       for (i = 0; i < struct_fc->members->len; i++) {
-               struct fs_sink_ctf_named_field_class *named_fc =
-                       fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                               struct_fc, i);
-               struct fs_sink_ctf_field_class *fc = named_fc->fc;
-
-               if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
-                       struct fs_sink_ctf_field_class_sequence *seq_fc =
-                               (void *) fc;
-
-                       if (seq_fc->length_is_before) {
-                               append_indent(ctx);
-                               append_integer_field_class_from_props(ctx,
-                                       32, 8, false,
-                                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-                                       NULL, seq_fc->length_ref->str, true);
-                       }
-               } else if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT) {
-                       struct fs_sink_ctf_field_class_variant *var_fc =
-                               (void *) fc;
-
-                       if (var_fc->tag_is_before) {
-                               append_indent(ctx);
-                               g_string_append(ctx->tsdl, "enum : ");
-                               append_integer_field_class_from_props(ctx,
-                                       16, 8, false,
-                                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-                                       NULL, NULL, false);
-                               g_string_append(ctx->tsdl, " {\n");
-                               ctx->indent_level++;
-
-                               for (i = 0; i < var_fc->options->len; i++) {
-                                       struct fs_sink_ctf_named_field_class *named_fc =
-                                               fs_sink_ctf_field_class_variant_borrow_option_by_index(
-                                                       var_fc, i);
-
-                                       append_indent(ctx);
-                                       g_string_append_printf(ctx->tsdl,
-                                               "\"%s\" = %" PRIu64 ",\n",
-                                               named_fc->name->str, i);
-                               }
-
-                               append_end_block(ctx);
-                               g_string_append_printf(ctx->tsdl, " %s;\n",
-                                       var_fc->tag_ref->str);
-                       }
-               }
-
-               append_indent(ctx);
-               append_member(ctx, named_fc->name->str, fc);
-       }
-}
-
-static
-void append_struct_field_class(struct ctx *ctx,
-               struct fs_sink_ctf_field_class_struct *fc)
-{
-       g_string_append(ctx->tsdl, "struct {\n");
-       ctx->indent_level++;
-       append_struct_field_class_members(ctx, fc);
-       append_end_block(ctx);
-       g_string_append_printf(ctx->tsdl, " align(%u)",
-               fc->base.alignment);
-}
-
-static
-void append_variant_field_class(struct ctx *ctx,
-               struct fs_sink_ctf_field_class_variant *var_fc)
-{
-       uint64_t i;
-
-       g_string_append_printf(ctx->tsdl, "variant <%s> {\n",
-               var_fc->tag_ref->str);
-       ctx->indent_level++;
-
-       for (i = 0; i < var_fc->options->len; i++) {
-               struct fs_sink_ctf_named_field_class *named_fc =
-                       fs_sink_ctf_field_class_variant_borrow_option_by_index(
-                               var_fc, i);
-
-               append_indent(ctx);
-               append_member(ctx, named_fc->name->str, named_fc->fc);
-       }
-
-       append_end_block(ctx);
-}
-
-static
-void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc)
-{
-       switch (fc->type) {
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_INT:
-               append_integer_field_class(ctx, (void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT:
-               append_float_field_class(ctx, (void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRING:
-               append_string_field_class(ctx, (void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-               append_struct_field_class(ctx, (void *) fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-               append_variant_field_class(ctx, (void *) fc);
-               break;
-       default:
-               abort();
-       }
-}
-
-static
-void append_event_class(struct ctx *ctx, struct fs_sink_ctf_event_class *ec)
-{
-       const char *str;
-       bt_event_class_log_level log_level;
-
-       /* Event class */
-       append_indent(ctx);
-       g_string_append(ctx->tsdl, "event {\n");
-       ctx->indent_level++;
-
-       /* Event class properties */
-       append_indent(ctx);
-       g_string_append(ctx->tsdl, "name = ");
-       str = bt_event_class_get_name(ec->ir_ec);
-       if (!str) {
-               str = "unknown";
-       }
-
-       append_quoted_string(ctx, str);
-       g_string_append(ctx->tsdl, ";\n");
-       append_indent(ctx);
-       g_string_append_printf(ctx->tsdl, "stream_id = %" PRIu64 ";\n",
-               bt_stream_class_get_id(ec->sc->ir_sc));
-       append_indent(ctx);
-       g_string_append_printf(ctx->tsdl, "id = %" PRIu64 ";\n",
-               bt_event_class_get_id(ec->ir_ec));
-
-       str = bt_event_class_get_emf_uri(ec->ir_ec);
-       if (str) {
-               append_indent(ctx);
-               g_string_append(ctx->tsdl, "model.emf.uri = ");
-               append_quoted_string(ctx, str);
-               g_string_append(ctx->tsdl, ";\n");
-       }
-
-       if (bt_event_class_get_log_level(ec->ir_ec, &log_level) ==
-                       BT_PROPERTY_AVAILABILITY_AVAILABLE) {
-               unsigned int level;
-
-               append_indent(ctx);
-               g_string_append(ctx->tsdl, "loglevel = ");
-
-               switch (log_level) {
-               case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
-                       level = 0;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
-                       level = 1;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
-                       level = 2;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
-                       level = 3;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
-                       level = 4;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
-                       level = 5;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_INFO:
-                       level = 6;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
-                       level = 7;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
-                       level = 8;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
-                       level = 9;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
-                       level = 10;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
-                       level = 11;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
-                       level = 12;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
-                       level = 13;
-                       break;
-               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
-                       level = 14;
-                       break;
-               default:
-                       abort();
-               }
-
-               g_string_append_printf(ctx->tsdl, "%u;\n", level);
-       }
-
-       /* Event specific context field class */
-       if (ec->spec_context_fc) {
-               append_indent(ctx);
-               g_string_append(ctx->tsdl, "context := ");
-               append_field_class(ctx, ec->spec_context_fc);
-               g_string_append(ctx->tsdl, ";\n");
-       }
-
-       /* Event payload field class */
-       if (ec->payload_fc) {
-               append_indent(ctx);
-               g_string_append(ctx->tsdl, "fields := ");
-               append_field_class(ctx, ec->payload_fc);
-               g_string_append(ctx->tsdl, ";\n");
-       }
-
-       append_end_block_semi_nl_nl(ctx);
-}
-
-static
-void append_stream_class(struct ctx *ctx,
-               struct fs_sink_ctf_stream_class *sc)
-{
-       uint64_t i;
-
-       /* Default clock class */
-       if (sc->default_clock_class) {
-               const char *descr;
-               int64_t offset_seconds;
-               uint64_t offset_cycles;
-               bt_uuid uuid;
-
-               append_indent(ctx);
-               g_string_append(ctx->tsdl, "clock {\n");
-               ctx->indent_level++;
-               BT_ASSERT(sc->default_clock_class_name->len > 0);
-               append_indent(ctx);
-               g_string_append_printf(ctx->tsdl, "name = %s;\n",
-                       sc->default_clock_class_name->str);
-               descr = bt_clock_class_get_description(sc->default_clock_class);
-               if (descr) {
-                       append_indent(ctx);
-                       g_string_append(ctx->tsdl, "description = ");
-                       append_quoted_string(ctx, descr);
-                       g_string_append(ctx->tsdl, ";\n");
-               }
-
-               append_indent(ctx);
-               g_string_append_printf(ctx->tsdl, "freq = %" PRIu64 ";\n",
-                       bt_clock_class_get_frequency(sc->default_clock_class));
-               append_indent(ctx);
-               g_string_append_printf(ctx->tsdl, "precision = %" PRIu64 ";\n",
-                       bt_clock_class_get_precision(sc->default_clock_class));
-               bt_clock_class_get_offset(sc->default_clock_class,
-                       &offset_seconds, &offset_cycles);
-               append_indent(ctx);
-               g_string_append_printf(ctx->tsdl, "offset_s = %" PRId64 ";\n",
-                       offset_seconds);
-               append_indent(ctx);
-               g_string_append_printf(ctx->tsdl, "offset = %" PRIu64 ";\n",
-                       offset_cycles);
-               append_indent(ctx);
-               g_string_append(ctx->tsdl, "absolute = ");
-
-               if (bt_clock_class_origin_is_unix_epoch(
-                               sc->default_clock_class)) {
-                       g_string_append(ctx->tsdl, "true");
-               } else {
-                       g_string_append(ctx->tsdl, "false");
-               }
-
-               g_string_append(ctx->tsdl, ";\n");
-               uuid = bt_clock_class_get_uuid(sc->default_clock_class);
-               if (uuid) {
-                       append_indent(ctx);
-                       g_string_append(ctx->tsdl, "uuid = ");
-                       append_uuid(ctx, uuid);
-                       g_string_append(ctx->tsdl, ";\n");
-               }
-
-               /* End clock class */
-               append_end_block_semi_nl_nl(ctx);
-       }
-
-       /* Stream class */
-       append_indent(ctx);
-       g_string_append(ctx->tsdl, "stream {\n");
-       ctx->indent_level++;
-
-       /* Stream class properties */
-       append_indent(ctx);
-       g_string_append_printf(ctx->tsdl, "id = %" PRIu64 ";\n",
-               bt_stream_class_get_id(sc->ir_sc));
-
-       /* Packet context field class */
-       append_indent(ctx);
-       g_string_append(ctx->tsdl, "packet.context := struct {\n");
-       ctx->indent_level++;
-       append_indent(ctx);
-       append_integer_field_class_from_props(ctx, 64, 8, false,
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-               NULL, "packet_size", true);
-       append_indent(ctx);
-       append_integer_field_class_from_props(ctx, 64, 8, false,
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-               NULL, "content_size", true);
-
-       if (sc->packets_have_ts_begin) {
-               append_indent(ctx);
-               append_integer_field_class_from_props(ctx, 64, 8, false,
-                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-                       sc->default_clock_class_name->str,
-                       "timestamp_begin", true);
-       }
-
-       if (sc->packets_have_ts_end) {
-               append_indent(ctx);
-               append_integer_field_class_from_props(ctx, 64, 8, false,
-                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-                       sc->default_clock_class_name->str,
-                       "timestamp_end", true);
-       }
-
-       if (sc->has_discarded_events) {
-               append_indent(ctx);
-               append_integer_field_class_from_props(ctx, 64, 8, false,
-                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-                       NULL, "events_discarded", true);
-       }
-
-       /*
-        * Unconditionnally write the packet sequence number as, even if
-        * there's no possible discarded packets message, it's still
-        * useful information to have.
-        */
-       append_indent(ctx);
-       append_integer_field_class_from_props(ctx, 64, 8, false,
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-               NULL, "packet_seq_num", true);
-
-       if (sc->packet_context_fc) {
-               append_struct_field_class_members(ctx,
-                       (void *) sc->packet_context_fc);
-               fs_sink_ctf_field_class_struct_align_at_least(
-                       (void *) sc->packet_context_fc, 8);
-       }
-
-       /* End packet context field class */
-       append_end_block(ctx);
-       g_string_append_printf(ctx->tsdl, " align(%u);\n\n",
-               sc->packet_context_fc ? sc->packet_context_fc->alignment : 8);
-
-       /* Event header field class */
-       append_indent(ctx);
-       g_string_append(ctx->tsdl, "event.header := struct {\n");
-       ctx->indent_level++;
-       append_indent(ctx);
-       append_integer_field_class_from_props(ctx, 64, 8, false,
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-               NULL, "id", true);
-
-       if (sc->default_clock_class) {
-               append_indent(ctx);
-               append_integer_field_class_from_props(ctx, 64, 8, false,
-                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-                       sc->default_clock_class_name->str,
-                       "timestamp", true);
-       }
-
-       /* End event header field class */
-       append_end_block(ctx);
-       g_string_append(ctx->tsdl, " align(8);\n");
-
-       /* Event common context field class */
-       if (sc->event_common_context_fc) {
-               append_indent(ctx);
-               g_string_append(ctx->tsdl, "event.context := ");
-               append_field_class(ctx,
-                       (void *) sc->event_common_context_fc);
-               g_string_append(ctx->tsdl, ";\n");
-       }
-
-       /* End stream class */
-       append_end_block_semi_nl_nl(ctx);
-
-       /* Event classes */
-       for (i = 0; i < sc->event_classes->len; i++) {
-               append_event_class(ctx, sc->event_classes->pdata[i]);
-       }
-}
-
-BT_HIDDEN
-void translate_trace_class_ctf_ir_to_tsdl(struct fs_sink_ctf_trace_class *tc,
-               GString *tsdl)
-{
-       struct ctx ctx = {
-               .indent_level = 0,
-               .tsdl = tsdl,
-       };
-       uint64_t i;
-       uint64_t count;
-
-       g_string_assign(tsdl, "/* CTF 1.8 */\n\n");
-       g_string_append(tsdl, "/* This was generated by a Babeltrace `sink.ctf.fs` component. */\n\n");
-
-       /* Trace class */
-       append_indent(&ctx);
-       g_string_append(tsdl, "trace {\n");
-       ctx.indent_level++;
-
-       /* Trace class properties */
-       append_indent(&ctx);
-       g_string_append(tsdl, "major = 1;\n");
-       append_indent(&ctx);
-       g_string_append(tsdl, "minor = 8;\n");
-       append_indent(&ctx);
-       g_string_append(tsdl, "uuid = ");
-       append_uuid(&ctx, tc->uuid);
-       g_string_append(tsdl, ";\n");
-       append_indent(&ctx);
-       g_string_append(tsdl, "byte_order = ");
-
-       if (BYTE_ORDER == LITTLE_ENDIAN) {
-               g_string_append(tsdl, "le");
-       } else {
-               g_string_append(tsdl, "be");
-       }
-
-       g_string_append(tsdl, ";\n");
-
-       /* Packet header field class */
-       append_indent(&ctx);
-       g_string_append(tsdl, "packet.header := struct {\n");
-       ctx.indent_level++;
-       append_indent(&ctx);
-       append_integer_field_class_from_props(&ctx, 32, 8, false,
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
-               NULL, "magic", true);
-       append_indent(&ctx);
-       append_integer_field_class_from_props(&ctx, 8, 8, false,
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-               NULL, "uuid[16]", true);
-       append_indent(&ctx);
-       append_integer_field_class_from_props(&ctx, 64, 8, false,
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-               NULL, "stream_id", true);
-       append_indent(&ctx);
-       append_integer_field_class_from_props(&ctx, 64, 8, false,
-               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
-               NULL, "stream_instance_id", true);
-
-       /* End packet header field class */
-       append_end_block(&ctx);
-       g_string_append(ctx.tsdl, " align(8);\n");
-
-       /* End trace class */
-       append_end_block_semi_nl_nl(&ctx);
-
-       /* Trace class environment */
-       count = bt_trace_class_get_environment_entry_count(tc->ir_tc);
-       if (count > 0) {
-               append_indent(&ctx);
-               g_string_append(tsdl, "env {\n");
-               ctx.indent_level++;
-
-               for (i = 0; i < count; i++) {
-                       const char *name;
-                       const bt_value *val;
-
-                       bt_trace_class_borrow_environment_entry_by_index_const(
-                               tc->ir_tc, i, &name, &val);
-                       append_indent(&ctx);
-                       g_string_append_printf(tsdl, "%s = ", name);
-
-                       switch (bt_value_get_type(val)) {
-                       case BT_VALUE_TYPE_SIGNED_INTEGER:
-                               g_string_append_printf(tsdl, "%" PRId64,
-                                       bt_value_signed_integer_get(val));
-                               break;
-                       case BT_VALUE_TYPE_STRING:
-                               append_quoted_string(&ctx, bt_value_string_get(val));
-                               break;
-                       default:
-                               /*
-                                * This is checked in
-                                * translate_trace_class_trace_ir_to_ctf_ir().
-                                */
-                               abort();
-                       }
-
-                       g_string_append(tsdl, ";\n");
-               }
-
-               /* End trace class environment */
-               append_end_block_semi_nl_nl(&ctx);
-       }
-
-       /* Stream classes and their event classes */
-       for (i = 0; i < tc->stream_classes->len; i++) {
-               append_stream_class(&ctx, tc->stream_classes->pdata[i]);
-       }
-}
diff --git a/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.h b/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.h
deleted file mode 100644 (file)
index 4ed0262..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_CTF_IR_TO_TSDL_H
-#define BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_CTF_IR_TO_TSDL_H
-
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-
-#include "fs-sink-ctf-meta.h"
-
-BT_HIDDEN
-void translate_trace_class_ctf_ir_to_tsdl(struct fs_sink_ctf_trace_class *tc,
-               GString *tsdl);
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_CTF_IR_TO_TSDL_H */
diff --git a/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c b/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c
deleted file mode 100644 (file)
index d398f65..0000000
+++ /dev/null
@@ -1,1290 +0,0 @@
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRANSLATE-TRACE-IR-TO-CTF-IR"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-#include <glib.h>
-
-#include "fs-sink-ctf-meta.h"
-
-struct field_path_elem {
-       uint64_t index_in_parent;
-       GString *name;
-
-       /* Weak */
-       const bt_field_class *ir_fc;
-
-       /* Weak */
-       struct fs_sink_ctf_field_class *parent_fc;
-};
-
-struct ctx {
-       /* Weak */
-       struct fs_sink_ctf_stream_class *cur_sc;
-
-       /* Weak */
-       struct fs_sink_ctf_event_class *cur_ec;
-
-       bt_scope cur_scope;
-
-       /*
-        * Array of `struct field_path_elem` */
-       GArray *cur_path;
-};
-
-static inline
-struct field_path_elem *cur_path_stack_at(struct ctx *ctx, uint64_t i)
-{
-       BT_ASSERT(i < ctx->cur_path->len);
-       return &g_array_index(ctx->cur_path, struct field_path_elem, i);
-}
-
-static inline
-struct field_path_elem *cur_path_stack_top(struct ctx *ctx)
-{
-       BT_ASSERT(ctx->cur_path->len > 0);
-       return cur_path_stack_at(ctx, ctx->cur_path->len - 1);
-}
-
-static inline
-bool is_reserved_member_name(const char *name, const char *reserved_name)
-{
-       bool is_reserved = false;
-
-       if (strcmp(name, reserved_name) == 0) {
-               is_reserved = true;
-               goto end;
-       }
-
-       if (name[0] == '_' && strcmp(&name[1], reserved_name) == 0) {
-               is_reserved = true;
-               goto end;
-       }
-
-end:
-       return is_reserved;
-}
-
-static inline
-int cur_path_stack_push(struct ctx *ctx,
-               uint64_t index_in_parent, const char *ir_name,
-               const bt_field_class *ir_fc,
-               struct fs_sink_ctf_field_class *parent_fc)
-{
-       int ret = 0;
-       struct field_path_elem *field_path_elem;
-
-       g_array_set_size(ctx->cur_path, ctx->cur_path->len + 1);
-       field_path_elem = cur_path_stack_top(ctx);
-       field_path_elem->index_in_parent = index_in_parent;
-       field_path_elem->name = g_string_new(ir_name);
-
-       if (ir_name) {
-               if (ctx->cur_scope == BT_SCOPE_PACKET_CONTEXT) {
-                       if (is_reserved_member_name(ir_name, "packet_size") ||
-                                       is_reserved_member_name(ir_name, "content_size") ||
-                                       is_reserved_member_name(ir_name, "timestamp_begin") ||
-                                       is_reserved_member_name(ir_name, "timestamp_end") ||
-                                       is_reserved_member_name(ir_name, "events_discarded") ||
-                                       is_reserved_member_name(ir_name, "packet_seq_num")) {
-                               BT_LOGE("Unsupported reserved TSDL structure field class member "
-                                       "or variant field class option name: name=\"%s\"",
-                                       ir_name);
-                               ret = -1;
-                               goto end;
-                       }
-               }
-
-               ret = fs_sink_ctf_protect_name(field_path_elem->name);
-               if (ret) {
-                       BT_LOGE("Unsupported non-TSDL structure field class member "
-                               "or variant field class option name: name=\"%s\"",
-                               ir_name);
-                       goto end;
-               }
-       }
-
-       field_path_elem->ir_fc = ir_fc;
-       field_path_elem->parent_fc = parent_fc;
-
-end:
-       return ret;
-}
-
-static inline
-void cur_path_stack_pop(struct ctx *ctx)
-{
-       struct field_path_elem *field_path_elem;
-
-       BT_ASSERT(ctx->cur_path->len > 0);
-       field_path_elem = cur_path_stack_top(ctx);
-
-       if (field_path_elem->name) {
-               g_string_free(field_path_elem->name, TRUE);
-               field_path_elem->name = NULL;
-       }
-
-       g_array_set_size(ctx->cur_path, ctx->cur_path->len - 1);
-}
-
-/*
- * Creates a relative field ref (a single name) from IR field path
- * `tgt_ir_field_path`.
- *
- * This function tries to locate the target field class recursively from
- * the top to the bottom of the context's current path using only the
- * target field class's own name. This is because many CTF reading tools
- * do not support a relative field ref with more than one element, for
- * example `prev_struct.len`.
- *
- * Returns a negative value if this resolving operation failed.
- */
-static
-int create_relative_field_ref(struct ctx *ctx,
-               const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
-{
-       int ret = 0;
-       struct fs_sink_ctf_field_class *tgt_fc = NULL;
-       uint64_t i;
-       int64_t si;
-       const char *tgt_fc_name = NULL;
-       struct field_path_elem *field_path_elem;
-
-       /* Get target field class's name */
-       switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
-       case BT_SCOPE_PACKET_CONTEXT:
-               BT_ASSERT(ctx->cur_sc);
-               tgt_fc = ctx->cur_sc->packet_context_fc;
-               break;
-       case BT_SCOPE_EVENT_COMMON_CONTEXT:
-               BT_ASSERT(ctx->cur_sc);
-               tgt_fc = ctx->cur_sc->event_common_context_fc;
-               break;
-       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               BT_ASSERT(ctx->cur_ec);
-               tgt_fc = ctx->cur_ec->spec_context_fc;
-               break;
-       case BT_SCOPE_EVENT_PAYLOAD:
-               BT_ASSERT(ctx->cur_ec);
-               tgt_fc = ctx->cur_ec->payload_fc;
-               break;
-       default:
-               abort();
-       }
-
-       i = 0;
-
-       while (i < bt_field_path_get_item_count(tgt_ir_field_path)) {
-               const bt_field_path_item *fp_item =
-                       bt_field_path_borrow_item_by_index_const(
-                               tgt_ir_field_path, i);
-               struct fs_sink_ctf_named_field_class *named_fc = NULL;
-
-               BT_ASSERT(tgt_fc);
-               BT_ASSERT(fp_item);
-
-               switch (tgt_fc->type) {
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
-                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
-                       named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                               (void *) tgt_fc,
-                               bt_field_path_item_index_get_index(fp_item));
-                       break;
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
-                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
-                       named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
-                               (void *) tgt_fc,
-                               bt_field_path_item_index_get_index(fp_item));
-                       break;
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
-               {
-                       struct fs_sink_ctf_field_class_array_base *array_base_fc =
-                               (void *) tgt_fc;
-
-                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
-                               BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
-                       tgt_fc = array_base_fc->elem_fc;
-                       break;
-               }
-               default:
-                       abort();
-               }
-
-               if (named_fc) {
-                       tgt_fc = named_fc->fc;
-                       tgt_fc_name = named_fc->name->str;
-                       i++;
-               }
-       }
-
-       BT_ASSERT(tgt_fc);
-       BT_ASSERT(tgt_fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_INT);
-       BT_ASSERT(tgt_fc_name);
-
-       /* Find target field class having this name in current context */
-       for (si = ctx->cur_path->len - 1; si >= 0; si--) {
-               struct fs_sink_ctf_field_class *fc;
-               struct fs_sink_ctf_field_class_struct *struct_fc;
-               struct fs_sink_ctf_field_class_variant *var_fc;
-               struct fs_sink_ctf_named_field_class *named_fc;
-               uint64_t len;
-
-               field_path_elem = cur_path_stack_at(ctx, (uint64_t) si);
-               fc = field_path_elem->parent_fc;
-               if (!fc) {
-                       /* Reached stack's bottom */
-                       ret = -1;
-                       goto end;
-               }
-
-               switch (fc->type) {
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-                       break;
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
-                       continue;
-               default:
-                       /* Not supported by TSDL 1.8 */
-                       ret = -1;
-                       goto end;
-               }
-
-               if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
-                       struct_fc = (void *) fc;
-                       len = struct_fc->members->len;
-               } else {
-                       var_fc = (void *) fc;
-                       len = var_fc->options->len;
-               }
-
-               for (i = 0; i < len; i++) {
-                       if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
-                               named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-                       } else {
-                               named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-                       }
-
-                       if (strcmp(named_fc->name->str, tgt_fc_name) == 0) {
-                               if (named_fc->fc == tgt_fc) {
-                                       g_string_assign(tgt_field_ref,
-                                               tgt_fc_name);
-                               } else {
-                                       /*
-                                        * Using only the target field
-                                        * class's name, we're not
-                                        * reaching the target field
-                                        * class. This is not supported
-                                        * by TSDL 1.8.
-                                        */
-                                       ret = -1;
-                               }
-
-                               goto end;
-                       }
-               }
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
- *
- * Returns a negative value if this resolving operation failed.
- */
-static
-int create_absolute_field_ref(struct ctx *ctx,
-               const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
-{
-       int ret = 0;
-       struct fs_sink_ctf_field_class *fc = NULL;
-       uint64_t i;
-
-       switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
-       case BT_SCOPE_PACKET_CONTEXT:
-               BT_ASSERT(ctx->cur_sc);
-               fc = ctx->cur_sc->packet_context_fc;
-               g_string_assign(tgt_field_ref, "stream.packet.context");
-               break;
-       case BT_SCOPE_EVENT_COMMON_CONTEXT:
-               BT_ASSERT(ctx->cur_sc);
-               fc = ctx->cur_sc->event_common_context_fc;
-               g_string_assign(tgt_field_ref, "stream.event.context");
-               break;
-       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               BT_ASSERT(ctx->cur_ec);
-               fc = ctx->cur_ec->spec_context_fc;
-               g_string_assign(tgt_field_ref, "event.context");
-               break;
-       case BT_SCOPE_EVENT_PAYLOAD:
-               BT_ASSERT(ctx->cur_ec);
-               fc = ctx->cur_ec->payload_fc;
-               g_string_assign(tgt_field_ref, "event.fields");
-               break;
-       default:
-               abort();
-       }
-
-       BT_ASSERT(fc);
-
-       for (i = 0; i < bt_field_path_get_item_count(tgt_ir_field_path); i++) {
-               const bt_field_path_item *fp_item =
-                       bt_field_path_borrow_item_by_index_const(
-                               tgt_ir_field_path, i);
-               struct fs_sink_ctf_named_field_class *named_fc = NULL;
-
-               if (bt_field_path_item_get_type(fp_item) !=
-                               BT_FIELD_PATH_ITEM_TYPE_INDEX) {
-                       /* Not supported by TSDL 1.8 */
-                       ret = -1;
-                       goto end;
-               }
-
-               switch (fc->type) {
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
-                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
-                       named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                               (void *) fc,
-                               bt_field_path_item_index_get_index(fp_item));
-                       break;
-               case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
-                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
-                       named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
-                               (void *) fc,
-                               bt_field_path_item_index_get_index(fp_item));
-                       break;
-               default:
-                       abort();
-               }
-
-               BT_ASSERT(named_fc);
-               g_string_append_c(tgt_field_ref, '.');
-               g_string_append(tgt_field_ref, named_fc->name->str);
-               fc = named_fc->fc;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Resolves a target field class located at `tgt_ir_field_path`, writing
- * the resolved field ref to `tgt_field_ref` and setting
- * `*create_before` according to whether or not the target field must be
- * created immediately before (in which case `tgt_field_ref` is
- * irrelevant).
- */
-static
-void resolve_field_class(struct ctx *ctx,
-               const bt_field_path *tgt_ir_field_path,
-               GString *tgt_field_ref, bool *create_before)
-{
-       int ret;
-       bt_scope tgt_scope;
-
-       *create_before = false;
-
-       if (!tgt_ir_field_path) {
-               *create_before = true;
-               goto end;
-       }
-
-       tgt_scope = bt_field_path_get_root_scope(tgt_ir_field_path);
-
-       if (tgt_scope == ctx->cur_scope) {
-               /*
-                * Try, in this order:
-                *
-                * 1. Use a relative path, using only the target field
-                *    class's name. This is what is the most commonly
-                *    supported by popular CTF reading tools.
-                *
-                * 2. Use an absolute path. This could fail if there's
-                *    an array field class from the current root's field
-                *    class to the target field class.
-                *
-                * 3. Create the target field class before the
-                *    requesting field class (fallback).
-                */
-               ret = create_relative_field_ref(ctx, tgt_ir_field_path,
-                       tgt_field_ref);
-               if (ret) {
-                       ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
-                               tgt_field_ref);
-                       if (ret) {
-                               *create_before = true;
-                               ret = 0;
-                               goto end;
-                       }
-               }
-       } else {
-               ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
-                       tgt_field_ref);
-
-               /* It must always work in previous scopes */
-               BT_ASSERT(ret == 0);
-       }
-
-end:
-       return;
-}
-
-static
-int translate_field_class(struct ctx *ctx);
-
-static inline
-void append_to_parent_field_class(struct ctx *ctx,
-               struct fs_sink_ctf_field_class *fc)
-{
-       struct fs_sink_ctf_field_class *parent_fc =
-               cur_path_stack_top(ctx)->parent_fc;
-
-       switch (parent_fc->type) {
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-               fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
-                       cur_path_stack_top(ctx)->name->str, fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-               fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
-                       cur_path_stack_top(ctx)->name->str, fc);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct fs_sink_ctf_field_class_array_base *array_base_fc =
-                       (void *) parent_fc;
-
-               BT_ASSERT(!array_base_fc->elem_fc);
-               array_base_fc->elem_fc = fc;
-               array_base_fc->base.alignment = fc->alignment;
-               break;
-       }
-       default:
-               abort();
-       }
-}
-
-static inline
-void update_parent_field_class_alignment(struct ctx *ctx,
-               unsigned int alignment)
-{
-       struct fs_sink_ctf_field_class *parent_fc =
-               cur_path_stack_top(ctx)->parent_fc;
-
-       switch (parent_fc->type) {
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-               fs_sink_ctf_field_class_struct_align_at_least(
-                       (void *) parent_fc, alignment);
-               break;
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct fs_sink_ctf_field_class_array_base *array_base_fc =
-                       (void *) parent_fc;
-
-               array_base_fc->base.alignment = alignment;
-               break;
-       }
-       default:
-               break;
-       }
-}
-
-static inline
-int translate_structure_field_class_members(struct ctx *ctx,
-               struct fs_sink_ctf_field_class_struct *struct_fc,
-               const bt_field_class *ir_fc)
-{
-       int ret = 0;
-       uint64_t i;
-
-       for (i = 0; i < bt_field_class_structure_get_member_count(ir_fc); i++) {
-               const bt_field_class_structure_member *member;
-               const char *name;
-               const bt_field_class *memb_ir_fc;
-
-               member =
-                       bt_field_class_structure_borrow_member_by_index_const(
-                               ir_fc, i);
-               name = bt_field_class_structure_member_get_name(member);
-               memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
-                       member);
-               ret = cur_path_stack_push(ctx, i, name, memb_ir_fc,
-                       (void *) struct_fc);
-               if (ret) {
-                       BT_LOGE("Cannot translate structure field class member: "
-                               "name=\"%s\"", name);
-                       goto end;
-               }
-
-               ret = translate_field_class(ctx);
-               if (ret) {
-                       BT_LOGE("Cannot translate structure field class member: "
-                               "name=\"%s\"", name);
-                       goto end;
-               }
-
-               cur_path_stack_pop(ctx);
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int translate_structure_field_class(struct ctx *ctx)
-{
-       int ret;
-       struct fs_sink_ctf_field_class_struct *fc =
-               fs_sink_ctf_field_class_struct_create_empty(
-                       cur_path_stack_top(ctx)->ir_fc,
-                       cur_path_stack_top(ctx)->index_in_parent);
-
-       BT_ASSERT(fc);
-       append_to_parent_field_class(ctx, (void *) fc);
-       ret = translate_structure_field_class_members(ctx, fc, fc->base.ir_fc);
-       if (ret) {
-               goto end;
-       }
-
-       update_parent_field_class_alignment(ctx, fc->base.alignment);
-
-end:
-       return ret;
-}
-
-static inline
-int translate_variant_field_class(struct ctx *ctx)
-{
-       int ret = 0;
-       uint64_t i;
-       struct fs_sink_ctf_field_class_variant *fc =
-               fs_sink_ctf_field_class_variant_create_empty(
-                       cur_path_stack_top(ctx)->ir_fc,
-                       cur_path_stack_top(ctx)->index_in_parent);
-
-       BT_ASSERT(fc);
-
-       /* Resolve tag field class before appending to parent */
-       resolve_field_class(ctx,
-               bt_field_class_variant_borrow_selector_field_path_const(
-                       fc->base.ir_fc), fc->tag_ref, &fc->tag_is_before);
-
-       append_to_parent_field_class(ctx, (void *) fc);
-
-       for (i = 0; i < bt_field_class_variant_get_option_count(fc->base.ir_fc);
-                       i++) {
-               const bt_field_class_variant_option *opt;
-               const char *name;
-               const bt_field_class *opt_ir_fc;
-
-               opt = bt_field_class_variant_borrow_option_by_index_const(
-                       fc->base.ir_fc, i);
-               name = bt_field_class_variant_option_get_name(opt);
-               opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
-                       opt);
-               ret = cur_path_stack_push(ctx, i, name, opt_ir_fc, (void *) fc);
-               if (ret) {
-                       BT_LOGE("Cannot translate variant field class option: "
-                               "name=\"%s\"", name);
-                       goto end;
-               }
-
-               ret = translate_field_class(ctx);
-               if (ret) {
-                       BT_LOGE("Cannot translate variant field class option: "
-                               "name=\"%s\"", name);
-                       goto end;
-               }
-
-               cur_path_stack_pop(ctx);
-       }
-
-end:
-       return ret;
-}
-
-static inline
-int translate_static_array_field_class(struct ctx *ctx)
-{
-       struct fs_sink_ctf_field_class_array *fc =
-               fs_sink_ctf_field_class_array_create_empty(
-                       cur_path_stack_top(ctx)->ir_fc,
-                       cur_path_stack_top(ctx)->index_in_parent);
-       const bt_field_class *elem_ir_fc =
-               bt_field_class_array_borrow_element_field_class_const(
-                       fc->base.base.ir_fc);
-       int ret;
-
-       BT_ASSERT(fc);
-       append_to_parent_field_class(ctx, (void *) fc);
-       ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
-               (void *) fc);
-       if (ret) {
-               BT_LOGE_STR("Cannot translate static array field class element.");
-               goto end;
-       }
-
-       ret = translate_field_class(ctx);
-       if (ret) {
-               BT_LOGE_STR("Cannot translate static array field class element.");
-               goto end;
-       }
-
-       cur_path_stack_pop(ctx);
-       update_parent_field_class_alignment(ctx, fc->base.base.alignment);
-
-end:
-       return ret;
-}
-
-static inline
-int translate_dynamic_array_field_class(struct ctx *ctx)
-{
-       struct fs_sink_ctf_field_class_sequence *fc =
-               fs_sink_ctf_field_class_sequence_create_empty(
-                       cur_path_stack_top(ctx)->ir_fc,
-                       cur_path_stack_top(ctx)->index_in_parent);
-       const bt_field_class *elem_ir_fc =
-               bt_field_class_array_borrow_element_field_class_const(
-                       fc->base.base.ir_fc);
-       int ret;
-
-       BT_ASSERT(fc);
-
-       /* Resolve length field class before appending to parent */
-       resolve_field_class(ctx,
-               bt_field_class_dynamic_array_borrow_length_field_path_const(
-                       fc->base.base.ir_fc),
-               fc->length_ref, &fc->length_is_before);
-
-       append_to_parent_field_class(ctx, (void *) fc);
-       ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
-               (void *) fc);
-       if (ret) {
-               BT_LOGE_STR("Cannot translate dynamic array field class element.");
-               goto end;
-       }
-
-       ret = translate_field_class(ctx);
-       if (ret) {
-               BT_LOGE_STR("Cannot translate dynamic array field class element.");
-               goto end;
-       }
-
-       cur_path_stack_pop(ctx);
-       update_parent_field_class_alignment(ctx, fc->base.base.alignment);
-
-end:
-       return ret;
-}
-
-static inline
-int translate_integer_field_class(struct ctx *ctx)
-{
-       struct fs_sink_ctf_field_class_int *fc =
-               fs_sink_ctf_field_class_int_create(
-                       cur_path_stack_top(ctx)->ir_fc,
-                       cur_path_stack_top(ctx)->index_in_parent);
-
-       BT_ASSERT(fc);
-       append_to_parent_field_class(ctx, (void *) fc);
-       return 0;
-}
-
-static inline
-int translate_real_field_class(struct ctx *ctx)
-{
-       struct fs_sink_ctf_field_class_float *fc =
-               fs_sink_ctf_field_class_float_create(
-                       cur_path_stack_top(ctx)->ir_fc,
-                       cur_path_stack_top(ctx)->index_in_parent);
-
-       BT_ASSERT(fc);
-       append_to_parent_field_class(ctx, (void *) fc);
-       return 0;
-}
-
-static inline
-int translate_string_field_class(struct ctx *ctx)
-{
-       struct fs_sink_ctf_field_class_string *fc =
-               fs_sink_ctf_field_class_string_create(
-                       cur_path_stack_top(ctx)->ir_fc,
-                       cur_path_stack_top(ctx)->index_in_parent);
-
-       BT_ASSERT(fc);
-       append_to_parent_field_class(ctx, (void *) fc);
-       return 0;
-}
-
-/*
- * Translates a field class, recursively.
- *
- * The field class's IR field class, parent field class, and index
- * within its parent are in the context's current path's top element
- * (cur_path_stack_top()).
- */
-static
-int translate_field_class(struct ctx *ctx)
-{
-       int ret;
-
-       switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
-       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-               ret = translate_integer_field_class(ctx);
-               break;
-       case BT_FIELD_CLASS_TYPE_REAL:
-               ret = translate_real_field_class(ctx);
-               break;
-       case BT_FIELD_CLASS_TYPE_STRING:
-               ret = translate_string_field_class(ctx);
-               break;
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-               ret = translate_structure_field_class(ctx);
-               break;
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-               ret = translate_static_array_field_class(ctx);
-               break;
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-               ret = translate_dynamic_array_field_class(ctx);
-               break;
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-               ret = translate_variant_field_class(ctx);
-               break;
-       default:
-               abort();
-       }
-
-       return ret;
-}
-
-static
-int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
-               struct fs_sink_ctf_field_class *parent_fc)
-{
-       int ret = 0;
-       GString *field_ref = NULL;
-       bool is_before;
-       const char *tgt_type;
-       struct fs_sink_ctf_field_class_struct *parent_struct_fc =
-               (void *) parent_fc;
-       uint64_t i;
-       unsigned int suffix = 0;
-
-       if (!fc_name || !parent_fc ||
-                       parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
-               /* Not supported */
-               ret = -1;
-               goto end;
-       }
-
-       switch (fc->type) {
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
-
-               field_ref = seq_fc->length_ref;
-               is_before = seq_fc->length_is_before;
-               tgt_type = "len";
-               break;
-       }
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
-
-               field_ref = var_fc->tag_ref;
-               is_before = var_fc->tag_is_before;
-               tgt_type = "tag";
-               break;
-       }
-       default:
-               abort();
-       }
-
-       BT_ASSERT(field_ref);
-
-       if (!is_before) {
-               goto end;
-       }
-
-       /* Initial field ref */
-       g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
-
-       /*
-        * Make sure field ref does not clash with an existing field
-        * class name within the same parent structure field class.
-        */
-       while (true) {
-               bool name_ok = true;
-
-               for (i = 0; i < parent_struct_fc->members->len; i++) {
-                       struct fs_sink_ctf_named_field_class *named_fc =
-                               fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                                       parent_struct_fc, i);
-
-                       if (strcmp(field_ref->str, named_fc->name->str) == 0) {
-                               /* Name clash */
-                               name_ok = false;
-                               break;
-                       }
-               }
-
-               if (name_ok) {
-                       /* No clash: we're done */
-                       break;
-               }
-
-               /* Append suffix and try again */
-               g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
-                       suffix);
-               suffix++;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * This function recursively sets field refs of sequence and variant
- * field classes when they are immediately before, avoiding name clashes
- * with existing field class names.
- *
- * It can fail at this point if, for example, a sequence field class of
- * which to set the length's field ref has something else than a
- * structure field class as its parent: in this case, there's no
- * location to place the length field class immediately before the
- * sequence field class.
- */
-static
-int set_field_refs(struct fs_sink_ctf_field_class * const fc,
-               const char *fc_name, struct fs_sink_ctf_field_class *parent_fc)
-{
-       int ret = 0;
-       enum fs_sink_ctf_field_class_type fc_type;
-       BT_ASSERT(fc);
-
-       fc_type = fc->type;
-
-       switch (fc_type) {
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
-       {
-               uint64_t i;
-               uint64_t len;
-               struct fs_sink_ctf_field_class_struct *struct_fc;
-               struct fs_sink_ctf_field_class_variant *var_fc = NULL;
-               struct fs_sink_ctf_named_field_class *named_fc;
-
-               if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
-                       struct_fc = (void *) fc;
-                       len = struct_fc->members->len;
-               } else {
-                       var_fc = (void *) fc;
-                       len = var_fc->options->len;
-                       ret = set_field_ref(fc, fc_name, parent_fc);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               for (i = 0; i < len; i++) {
-                       if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
-                               named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
-                                       struct_fc, i);
-                       } else {
-                               named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
-                                       var_fc, i);
-                       }
-
-                       ret = set_field_refs(named_fc->fc, named_fc->name->str,
-                               fc);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               break;
-       }
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
-       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
-       {
-               struct fs_sink_ctf_field_class_array_base *array_base_fc =
-                       (void *) fc;
-
-               if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
-                       ret = set_field_ref(fc, fc_name, parent_fc);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
-               if (ret) {
-                       goto end;
-               }
-
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * This function translates a root scope trace IR field class to
- * a CTF IR field class.
- *
- * The resulting CTF IR field class is written to `*fc` so that it
- * exists as the parent object's (stream class or event class) true root
- * field class during the recursive translation for resolving purposes.
- * This is also why this function creates the empty structure field
- * class and then calls translate_structure_field_class_members() to
- * fill it.
- */
-static
-int translate_scope_field_class(struct ctx *ctx, bt_scope scope,
-               struct fs_sink_ctf_field_class **fc,
-               const bt_field_class *ir_fc)
-{
-       int ret = 0;
-
-       if (!ir_fc) {
-               goto end;
-       }
-
-       BT_ASSERT(bt_field_class_get_type(ir_fc) ==
-                       BT_FIELD_CLASS_TYPE_STRUCTURE);
-       BT_ASSERT(fc);
-       *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
-               ir_fc, UINT64_C(-1));
-       BT_ASSERT(*fc);
-       ctx->cur_scope = scope;
-       BT_ASSERT(ctx->cur_path->len == 0);
-       ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, ir_fc, NULL);
-       if (ret) {
-               BT_LOGE("Cannot translate scope structure field class: "
-                       "scope=%d", scope);
-               goto end;
-       }
-
-       ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
-       if (ret) {
-               BT_LOGE("Cannot translate scope structure field class: "
-                       "scope=%d", scope);
-               goto end;
-       }
-
-       cur_path_stack_pop(ctx);
-
-       /* Set field refs for preceding targets */
-       ret = set_field_refs(*fc, NULL, NULL);
-
-end:
-       return ret;
-}
-
-static inline
-void ctx_init(struct ctx *ctx)
-{
-       memset(ctx, 0, sizeof(struct ctx));
-       ctx->cur_path = g_array_new(FALSE, TRUE,
-               sizeof(struct field_path_elem));
-       BT_ASSERT(ctx->cur_path);
-}
-
-static inline
-void ctx_fini(struct ctx *ctx)
-{
-       if (ctx->cur_path) {
-               g_array_free(ctx->cur_path, TRUE);
-               ctx->cur_path = NULL;
-       }
-}
-
-static
-int translate_event_class(struct fs_sink_ctf_stream_class *sc,
-               const bt_event_class *ir_ec,
-               struct fs_sink_ctf_event_class **out_ec)
-{
-       int ret = 0;
-       struct ctx ctx;
-       struct fs_sink_ctf_event_class *ec;
-
-       BT_ASSERT(sc);
-       BT_ASSERT(ir_ec);
-
-       ctx_init(&ctx);
-       ec = fs_sink_ctf_event_class_create(sc, ir_ec);
-       BT_ASSERT(ec);
-       ctx.cur_sc = sc;
-       ctx.cur_ec = ec;
-       ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
-               &ec->spec_context_fc,
-               bt_event_class_borrow_specific_context_field_class_const(
-                       ir_ec));
-       if (ret) {
-               goto end;
-       }
-
-       ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_PAYLOAD,
-               &ec->payload_fc,
-               bt_event_class_borrow_payload_field_class_const(ir_ec));
-       if (ret) {
-               goto end;
-       }
-
-end:
-       ctx_fini(&ctx);
-       *out_ec = ec;
-       return ret;
-}
-
-BT_HIDDEN
-int try_translate_event_class_trace_ir_to_ctf_ir(
-               struct fs_sink_ctf_stream_class *sc,
-               const bt_event_class *ir_ec,
-               struct fs_sink_ctf_event_class **out_ec)
-{
-       int ret = 0;
-
-       BT_ASSERT(sc);
-       BT_ASSERT(ir_ec);
-
-       /* Check in hash table first */
-       *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
-       if (likely(*out_ec)) {
-               goto end;
-       }
-
-       ret = translate_event_class(sc, ir_ec, out_ec);
-
-end:
-       return ret;
-}
-
-bool default_clock_class_name_exists(struct fs_sink_ctf_trace_class *tc,
-               const char *name)
-{
-       bool exists = false;
-       uint64_t i;
-
-       for (i = 0; i < tc->stream_classes->len; i++) {
-               struct fs_sink_ctf_stream_class *sc =
-                       tc->stream_classes->pdata[i];
-
-               if (sc->default_clock_class_name->len == 0) {
-                       /* No default clock class */
-                       continue;
-               }
-
-               if (strcmp(sc->default_clock_class_name->str, name) == 0) {
-                       exists = true;
-                       goto end;
-               }
-       }
-
-end:
-       return exists;
-}
-
-static
-void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
-{
-       unsigned int suffix = 0;
-       char buf[16];
-
-       g_string_assign(sc->default_clock_class_name, "");
-       sprintf(buf, "default");
-
-       while (default_clock_class_name_exists(sc->tc, buf)) {
-               sprintf(buf, "default%u", suffix);
-               suffix++;
-       }
-
-       g_string_assign(sc->default_clock_class_name, buf);
-}
-
-static
-int translate_stream_class(struct fs_sink_ctf_trace_class *tc,
-               const bt_stream_class *ir_sc,
-               struct fs_sink_ctf_stream_class **out_sc)
-{
-       int ret = 0;
-       struct ctx ctx;
-
-       BT_ASSERT(tc);
-       BT_ASSERT(ir_sc);
-       ctx_init(&ctx);
-       *out_sc = fs_sink_ctf_stream_class_create(tc, ir_sc);
-       BT_ASSERT(*out_sc);
-
-       /* Set default clock class's protected name, if any */
-       if ((*out_sc)->default_clock_class) {
-               const char *name = bt_clock_class_get_name(
-                       (*out_sc)->default_clock_class);
-
-               if (name) {
-                       /* Try original name, protected */
-                       g_string_assign((*out_sc)->default_clock_class_name,
-                               name);
-                       ret = fs_sink_ctf_protect_name(
-                               (*out_sc)->default_clock_class_name);
-                       if (ret) {
-                               /* Invalid: create a new name */
-                               make_unique_default_clock_class_name(*out_sc);
-                               ret = 0;
-                       }
-               } else {
-                       /* No name: create a name */
-                       make_unique_default_clock_class_name(*out_sc);
-               }
-       }
-
-       ctx.cur_sc = *out_sc;
-       ret = translate_scope_field_class(&ctx, BT_SCOPE_PACKET_CONTEXT,
-               &(*out_sc)->packet_context_fc,
-               bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
-       if (ret) {
-               goto error;
-       }
-
-       if ((*out_sc)->packet_context_fc) {
-               /*
-                * Make sure the structure field class's alignment is
-                * enough: 8 is what we use for our own special members
-                * in the packet context.
-                */
-               fs_sink_ctf_field_class_struct_align_at_least(
-                       (void *) (*out_sc)->packet_context_fc, 8);
-       }
-
-       ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_COMMON_CONTEXT,
-               &(*out_sc)->event_common_context_fc,
-               bt_stream_class_borrow_event_common_context_field_class_const(
-                       ir_sc));
-       if (ret) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       fs_sink_ctf_stream_class_destroy(*out_sc);
-       *out_sc = NULL;
-
-end:
-       ctx_fini(&ctx);
-       return ret;
-}
-
-BT_HIDDEN
-int try_translate_stream_class_trace_ir_to_ctf_ir(
-               struct fs_sink_ctf_trace_class *tc,
-               const bt_stream_class *ir_sc,
-               struct fs_sink_ctf_stream_class **out_sc)
-{
-       int ret = 0;
-       uint64_t i;
-
-       BT_ASSERT(tc);
-       BT_ASSERT(ir_sc);
-
-       for (i = 0; i < tc->stream_classes->len; i++) {
-               *out_sc = tc->stream_classes->pdata[i];
-
-               if ((*out_sc)->ir_sc == ir_sc) {
-                       goto end;
-               }
-       }
-
-       ret = translate_stream_class(tc, ir_sc, out_sc);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct fs_sink_ctf_trace_class *translate_trace_class_trace_ir_to_ctf_ir(
-               const bt_trace_class *ir_tc)
-{
-       uint64_t count;
-       uint64_t i;
-       struct fs_sink_ctf_trace_class *tc = NULL;
-
-       /* Check that trace class's environment is TSDL-compatible */
-       count = bt_trace_class_get_environment_entry_count(ir_tc);
-       for (i = 0; i < count; i++) {
-               const char *name;
-               const bt_value *val;
-
-               bt_trace_class_borrow_environment_entry_by_index_const(
-                       ir_tc, i, &name, &val);
-
-               if (!fs_sink_ctf_ist_valid_identifier(name)) {
-                       BT_LOGE("Unsupported trace class's environment entry name: "
-                               "name=\"%s\"", name);
-                       goto end;
-               }
-
-               switch (bt_value_get_type(val)) {
-               case BT_VALUE_TYPE_SIGNED_INTEGER:
-               case BT_VALUE_TYPE_STRING:
-                       break;
-               default:
-                       BT_LOGE("Unsupported trace class's environment entry value type: "
-                               "type=%s",
-                               bt_common_value_type_string(
-                                       bt_value_get_type(val)));
-                       goto end;
-               }
-       }
-
-       tc = fs_sink_ctf_trace_class_create(ir_tc);
-       BT_ASSERT(tc);
-
-end:
-       return tc;
-}
diff --git a/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.h b/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.h
deleted file mode 100644 (file)
index 23cd5d9..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_TRACE_IR_TO_CTF_IR_H
-#define BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_TRACE_IR_TO_CTF_IR_H
-
-/*
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "fs-sink-ctf-meta.h"
-
-BT_HIDDEN
-int try_translate_event_class_trace_ir_to_ctf_ir(
-               struct fs_sink_ctf_stream_class *sc,
-               const bt_event_class *ir_ec,
-               struct fs_sink_ctf_event_class **out_ec);
-
-BT_HIDDEN
-int try_translate_stream_class_trace_ir_to_ctf_ir(
-               struct fs_sink_ctf_trace_class *tc,
-               const bt_stream_class *ir_sc,
-               struct fs_sink_ctf_stream_class **out_sc);
-
-BT_HIDDEN
-struct fs_sink_ctf_trace_class *translate_trace_class_trace_ir_to_ctf_ir(
-               const bt_trace_class *ir_tc);
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_TRACE_IR_TO_CTF_IR_H */
diff --git a/plugins/ctf/fs-src/Makefile.am b/plugins/ctf/fs-src/Makefile.am
deleted file mode 100644 (file)
index 012f4eb..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-ctf-fs-src.la
-
-libbabeltrace2_plugin_ctf_fs_src_la_SOURCES = \
-       data-stream-file.c \
-       data-stream-file.h \
-       file.c \
-       file.h \
-       fs.c \
-       fs.h \
-       lttng-index.h \
-       metadata.c \
-       metadata.h \
-       query.h \
-       query.c \
-       logging.h \
-       logging.c
diff --git a/plugins/ctf/fs-src/data-stream-file.c b/plugins/ctf/fs-src/data-stream-file.c
deleted file mode 100644 (file)
index 99d3b47..0000000
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <babeltrace2/compat/mman-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/common-internal.h>
-#include "file.h"
-#include "metadata.h"
-#include "../common/msg-iter/msg-iter.h"
-#include <babeltrace2/assert-internal.h>
-#include "data-stream-file.h"
-#include <string.h>
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-SRC-DS"
-#include "logging.h"
-
-static inline
-size_t remaining_mmap_bytes(struct ctf_fs_ds_file *ds_file)
-{
-       return ds_file->mmap_len - ds_file->request_offset;
-}
-
-static
-int ds_file_munmap(struct ctf_fs_ds_file *ds_file)
-{
-       int ret = 0;
-
-       if (!ds_file || !ds_file->mmap_addr) {
-               goto end;
-       }
-
-       if (bt_munmap(ds_file->mmap_addr, ds_file->mmap_len)) {
-               BT_LOGE_ERRNO("Cannot memory-unmap file",
-                       ": address=%p, size=%zu, file_path=\"%s\", file=%p",
-                       ds_file->mmap_addr, ds_file->mmap_len,
-                       ds_file->file ? ds_file->file->path->str : "NULL",
-                       ds_file->file ? ds_file->file->fp : NULL);
-               ret = -1;
-               goto end;
-       }
-
-       ds_file->mmap_addr = NULL;
-
-end:
-       return ret;
-}
-
-static
-enum bt_msg_iter_medium_status ds_file_mmap_next(
-               struct ctf_fs_ds_file *ds_file)
-{
-       enum bt_msg_iter_medium_status ret =
-                       BT_MSG_ITER_MEDIUM_STATUS_OK;
-
-       /* Unmap old region */
-       if (ds_file->mmap_addr) {
-               if (ds_file_munmap(ds_file)) {
-                       goto error;
-               }
-
-               /*
-                * mmap_len is guaranteed to be page-aligned except on the
-                * last mapping where it may not be possible (since the file's
-                * size itself may not be a page multiple).
-                */
-               ds_file->mmap_offset += ds_file->mmap_len;
-               ds_file->request_offset = 0;
-       }
-
-       ds_file->mmap_len = MIN(ds_file->file->size - ds_file->mmap_offset,
-                       ds_file->mmap_max_len);
-       if (ds_file->mmap_len == 0) {
-               ret = BT_MSG_ITER_MEDIUM_STATUS_EOF;
-               goto end;
-       }
-       /* Map new region */
-       BT_ASSERT(ds_file->mmap_len);
-       ds_file->mmap_addr = bt_mmap((void *) 0, ds_file->mmap_len,
-                       PROT_READ, MAP_PRIVATE, fileno(ds_file->file->fp),
-                       ds_file->mmap_offset);
-       if (ds_file->mmap_addr == MAP_FAILED) {
-               BT_LOGE("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %jd: %s",
-                               ds_file->mmap_len, ds_file->file->path->str,
-                               ds_file->file->fp, (intmax_t) ds_file->mmap_offset,
-                               strerror(errno));
-               goto error;
-       }
-
-       goto end;
-error:
-       ds_file_munmap(ds_file);
-       ret = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
-end:
-       return ret;
-}
-
-static
-enum bt_msg_iter_medium_status medop_request_bytes(
-               size_t request_sz, uint8_t **buffer_addr,
-               size_t *buffer_sz, void *data)
-{
-       enum bt_msg_iter_medium_status status =
-               BT_MSG_ITER_MEDIUM_STATUS_OK;
-       struct ctf_fs_ds_file *ds_file = data;
-
-       if (request_sz == 0) {
-               goto end;
-       }
-
-       /* Check if we have at least one memory-mapped byte left */
-       if (remaining_mmap_bytes(ds_file) == 0) {
-               /* Are we at the end of the file? */
-               if (ds_file->mmap_offset >= ds_file->file->size) {
-                       BT_LOGD("Reached end of file \"%s\" (%p)",
-                               ds_file->file->path->str, ds_file->file->fp);
-                       status = BT_MSG_ITER_MEDIUM_STATUS_EOF;
-                       goto end;
-               }
-
-               status = ds_file_mmap_next(ds_file);
-               switch (status) {
-               case BT_MSG_ITER_MEDIUM_STATUS_OK:
-                       break;
-               case BT_MSG_ITER_MEDIUM_STATUS_EOF:
-                       goto end;
-               default:
-                       BT_LOGE("Cannot memory-map next region of file \"%s\" (%p)",
-                                       ds_file->file->path->str,
-                                       ds_file->file->fp);
-                       goto error;
-               }
-       }
-
-       *buffer_sz = MIN(remaining_mmap_bytes(ds_file), request_sz);
-       *buffer_addr = ((uint8_t *) ds_file->mmap_addr) + ds_file->request_offset;
-       ds_file->request_offset += *buffer_sz;
-       goto end;
-
-error:
-       status = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
-
-end:
-       return status;
-}
-
-static
-bt_stream *medop_borrow_stream(bt_stream_class *stream_class, int64_t stream_id,
-               void *data)
-{
-       struct ctf_fs_ds_file *ds_file = data;
-       bt_stream_class *ds_file_stream_class;
-       bt_stream *stream = NULL;
-
-       ds_file_stream_class = bt_stream_borrow_class(
-               ds_file->stream);
-
-       if (stream_class != ds_file_stream_class) {
-               /*
-                * Not supported: two packets described by two different
-                * stream classes within the same data stream file.
-                */
-               goto end;
-       }
-
-       stream = ds_file->stream;
-
-end:
-       return stream;
-}
-
-static
-enum bt_msg_iter_medium_status medop_seek(enum bt_msg_iter_seek_whence whence,
-               off_t offset, void *data)
-{
-       enum bt_msg_iter_medium_status ret =
-                       BT_MSG_ITER_MEDIUM_STATUS_OK;
-       struct ctf_fs_ds_file *ds_file = data;
-       off_t file_size = ds_file->file->size;
-
-       if (whence != BT_MSG_ITER_SEEK_WHENCE_SET ||
-               offset < 0 || offset > file_size) {
-               BT_LOGE("Invalid medium seek request: whence=%d, offset=%jd, "
-                               "file-size=%jd", (int) whence, offset,
-                               file_size);
-               ret = BT_MSG_ITER_MEDIUM_STATUS_INVAL;
-               goto end;
-       }
-
-       /*
-        * Determine whether or not the destination is contained within the
-        * current mapping.
-        */
-       if (ds_file->mmap_addr && (offset < ds_file->mmap_offset ||
-                       offset >= ds_file->mmap_offset + ds_file->mmap_len)) {
-               int unmap_ret;
-               off_t offset_in_mapping = offset % bt_common_get_page_size();
-
-               BT_LOGD("Medium seek request cannot be accomodated by the current "
-                               "file mapping: offset=%jd, mmap-offset=%jd, "
-                               "mmap-len=%zu", offset, ds_file->mmap_offset,
-                               ds_file->mmap_len);
-               unmap_ret = ds_file_munmap(ds_file);
-               if (unmap_ret) {
-                       ret = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
-                       goto end;
-               }
-
-               ds_file->mmap_offset = offset - offset_in_mapping;
-               ds_file->request_offset = offset_in_mapping;
-               ret = ds_file_mmap_next(ds_file);
-               if (ret != BT_MSG_ITER_MEDIUM_STATUS_OK) {
-                       goto end;
-               }
-       } else {
-               ds_file->request_offset = offset - ds_file->mmap_offset;
-       }
-
-       ds_file->end_reached = (offset == file_size);
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_msg_iter_medium_ops ctf_fs_ds_file_medops = {
-       .request_bytes = medop_request_bytes,
-       .borrow_stream = medop_borrow_stream,
-       .seek = medop_seek,
-};
-
-static
-int convert_cycles_to_ns(struct ctf_clock_class *clock_class,
-               uint64_t cycles, int64_t *ns)
-{
-       return bt_util_clock_cycles_to_ns_from_origin(cycles,
-                       clock_class->frequency, clock_class->offset_seconds,
-                       clock_class->offset_cycles, ns);
-}
-
-static
-struct ctf_fs_ds_index *build_index_from_idx_file(
-               struct ctf_fs_ds_file *ds_file)
-{
-       int ret;
-       gchar *directory = NULL;
-       gchar *basename = NULL;
-       GString *index_basename = NULL;
-       gchar *index_file_path = NULL;
-       GMappedFile *mapped_file = NULL;
-       gsize filesize;
-       const char *mmap_begin = NULL, *file_pos = NULL;
-       const struct ctf_packet_index_file_hdr *header = NULL;
-       struct ctf_fs_ds_index *index = NULL;
-       struct ctf_fs_ds_index_entry *index_entry = NULL;
-       uint64_t total_packets_size = 0;
-       size_t file_index_entry_size;
-       size_t file_entry_count;
-       size_t i;
-       struct ctf_stream_class *sc;
-       struct bt_msg_iter_packet_properties props;
-
-       BT_LOGD("Building index from .idx file of stream file %s",
-                       ds_file->file->path->str);
-       ret = bt_msg_iter_get_packet_properties(ds_file->msg_iter, &props);
-       if (ret) {
-               BT_LOGD_STR("Cannot read first packet's header and context fields.");
-               goto error;
-       }
-
-       sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
-               props.stream_class_id);
-       BT_ASSERT(sc);
-       if (!sc->default_clock_class) {
-               BT_LOGD_STR("Cannot find stream class's default clock class.");
-               goto error;
-       }
-
-       /* Look for index file in relative path index/name.idx. */
-       basename = g_path_get_basename(ds_file->file->path->str);
-       if (!basename) {
-               BT_LOGE("Cannot get the basename of datastream file %s",
-                               ds_file->file->path->str);
-               goto error;
-       }
-
-       directory = g_path_get_dirname(ds_file->file->path->str);
-       if (!directory) {
-               BT_LOGE("Cannot get dirname of datastream file %s",
-                               ds_file->file->path->str);
-               goto error;
-       }
-
-       index_basename = g_string_new(basename);
-       if (!index_basename) {
-               BT_LOGE_STR("Cannot allocate index file basename string");
-               goto error;
-       }
-
-       g_string_append(index_basename, ".idx");
-       index_file_path = g_build_filename(directory, "index",
-                       index_basename->str, NULL);
-       mapped_file = g_mapped_file_new(index_file_path, FALSE, NULL);
-       if (!mapped_file) {
-               BT_LOGD("Cannot create new mapped file %s",
-                               index_file_path);
-               goto error;
-       }
-
-       /*
-        * The g_mapped_file API limits us to 4GB files on 32-bit.
-        * Traces with such large indexes have never been seen in the wild,
-        * but this would need to be adjusted to support them.
-        */
-       filesize = g_mapped_file_get_length(mapped_file);
-       if (filesize < sizeof(*header)) {
-               BT_LOGW("Invalid LTTng trace index file: "
-                       "file size (%zu bytes) < header size (%zu bytes)",
-                       filesize, sizeof(*header));
-               goto error;
-       }
-
-       mmap_begin = g_mapped_file_get_contents(mapped_file);
-       header = (struct ctf_packet_index_file_hdr *) mmap_begin;
-
-       file_pos = g_mapped_file_get_contents(mapped_file) + sizeof(*header);
-       if (be32toh(header->magic) != CTF_INDEX_MAGIC) {
-               BT_LOGW_STR("Invalid LTTng trace index: \"magic\" field validation failed");
-               goto error;
-       }
-
-       file_index_entry_size = be32toh(header->packet_index_len);
-       file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size;
-       if ((filesize - sizeof(*header)) % file_index_entry_size) {
-               BT_LOGW("Invalid LTTng trace index: the index's size after the header "
-                       "(%zu bytes) is not a multiple of the index entry size "
-                       "(%zu bytes)", (filesize - sizeof(*header)),
-                       sizeof(*header));
-               goto error;
-       }
-
-       index = ctf_fs_ds_index_create();
-       if (!index) {
-               goto error;
-       }
-
-       for (i = 0; i < file_entry_count; i++) {
-               struct ctf_packet_index *file_index =
-                               (struct ctf_packet_index *) file_pos;
-               uint64_t packet_size = be64toh(file_index->packet_size);
-
-               if (packet_size % CHAR_BIT) {
-                       BT_LOGW("Invalid packet size encountered in LTTng trace index file");
-                       goto error;
-               }
-
-               index_entry = g_new0(struct ctf_fs_ds_index_entry, 1);
-               if (!index_entry) {
-                       goto error;
-               }
-
-               /* Convert size in bits to bytes. */
-               packet_size /= CHAR_BIT;
-               index_entry->packet_size = packet_size;
-
-               index_entry->offset = be64toh(file_index->offset);
-               if (i != 0 && index_entry->offset < (index_entry - 1)->offset) {
-                       BT_LOGW("Invalid, non-monotonic, packet offset encountered in LTTng trace index file: "
-                               "previous offset=%" PRIu64 ", current offset=%" PRIu64,
-                               (index_entry - 1)->offset, index_entry->offset);
-                       goto error;
-               }
-
-               index_entry->timestamp_begin = be64toh(file_index->timestamp_begin);
-               index_entry->timestamp_end = be64toh(file_index->timestamp_end);
-               if (index_entry->timestamp_end < index_entry->timestamp_begin) {
-                       BT_LOGW("Invalid packet time bounds encountered in LTTng trace index file (begin > end): "
-                               "timestamp_begin=%" PRIu64 "timestamp_end=%" PRIu64,
-                               index_entry->timestamp_begin,
-                               index_entry->timestamp_end);
-                       goto error;
-               }
-
-               /* Convert the packet's bound to nanoseconds since Epoch. */
-               ret = convert_cycles_to_ns(sc->default_clock_class,
-                               index_entry->timestamp_begin,
-                               &index_entry->timestamp_begin_ns);
-               if (ret) {
-                       BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch during index parsing");
-                       goto error;
-               }
-               ret = convert_cycles_to_ns(sc->default_clock_class,
-                               index_entry->timestamp_end,
-                               &index_entry->timestamp_end_ns);
-               if (ret) {
-                       BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch during LTTng trace index parsing");
-                       goto error;
-               }
-
-               total_packets_size += packet_size;
-               file_pos += file_index_entry_size;
-
-               g_ptr_array_add(index->entries, index_entry);
-       }
-
-       /* Validate that the index addresses the complete stream. */
-       if (ds_file->file->size != total_packets_size) {
-               BT_LOGW("Invalid LTTng trace index file; indexed size != stream file size: "
-                       "file-size=%" PRIu64 ", total-packets-size=%" PRIu64,
-                       ds_file->file->size, total_packets_size);
-               goto error;
-       }
-end:
-       g_free(directory);
-       g_free(basename);
-       g_free(index_file_path);
-       if (index_basename) {
-               g_string_free(index_basename, TRUE);
-       }
-       if (mapped_file) {
-               g_mapped_file_unref(mapped_file);
-       }
-       return index;
-error:
-       ctf_fs_ds_index_destroy(index);
-       g_free(index_entry);
-       index = NULL;
-       goto end;
-}
-
-static
-int init_index_entry(struct ctf_fs_ds_index_entry *entry,
-               struct ctf_fs_ds_file *ds_file,
-               struct bt_msg_iter_packet_properties *props,
-               off_t packet_size, off_t packet_offset)
-{
-       int ret = 0;
-       struct ctf_stream_class *sc;
-
-       sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
-               props->stream_class_id);
-       BT_ASSERT(sc);
-       BT_ASSERT(packet_offset >= 0);
-       entry->offset = packet_offset;
-       BT_ASSERT(packet_size >= 0);
-       entry->packet_size = packet_size;
-
-       if (props->snapshots.beginning_clock != UINT64_C(-1)) {
-               /* Convert the packet's bound to nanoseconds since Epoch. */
-               ret = convert_cycles_to_ns(sc->default_clock_class,
-                                          props->snapshots.beginning_clock,
-                                          &entry->timestamp_begin_ns);
-               if (ret) {
-                       BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
-                       goto end;
-               }
-       } else {
-               entry->timestamp_begin_ns = UINT64_C(-1);
-       }
-
-       if (props->snapshots.end_clock != UINT64_C(-1)) {
-               ret = convert_cycles_to_ns(sc->default_clock_class,
-                                          props->snapshots.end_clock,
-                                          &entry->timestamp_end_ns);
-               if (ret) {
-                       BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
-                       goto end;
-               }
-       } else {
-               entry->timestamp_end_ns = UINT64_C(-1);
-       }
-
-end:
-       return ret;
-}
-
-static
-struct ctf_fs_ds_index *build_index_from_stream_file(
-               struct ctf_fs_ds_file *ds_file)
-{
-       int ret;
-       struct ctf_fs_ds_index *index = NULL;
-       enum bt_msg_iter_status iter_status = BT_MSG_ITER_STATUS_OK;
-       off_t current_packet_offset_bytes = 0;
-
-       BT_LOGD("Indexing stream file %s", ds_file->file->path->str);
-
-       index = ctf_fs_ds_index_create();
-       if (!index) {
-               goto error;
-       }
-
-       do {
-               off_t current_packet_size_bytes;
-               struct ctf_fs_ds_index_entry *index_entry;
-               struct bt_msg_iter_packet_properties props;
-
-               if (current_packet_offset_bytes < 0) {
-                       BT_LOGE_STR("Cannot get the current packet's offset.");
-                       goto error;
-               } else if (current_packet_offset_bytes > ds_file->file->size) {
-                       BT_LOGE_STR("Unexpected current packet's offset (larger than file).");
-                       goto error;
-               } else if (current_packet_offset_bytes == ds_file->file->size) {
-                       /* No more data */
-                       break;
-               }
-
-               iter_status = bt_msg_iter_seek(ds_file->msg_iter,
-                               current_packet_offset_bytes);
-               if (iter_status != BT_MSG_ITER_STATUS_OK) {
-                       goto error;
-               }
-
-               iter_status = bt_msg_iter_get_packet_properties(
-                       ds_file->msg_iter, &props);
-               if (iter_status != BT_MSG_ITER_STATUS_OK) {
-                       goto error;
-               }
-
-               if (props.exp_packet_total_size >= 0) {
-                       current_packet_size_bytes =
-                               (uint64_t) props.exp_packet_total_size / 8;
-               } else {
-                       current_packet_size_bytes = ds_file->file->size;
-               }
-
-               if (current_packet_offset_bytes + current_packet_size_bytes >
-                               ds_file->file->size) {
-                       BT_LOGW("Invalid packet size reported in file: stream=\"%s\", "
-                                       "packet-offset=%jd, packet-size-bytes=%jd, "
-                                       "file-size=%jd",
-                                       ds_file->file->path->str,
-                                       current_packet_offset_bytes,
-                                       current_packet_size_bytes,
-                                       ds_file->file->size);
-                       goto error;
-               }
-
-               index_entry = g_new0(struct ctf_fs_ds_index_entry, 1);
-               if (!index_entry) {
-                       BT_LOGE_STR("Failed to allocate a new index entry.");
-                       goto error;
-               }
-
-               ret = init_index_entry(index_entry, ds_file, &props,
-                       current_packet_size_bytes, current_packet_offset_bytes);
-               if (ret) {
-                       g_free(index_entry);
-                       goto error;
-               }
-
-               g_ptr_array_add(index->entries, index_entry);
-
-               current_packet_offset_bytes += current_packet_size_bytes;
-               BT_LOGD("Seeking to next packet: current-packet-offset=%jd, "
-                       "next-packet-offset=%jd",
-                       current_packet_offset_bytes - current_packet_size_bytes,
-                       current_packet_offset_bytes);
-
-       } while (iter_status == BT_MSG_ITER_STATUS_OK);
-
-       if (iter_status != BT_MSG_ITER_STATUS_OK) {
-               goto error;
-       }
-
-end:
-       return index;
-
-error:
-       ctf_fs_ds_index_destroy(index);
-       index = NULL;
-       goto end;
-}
-
-BT_HIDDEN
-struct ctf_fs_ds_file *ctf_fs_ds_file_create(
-               struct ctf_fs_trace *ctf_fs_trace,
-               bt_self_message_iterator *pc_msg_iter,
-               struct bt_msg_iter *msg_iter,
-               bt_stream *stream, const char *path)
-{
-       int ret;
-       const size_t page_size = bt_common_get_page_size();
-       struct ctf_fs_ds_file *ds_file = g_new0(struct ctf_fs_ds_file, 1);
-
-       if (!ds_file) {
-               goto error;
-       }
-
-       ds_file->pc_msg_iter = pc_msg_iter;
-       ds_file->file = ctf_fs_file_create();
-       if (!ds_file->file) {
-               goto error;
-       }
-
-       ds_file->stream = stream;
-       bt_stream_get_ref(ds_file->stream);
-       ds_file->metadata = ctf_fs_trace->metadata;
-       g_string_assign(ds_file->file->path, path);
-       ret = ctf_fs_file_open(ds_file->file, "rb");
-       if (ret) {
-               goto error;
-       }
-
-       ds_file->msg_iter = msg_iter;
-       bt_msg_iter_set_medops_data(ds_file->msg_iter, ds_file);
-       if (!ds_file->msg_iter) {
-               goto error;
-       }
-
-       ds_file->mmap_max_len = page_size * 2048;
-
-       goto end;
-
-error:
-       /* Do not touch "borrowed" file. */
-       ctf_fs_ds_file_destroy(ds_file);
-       ds_file = NULL;
-
-end:
-       return ds_file;
-}
-
-BT_HIDDEN
-struct ctf_fs_ds_index *ctf_fs_ds_file_build_index(
-               struct ctf_fs_ds_file *ds_file)
-{
-       struct ctf_fs_ds_index *index;
-
-       index = build_index_from_idx_file(ds_file);
-       if (index) {
-               goto end;
-       }
-
-       BT_LOGD("Failed to build index from .index file; "
-               "falling back to stream indexing.");
-       index = build_index_from_stream_file(ds_file);
-end:
-       return index;
-}
-
-BT_HIDDEN
-struct ctf_fs_ds_index *ctf_fs_ds_index_create()
-{
-       struct ctf_fs_ds_index *index = g_new0(struct ctf_fs_ds_index, 1);
-
-       if (!index) {
-               BT_LOGE_STR("Failed to allocate index");
-               goto error;
-       }
-
-       index->entries = g_ptr_array_new_with_free_func((GDestroyNotify) g_free);
-       if (!index->entries) {
-               BT_LOGE("Failed to allocate index entries.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ctf_fs_ds_index_destroy(index);
-       index = NULL;
-end:
-       return index;
-}
-
-BT_HIDDEN
-void ctf_fs_ds_file_destroy(struct ctf_fs_ds_file *ds_file)
-{
-       if (!ds_file) {
-               return;
-       }
-
-       bt_stream_put_ref(ds_file->stream);
-       (void) ds_file_munmap(ds_file);
-
-       if (ds_file->file) {
-               ctf_fs_file_destroy(ds_file->file);
-       }
-
-       g_free(ds_file);
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status ctf_fs_ds_file_next(
-               struct ctf_fs_ds_file *ds_file,
-               bt_message **msg)
-{
-       enum bt_msg_iter_status msg_iter_status;
-       bt_self_message_iterator_status status;
-
-       msg_iter_status = bt_msg_iter_get_next_message(
-               ds_file->msg_iter, ds_file->pc_msg_iter, msg);
-
-       switch (msg_iter_status) {
-       case BT_MSG_ITER_STATUS_EOF:
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-               break;
-       case BT_MSG_ITER_STATUS_OK:
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-               break;
-       case BT_MSG_ITER_STATUS_AGAIN:
-               /*
-                * Should not make it this far as this is
-                * medium-specific; there is nothing for the user to do
-                * and it should have been handled upstream.
-                */
-               abort();
-       case BT_MSG_ITER_STATUS_INVAL:
-       case BT_MSG_ITER_STATUS_ERROR:
-       default:
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               break;
-       }
-       return status;
-}
-
-BT_HIDDEN
-void ctf_fs_ds_index_destroy(struct ctf_fs_ds_index *index)
-{
-       if (!index) {
-               return;
-       }
-
-       if (index->entries) {
-               g_ptr_array_free(index->entries, TRUE);
-       }
-       g_free(index);
-}
diff --git a/plugins/ctf/fs-src/data-stream-file.h b/plugins/ctf/fs-src/data-stream-file.h
deleted file mode 100644 (file)
index feeef67..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#ifndef CTF_FS_DS_FILE_H
-#define CTF_FS_DS_FILE_H
-
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "../common/msg-iter/msg-iter.h"
-#include "lttng-index.h"
-
-struct ctf_fs_component;
-struct ctf_fs_file;
-struct ctf_fs_trace;
-struct ctf_fs_ds_file;
-
-struct ctf_fs_ds_file_info {
-       /* Owned by this. */
-       GString *path;
-
-       /* Guaranteed to be set, as opposed to the index. */
-       int64_t begin_ns;
-};
-
-struct ctf_fs_metadata;
-
-struct ctf_fs_ds_file {
-       /* Weak */
-       struct ctf_fs_metadata *metadata;
-
-       /* Weak */
-       bt_self_message_iterator *pc_msg_iter;
-
-       /* Owned by this */
-       struct ctf_fs_file *file;
-
-       /* Owned by this */
-       bt_stream *stream;
-
-       /* Weak */
-       struct bt_msg_iter *msg_iter;
-
-       void *mmap_addr;
-
-       /*
-        * Max length of chunk to mmap() when updating the current mapping.
-        * This value must be page-aligned.
-        */
-       size_t mmap_max_len;
-
-       /* Length of the current mapping. Never exceeds the file's length. */
-       size_t mmap_len;
-
-       /* Offset in the file where the current mapping starts. */
-       off_t mmap_offset;
-
-       /*
-        * Offset, in the current mapping, of the address to return on the next
-        * request.
-        */
-       off_t request_offset;
-
-       bool end_reached;
-};
-
-BT_HIDDEN
-struct ctf_fs_ds_file *ctf_fs_ds_file_create(
-               struct ctf_fs_trace *ctf_fs_trace,
-               bt_self_message_iterator *pc_msg_iter,
-               struct bt_msg_iter *msg_iter,
-               bt_stream *stream, const char *path);
-
-BT_HIDDEN
-void ctf_fs_ds_file_destroy(struct ctf_fs_ds_file *stream);
-
-BT_HIDDEN
-bt_self_message_iterator_status ctf_fs_ds_file_next(
-               struct ctf_fs_ds_file *ds_file,
-               bt_message **msg);
-
-BT_HIDDEN
-struct ctf_fs_ds_index *ctf_fs_ds_file_build_index(
-               struct ctf_fs_ds_file *ds_file);
-
-BT_HIDDEN
-struct ctf_fs_ds_index *ctf_fs_ds_index_create();
-
-BT_HIDDEN
-void ctf_fs_ds_index_destroy(struct ctf_fs_ds_index *index);
-
-extern struct bt_msg_iter_medium_ops ctf_fs_ds_file_medops;
-
-#endif /* CTF_FS_DS_FILE_H */
diff --git a/plugins/ctf/fs-src/file.c b/plugins/ctf/fs-src/file.c
deleted file mode 100644 (file)
index 585faef..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <glib.h>
-#include "file.h"
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-FILE-SRC"
-#include "logging.h"
-
-BT_HIDDEN
-void ctf_fs_file_destroy(struct ctf_fs_file *file)
-{
-       if (!file) {
-               return;
-       }
-
-       if (file->fp) {
-               BT_LOGD("Closing file \"%s\" (%p)",
-                               file->path ? file->path->str : NULL, file->fp);
-
-               if (fclose(file->fp)) {
-                       BT_LOGE("Cannot close file \"%s\": %s",
-                                       file->path ? file->path->str : "NULL",
-                                       strerror(errno));
-               }
-       }
-
-       if (file->path) {
-               g_string_free(file->path, TRUE);
-       }
-
-       g_free(file);
-}
-
-BT_HIDDEN
-struct ctf_fs_file *ctf_fs_file_create(void)
-{
-       struct ctf_fs_file *file = g_new0(struct ctf_fs_file, 1);
-
-       if (!file) {
-               goto error;
-       }
-
-       file->path = g_string_new(NULL);
-       if (!file->path) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ctf_fs_file_destroy(file);
-       file = NULL;
-
-end:
-       return file;
-}
-
-BT_HIDDEN
-int ctf_fs_file_open(struct ctf_fs_file *file, const char *mode)
-{
-       int ret = 0;
-       struct stat stat;
-
-       BT_LOGD("Opening file \"%s\" with mode \"%s\"", file->path->str, mode);
-       file->fp = fopen(file->path->str, mode);
-       if (!file->fp) {
-               BT_LOGE("Cannot open file \"%s\" with mode \"%s\": %s",
-                       file->path->str, mode, strerror(errno));
-               goto error;
-       }
-
-       BT_LOGD("Opened file: %p", file->fp);
-
-       if (fstat(fileno(file->fp), &stat)) {
-               BT_LOGE("Cannot get file information: %s", strerror(errno));
-               goto error;
-       }
-
-       file->size = stat.st_size;
-       BT_LOGD("File is %jd bytes", (intmax_t) file->size);
-       goto end;
-
-error:
-       ret = -1;
-
-       if (file->fp) {
-               if (fclose(file->fp)) {
-                       BT_LOGE("Cannot close file \"%s\": %s", file->path->str,
-                               strerror(errno));
-               }
-       }
-
-end:
-       return ret;
-}
diff --git a/plugins/ctf/fs-src/file.h b/plugins/ctf/fs-src/file.h
deleted file mode 100644 (file)
index 4e578af..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef CTF_FS_FILE_H
-#define CTF_FS_FILE_H
-
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include "fs.h"
-
-BT_HIDDEN
-void ctf_fs_file_destroy(struct ctf_fs_file *file);
-
-BT_HIDDEN
-struct ctf_fs_file *ctf_fs_file_create(void);
-
-BT_HIDDEN
-int ctf_fs_file_open(struct ctf_fs_file *file, const char *mode);
-
-#endif /* CTF_FS_FILE_H */
diff --git a/plugins/ctf/fs-src/fs.c b/plugins/ctf/fs-src/fs.c
deleted file mode 100644 (file)
index 3cee435..0000000
+++ /dev/null
@@ -1,1964 +0,0 @@
-/*
- * fs.c
- *
- * Babeltrace CTF file system Reader Component
- *
- * Copyright 2015-2017 Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <plugins-common.h>
-#include <glib.h>
-#include <babeltrace2/assert-internal.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include "fs.h"
-#include "metadata.h"
-#include "data-stream-file.h"
-#include "file.h"
-#include "../common/metadata/decoder.h"
-#include "../common/msg-iter/msg-iter.h"
-#include "../common/utils/utils.h"
-#include "query.h"
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-SRC"
-#include "logging.h"
-
-static
-int msg_iter_data_set_current_ds_file(struct ctf_fs_msg_iter_data *msg_iter_data)
-{
-       struct ctf_fs_ds_file_info *ds_file_info;
-       int ret = 0;
-
-       BT_ASSERT(msg_iter_data->ds_file_info_index <
-               msg_iter_data->ds_file_group->ds_file_infos->len);
-       ds_file_info = g_ptr_array_index(
-               msg_iter_data->ds_file_group->ds_file_infos,
-               msg_iter_data->ds_file_info_index);
-
-       ctf_fs_ds_file_destroy(msg_iter_data->ds_file);
-       msg_iter_data->ds_file = ctf_fs_ds_file_create(
-               msg_iter_data->ds_file_group->ctf_fs_trace,
-               msg_iter_data->pc_msg_iter,
-               msg_iter_data->msg_iter,
-               msg_iter_data->ds_file_group->stream,
-               ds_file_info->path->str);
-       if (!msg_iter_data->ds_file) {
-               ret = -1;
-       }
-
-       return ret;
-}
-
-static
-void ctf_fs_msg_iter_data_destroy(
-               struct ctf_fs_msg_iter_data *msg_iter_data)
-{
-       if (!msg_iter_data) {
-               return;
-       }
-
-       ctf_fs_ds_file_destroy(msg_iter_data->ds_file);
-
-       if (msg_iter_data->msg_iter) {
-               bt_msg_iter_destroy(msg_iter_data->msg_iter);
-       }
-
-       g_free(msg_iter_data);
-}
-
-static
-void set_msg_iter_emits_stream_beginning_end_messages(
-               struct ctf_fs_msg_iter_data *msg_iter_data)
-{
-       bt_msg_iter_set_emit_stream_beginning_message(
-               msg_iter_data->ds_file->msg_iter,
-               msg_iter_data->ds_file_info_index == 0);
-       bt_msg_iter_set_emit_stream_end_message(
-               msg_iter_data->ds_file->msg_iter,
-               msg_iter_data->ds_file_info_index ==
-                       msg_iter_data->ds_file_group->ds_file_infos->len - 1);
-}
-
-static
-bt_self_message_iterator_status ctf_fs_iterator_next_one(
-               struct ctf_fs_msg_iter_data *msg_iter_data,
-               const bt_message **out_msg)
-{
-       bt_self_message_iterator_status status;
-
-       BT_ASSERT(msg_iter_data->ds_file);
-
-       while (true) {
-               bt_message *msg;
-
-               status = ctf_fs_ds_file_next(msg_iter_data->ds_file, &msg);
-               switch (status) {
-               case BT_SELF_MESSAGE_ITERATOR_STATUS_OK:
-                       *out_msg = msg;
-                       msg = NULL;
-                       goto end;
-               case BT_SELF_MESSAGE_ITERATOR_STATUS_END:
-               {
-                       int ret;
-
-                       if (msg_iter_data->ds_file_info_index ==
-                                       msg_iter_data->ds_file_group->ds_file_infos->len - 1) {
-                               /* End of all group's stream files */
-                               goto end;
-                       }
-
-                       msg_iter_data->ds_file_info_index++;
-                       bt_msg_iter_reset_for_next_stream_file(
-                               msg_iter_data->msg_iter);
-                       set_msg_iter_emits_stream_beginning_end_messages(
-                               msg_iter_data);
-
-                       /*
-                        * Open and start reading the next stream file
-                        * within our stream file group.
-                        */
-                       ret = msg_iter_data_set_current_ds_file(msg_iter_data);
-                       if (ret) {
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       /* Continue the loop to get the next message */
-                       break;
-               }
-               default:
-                       goto end;
-               }
-       }
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status ctf_fs_iterator_next(
-               bt_self_message_iterator *iterator,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       struct ctf_fs_msg_iter_data *msg_iter_data =
-               bt_self_message_iterator_get_data(iterator);
-       uint64_t i = 0;
-
-       while (i < capacity && status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-               status = ctf_fs_iterator_next_one(msg_iter_data, &msgs[i]);
-               if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                       i++;
-               }
-       }
-
-       if (i > 0) {
-               /*
-                * Even if ctf_fs_iterator_next_one() returned something
-                * else than BT_SELF_MESSAGE_ITERATOR_STATUS_OK, we
-                * accumulated message objects in the output
-                * message array, so we need to return
-                * BT_SELF_MESSAGE_ITERATOR_STATUS_OK so that they are
-                * transfered to downstream. This other status occurs
-                * again the next time muxer_msg_iter_do_next() is
-                * called, possibly without any accumulated
-                * message, in which case we'll return it.
-                */
-               *count = i;
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       }
-
-       return status;
-}
-
-static
-int ctf_fs_iterator_reset(struct ctf_fs_msg_iter_data *msg_iter_data)
-{
-       int ret;
-
-       msg_iter_data->ds_file_info_index = 0;
-       ret = msg_iter_data_set_current_ds_file(msg_iter_data);
-       if (ret) {
-               goto end;
-       }
-
-       bt_msg_iter_reset(msg_iter_data->msg_iter);
-       set_msg_iter_emits_stream_beginning_end_messages(msg_iter_data);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status ctf_fs_iterator_seek_beginning(
-               bt_self_message_iterator *it)
-{
-       struct ctf_fs_msg_iter_data *msg_iter_data =
-               bt_self_message_iterator_get_data(it);
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_ASSERT(msg_iter_data);
-       if (ctf_fs_iterator_reset(msg_iter_data)) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-void ctf_fs_iterator_finalize(bt_self_message_iterator *it)
-{
-       ctf_fs_msg_iter_data_destroy(
-               bt_self_message_iterator_get_data(it));
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status ctf_fs_iterator_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_source *self_comp,
-               bt_self_component_port_output *self_port)
-{
-       struct ctf_fs_port_data *port_data;
-       struct ctf_fs_msg_iter_data *msg_iter_data = NULL;
-       bt_self_message_iterator_status ret =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       port_data = bt_self_component_port_get_data(
-               bt_self_component_port_output_as_self_component_port(
-                       self_port));
-       BT_ASSERT(port_data);
-       msg_iter_data = g_new0(struct ctf_fs_msg_iter_data, 1);
-       if (!msg_iter_data) {
-               ret = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto error;
-       }
-
-       msg_iter_data->pc_msg_iter = self_msg_iter;
-       msg_iter_data->msg_iter = bt_msg_iter_create(
-               port_data->ds_file_group->ctf_fs_trace->metadata->tc,
-               bt_common_get_page_size() * 8,
-               ctf_fs_ds_file_medops, NULL);
-       if (!msg_iter_data->msg_iter) {
-               BT_LOGE_STR("Cannot create a CTF message iterator.");
-               ret = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto error;
-       }
-
-       msg_iter_data->ds_file_group = port_data->ds_file_group;
-       if (ctf_fs_iterator_reset(msg_iter_data)) {
-               ret = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto error;
-       }
-
-       bt_self_message_iterator_set_data(self_msg_iter,
-               msg_iter_data);
-       if (ret != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-               goto error;
-       }
-
-       msg_iter_data = NULL;
-       goto end;
-
-error:
-       bt_self_message_iterator_set_data(self_msg_iter, NULL);
-
-end:
-       ctf_fs_msg_iter_data_destroy(msg_iter_data);
-       return ret;
-}
-
-BT_HIDDEN
-void ctf_fs_destroy(struct ctf_fs_component *ctf_fs)
-{
-       if (!ctf_fs) {
-               return;
-       }
-
-       if (ctf_fs->traces) {
-               g_ptr_array_free(ctf_fs->traces, TRUE);
-       }
-
-       if (ctf_fs->port_data) {
-               g_ptr_array_free(ctf_fs->port_data, TRUE);
-       }
-
-       g_free(ctf_fs);
-}
-
-static
-void port_data_destroy(struct ctf_fs_port_data *port_data)
-{
-       if (!port_data) {
-               return;
-       }
-
-       g_free(port_data);
-}
-
-static
-void port_data_destroy_notifier(void *data) {
-       port_data_destroy(data);
-}
-
-static
-void ctf_fs_trace_destroy(struct ctf_fs_trace *ctf_fs_trace)
-{
-       if (!ctf_fs_trace) {
-               return;
-       }
-
-       if (ctf_fs_trace->ds_file_groups) {
-               g_ptr_array_free(ctf_fs_trace->ds_file_groups, TRUE);
-       }
-
-       BT_TRACE_PUT_REF_AND_RESET(ctf_fs_trace->trace);
-
-       if (ctf_fs_trace->path) {
-               g_string_free(ctf_fs_trace->path, TRUE);
-       }
-
-       if (ctf_fs_trace->name) {
-               g_string_free(ctf_fs_trace->name, TRUE);
-       }
-
-       if (ctf_fs_trace->metadata) {
-               ctf_fs_metadata_fini(ctf_fs_trace->metadata);
-               g_free(ctf_fs_trace->metadata);
-       }
-
-       g_free(ctf_fs_trace);
-}
-
-static
-void ctf_fs_trace_destroy_notifier(void *data)
-{
-       struct ctf_fs_trace *trace = data;
-       ctf_fs_trace_destroy(trace);
-}
-
-struct ctf_fs_component *ctf_fs_component_create(void)
-{
-       struct ctf_fs_component *ctf_fs;
-
-       ctf_fs = g_new0(struct ctf_fs_component, 1);
-       if (!ctf_fs) {
-               goto error;
-       }
-
-       ctf_fs->port_data =
-               g_ptr_array_new_with_free_func(port_data_destroy_notifier);
-       if (!ctf_fs->port_data) {
-               goto error;
-       }
-
-       ctf_fs->traces =
-               g_ptr_array_new_with_free_func(ctf_fs_trace_destroy_notifier);
-       if (!ctf_fs->traces) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       if (ctf_fs) {
-               ctf_fs_destroy(ctf_fs);
-       }
-
-end:
-       return ctf_fs;
-}
-
-void ctf_fs_finalize(bt_self_component_source *component)
-{
-       ctf_fs_destroy(bt_self_component_get_data(
-               bt_self_component_source_as_self_component(component)));
-}
-
-gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group)
-{
-       GString *name = g_string_new(NULL);
-
-       /*
-        * The unique port name is generated by concatenating unique identifiers
-        * for:
-        *
-        *   - the trace
-        *   - the stream class
-        *   - the stream
-        */
-
-       /* For the trace, use the uuid if present, else the path. */
-       if (ds_file_group->ctf_fs_trace->metadata->tc->is_uuid_set) {
-               char uuid_str[BABELTRACE_UUID_STR_LEN];
-
-               bt_uuid_unparse(ds_file_group->ctf_fs_trace->metadata->tc->uuid, uuid_str);
-               g_string_assign(name, uuid_str);
-       } else {
-               g_string_assign(name, ds_file_group->ctf_fs_trace->path->str);
-       }
-
-       /*
-        * For the stream class, use the id if present.  We can omit this field
-        * otherwise, as there will only be a single stream class.
-        */
-       if (ds_file_group->sc->id != UINT64_C(-1)) {
-               g_string_append_printf(name, " | %" PRIu64, ds_file_group->sc->id);
-       }
-
-       /* For the stream, use the id if present, else, use the path. */
-       if (ds_file_group->stream_id != UINT64_C(-1)) {
-               g_string_append_printf(name, " | %" PRIu64, ds_file_group->stream_id);
-       } else {
-               BT_ASSERT(ds_file_group->ds_file_infos->len == 1);
-               struct ctf_fs_ds_file_info *ds_file_info =
-                       g_ptr_array_index(ds_file_group->ds_file_infos, 0);
-               g_string_append_printf(name, " | %s", ds_file_info->path->str);
-       }
-
-       return g_string_free(name, FALSE);
-}
-
-static
-int create_one_port_for_trace(struct ctf_fs_component *ctf_fs,
-               struct ctf_fs_trace *ctf_fs_trace,
-               struct ctf_fs_ds_file_group *ds_file_group)
-{
-       int ret = 0;
-       struct ctf_fs_port_data *port_data = NULL;
-       gchar *port_name;
-
-       port_name = ctf_fs_make_port_name(ds_file_group);
-       if (!port_name) {
-               goto error;
-       }
-
-       BT_LOGD("Creating one port named `%s`", port_name);
-
-       /* Create output port for this file */
-       port_data = g_new0(struct ctf_fs_port_data, 1);
-       if (!port_data) {
-               goto error;
-       }
-
-       port_data->ctf_fs = ctf_fs;
-       port_data->ds_file_group = ds_file_group;
-       ret = bt_self_component_source_add_output_port(
-               ctf_fs->self_comp, port_name, port_data, NULL);
-       if (ret) {
-               goto error;
-       }
-
-       g_ptr_array_add(ctf_fs->port_data, port_data);
-       port_data = NULL;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       if (port_name) {
-               g_free(port_name);
-       }
-
-       port_data_destroy(port_data);
-       return ret;
-}
-
-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;
-}
-
-static
-void ctf_fs_ds_file_info_destroy(struct ctf_fs_ds_file_info *ds_file_info)
-{
-       if (!ds_file_info) {
-               return;
-       }
-
-       if (ds_file_info->path) {
-               g_string_free(ds_file_info->path, TRUE);
-       }
-
-       g_free(ds_file_info);
-}
-
-static
-struct ctf_fs_ds_file_info *ctf_fs_ds_file_info_create(const char *path,
-               int64_t begin_ns)
-{
-       struct ctf_fs_ds_file_info *ds_file_info;
-
-       ds_file_info = g_new0(struct ctf_fs_ds_file_info, 1);
-       if (!ds_file_info) {
-               goto end;
-       }
-
-       ds_file_info->path = g_string_new(path);
-       if (!ds_file_info->path) {
-               ctf_fs_ds_file_info_destroy(ds_file_info);
-               ds_file_info = NULL;
-               goto end;
-       }
-
-       ds_file_info->begin_ns = begin_ns;
-
-end:
-       return ds_file_info;
-}
-
-static
-void ctf_fs_ds_file_group_destroy(struct ctf_fs_ds_file_group *ds_file_group)
-{
-       if (!ds_file_group) {
-               return;
-       }
-
-       if (ds_file_group->ds_file_infos) {
-               g_ptr_array_free(ds_file_group->ds_file_infos, TRUE);
-       }
-
-       if (ds_file_group->index) {
-               if (ds_file_group->index->entries) {
-                       g_ptr_array_free(ds_file_group->index->entries, TRUE);
-               }
-               g_free(ds_file_group->index);
-       }
-
-       bt_stream_put_ref(ds_file_group->stream);
-       g_free(ds_file_group);
-}
-
-static
-struct ctf_fs_ds_file_group *ctf_fs_ds_file_group_create(
-               struct ctf_fs_trace *ctf_fs_trace,
-               struct ctf_stream_class *sc,
-               uint64_t stream_instance_id,
-               struct ctf_fs_ds_index *index)
-{
-       struct ctf_fs_ds_file_group *ds_file_group;
-
-       ds_file_group = g_new0(struct ctf_fs_ds_file_group, 1);
-       if (!ds_file_group) {
-               goto error;
-       }
-
-       ds_file_group->ds_file_infos = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) ctf_fs_ds_file_info_destroy);
-       if (!ds_file_group->ds_file_infos) {
-               goto error;
-       }
-
-       ds_file_group->index = index;
-
-       ds_file_group->stream_id = stream_instance_id;
-       BT_ASSERT(sc);
-       ds_file_group->sc = sc;
-       ds_file_group->ctf_fs_trace = ctf_fs_trace;
-       goto end;
-
-error:
-       ctf_fs_ds_file_group_destroy(ds_file_group);
-       ctf_fs_ds_index_destroy(index);
-       ds_file_group = NULL;
-
-end:
-       return ds_file_group;
-}
-
-/* Replace by g_ptr_array_insert when we depend on glib >= 2.40. */
-static
-void array_insert(GPtrArray *array, gpointer element, size_t pos)
-{
-       size_t original_array_len = array->len;
-
-       /* Allocate an unused element at the end of the array. */
-       g_ptr_array_add(array, NULL);
-
-       /* If we are not inserting at the end, move the elements by one. */
-       if (pos < original_array_len) {
-               memmove(&(array->pdata[pos + 1]),
-                       &(array->pdata[pos]),
-                       (original_array_len - pos) * sizeof(gpointer));
-       }
-
-       /* Insert the value. */
-       array->pdata[pos] = element;
-}
-
-/*
- * Insert ds_file_info in ds_file_group's list of ds_file_infos at the right
- * place to keep it sorted.
- */
-
-static
-void ds_file_group_insert_ds_file_info_sorted(
-               struct ctf_fs_ds_file_group *ds_file_group,
-               struct ctf_fs_ds_file_info *ds_file_info)
-{
-       guint i;
-
-       /* Find the spot where to insert this ds_file_info. */
-       for (i = 0; i < ds_file_group->ds_file_infos->len; i++) {
-               struct ctf_fs_ds_file_info *other_ds_file_info =
-                       g_ptr_array_index(ds_file_group->ds_file_infos, i);
-
-               if (ds_file_info->begin_ns < other_ds_file_info->begin_ns) {
-                       break;
-               }
-       }
-
-       array_insert(ds_file_group->ds_file_infos, ds_file_info, i);
-}
-
-static
-void ds_file_group_insert_ds_index_entry_sorted(
-       struct ctf_fs_ds_file_group *ds_file_group,
-       struct ctf_fs_ds_index_entry *entry)
-{
-       guint i;
-
-       /* Find the spot where to insert this index entry. */
-       for (i = 0; i < ds_file_group->index->entries->len; i++) {
-               struct ctf_fs_ds_index_entry *other_entry = g_ptr_array_index(
-                       ds_file_group->index->entries, i);
-
-               if (entry->timestamp_begin_ns < other_entry->timestamp_begin_ns) {
-                       break;
-               }
-       }
-
-       array_insert(ds_file_group->index->entries, entry, i);
-}
-
-/*
- * Create a new ds_file_info using the provided path, begin_ns and index, then
- * add it to ds_file_group's list of ds_file_infos.
- */
-
-static
-int ctf_fs_ds_file_group_add_ds_file_info(
-               struct ctf_fs_ds_file_group *ds_file_group,
-               const char *path, int64_t begin_ns)
-{
-       struct ctf_fs_ds_file_info *ds_file_info;
-       int ret = 0;
-
-       ds_file_info = ctf_fs_ds_file_info_create(path, begin_ns);
-       if (!ds_file_info) {
-               goto error;
-       }
-
-       ds_file_group_insert_ds_file_info_sorted(ds_file_group, ds_file_info);
-
-       ds_file_info = NULL;
-       goto end;
-
-error:
-       ctf_fs_ds_file_info_destroy(ds_file_info);
-       ret = -1;
-end:
-       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), index);
-               /* Ownership of index is transferred. */
-               index = NULL;
-
-               if (!ds_file_group) {
-                       goto error;
-               }
-
-               ret = ctf_fs_ds_file_group_add_ds_file_info(ds_file_group,
-                       path, begin_ns);
-               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, index);
-               /* Ownership of index is transferred. */
-               index = NULL;
-               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);
-       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;
-}
-
-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 set_trace_name(bt_trace *trace, const char *name_suffix)
-{
-       int ret = 0;
-       const bt_trace_class *tc = bt_trace_borrow_class_const(trace);
-       const bt_value *val;
-       GString *name;
-
-       name = g_string_new(NULL);
-       if (!name) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Check if we have a trace environment string value named `hostname`.
-        * If so, use it as the trace name's prefix.
-        */
-       val = bt_trace_class_borrow_environment_entry_value_by_name_const(
-               tc, "hostname");
-       if (val && bt_value_is_string(val)) {
-               g_string_append(name, bt_value_string_get(val));
-
-               if (name_suffix) {
-                       g_string_append_c(name, G_DIR_SEPARATOR);
-               }
-       }
-
-       if (name_suffix) {
-               g_string_append(name, name_suffix);
-       }
-
-       ret = bt_trace_set_name(trace, name->str);
-       if (ret) {
-               goto end;
-       }
-
-       goto end;
-
-end:
-       if (name) {
-               g_string_free(name, TRUE);
-       }
-
-       return ret;
-}
-
-static
-struct ctf_fs_trace *ctf_fs_trace_create(bt_self_component_source *self_comp,
-               const char *path, const char *name,
-               struct ctf_fs_metadata_config *metadata_config)
-{
-       struct ctf_fs_trace *ctf_fs_trace;
-       int ret;
-
-       ctf_fs_trace = g_new0(struct ctf_fs_trace, 1);
-       if (!ctf_fs_trace) {
-               goto end;
-       }
-
-       ctf_fs_trace->path = g_string_new(path);
-       if (!ctf_fs_trace->path) {
-               goto error;
-       }
-
-       ctf_fs_trace->name = g_string_new(name);
-       if (!ctf_fs_trace->name) {
-               goto error;
-       }
-
-       ctf_fs_trace->metadata = g_new0(struct ctf_fs_metadata, 1);
-       if (!ctf_fs_trace->metadata) {
-               goto error;
-       }
-
-       ctf_fs_metadata_init(ctf_fs_trace->metadata);
-       ctf_fs_trace->ds_file_groups = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) ctf_fs_ds_file_group_destroy);
-       if (!ctf_fs_trace->ds_file_groups) {
-               goto error;
-       }
-
-       ret = ctf_fs_metadata_set_trace_class(self_comp,
-               ctf_fs_trace, metadata_config);
-       if (ret) {
-               goto error;
-       }
-
-       if (ctf_fs_trace->metadata->trace_class) {
-               ctf_fs_trace->trace =
-                       bt_trace_create(ctf_fs_trace->metadata->trace_class);
-               if (!ctf_fs_trace->trace) {
-                       goto error;
-               }
-       }
-
-       if (ctf_fs_trace->trace) {
-               ret = set_trace_name(ctf_fs_trace->trace, name);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       ret = create_ds_file_groups(ctf_fs_trace);
-       if (ret) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ctf_fs_trace_destroy(ctf_fs_trace);
-       ctf_fs_trace = NULL;
-
-end:
-       return ctf_fs_trace;
-}
-
-static
-int path_is_ctf_trace(const char *path)
-{
-       GString *metadata_path = g_string_new(NULL);
-       int ret = 0;
-
-       if (!metadata_path) {
-               ret = -1;
-               goto end;
-       }
-
-       g_string_printf(metadata_path, "%s" G_DIR_SEPARATOR_S "%s", path, CTF_FS_METADATA_FILENAME);
-
-       if (g_file_test(metadata_path->str, G_FILE_TEST_IS_REGULAR)) {
-               ret = 1;
-               goto end;
-       }
-
-end:
-       g_string_free(metadata_path, TRUE);
-       return ret;
-}
-
-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;
-}
-
-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
-GList *ctf_fs_create_trace_names(GList *trace_paths, const char *base_path) {
-       GList *trace_names = NULL;
-       GList *node;
-       const char *last_sep;
-       size_t base_dist;
-
-       /*
-        * At this point we know that all the trace paths are
-        * normalized, and so is the base path. This means that
-        * they are absolute and they don't end with a separator.
-        * We can simply find the location of the last separator
-        * in the base path, which gives us the name of the actual
-        * directory to look into, and use this location as the
-        * start of each trace name within each trace path.
-        *
-        * For example:
-        *
-        *     Base path: /home/user/my-traces/some-trace
-        *     Trace paths:
-        *       - /home/user/my-traces/some-trace/host1/trace1
-        *       - /home/user/my-traces/some-trace/host1/trace2
-        *       - /home/user/my-traces/some-trace/host2/trace
-        *       - /home/user/my-traces/some-trace/other-trace
-        *
-        * In this case the trace names are:
-        *
-        *       - some-trace/host1/trace1
-        *       - some-trace/host1/trace2
-        *       - some-trace/host2/trace
-        *       - some-trace/other-trace
-        */
-       last_sep = strrchr(base_path, G_DIR_SEPARATOR);
-
-       /* We know there's at least one separator */
-       BT_ASSERT(last_sep);
-
-       /* Distance to base */
-       base_dist = last_sep - base_path + 1;
-
-       /* Create the trace names */
-       for (node = trace_paths; node; node = g_list_next(node)) {
-               GString *trace_name = g_string_new(NULL);
-               GString *trace_path = node->data;
-
-               BT_ASSERT(trace_name);
-               g_string_assign(trace_name, &trace_path->str[base_dist]);
-               trace_names = g_list_append(trace_names, trace_name);
-       }
-
-       return trace_names;
-}
-
-/* Helper for ctf_fs_component_create_ctf_fs_traces, to handle a single path/root. */
-
-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;
-}
-
-/* GCompareFunc to sort traces by UUID. */
-
-static
-gint sort_traces_by_uuid(gconstpointer a, gconstpointer b)
-{
-       const struct ctf_fs_trace *trace_a = *((const struct ctf_fs_trace **) a);
-       const struct ctf_fs_trace *trace_b = *((const struct ctf_fs_trace **) b);
-
-       bool trace_a_has_uuid = trace_a->metadata->tc->is_uuid_set;
-       bool trace_b_has_uuid = trace_b->metadata->tc->is_uuid_set;
-       gint ret;
-
-       /* Order traces without uuid first. */
-       if (!trace_a_has_uuid && trace_b_has_uuid) {
-               ret = -1;
-       } else if (trace_a_has_uuid && !trace_b_has_uuid) {
-               ret = 1;
-       } else if (!trace_a_has_uuid && !trace_b_has_uuid) {
-               ret = 0;
-       } else {
-               ret = bt_uuid_compare(trace_a->metadata->tc->uuid, trace_b->metadata->tc->uuid);
-       }
-
-       return ret;
-}
-
-/*
- * Count the number of stream and event classes defined by this trace's metadata.
- *
- * This is used to determine which metadata is the "latest", out of multiple
- * traces sharing the same UUID.  It is assumed that amongst all these metadatas,
- * a bigger metadata is a superset of a smaller metadata.  Therefore, it is
- * enough to just count the classes.
- */
-
-static
-unsigned int metadata_count_stream_and_event_classes(struct ctf_fs_trace *trace)
-{
-       unsigned int num = trace->metadata->tc->stream_classes->len;
-       guint i;
-
-       for (i = 0; i < trace->metadata->tc->stream_classes->len; i++) {
-               struct ctf_stream_class *sc = trace->metadata->tc->stream_classes->pdata[i];
-               num += sc->event_classes->len;
-       }
-
-       return num;
-}
-
-/*
- * Merge the src ds_file_group into dest.  This consists of merging their
- * ds_file_infos, making sure to keep the result sorted.
- */
-
-static
-void merge_ctf_fs_ds_file_groups(struct ctf_fs_ds_file_group *dest, struct ctf_fs_ds_file_group *src)
-{
-       guint i;
-
-       for (i = 0; i < src->ds_file_infos->len; i++) {
-               struct ctf_fs_ds_file_info *ds_file_info =
-                       g_ptr_array_index(src->ds_file_infos, i);
-
-               /* Ownership of the ds_file_info is transferred to dest. */
-               g_ptr_array_index(src->ds_file_infos, i) = NULL;
-
-               ds_file_group_insert_ds_file_info_sorted(dest, ds_file_info);
-       }
-
-       /* Merge both indexes. */
-       for (i = 0; i < src->index->entries->len; i++) {
-               struct ctf_fs_ds_index_entry *entry = g_ptr_array_index(
-                       src->index->entries, i);
-
-               /*
-                * Ownership of the ctf_fs_ds_index_entry is transferred to
-                * dest.
-                */
-               g_ptr_array_index(src->index->entries, i) = NULL;
-
-               ds_file_group_insert_ds_index_entry_sorted(dest, entry);
-       }
-}
-/* Merge src_trace's data stream file groups into dest_trace's. */
-
-static
-int merge_matching_ctf_fs_ds_file_groups(
-               struct ctf_fs_trace *dest_trace,
-               struct ctf_fs_trace *src_trace)
-{
-
-       GPtrArray *dest = dest_trace->ds_file_groups;
-       GPtrArray *src = src_trace->ds_file_groups;
-       guint s_i;
-       int ret = 0;
-
-       /*
-        * Save the initial length of dest: we only want to check against the
-        * original elements in the inner loop.
-        */
-       const guint dest_len = dest->len;
-
-       for (s_i = 0; s_i < src->len; s_i++) {
-               struct ctf_fs_ds_file_group *src_group = g_ptr_array_index(src, s_i);
-               struct ctf_fs_ds_file_group *dest_group = NULL;
-
-               /* A stream instance without ID can't match a stream in the other trace.  */
-               if (src_group->stream_id != -1) {
-                       guint d_i;
-
-                       /* Let's search for a matching ds_file_group in the destination.  */
-                       for (d_i = 0; d_i < dest_len; d_i++) {
-                               struct ctf_fs_ds_file_group *candidate_dest = g_ptr_array_index(dest, d_i);
-
-                               /* Can't match a stream instance without ID.  */
-                               if (candidate_dest->stream_id == -1) {
-                                       continue;
-                               }
-
-                               /*
-                                * If the two groups have the same stream instance id
-                                * and belong to the same stream class (stream instance
-                                * ids are per-stream class), they represent the same
-                                * stream instance.
-                                */
-                               if (candidate_dest->stream_id != src_group->stream_id ||
-                                               candidate_dest->sc->id != src_group->sc->id) {
-                                       continue;
-                               }
-
-                               dest_group = candidate_dest;
-                               break;
-                       }
-               }
-
-               /*
-                * Didn't find a friend in dest to merge our src_group into?
-                * Create a new empty one. This can happen if a stream was
-                * active in the source trace chunk but not in the destination
-                * trace chunk.
-                */
-               if (!dest_group) {
-                       struct ctf_stream_class *sc;
-                       struct ctf_fs_ds_index *index;
-
-                       sc = ctf_trace_class_borrow_stream_class_by_id(
-                               dest_trace->metadata->tc, src_group->sc->id);
-                       BT_ASSERT(sc);
-
-                       index = ctf_fs_ds_index_create();
-                       if (!index) {
-                               ret = -1;
-                               goto end;
-                       }
-
-                       dest_group = ctf_fs_ds_file_group_create(dest_trace, sc,
-                               src_group->stream_id, index);
-                       /* Ownership of index is transferred. */
-                       index = NULL;
-                       if (!dest_group) {
-                               ret = -1;
-                               goto end;
-                       }
-
-                       g_ptr_array_add(dest_trace->ds_file_groups, dest_group);
-               }
-
-               BT_ASSERT(dest_group);
-               merge_ctf_fs_ds_file_groups(dest_group, src_group);
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Collapse the given traces, which must all share the same UUID, in a single
- * one.
- *
- * The trace with the most expansive metadata is chosen and all other traces
- * are merged into that one.  The array slots of all the traces that get merged
- * in the chosen one are set to NULL, so only the slot of the chosen trace
- * remains non-NULL.
- */
-
-static
-int merge_ctf_fs_traces(struct ctf_fs_trace **traces, unsigned int num_traces)
-{
-       unsigned int winner_count;
-       struct ctf_fs_trace *winner;
-       guint i;
-       int ret = 0;
-       char uuid_str[BABELTRACE_UUID_STR_LEN];
-
-       BT_ASSERT(num_traces >= 2);
-
-       winner_count = metadata_count_stream_and_event_classes(traces[0]);
-       winner = traces[0];
-
-       /* Find the trace with the largest metadata. */
-       for (i = 1; i < num_traces; i++) {
-               struct ctf_fs_trace *candidate;
-               unsigned int candidate_count;
-
-               candidate = traces[i];
-
-               /* A bit of sanity check. */
-               BT_ASSERT(bt_uuid_compare(winner->metadata->tc->uuid, candidate->metadata->tc->uuid) == 0);
-
-               candidate_count = metadata_count_stream_and_event_classes(candidate);
-
-               if (candidate_count > winner_count) {
-                       winner_count = candidate_count;
-                       winner = candidate;
-               }
-       }
-
-       /* Merge all the other traces in the winning trace. */
-       for (i = 0; i < num_traces; i++) {
-               struct ctf_fs_trace *trace = traces[i];
-
-               /* Don't merge the winner into itself. */
-               if (trace == winner) {
-                       continue;
-               }
-
-               /* Merge trace's data stream file groups into winner's. */
-               ret = merge_matching_ctf_fs_ds_file_groups(winner, trace);
-               if (ret) {
-                       goto end;
-               }
-
-               /* Free the trace that got merged into winner, clear the slot in the array. */
-               ctf_fs_trace_destroy(trace);
-               traces[i] = NULL;
-       }
-
-       /* Use the string representation of the UUID as the trace name. */
-       bt_uuid_unparse(winner->metadata->tc->uuid, uuid_str);
-       g_string_printf(winner->name, "%s", uuid_str);
-
-end:
-       return ret;
-}
-
-/*
- * Merge all traces of `ctf_fs` that share the same UUID in a single trace.
- * Traces with no UUID are not merged.
- */
-
-static
-int merge_traces_with_same_uuid(struct ctf_fs_component *ctf_fs)
-{
-       GPtrArray *traces = ctf_fs->traces;
-       guint range_start_idx = 0;
-       unsigned int num_traces = 0;
-       guint i;
-       int ret = 0;
-
-       /* Sort the traces by uuid, then collapse traces with the same uuid in a single one. */
-       g_ptr_array_sort(traces, sort_traces_by_uuid);
-
-       /* Find ranges of consecutive traces that share the same UUID.  */
-       while (range_start_idx < traces->len) {
-               guint range_len;
-               struct ctf_fs_trace *range_start_trace = g_ptr_array_index(traces, range_start_idx);
-
-               /* Exclusive end of range. */
-               guint range_end_exc_idx = range_start_idx + 1;
-
-               while (range_end_exc_idx < traces->len) {
-                       struct ctf_fs_trace *this_trace = g_ptr_array_index(traces, range_end_exc_idx);
-
-                       if (!range_start_trace->metadata->tc->is_uuid_set ||
-                               (bt_uuid_compare(range_start_trace->metadata->tc->uuid, this_trace->metadata->tc->uuid) != 0)) {
-                               break;
-                       }
-
-                       range_end_exc_idx++;
-               }
-
-               /* If we have two or more traces with matching UUIDs, merge them. */
-               range_len = range_end_exc_idx - range_start_idx;
-               if (range_len > 1) {
-                       struct ctf_fs_trace **range_start = (struct ctf_fs_trace **) &traces->pdata[range_start_idx];
-                       ret = merge_ctf_fs_traces(range_start, range_len);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-
-               num_traces++;
-               range_start_idx = range_end_exc_idx;
-       }
-
-       /* Clear any NULL slot (traces that got merged in another one) in the array.  */
-       for (i = 0; i < traces->len;) {
-               if (g_ptr_array_index(traces, i) == NULL) {
-                       g_ptr_array_remove_index_fast(traces, i);
-               } else {
-                       i++;
-               }
-       }
-
-       BT_ASSERT(num_traces == traces->len);
-
-end:
-       return ret;
-}
-
-int ctf_fs_component_create_ctf_fs_traces(bt_self_component_source *self_comp,
-               struct ctf_fs_component *ctf_fs,
-               const bt_value *paths_value)
-{
-       int ret = 0;
-       uint64_t i;
-
-       for (i = 0; i < bt_value_array_get_size(paths_value); i++) {
-               const bt_value *path_value = bt_value_array_borrow_element_by_index_const(paths_value, i);
-               const char *path = bt_value_string_get(path_value);
-
-               ret = ctf_fs_component_create_ctf_fs_traces_one_root(self_comp, ctf_fs, path);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       ret = merge_traces_with_same_uuid(ctf_fs);
-
-end:
-       return ret;
-}
-
-static
-GString *get_stream_instance_unique_name(
-               struct ctf_fs_ds_file_group *ds_file_group)
-{
-       GString *name;
-       struct ctf_fs_ds_file_info *ds_file_info;
-
-       name = g_string_new(NULL);
-       if (!name) {
-               goto end;
-       }
-
-       /*
-        * If there's more than one stream file in the stream file
-        * group, the first (earliest) stream file's path is used as
-        * the stream's unique name.
-        */
-       BT_ASSERT(ds_file_group->ds_file_infos->len > 0);
-       ds_file_info = g_ptr_array_index(ds_file_group->ds_file_infos, 0);
-       g_string_assign(name, ds_file_info->path->str);
-
-end:
-       return name;
-}
-
-/* Create the IR stream objects for ctf_fs_trace. */
-
-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;
-}
-
-/*
- * Validate the "paths" parameter passed to this component.  It must be
- * present, and it must be an array of strings.
- */
-
-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;
-}
-
-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;
-}
-
-static
-struct ctf_fs_component *ctf_fs_create(
-               bt_self_component_source *self_comp,
-               const bt_value *params)
-{
-       struct ctf_fs_component *ctf_fs = NULL;
-       guint i;
-       const bt_value *paths_value;
-
-       ctf_fs = ctf_fs_component_create();
-       if (!ctf_fs) {
-               goto error;
-       }
-
-       if (!read_src_fs_parameters(params, &paths_value, ctf_fs)) {
-               goto error;
-       }
-
-       bt_self_component_set_data(
-               bt_self_component_source_as_self_component(self_comp),
-               ctf_fs);
-
-       /*
-        * We don't need to get a new reference here because as long as
-        * our private ctf_fs_component object exists, the containing
-        * private component should also exist.
-        */
-       ctf_fs->self_comp = self_comp;
-
-       if (ctf_fs_component_create_ctf_fs_traces(self_comp, ctf_fs, paths_value)) {
-               goto error;
-       }
-
-       for (i = 0; i < ctf_fs->traces->len; i++) {
-               struct ctf_fs_trace *trace = g_ptr_array_index(ctf_fs->traces, i);
-
-               if (create_streams_for_trace(trace)) {
-                       goto error;
-               }
-
-               if (create_ports_for_trace(ctf_fs, trace)) {
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       ctf_fs_destroy(ctf_fs);
-       ctf_fs = NULL;
-       bt_self_component_set_data(
-               bt_self_component_source_as_self_component(self_comp),
-               NULL);
-
-end:
-       return ctf_fs;
-}
-
-BT_HIDDEN
-bt_self_component_status ctf_fs_init(
-               bt_self_component_source *self_comp,
-               const bt_value *params, UNUSED_VAR void *init_method_data)
-{
-       struct ctf_fs_component *ctf_fs;
-       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
-
-       ctf_fs = ctf_fs_create(self_comp, params);
-       if (!ctf_fs) {
-               ret = BT_SELF_COMPONENT_STATUS_ERROR;
-       }
-
-       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;
-}
diff --git a/plugins/ctf/fs-src/fs.h b/plugins/ctf/fs-src/fs.h
deleted file mode 100644 (file)
index 9e9ee84..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_H
-#define BABELTRACE_PLUGIN_CTF_FS_H
-
-/*
- * BabelTrace - CTF on File System Component
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdbool.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include "data-stream-file.h"
-#include "metadata.h"
-#include "../common/metadata/decoder.h"
-
-BT_HIDDEN
-extern bool ctf_fs_debug;
-
-struct ctf_fs_file {
-       /* Owned by this */
-       GString *path;
-
-       /* Owned by this */
-       FILE *fp;
-
-       off_t size;
-};
-
-struct ctf_fs_metadata {
-       /* Owned by this */
-       struct ctf_metadata_decoder *decoder;
-
-       /* Owned by this */
-       bt_trace_class *trace_class;
-
-       /* Weak (owned by `decoder` above) */
-       struct ctf_trace_class *tc;
-
-       /* Owned by this */
-
-       /* Owned by this */
-       char *text;
-
-       int bo;
-};
-
-struct ctf_fs_component {
-       /* Weak, guaranteed to exist */
-       bt_self_component_source *self_comp;
-
-       /* Array of struct ctf_fs_port_data *, owned by this */
-       GPtrArray *port_data;
-
-       /* Array of struct ctf_fs_trace *, owned by this */
-       GPtrArray *traces;
-
-       struct ctf_fs_metadata_config metadata_config;
-};
-
-struct ctf_fs_trace {
-       /* Owned by this */
-       struct ctf_fs_metadata *metadata;
-
-       /* Owned by this */
-       bt_trace *trace;
-
-       /* Array of struct ctf_fs_ds_file_group *, owned by this */
-       GPtrArray *ds_file_groups;
-
-       /* Owned by this */
-       GString *path;
-
-       /* Owned by this */
-       GString *name;
-
-       /* Next automatic stream ID when not provided by packet header */
-       uint64_t next_stream_id;
-};
-
-struct ctf_fs_ds_index_entry {
-       /* Position, in bytes, of the packet from the beginning of the file. */
-       uint64_t offset;
-
-       /* Size of the packet, in bytes. */
-       uint64_t packet_size;
-
-       /*
-        * Extracted from the packet context, relative to the respective fields'
-        * mapped clock classes (in cycles).
-        */
-       uint64_t timestamp_begin, timestamp_end;
-
-       /*
-        * Converted from the packet context, relative to the trace's EPOCH
-        * (in ns since EPOCH).
-        */
-       int64_t timestamp_begin_ns, timestamp_end_ns;
-};
-
-struct ctf_fs_ds_index {
-       /* Array of pointer to struct ctf_fs_fd_index_entry. */
-       GPtrArray *entries;
-};
-
-struct ctf_fs_ds_file_group {
-       /*
-        * Array of struct ctf_fs_ds_file_info, owned by this.
-        *
-        * This is an _ordered_ array of data stream file infos which
-        * belong to this group (a single stream instance).
-        *
-        * You can call ctf_fs_ds_file_create() with one of those paths
-        * and the trace IR stream below.
-        */
-       GPtrArray *ds_file_infos;
-
-       /* Owned by this */
-       struct ctf_stream_class *sc;
-
-       /* Owned by this */
-       bt_stream *stream;
-
-       /* Stream (instance) ID; -1ULL means none */
-       uint64_t stream_id;
-
-       /* Weak, belongs to component */
-       struct ctf_fs_trace *ctf_fs_trace;
-
-       /*
-        * Owned by this. May be NULL.
-        *
-        * A stream cannot be assumed to be indexed as the indexing might have
-        * been skipped. Moreover, the index's fields may not all be available
-        * depending on the producer (e.g. timestamp_begin/end are not
-        * mandatory).
-        */
-       struct ctf_fs_ds_index *index;
-};
-
-struct ctf_fs_port_data {
-       /* Weak, belongs to ctf_fs_trace */
-       struct ctf_fs_ds_file_group *ds_file_group;
-
-       /* Weak */
-       struct ctf_fs_component *ctf_fs;
-};
-
-struct ctf_fs_msg_iter_data {
-       /* Weak */
-       bt_self_message_iterator *pc_msg_iter;
-
-       /* Weak, belongs to ctf_fs_trace */
-       struct ctf_fs_ds_file_group *ds_file_group;
-
-       /* Owned by this */
-       struct ctf_fs_ds_file *ds_file;
-
-       /* Which file the iterator is _currently_ operating on */
-       size_t ds_file_info_index;
-
-       /* Owned by this */
-       struct bt_msg_iter *msg_iter;
-};
-
-BT_HIDDEN
-bt_self_component_status ctf_fs_init(
-               bt_self_component_source *source,
-               const bt_value *params, void *init_method_data);
-
-BT_HIDDEN
-void ctf_fs_finalize(bt_self_component_source *component);
-
-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_HIDDEN
-bt_self_message_iterator_status ctf_fs_iterator_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_source *self_comp,
-               bt_self_component_port_output *self_port);
-
-BT_HIDDEN
-void ctf_fs_iterator_finalize(bt_self_message_iterator *it);
-
-BT_HIDDEN
-bt_self_message_iterator_status ctf_fs_iterator_next(
-               bt_self_message_iterator *iterator,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count);
-
-BT_HIDDEN
-bt_self_message_iterator_status ctf_fs_iterator_seek_beginning(
-               bt_self_message_iterator *message_iterator);
-
-/* Create and initialize a new, empty ctf_fs_component. */
-
-BT_HIDDEN
-struct ctf_fs_component *ctf_fs_component_create(void);
-
-/*
- * Search recursively under all paths in `paths_value` (an array of strings),
- * for CTF traces. For each CTF trace found, create a ctf_fs_trace in
- * `ctf_fs` representing that trace.
- */
-
-BT_HIDDEN
-int ctf_fs_component_create_ctf_fs_traces(bt_self_component_source *self_comp,
-               struct ctf_fs_component *ctf_fs,
-               const bt_value *paths_value);
-
-/* Free `ctf_fs` and everything it owns. */
-
-BT_HIDDEN
-void ctf_fs_destroy(struct ctf_fs_component *ctf_fs);
-
-/*
- * Read and validate parameters taken by the src.ctf.fs plugin.
- *
- *  - The mandatory `paths` parameter is returned in `*paths`.
- *  - The optional `clock-class-offset-s` and `clock-class-offset-ns`, if
- *    present, are recorded in the `ctf_fs` structure.
- *
- * Return true on success, false if any parameter didn't pass validation.
- */
-
-BT_HIDDEN
-bool read_src_fs_parameters(const bt_value *params,
-               const bt_value **paths, struct ctf_fs_component *ctf_fs);
-
-/*
- * Generate the port name to be used for a given data stream file group.
- *
- * The result must be freed using g_free by the caller.
- */
-
-BT_HIDDEN
-gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group);
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_H */
diff --git a/plugins/ctf/fs-src/logging.c b/plugins/ctf/fs-src/logging.c
deleted file mode 100644 (file)
index 6f24ce7..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL ctf_fs_src_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(BT_LOG_OUTPUT_LEVEL, "BABELTRACE_SRC_CTF_FS_LOG_LEVEL");
diff --git a/plugins/ctf/fs-src/logging.h b/plugins/ctf/fs-src/logging.h
deleted file mode 100644 (file)
index 8a249dc..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef CTF_FS_SRC_LOGGING_H
-#define CTF_FS_SRC_LOGGING_H
-
-#define BT_LOG_OUTPUT_LEVEL ctf_fs_src_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(ctf_fs_src_log_level);
-
-#endif /* CTF_FS_SRC_LOGGING_H */
diff --git a/plugins/ctf/fs-src/lttng-index.h b/plugins/ctf/fs-src/lttng-index.h
deleted file mode 100644 (file)
index 037010d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
- *                      Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *                      David Goulet <dgoulet@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef LTTNG_INDEX_H
-#define LTTNG_INDEX_H
-
-#include <babeltrace2/compat/limits-internal.h>
-
-#define CTF_INDEX_MAGIC 0xC1F1DCC1
-#define CTF_INDEX_MAJOR 1
-#define CTF_INDEX_MINOR 1
-
-/*
- * Header at the beginning of each index file.
- * All integer fields are stored in big endian.
- */
-struct ctf_packet_index_file_hdr {
-       uint32_t magic;
-       uint32_t index_major;
-       uint32_t index_minor;
-       /* size of struct ctf_packet_index, in bytes. */
-       uint32_t packet_index_len;
-} __attribute__((__packed__));
-
-/*
- * Packet index generated for each trace packet store in a trace file.
- * All integer fields are stored in big endian.
- */
-struct ctf_packet_index {
-       uint64_t offset;                /* offset of the packet in the file, in bytes */
-       uint64_t packet_size;           /* packet size, in bits */
-       uint64_t content_size;          /* content size, in bits */
-       uint64_t timestamp_begin;
-       uint64_t timestamp_end;
-       uint64_t events_discarded;
-       uint64_t stream_id;
-       /* CTF_INDEX 1.0 limit */
-       uint64_t stream_instance_id;    /* ID of the channel instance */
-       uint64_t packet_seq_num;        /* packet sequence number */
-} __attribute__((__packed__));
-
-#endif /* LTTNG_INDEX_H */
diff --git a/plugins/ctf/fs-src/metadata.c b/plugins/ctf/fs-src/metadata.c
deleted file mode 100644 (file)
index 75043dc..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
- *
- * Some functions are based on older functions written by Mathieu Desnoyers.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <babeltrace2/assert-internal.h>
-#include <glib.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/compat/memstream-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "fs.h"
-#include "file.h"
-#include "metadata.h"
-#include "../common/metadata/decoder.h"
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-METADATA-SRC"
-#include "logging.h"
-
-BT_HIDDEN
-FILE *ctf_fs_metadata_open_file(const char *trace_path)
-{
-       GString *metadata_path;
-       FILE *fp = NULL;
-
-       metadata_path = g_string_new(trace_path);
-       if (!metadata_path) {
-               goto end;
-       }
-
-       g_string_append(metadata_path, G_DIR_SEPARATOR_S CTF_FS_METADATA_FILENAME);
-       fp = fopen(metadata_path->str, "rb");
-       g_string_free(metadata_path, TRUE);
-end:
-       return fp;
-}
-
-static struct ctf_fs_file *get_file(const char *trace_path)
-{
-       struct ctf_fs_file *file = ctf_fs_file_create();
-
-       if (!file) {
-               goto error;
-       }
-
-       g_string_append(file->path, trace_path);
-       g_string_append(file->path, G_DIR_SEPARATOR_S CTF_FS_METADATA_FILENAME);
-
-       if (ctf_fs_file_open(file, "rb")) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       if (file) {
-               ctf_fs_file_destroy(file);
-               file = NULL;
-       }
-
-end:
-       return file;
-}
-
-BT_HIDDEN
-int ctf_fs_metadata_set_trace_class(
-               bt_self_component_source *self_comp,
-               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_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;
-       }
-
-       ctf_fs_trace->metadata->decoder = ctf_metadata_decoder_create(self_comp,
-               config ? &decoder_config : NULL);
-       if (!ctf_fs_trace->metadata->decoder) {
-               BT_LOGE("Cannot create metadata decoder object");
-               ret = -1;
-               goto end;
-       }
-
-       ret = ctf_metadata_decoder_decode(ctf_fs_trace->metadata->decoder,
-               file->fp);
-       if (ret) {
-               BT_LOGE("Cannot decode metadata file");
-               goto end;
-       }
-
-       ctf_fs_trace->metadata->trace_class =
-               ctf_metadata_decoder_get_ir_trace_class(
-                       ctf_fs_trace->metadata->decoder);
-       BT_ASSERT(!self_comp || ctf_fs_trace->metadata->trace_class);
-       ctf_fs_trace->metadata->tc =
-               ctf_metadata_decoder_borrow_ctf_trace_class(
-                       ctf_fs_trace->metadata->decoder);
-       BT_ASSERT(ctf_fs_trace->metadata->tc);
-
-end:
-       ctf_fs_file_destroy(file);
-       return ret;
-}
-
-BT_HIDDEN
-int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata)
-{
-       /* Nothing to initialize for the moment. */
-       return 0;
-}
-
-BT_HIDDEN
-void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata)
-{
-       if (metadata->text) {
-               free(metadata->text);
-       }
-
-       if (metadata->trace_class) {
-               BT_TRACE_CLASS_PUT_REF_AND_RESET(metadata->trace_class);
-       }
-
-       if (metadata->decoder) {
-               ctf_metadata_decoder_destroy(metadata->decoder);
-       }
-}
diff --git a/plugins/ctf/fs-src/metadata.h b/plugins/ctf/fs-src/metadata.h
deleted file mode 100644 (file)
index 6ddc029..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef CTF_FS_METADATA_H
-#define CTF_FS_METADATA_H
-
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#define CTF_FS_METADATA_FILENAME       "metadata"
-
-struct ctf_fs_trace;
-struct ctf_fs_metadata;
-
-struct ctf_fs_metadata_config {
-       int64_t clock_class_offset_s;
-       int64_t clock_class_offset_ns;
-};
-
-BT_HIDDEN
-int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata);
-
-BT_HIDDEN
-void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata);
-
-BT_HIDDEN
-int ctf_fs_metadata_set_trace_class(bt_self_component_source *self_comp,
-               struct ctf_fs_trace *ctf_fs_trace,
-               struct ctf_fs_metadata_config *config);
-
-BT_HIDDEN
-FILE *ctf_fs_metadata_open_file(const char *trace_path);
-
-BT_HIDDEN
-bool ctf_metadata_is_packetized(FILE *fp, int *byte_order);
-
-#endif /* CTF_FS_METADATA_H */
diff --git a/plugins/ctf/fs-src/query.c b/plugins/ctf/fs-src/query.c
deleted file mode 100644 (file)
index e2018b1..0000000
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * query.c
- *
- * Babeltrace CTF file system Reader Component queries
- *
- * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "query.h"
-#include <stdbool.h>
-#include <babeltrace2/assert-internal.h>
-#include "metadata.h"
-#include "../common/metadata/decoder.h"
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include "fs.h"
-
-#define BT_LOG_TAG "PLUGIN-CTF-FS-QUERY-SRC"
-#include "logging.h"
-
-#define METADATA_TEXT_SIG      "/* CTF 1.8"
-
-struct range {
-       int64_t begin_ns;
-       int64_t end_ns;
-       bool set;
-};
-
-BT_HIDDEN
-bt_query_status metadata_info_query(
-               bt_self_component_class_source *comp_class,
-               const bt_value *params,
-               const bt_value **user_result)
-{
-       bt_query_status status = BT_QUERY_STATUS_OK;
-       bt_value *result = NULL;
-       const bt_value *path_value = NULL;
-       char *metadata_text = NULL;
-       FILE *metadata_fp = NULL;
-       GString *g_metadata_text = NULL;
-       int ret;
-       int bo;
-       const char *path;
-       bool is_packetized;
-
-       result = bt_value_map_create();
-       if (!result) {
-               status = BT_QUERY_STATUS_NOMEM;
-               goto error;
-       }
-
-       BT_ASSERT(params);
-
-       if (!bt_value_is_map(params)) {
-               BT_LOGE_STR("Query parameters is not a map value object.");
-               status = BT_QUERY_STATUS_INVALID_PARAMS;
-               goto error;
-       }
-
-       path_value = bt_value_map_borrow_entry_value_const(params, "path");
-       if (!path_value) {
-               BT_LOGE_STR("Mandatory `path` parameter missing");
-               status = BT_QUERY_STATUS_INVALID_PARAMS;
-               goto error;
-       }
-
-       if (!bt_value_is_string(path_value)) {
-               BT_LOGE_STR("`path` parameter is required to be a string value");
-               status = BT_QUERY_STATUS_INVALID_PARAMS;
-               goto error;
-       }
-
-       path = bt_value_string_get(path_value);
-
-       BT_ASSERT(path);
-       metadata_fp = ctf_fs_metadata_open_file(path);
-       if (!metadata_fp) {
-               BT_LOGE("Cannot open trace metadata: path=\"%s\".", path);
-               goto error;
-       }
-
-       is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp,
-               &bo);
-
-       if (is_packetized) {
-               ret = ctf_metadata_decoder_packetized_file_stream_to_buf(
-                       metadata_fp, &metadata_text, bo);
-               if (ret) {
-                       BT_LOGE("Cannot decode packetized metadata file: path=\"%s\"",
-                               path);
-                       goto error;
-               }
-       } else {
-               long filesize;
-
-               ret = fseek(metadata_fp, 0, SEEK_END);
-               if (ret) {
-                       BT_LOGE_ERRNO("Failed to seek to the end of the metadata file",
-                               ": path=\"%s\"", path);
-                       goto error;
-               }
-               filesize = ftell(metadata_fp);
-               if (filesize < 0) {
-                       BT_LOGE_ERRNO("Failed to get the current position in the metadata file",
-                               ": path=\"%s\"", path);
-                       goto error;
-               }
-               rewind(metadata_fp);
-               metadata_text = malloc(filesize + 1);
-               if (!metadata_text) {
-                       BT_LOGE_STR("Cannot allocate buffer for metadata text.");
-                       goto error;
-               }
-
-               if (fread(metadata_text, filesize, 1, metadata_fp) != 1) {
-                       BT_LOGE_ERRNO("Cannot read metadata file", ": path=\"%s\"",
-                               path);
-                       goto error;
-               }
-
-               metadata_text[filesize] = '\0';
-       }
-
-       g_metadata_text = g_string_new(NULL);
-       if (!g_metadata_text) {
-               goto error;
-       }
-
-       if (strncmp(metadata_text, METADATA_TEXT_SIG,
-                       sizeof(METADATA_TEXT_SIG) - 1) != 0) {
-               g_string_assign(g_metadata_text, METADATA_TEXT_SIG);
-               g_string_append(g_metadata_text, " */\n\n");
-       }
-
-       g_string_append(g_metadata_text, metadata_text);
-
-       ret = bt_value_map_insert_string_entry(result, "text",
-               g_metadata_text->str);
-       if (ret) {
-               BT_LOGE_STR("Cannot insert metadata text into query result.");
-               goto error;
-       }
-
-       ret = bt_value_map_insert_bool_entry(result, "is-packetized",
-               is_packetized);
-       if (ret) {
-               BT_LOGE_STR("Cannot insert \"is-packetized\" attribute into query result.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(result);
-       result = NULL;
-
-       if (status >= 0) {
-               status = BT_QUERY_STATUS_ERROR;
-       }
-
-end:
-       free(metadata_text);
-
-       if (g_metadata_text) {
-               g_string_free(g_metadata_text, TRUE);
-       }
-
-       if (metadata_fp) {
-               fclose(metadata_fp);
-       }
-
-       *user_result = result;
-       return status;
-}
-
-static
-int add_range(bt_value *info, struct range *range,
-               const char *range_name)
-{
-       int ret = 0;
-       bt_value_status status;
-       bt_value *range_map = NULL;
-
-       if (!range->set) {
-               /* Not an error. */
-               goto end;
-       }
-
-       range_map = bt_value_map_create();
-       if (!range_map) {
-               ret = -1;
-               goto end;
-       }
-
-       status = bt_value_map_insert_signed_integer_entry(range_map, "begin",
-                       range->begin_ns);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-       status = bt_value_map_insert_signed_integer_entry(range_map, "end",
-                       range->end_ns);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-       status = bt_value_map_insert_entry(info, range_name,
-               range_map);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-end:
-       bt_value_put_ref(range_map);
-       return ret;
-}
-
-static
-int add_stream_ids(bt_value *info, struct ctf_fs_ds_file_group *ds_file_group)
-{
-       int ret = 0;
-       bt_value_status status;
-
-       if (ds_file_group->stream_id != UINT64_C(-1)) {
-               status = bt_value_map_insert_unsigned_integer_entry(info, "id",
-                       ds_file_group->stream_id);
-               if (status != BT_VALUE_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       status = bt_value_map_insert_unsigned_integer_entry(info, "class-id",
-               ds_file_group->sc->id);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int populate_stream_info(struct ctf_fs_ds_file_group *group,
-               bt_value *group_info, struct range *stream_range)
-{
-       int ret = 0;
-       size_t file_idx;
-       bt_value_status status;
-       bt_value *file_paths;
-       struct ctf_fs_ds_index_entry *first_ds_index_entry, *last_ds_index_entry;
-       gchar *port_name = NULL;
-
-       file_paths = bt_value_array_create();
-       if (!file_paths) {
-               ret = -1;
-               goto end;
-       }
-
-       for (file_idx = 0; file_idx < group->ds_file_infos->len; file_idx++) {
-               struct ctf_fs_ds_file_info *info =
-                       g_ptr_array_index(group->ds_file_infos,
-                               file_idx);
-
-               status = bt_value_array_append_string_element(file_paths,
-                               info->path->str);
-               if (status != BT_VALUE_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /*
-        * Since each `struct ctf_fs_ds_file_group` has a sorted array of
-        * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
-        * the timestamp_begin of the first index entry and the timestamp_end
-        * of the last index entry.
-        */
-       BT_ASSERT(group->index);
-       BT_ASSERT(group->index->entries);
-       BT_ASSERT(group->index->entries->len > 0);
-
-       /* First entry. */
-       first_ds_index_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index(
-               group->index->entries, 0);
-
-       /* Last entry. */
-       last_ds_index_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index(
-               group->index->entries, group->index->entries->len - 1);
-
-       stream_range->begin_ns = first_ds_index_entry->timestamp_begin_ns;
-       stream_range->end_ns = last_ds_index_entry->timestamp_end_ns;
-
-       /*
-        * If any of the begin and end timestamps is not set it means that
-        * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
-        * in their packet context so we can't set the range.
-        */
-       stream_range->set = stream_range->begin_ns != UINT64_C(-1) &&
-               stream_range->end_ns != UINT64_C(-1);
-
-       ret = add_range(group_info, stream_range, "range-ns");
-       if (ret) {
-               goto end;
-       }
-
-       status = bt_value_map_insert_entry(group_info, "paths",
-               file_paths);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = add_stream_ids(group_info, group);
-       if (ret) {
-               goto end;
-       }
-
-       port_name = ctf_fs_make_port_name(group);
-       if (!port_name) {
-               ret = -1;
-               goto end;
-       }
-
-       status = bt_value_map_insert_string_entry(group_info, "port-name",
-               port_name);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-end:
-       bt_value_put_ref(file_paths);
-       return ret;
-}
-
-static
-int populate_trace_info(const struct ctf_fs_trace *trace, bt_value *trace_info)
-{
-       int ret = 0;
-       size_t group_idx;
-       bt_value_status status;
-       bt_value *file_groups = NULL;
-       struct range trace_range = {
-               .begin_ns = INT64_MAX,
-               .end_ns = 0,
-               .set = false,
-       };
-       struct range trace_intersection = {
-               .begin_ns = 0,
-               .end_ns = INT64_MAX,
-               .set = false,
-       };
-
-       BT_ASSERT(trace->ds_file_groups);
-       /* Add trace range info only if it contains streams. */
-       if (trace->ds_file_groups->len == 0) {
-               ret = -1;
-               goto end;
-       }
-
-       file_groups = bt_value_array_create();
-       if (!file_groups) {
-               goto end;
-       }
-
-       status = bt_value_map_insert_string_entry(trace_info, "name",
-               trace->name->str);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-       status = bt_value_map_insert_string_entry(trace_info, "path",
-               trace->path->str);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Find range of all stream groups, and of the trace. */
-       for (group_idx = 0; group_idx < trace->ds_file_groups->len;
-                       group_idx++) {
-               bt_value *group_info;
-               struct range group_range = { .set = false };
-               struct ctf_fs_ds_file_group *group = g_ptr_array_index(
-                               trace->ds_file_groups, group_idx);
-
-               group_info = bt_value_map_create();
-               if (!group_info) {
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = populate_stream_info(group, group_info, &group_range);
-               if (ret) {
-                       bt_value_put_ref(group_info);
-                       goto end;
-               }
-
-               status = bt_value_array_append_element(file_groups, group_info);
-               bt_value_put_ref(group_info);
-               if (status != BT_VALUE_STATUS_OK) {
-                       goto end;
-               }
-
-               if (group_range.set) {
-                       trace_range.begin_ns = min(trace_range.begin_ns,
-                                       group_range.begin_ns);
-                       trace_range.end_ns = max(trace_range.end_ns,
-                                       group_range.end_ns);
-                       trace_range.set = true;
-
-                       trace_intersection.begin_ns = max(trace_intersection.begin_ns,
-                                       group_range.begin_ns);
-                       trace_intersection.end_ns = min(trace_intersection.end_ns,
-                                       group_range.end_ns);
-                       trace_intersection.set = true;
-               }
-       }
-
-       ret = add_range(trace_info, &trace_range, "range-ns");
-       if (ret) {
-               goto end;
-       }
-
-       if (trace_intersection.begin_ns < trace_intersection.end_ns) {
-               ret = add_range(trace_info, &trace_intersection,
-                               "intersection-range-ns");
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       status = bt_value_map_insert_entry(trace_info, "streams",
-               file_groups);
-       BT_VALUE_PUT_REF_AND_RESET(file_groups);
-       if (status != BT_VALUE_STATUS_OK) {
-               ret = -1;
-               goto end;
-       }
-
-end:
-       bt_value_put_ref(file_groups);
-       return ret;
-}
-
-BT_HIDDEN
-bt_query_status trace_info_query(
-               bt_self_component_class_source *comp_class,
-               const bt_value *params,
-               const bt_value **user_result)
-{
-       struct ctf_fs_component *ctf_fs = NULL;
-       bt_query_status status = BT_QUERY_STATUS_OK;
-       bt_value *result = NULL;
-       const bt_value *paths_value = NULL;
-       int ret = 0;
-       guint i;
-
-       BT_ASSERT(params);
-
-       if (!bt_value_is_map(params)) {
-               BT_LOGE("Query parameters is not a map value object.");
-               status = BT_QUERY_STATUS_INVALID_PARAMS;
-               goto error;
-       }
-
-       ctf_fs = ctf_fs_component_create();
-       if (!ctf_fs) {
-               goto error;
-       }
-
-       if (!read_src_fs_parameters(params, &paths_value, ctf_fs)) {
-               status = BT_QUERY_STATUS_INVALID_PARAMS;
-               goto error;
-       }
-
-       if (ctf_fs_component_create_ctf_fs_traces(NULL, ctf_fs, paths_value)) {
-               goto error;
-       }
-
-       result = bt_value_array_create();
-       if (!result) {
-               status = BT_QUERY_STATUS_NOMEM;
-               goto error;
-       }
-
-       for (i = 0; i < ctf_fs->traces->len; i++) {
-               struct ctf_fs_trace *trace;
-               bt_value *trace_info;
-               bt_value_status status;
-
-               trace = g_ptr_array_index(ctf_fs->traces, i);
-               BT_ASSERT(trace);
-
-               trace_info = bt_value_map_create();
-               if (!trace_info) {
-                       BT_LOGE("Failed to create trace info map.");
-                       goto error;
-               }
-
-               ret = populate_trace_info(trace, trace_info);
-               if (ret) {
-                       bt_value_put_ref(trace_info);
-                       goto error;
-               }
-
-               status = bt_value_array_append_element(result, trace_info);
-               bt_value_put_ref(trace_info);
-               if (status != BT_VALUE_STATUS_OK) {
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(result);
-       result = NULL;
-
-       if (status >= 0) {
-               status = BT_QUERY_STATUS_ERROR;
-       }
-
-end:
-       if (ctf_fs) {
-               ctf_fs_destroy(ctf_fs);
-               ctf_fs = NULL;
-       }
-
-       *user_result = result;
-       return status;
-}
diff --git a/plugins/ctf/fs-src/query.h b/plugins/ctf/fs-src/query.h
deleted file mode 100644 (file)
index d19a139..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_FS_QUERY_H
-#define BABELTRACE_PLUGIN_CTF_FS_QUERY_H
-
-/*
- * BabelTrace - CTF on File System Component
- *
- * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-BT_HIDDEN
-bt_query_status metadata_info_query(
-               bt_self_component_class_source *comp_class,
-               const bt_value *params, const bt_value **result);
-
-BT_HIDDEN
-bt_query_status trace_info_query(
-               bt_self_component_class_source *comp_class,
-               const bt_value *params, const bt_value **result);
-
-#endif /* BABELTRACE_PLUGIN_CTF_FS_QUERY_H */
diff --git a/plugins/ctf/lttng-live/Makefile.am b/plugins/ctf/lttng-live/Makefile.am
deleted file mode 100644 (file)
index aecd839..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-libbabeltrace2_plugin_ctf_lttng_live_la_SOURCES = \
-               lttng-live.c \
-               lttng-live.h \
-               data-stream.c \
-               data-stream.h \
-               metadata.c \
-               metadata.h \
-               viewer-connection.c \
-               viewer-connection.h \
-               lttng-viewer-abi.h \
-               logging.c \
-               logging.h
-
-if BABELTRACE_BUILD_WITH_MINGW
-libbabeltrace2_plugin_ctf_lttng_live_la_LIBADD = -lws2_32
-endif
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-ctf-lttng-live.la
diff --git a/plugins/ctf/lttng-live/data-stream.c b/plugins/ctf/lttng-live/data-stream.c
deleted file mode 100644 (file)
index d617c30..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-LIVE-SRC-DS"
-#include "logging.h"
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <babeltrace2/compat/mman-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include "../common/msg-iter/msg-iter.h"
-#include <babeltrace2/assert-internal.h>
-
-#include "data-stream.h"
-
-#define STREAM_NAME_PREFIX     "stream-"
-
-static
-enum bt_msg_iter_medium_status medop_request_bytes(
-               size_t request_sz, uint8_t **buffer_addr,
-               size_t *buffer_sz, void *data)
-{
-       enum bt_msg_iter_medium_status status =
-               BT_MSG_ITER_MEDIUM_STATUS_OK;
-       struct lttng_live_stream_iterator *stream = data;
-       struct lttng_live_trace *trace = stream->trace;
-       struct lttng_live_session *session = trace->session;
-       struct lttng_live_msg_iter *live_msg_iter = session->lttng_live_msg_iter;
-       uint64_t recv_len = 0;
-       uint64_t len_left;
-       uint64_t read_len;
-
-       len_left = stream->base_offset + stream->len - stream->offset;
-       if (!len_left) {
-               stream->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
-               status = BT_MSG_ITER_MEDIUM_STATUS_AGAIN;
-               return status;
-       }
-       read_len = MIN(request_sz, stream->buflen);
-       read_len = MIN(read_len, len_left);
-       status = lttng_live_get_stream_bytes(live_msg_iter,
-                       stream, stream->buf, stream->offset,
-                       read_len, &recv_len);
-       *buffer_addr = stream->buf;
-       *buffer_sz = recv_len;
-       stream->offset += recv_len;
-       return status;
-}
-
-static
-bt_stream *medop_borrow_stream(bt_stream_class *stream_class,
-               int64_t stream_id, void *data)
-{
-       struct lttng_live_stream_iterator *lttng_live_stream = data;
-
-       if (!lttng_live_stream->stream) {
-               uint64_t stream_class_id = bt_stream_class_get_id(stream_class);
-
-               BT_LOGD("Creating stream %s (ID: %" PRIu64 ") out of stream "
-                       "class %" PRId64, lttng_live_stream->name->str,
-                       stream_id, stream_class_id);
-
-               if (stream_id < 0) {
-                       /*
-                        * No stream instance ID in the stream. It's possible
-                        * to encounter this situation with older version of
-                        * LTTng. In these cases, use the viewer_stream_id that
-                        * is unique for a live viewer session.
-                        */
-                       lttng_live_stream->stream = bt_stream_create_with_id(
-                               stream_class, lttng_live_stream->trace->trace,
-                               lttng_live_stream->viewer_stream_id);
-               } else {
-                       lttng_live_stream->stream = bt_stream_create_with_id(
-                               stream_class, lttng_live_stream->trace->trace,
-                               (uint64_t) stream_id);
-               }
-
-               if (!lttng_live_stream->stream) {
-                       BT_LOGE("Cannot create stream %s (stream class ID "
-                               "%" PRId64 ", stream ID %" PRIu64 ")",
-                               lttng_live_stream->name->str,
-                               stream_class_id, stream_id);
-               }
-               bt_stream_set_name(lttng_live_stream->stream,
-                       lttng_live_stream->name->str);
-       }
-
-       return lttng_live_stream->stream;
-}
-
-static struct bt_msg_iter_medium_ops medops = {
-       .request_bytes = medop_request_bytes,
-       .seek = NULL,
-       .borrow_stream = medop_borrow_stream,
-};
-
-BT_HIDDEN
-enum lttng_live_iterator_status lttng_live_lazy_msg_init(
-               struct lttng_live_session *session)
-{
-       struct lttng_live_component *lttng_live =
-               session->lttng_live_msg_iter->lttng_live_comp;
-       uint64_t trace_idx, stream_iter_idx;
-
-       if (!session->lazy_stream_msg_init) {
-               return LTTNG_LIVE_ITERATOR_STATUS_OK;
-       }
-
-       for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
-               struct lttng_live_trace *trace =
-                       g_ptr_array_index(session->traces, trace_idx);
-
-               for (stream_iter_idx = 0;
-                               stream_iter_idx < trace->stream_iterators->len;
-                               stream_iter_idx++) {
-                       struct ctf_trace_class *ctf_tc;
-                       struct lttng_live_stream_iterator *stream_iter =
-                               g_ptr_array_index(trace->stream_iterators,
-                                               stream_iter_idx);
-
-                       if (stream_iter->msg_iter) {
-                               continue;
-                       }
-                       ctf_tc = ctf_metadata_decoder_borrow_ctf_trace_class(
-                                               trace->metadata->decoder);
-                       stream_iter->msg_iter = bt_msg_iter_create(ctf_tc,
-                                       lttng_live->max_query_size, medops,
-                                       stream_iter);
-                       if (!stream_iter->msg_iter) {
-                               goto error;
-                       }
-               }
-       }
-
-       session->lazy_stream_msg_init = false;
-
-       return LTTNG_LIVE_ITERATOR_STATUS_OK;
-
-error:
-       return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-}
-
-BT_HIDDEN
-struct lttng_live_stream_iterator *lttng_live_stream_iterator_create(
-               struct lttng_live_session *session,
-               uint64_t ctf_trace_id,
-               uint64_t stream_id)
-{
-       struct lttng_live_stream_iterator *stream_iter;
-       struct lttng_live_component *lttng_live;
-       struct lttng_live_trace *trace;
-
-       BT_ASSERT(session);
-       BT_ASSERT(session->lttng_live_msg_iter);
-       BT_ASSERT(session->lttng_live_msg_iter->lttng_live_comp);
-
-       lttng_live = session->lttng_live_msg_iter->lttng_live_comp;
-
-       stream_iter = g_new0(struct lttng_live_stream_iterator, 1);
-       if (!stream_iter) {
-               goto error;
-       }
-
-       trace = lttng_live_borrow_trace(session, ctf_trace_id);
-       if (!trace) {
-               goto error;
-       }
-
-       stream_iter->trace = trace;
-       stream_iter->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
-       stream_iter->viewer_stream_id = stream_id;
-       stream_iter->ctf_stream_class_id = -1ULL;
-       stream_iter->last_inactivity_ts = INT64_MIN;
-
-       if (trace->trace) {
-               struct ctf_trace_class *ctf_tc =
-                       ctf_metadata_decoder_borrow_ctf_trace_class(
-                                       trace->metadata->decoder);
-               BT_ASSERT(!stream_iter->msg_iter);
-               stream_iter->msg_iter = bt_msg_iter_create(ctf_tc,
-                               lttng_live->max_query_size, medops,
-                               stream_iter);
-               if (!stream_iter->msg_iter) {
-                       goto error;
-               }
-       }
-       stream_iter->buf = g_new0(uint8_t, lttng_live->max_query_size);
-       if (!stream_iter->buf) {
-               goto error;
-       }
-
-       stream_iter->buflen = lttng_live->max_query_size;
-       stream_iter->name = g_string_new(NULL);
-       if (!stream_iter->name) {
-               goto error;
-       }
-
-       g_string_printf(stream_iter->name, STREAM_NAME_PREFIX "%" PRIu64,
-                       stream_iter->viewer_stream_id);
-       g_ptr_array_add(trace->stream_iterators, stream_iter);
-
-       /* Track the number of active stream iterator. */
-       session->lttng_live_msg_iter->active_stream_iter++;
-
-       goto end;
-error:
-       lttng_live_stream_iterator_destroy(stream_iter);
-       stream_iter = NULL;
-end:
-       return stream_iter;
-}
-
-BT_HIDDEN
-void lttng_live_stream_iterator_destroy(
-               struct lttng_live_stream_iterator *stream_iter)
-{
-       if (!stream_iter) {
-               return;
-       }
-
-       if (stream_iter->stream) {
-               BT_STREAM_PUT_REF_AND_RESET(stream_iter->stream);
-       }
-
-       if (stream_iter->msg_iter) {
-               bt_msg_iter_destroy(stream_iter->msg_iter);
-       }
-       if (stream_iter->buf) {
-               g_free(stream_iter->buf);
-       }
-       if (stream_iter->name) {
-               g_string_free(stream_iter->name, TRUE);
-       }
-
-       bt_message_put_ref(stream_iter->current_msg);
-
-       /* Track the number of active stream iterator. */
-       stream_iter->trace->session->lttng_live_msg_iter->active_stream_iter--;
-
-       /*
-        * Ensure we poke the trace metadata in the future, which is
-        * required to release the metadata reference on the trace.
-        */
-       stream_iter->trace->new_metadata_needed = true;
-       g_free(stream_iter);
-}
diff --git a/plugins/ctf/lttng-live/data-stream.h b/plugins/ctf/lttng-live/data-stream.h
deleted file mode 100644 (file)
index 8ae5e59..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef LTTNG_LIVE_DATA_STREAM_H
-#define LTTNG_LIVE_DATA_STREAM_H
-
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "lttng-live.h"
-#include "../common/msg-iter/msg-iter.h"
-
-enum lttng_live_iterator_status lttng_live_lazy_msg_init(
-               struct lttng_live_session *session);
-
-struct lttng_live_stream_iterator *lttng_live_stream_iterator_create(
-               struct lttng_live_session *session,
-               uint64_t ctf_trace_id,
-               uint64_t stream_id);
-
-void lttng_live_stream_iterator_destroy(
-               struct lttng_live_stream_iterator *stream);
-
-#endif /* LTTNG_LIVE_DATA_STREAM_H */
diff --git a/plugins/ctf/lttng-live/logging.c b/plugins/ctf/lttng-live/logging.c
deleted file mode 100644 (file)
index bb08159..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL lttng_live_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(lttng_live_log_level, "BABELTRACE_SRC_CTF_LTTNG_LIVE_LOG_LEVEL");
diff --git a/plugins/ctf/lttng-live/logging.h b/plugins/ctf/lttng-live/logging.h
deleted file mode 100644 (file)
index cd9b071..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef LTTNG_LIVE_LOGGING_H
-#define LTTNG_LIVE_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL lttng_live_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(lttng_live_log_level);
-
-#endif /* LTTNG_LIVE_LOGGING_H */
diff --git a/plugins/ctf/lttng-live/lttng-live.c b/plugins/ctf/lttng-live/lttng-live.c
deleted file mode 100644 (file)
index 24544a3..0000000
+++ /dev/null
@@ -1,1601 +0,0 @@
-/*
- * lttng-live.c
- *
- * Babeltrace CTF LTTng-live Client Component
- *
- * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-LIVE-SRC"
-#include "logging.h"
-
-#include <glib.h>
-#include <inttypes.h>
-#include <unistd.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/types.h>
-#include <plugins-common.h>
-
-#include "data-stream.h"
-#include "metadata.h"
-#include "lttng-live.h"
-
-#define MAX_QUERY_SIZE                     (256*1024)
-#define URL_PARAM                          "url"
-#define SESS_NOT_FOUND_ACTION_PARAM        "session-not-found-action"
-#define SESS_NOT_FOUND_ACTION_CONTINUE_STR  "continue"
-#define SESS_NOT_FOUND_ACTION_FAIL_STR     "fail"
-#define SESS_NOT_FOUND_ACTION_END_STR      "end"
-
-#define print_dbg(fmt, ...)    BT_LOGD(fmt, ## __VA_ARGS__)
-
-static
-const char *print_live_iterator_status(enum lttng_live_iterator_status status)
-{
-       switch (status) {
-       case LTTNG_LIVE_ITERATOR_STATUS_CONTINUE:
-               return "LTTNG_LIVE_ITERATOR_STATUS_CONTINUE";
-       case LTTNG_LIVE_ITERATOR_STATUS_AGAIN:
-               return "LTTNG_LIVE_ITERATOR_STATUS_AGAIN";
-       case LTTNG_LIVE_ITERATOR_STATUS_END:
-               return "LTTNG_LIVE_ITERATOR_STATUS_END";
-       case LTTNG_LIVE_ITERATOR_STATUS_OK:
-               return "LTTNG_LIVE_ITERATOR_STATUS_OK";
-       case LTTNG_LIVE_ITERATOR_STATUS_INVAL:
-               return "LTTNG_LIVE_ITERATOR_STATUS_INVAL";
-       case LTTNG_LIVE_ITERATOR_STATUS_ERROR:
-               return "LTTNG_LIVE_ITERATOR_STATUS_ERROR";
-       case LTTNG_LIVE_ITERATOR_STATUS_NOMEM:
-               return "LTTNG_LIVE_ITERATOR_STATUS_NOMEM";
-       case LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED:
-               return "LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED";
-       default:
-               abort();
-       }
-}
-
-static
-const char *print_state(struct lttng_live_stream_iterator *s)
-{
-       switch (s->state) {
-       case LTTNG_LIVE_STREAM_ACTIVE_NO_DATA:
-               return "ACTIVE_NO_DATA";
-       case LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA:
-               return "QUIESCENT_NO_DATA";
-       case LTTNG_LIVE_STREAM_QUIESCENT:
-               return "QUIESCENT";
-       case LTTNG_LIVE_STREAM_ACTIVE_DATA:
-               return "ACTIVE_DATA";
-       case LTTNG_LIVE_STREAM_EOF:
-               return "EOF";
-       default:
-               return "ERROR";
-       }
-}
-
-#define print_stream_state(live_stream_iter) \
-       do { \
-               BT_LOGD("stream state %s last_inact_ts %" PRId64  \
-                       ", curr_inact_ts %" PRId64, \
-                       print_state(live_stream_iter), \
-                       live_stream_iter->last_inactivity_ts, \
-                       live_stream_iter->current_inactivity_ts); \
-       } while (0);
-
-BT_HIDDEN
-bool lttng_live_graph_is_canceled(struct lttng_live_component *lttng_live)
-{
-       const bt_component *component;
-       bool ret;
-
-       if (!lttng_live) {
-               ret = false;
-               goto end;
-       }
-
-       component = bt_component_source_as_component_const(
-               bt_self_component_source_as_component_source(
-               lttng_live->self_comp));
-
-       ret = bt_component_graph_is_canceled(component);
-
-end:
-       return ret;
-}
-
-static
-struct lttng_live_trace *lttng_live_find_trace(struct lttng_live_session *session,
-               uint64_t trace_id)
-{
-       uint64_t trace_idx;
-       struct lttng_live_trace *ret_trace = NULL;
-
-       for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
-               struct lttng_live_trace *trace =
-                       g_ptr_array_index(session->traces, trace_idx);
-               if (trace->id == trace_id) {
-                       ret_trace = trace;
-                       goto end;
-               }
-       }
-
-end:
-       return ret_trace;
-}
-
-static
-void lttng_live_destroy_trace(struct lttng_live_trace *trace)
-{
-       BT_LOGD("Destroy lttng_live_trace");
-
-       BT_ASSERT(trace->stream_iterators);
-       g_ptr_array_free(trace->stream_iterators, TRUE);
-
-       BT_TRACE_PUT_REF_AND_RESET(trace->trace);
-       BT_TRACE_CLASS_PUT_REF_AND_RESET(trace->trace_class);
-
-       lttng_live_metadata_fini(trace);
-       g_free(trace);
-}
-
-static
-struct lttng_live_trace *lttng_live_create_trace(struct lttng_live_session *session,
-               uint64_t trace_id)
-{
-       struct lttng_live_trace *trace = NULL;
-
-       trace = g_new0(struct lttng_live_trace, 1);
-       if (!trace) {
-               goto error;
-       }
-       trace->session = session;
-       trace->id = trace_id;
-       trace->trace_class = NULL;
-       trace->trace = NULL;
-       trace->stream_iterators = g_ptr_array_new_with_free_func(
-                       (GDestroyNotify) lttng_live_stream_iterator_destroy);
-       BT_ASSERT(trace->stream_iterators);
-       trace->new_metadata_needed = true;
-       g_ptr_array_add(session->traces, trace);
-
-       BT_LOGI("Create trace");
-       goto end;
-error:
-       g_free(trace);
-       trace = NULL;
-end:
-       return trace;
-}
-
-BT_HIDDEN
-struct lttng_live_trace *lttng_live_borrow_trace(
-               struct lttng_live_session *session, uint64_t trace_id)
-{
-       struct lttng_live_trace *trace;
-
-       trace = lttng_live_find_trace(session, trace_id);
-       if (trace) {
-               goto end;
-       }
-
-       /* The session is the owner of the newly created trace. */
-       trace = lttng_live_create_trace(session, trace_id);
-
-end:
-       return trace;
-}
-
-BT_HIDDEN
-int lttng_live_add_session(struct lttng_live_msg_iter *lttng_live_msg_iter,
-               uint64_t session_id, const char *hostname,
-               const char *session_name)
-{
-       int ret = 0;
-       struct lttng_live_session *session;
-
-       session = g_new0(struct lttng_live_session, 1);
-       if (!session) {
-               goto error;
-       }
-
-       session->id = session_id;
-       session->traces = g_ptr_array_new_with_free_func(
-                       (GDestroyNotify) lttng_live_destroy_trace);
-       BT_ASSERT(session->traces);
-       session->lttng_live_msg_iter = lttng_live_msg_iter;
-       session->new_streams_needed = true;
-       session->hostname = g_string_new(hostname);
-       BT_ASSERT(session->hostname);
-
-       session->session_name = g_string_new(session_name);
-       BT_ASSERT(session->session_name);
-
-       BT_LOGI("Reading from session: %" PRIu64 " hostname: %s session_name: %s",
-               session->id, hostname, session_name);
-       g_ptr_array_add(lttng_live_msg_iter->sessions, session);
-       goto end;
-error:
-       BT_LOGE("Error adding session");
-       g_free(session);
-       ret = -1;
-end:
-       return ret;
-}
-
-static
-void lttng_live_destroy_session(struct lttng_live_session *session)
-{
-       struct lttng_live_component *live_comp;
-
-       if (!session) {
-               goto end;
-       }
-
-       BT_LOGD("Destroy lttng live session");
-       if (session->id != -1ULL) {
-               if (lttng_live_detach_session(session)) {
-                       live_comp = session->lttng_live_msg_iter->lttng_live_comp;
-                       if (session->lttng_live_msg_iter &&
-                                       !lttng_live_graph_is_canceled(live_comp)) {
-                               /* Old relayd cannot detach sessions. */
-                               BT_LOGD("Unable to detach lttng live session %" PRIu64,
-                                       session->id);
-                       }
-               }
-               session->id = -1ULL;
-       }
-
-       if (session->traces) {
-               g_ptr_array_free(session->traces, TRUE);
-       }
-
-       if (session->hostname) {
-               g_string_free(session->hostname, TRUE);
-       }
-       if (session->session_name) {
-               g_string_free(session->session_name, TRUE);
-       }
-       g_free(session);
-
-end:
-       return;
-}
-
-static
-void lttng_live_msg_iter_destroy(struct lttng_live_msg_iter *lttng_live_msg_iter)
-{
-       if (!lttng_live_msg_iter) {
-               goto end;
-       }
-
-       if (lttng_live_msg_iter->sessions) {
-               g_ptr_array_free(lttng_live_msg_iter->sessions, TRUE);
-       }
-
-       BT_OBJECT_PUT_REF_AND_RESET(lttng_live_msg_iter->viewer_connection);
-       BT_ASSERT(lttng_live_msg_iter->lttng_live_comp);
-       BT_ASSERT(lttng_live_msg_iter->lttng_live_comp->has_msg_iter);
-
-       /* All stream iterators must be destroyed at this point. */
-       BT_ASSERT(lttng_live_msg_iter->active_stream_iter == 0);
-       lttng_live_msg_iter->lttng_live_comp->has_msg_iter = false;
-
-       g_free(lttng_live_msg_iter);
-
-end:
-       return;
-}
-
-BT_HIDDEN
-void lttng_live_msg_iter_finalize(bt_self_message_iterator *self_msg_iter)
-{
-       struct lttng_live_msg_iter *lttng_live_msg_iter;
-
-       BT_ASSERT(self_msg_iter);
-
-       lttng_live_msg_iter = bt_self_message_iterator_get_data(self_msg_iter);
-       BT_ASSERT(lttng_live_msg_iter);
-       lttng_live_msg_iter_destroy(lttng_live_msg_iter);
-}
-
-static
-enum lttng_live_iterator_status lttng_live_iterator_next_check_stream_state(
-               struct lttng_live_stream_iterator *lttng_live_stream)
-{
-       switch (lttng_live_stream->state) {
-       case LTTNG_LIVE_STREAM_QUIESCENT:
-       case LTTNG_LIVE_STREAM_ACTIVE_DATA:
-               break;
-       case LTTNG_LIVE_STREAM_ACTIVE_NO_DATA:
-               /* Invalid state. */
-               BT_LOGF("Unexpected stream state \"ACTIVE_NO_DATA\"");
-               abort();
-       case LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA:
-               /* Invalid state. */
-               BT_LOGF("Unexpected stream state \"QUIESCENT_NO_DATA\"");
-               abort();
-       case LTTNG_LIVE_STREAM_EOF:
-               break;
-       }
-       return LTTNG_LIVE_ITERATOR_STATUS_OK;
-}
-
-/*
- * For active no data stream, fetch next data. It can be either:
- * - quiescent: need to put it in the prio heap at quiescent end
- *   timestamp,
- * - have data: need to wire up first event into the prio heap,
- * - have no data on this stream at this point: need to retry (AGAIN) or
- *   return EOF.
- */
-static
-enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_no_data_stream(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *lttng_live_stream)
-{
-       enum lttng_live_iterator_status ret =
-                       LTTNG_LIVE_ITERATOR_STATUS_OK;
-       struct packet_index index;
-       enum lttng_live_stream_state orig_state = lttng_live_stream->state;
-
-       if (lttng_live_stream->trace->new_metadata_needed) {
-               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-               goto end;
-       }
-       if (lttng_live_stream->trace->session->new_streams_needed) {
-               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-               goto end;
-       }
-       if (lttng_live_stream->state != LTTNG_LIVE_STREAM_ACTIVE_NO_DATA &&
-                       lttng_live_stream->state != LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA) {
-               goto end;
-       }
-       ret = lttng_live_get_next_index(lttng_live_msg_iter, lttng_live_stream,
-               &index);
-       if (ret != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-               goto end;
-       }
-       BT_ASSERT(lttng_live_stream->state != LTTNG_LIVE_STREAM_EOF);
-       if (lttng_live_stream->state == LTTNG_LIVE_STREAM_QUIESCENT) {
-               uint64_t last_inact_ts = lttng_live_stream->last_inactivity_ts,
-                        curr_inact_ts = lttng_live_stream->current_inactivity_ts;
-
-               if (orig_state == LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA &&
-                               last_inact_ts == curr_inact_ts) {
-                       ret = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-                       print_stream_state(lttng_live_stream);
-               } else {
-                       ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-               }
-               goto end;
-       }
-       lttng_live_stream->base_offset = index.offset;
-       lttng_live_stream->offset = index.offset;
-       lttng_live_stream->len = index.packet_size / CHAR_BIT;
-end:
-       if (ret == LTTNG_LIVE_ITERATOR_STATUS_OK) {
-               ret = lttng_live_iterator_next_check_stream_state(lttng_live_stream);
-       }
-       return ret;
-}
-
-/*
- * Creation of the message requires the ctf trace class to be created
- * beforehand, but the live protocol gives us all streams (including metadata)
- * at once. So we split it in three steps: getting streams, getting metadata
- * (which creates the ctf trace class), and then creating the per-stream
- * messages.
- */
-static
-enum lttng_live_iterator_status lttng_live_get_session(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_session *session)
-{
-       enum lttng_live_iterator_status status;
-       uint64_t trace_idx;
-       int ret = 0;
-
-       if (!session->attached) {
-               ret = lttng_live_attach_session(session);
-               if (ret) {
-                       if (lttng_live_msg_iter && lttng_live_graph_is_canceled(
-                                               lttng_live_msg_iter->lttng_live_comp)) {
-                               status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-                       } else {
-                               status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-                       }
-                       goto end;
-               }
-       }
-
-       status = lttng_live_get_new_streams(session);
-       if (status != LTTNG_LIVE_ITERATOR_STATUS_OK &&
-                       status != LTTNG_LIVE_ITERATOR_STATUS_END) {
-               goto end;
-       }
-       for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
-               struct lttng_live_trace *trace =
-                       g_ptr_array_index(session->traces, trace_idx);
-
-               status = lttng_live_metadata_update(trace);
-               if (status != LTTNG_LIVE_ITERATOR_STATUS_OK &&
-                               status != LTTNG_LIVE_ITERATOR_STATUS_END) {
-                       goto end;
-               }
-       }
-       status = lttng_live_lazy_msg_init(session);
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-void lttng_live_need_new_streams(struct lttng_live_msg_iter *lttng_live_msg_iter)
-{
-       uint64_t session_idx;
-
-       for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len;
-                       session_idx++) {
-               struct lttng_live_session *session =
-                       g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
-               session->new_streams_needed = true;
-       }
-}
-
-static
-void lttng_live_force_new_streams_and_metadata(struct lttng_live_msg_iter *lttng_live_msg_iter)
-{
-       uint64_t session_idx, trace_idx;
-
-       for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len;
-                       session_idx++) {
-               struct lttng_live_session *session =
-                       g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
-               session->new_streams_needed = true;
-               for (trace_idx = 0; trace_idx < session->traces->len;
-                               trace_idx++) {
-                       struct lttng_live_trace *trace =
-                               g_ptr_array_index(session->traces, trace_idx);
-                       trace->new_metadata_needed = true;
-               }
-       }
-}
-
-static
-enum lttng_live_iterator_status
-lttng_live_iterator_handle_new_streams_and_metadata(
-               struct lttng_live_msg_iter *lttng_live_msg_iter)
-{
-       enum lttng_live_iterator_status ret =
-                       LTTNG_LIVE_ITERATOR_STATUS_OK;
-       uint64_t session_idx = 0, nr_sessions_opened = 0;
-       struct lttng_live_session *session;
-       enum session_not_found_action sess_not_found_act =
-               lttng_live_msg_iter->lttng_live_comp->params.sess_not_found_act;
-
-       /*
-        * In a remotely distant future, we could add a "new
-        * session" flag to the protocol, which would tell us that we
-        * need to query for new sessions even though we have sessions
-        * currently ongoing.
-        */
-       if (lttng_live_msg_iter->sessions->len == 0) {
-               if (sess_not_found_act != SESSION_NOT_FOUND_ACTION_CONTINUE) {
-                       ret = LTTNG_LIVE_ITERATOR_STATUS_END;
-                       goto end;
-               } else {
-                       /*
-                        * Retry to create a viewer session for the requested
-                        * session name.
-                        */
-                       if (lttng_live_create_viewer_session(lttng_live_msg_iter)) {
-                               ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-               }
-       }
-
-       for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len;
-                       session_idx++) {
-               session = g_ptr_array_index(lttng_live_msg_iter->sessions,
-                               session_idx);
-               ret = lttng_live_get_session(lttng_live_msg_iter, session);
-               switch (ret) {
-               case LTTNG_LIVE_ITERATOR_STATUS_OK:
-                       break;
-               case LTTNG_LIVE_ITERATOR_STATUS_END:
-                       ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
-                       break;
-               default:
-                       goto end;
-               }
-               if (!session->closed) {
-                       nr_sessions_opened++;
-               }
-       }
-end:
-       if (ret == LTTNG_LIVE_ITERATOR_STATUS_OK &&
-                       sess_not_found_act != SESSION_NOT_FOUND_ACTION_CONTINUE &&
-                       nr_sessions_opened == 0) {
-               ret = LTTNG_LIVE_ITERATOR_STATUS_END;
-       }
-       return ret;
-}
-
-static
-enum lttng_live_iterator_status emit_inactivity_message(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *stream_iter,
-               bt_message **message, uint64_t timestamp)
-{
-       enum lttng_live_iterator_status ret =
-                       LTTNG_LIVE_ITERATOR_STATUS_OK;
-       bt_message *msg = NULL;
-
-       BT_ASSERT(stream_iter->trace->clock_class);
-
-       msg = bt_message_message_iterator_inactivity_create(
-                       lttng_live_msg_iter->self_msg_iter,
-                       stream_iter->trace->clock_class,
-                       timestamp);
-       if (!msg) {
-               goto error;
-       }
-
-       *message = msg;
-end:
-       return ret;
-
-error:
-       ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-       bt_message_put_ref(msg);
-       goto end;
-}
-
-static
-enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_quiescent_stream(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *lttng_live_stream,
-               bt_message **message)
-{
-       enum lttng_live_iterator_status ret =
-                       LTTNG_LIVE_ITERATOR_STATUS_OK;
-
-       if (lttng_live_stream->state != LTTNG_LIVE_STREAM_QUIESCENT) {
-               return LTTNG_LIVE_ITERATOR_STATUS_OK;
-       }
-
-       if (lttng_live_stream->current_inactivity_ts ==
-                       lttng_live_stream->last_inactivity_ts) {
-               lttng_live_stream->state = LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA;
-               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-               goto end;
-       }
-
-       ret = emit_inactivity_message(lttng_live_msg_iter, lttng_live_stream,
-                       message, lttng_live_stream->current_inactivity_ts);
-
-       lttng_live_stream->last_inactivity_ts =
-                       lttng_live_stream->current_inactivity_ts;
-end:
-       return ret;
-}
-
-static
-int live_get_msg_ts_ns(struct lttng_live_stream_iterator *stream_iter,
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               const bt_message *msg, int64_t last_msg_ts_ns,
-               int64_t *ts_ns)
-{
-       const bt_clock_class *clock_class = NULL;
-       const bt_clock_snapshot *clock_snapshot = NULL;
-       int ret = 0;
-       bt_message_stream_activity_clock_snapshot_state sa_cs_state;
-
-       BT_ASSERT(msg);
-       BT_ASSERT(ts_ns);
-
-       BT_LOGV("Getting message's timestamp: iter-data-addr=%p, msg-addr=%p, "
-               "last-msg-ts=%" PRId64, lttng_live_msg_iter, msg,
-               last_msg_ts_ns);
-
-       switch (bt_message_get_type(msg)) {
-       case BT_MESSAGE_TYPE_EVENT:
-               clock_class =
-                       bt_message_event_borrow_stream_class_default_clock_class_const(
-                               msg);
-               BT_ASSERT(clock_class);
-
-               clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-               clock_class =
-                       bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
-                       msg);
-               BT_ASSERT(clock_class);
-
-               clock_snapshot = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_PACKET_END:
-               clock_class =
-                       bt_message_packet_end_borrow_stream_class_default_clock_class_const(
-                       msg);
-               BT_ASSERT(clock_class);
-
-               clock_snapshot = bt_message_packet_end_borrow_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-               clock_class =
-                       bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
-                       msg);
-               BT_ASSERT(clock_class);
-
-               clock_snapshot = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-               clock_class =
-                       bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
-                       msg);
-               BT_ASSERT(clock_class);
-
-               clock_snapshot = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-               clock_class =
-                       bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
-                       msg);
-               BT_ASSERT(clock_class);
-
-               sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
-                       msg, &clock_snapshot);
-               if (sa_cs_state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-               clock_class =
-                       bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
-                       msg);
-               BT_ASSERT(clock_class);
-
-               sa_cs_state = bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
-                       msg, &clock_snapshot);
-               if (sa_cs_state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-               clock_snapshot =
-                       bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
-                               msg);
-               break;
-       default:
-               /* All the other messages have a higher priority */
-               BT_LOGV_STR("Message has no timestamp: using the last message timestamp.");
-               *ts_ns = last_msg_ts_ns;
-               goto end;
-       }
-
-       clock_class = bt_clock_snapshot_borrow_clock_class_const(clock_snapshot);
-       BT_ASSERT(clock_class);
-
-       ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot, ts_ns);
-       if (ret) {
-               BT_LOGE("Cannot get nanoseconds from Epoch of clock snapshot: "
-                       "clock-snapshot-addr=%p", clock_snapshot);
-               goto error;
-       }
-
-       goto end;
-
-no_clock_snapshot:
-       BT_LOGV_STR("Message's default clock snapshot is missing: "
-               "using the last message timestamp.");
-       *ts_ns = last_msg_ts_ns;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       if (ret == 0) {
-               BT_LOGV("Found message's timestamp: "
-                       "iter-data-addr=%p, msg-addr=%p, "
-                       "last-msg-ts=%" PRId64 ", ts=%" PRId64,
-                       lttng_live_msg_iter, msg, last_msg_ts_ns, *ts_ns);
-       }
-
-       return ret;
-}
-
-static
-enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_active_data_stream(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *lttng_live_stream,
-               bt_message **message)
-{
-       enum lttng_live_iterator_status ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
-       enum bt_msg_iter_status status;
-       uint64_t session_idx, trace_idx;
-
-       for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len;
-                       session_idx++) {
-               struct lttng_live_session *session =
-                       g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
-
-               if (session->new_streams_needed) {
-                       ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-                       goto end;
-               }
-               for (trace_idx = 0; trace_idx < session->traces->len;
-                               trace_idx++) {
-                       struct lttng_live_trace *trace =
-                               g_ptr_array_index(session->traces, trace_idx);
-                       if (trace->new_metadata_needed) {
-                               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-                               goto end;
-                       }
-               }
-       }
-
-       if (lttng_live_stream->state != LTTNG_LIVE_STREAM_ACTIVE_DATA) {
-               ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       status = bt_msg_iter_get_next_message(lttng_live_stream->msg_iter,
-               lttng_live_msg_iter->self_msg_iter, message);
-       switch (status) {
-       case BT_MSG_ITER_STATUS_EOF:
-               ret = LTTNG_LIVE_ITERATOR_STATUS_END;
-               break;
-       case BT_MSG_ITER_STATUS_OK:
-               ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
-               break;
-       case BT_MSG_ITER_STATUS_AGAIN:
-               /*
-                * Continue immediately (end of packet). The next
-                * get_index may return AGAIN to delay the following
-                * attempt.
-                */
-               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
-               break;
-       case BT_MSG_ITER_STATUS_INVAL:
-               /* No argument provided by the user, so don't return INVAL. */
-       case BT_MSG_ITER_STATUS_ERROR:
-       default:
-               ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-               BT_LOGW("CTF msg iterator return an error or failed msg_iter=%p",
-                       lttng_live_stream->msg_iter);
-               break;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * helper function:
- *            handle_no_data_streams()
- *              retry:
- *                - for each ACTIVE_NO_DATA stream:
- *                  - query relayd for stream data, or quiescence info.
- *                    - if need metadata, get metadata, goto retry.
- *                    - if new stream, get new stream as ACTIVE_NO_DATA, goto retry
- *                  - if quiescent, move to QUIESCENT streams
- *                  - if fetched data, move to ACTIVE_DATA streams
- *                (at this point each stream either has data, or is quiescent)
- *
- *
- * iterator_next:
- *            handle_new_streams_and_metadata()
- *                  - query relayd for known streams, add them as ACTIVE_NO_DATA
- *                  - query relayd for metadata
- *
- *            call handle_active_no_data_streams()
- *
- *            handle_quiescent_streams()
- *                - if at least one stream is ACTIVE_DATA:
- *                  - peek stream event with lowest timestamp -> next_ts
- *                  - for each quiescent stream
- *                    - if next_ts >= quiescent end
- *                      - set state to ACTIVE_NO_DATA
- *                - else
- *                  - for each quiescent stream
- *                      - set state to ACTIVE_NO_DATA
- *
- *            call handle_active_no_data_streams()
- *
- *            handle_active_data_streams()
- *                - if at least one stream is ACTIVE_DATA:
- *                    - get stream event with lowest timestamp from heap
- *                    - make that stream event the current message.
- *                    - move this stream heap position to its next event
- *                      - if we need to fetch data from relayd, move
- *                        stream to ACTIVE_NO_DATA.
- *                    - return OK
- *                - return AGAIN
- *
- * end criterion: ctrl-c on client. If relayd exits or the session
- * closes on the relay daemon side, we keep on waiting for streams.
- * Eventually handle --end timestamp (also an end criterion).
- *
- * When disconnected from relayd: try to re-connect endlessly.
- */
-static
-enum lttng_live_iterator_status lttng_live_iterator_next_on_stream(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *stream_iter,
-               bt_message **curr_msg)
-{
-       enum lttng_live_iterator_status live_status;
-
-retry:
-       print_stream_state(stream_iter);
-       live_status = lttng_live_iterator_handle_new_streams_and_metadata(
-                       lttng_live_msg_iter);
-       if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-               goto end;
-       }
-       live_status = lttng_live_iterator_next_handle_one_no_data_stream(
-                       lttng_live_msg_iter, stream_iter);
-       if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-               goto end;
-       }
-       live_status = lttng_live_iterator_next_handle_one_quiescent_stream(
-                       lttng_live_msg_iter, stream_iter, curr_msg);
-       if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-               BT_ASSERT(*curr_msg == NULL);
-               goto end;
-       }
-       if (*curr_msg) {
-               goto end;
-       }
-       live_status = lttng_live_iterator_next_handle_one_active_data_stream(
-                       lttng_live_msg_iter, stream_iter, curr_msg);
-       if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-               BT_ASSERT(*curr_msg == NULL);
-       }
-
-end:
-       if (live_status == LTTNG_LIVE_ITERATOR_STATUS_CONTINUE) {
-               goto retry;
-       }
-
-       return live_status;
-}
-
-static
-enum lttng_live_iterator_status next_stream_iterator_for_trace(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_trace *live_trace,
-               struct lttng_live_stream_iterator **candidate_stream_iter)
-{
-       struct lttng_live_stream_iterator *curr_candidate_stream_iter = NULL;
-       enum lttng_live_iterator_status stream_iter_status;;
-       int64_t curr_candidate_msg_ts = INT64_MAX;
-       uint64_t stream_iter_idx;
-
-       BT_ASSERT(live_trace);
-       BT_ASSERT(live_trace->stream_iterators);
-       /*
-        * Update the current message of every stream iterators of this trace.
-        * The current msg of every stream must have a timestamp equal or
-        * larger than the last message returned by this iterator. We must
-        * ensure monotonicity.
-        */
-       stream_iter_idx = 0;
-       while (stream_iter_idx < live_trace->stream_iterators->len) {
-               bool stream_iter_is_ended = false;
-               struct lttng_live_stream_iterator *stream_iter =
-                       g_ptr_array_index(live_trace->stream_iterators,
-                                       stream_iter_idx);
-
-               /*
-                * Find if there is are now current message for this stream
-                * iterator get it.
-                */
-               while (!stream_iter->current_msg) {
-                       bt_message *msg = NULL;
-                       int64_t curr_msg_ts_ns = INT64_MAX;
-                       stream_iter_status = lttng_live_iterator_next_on_stream(
-                                       lttng_live_msg_iter, stream_iter, &msg);
-
-                       BT_LOGD("live stream iterator returned status :%s",
-                                       print_live_iterator_status(stream_iter_status));
-                       if (stream_iter_status == LTTNG_LIVE_ITERATOR_STATUS_END) {
-                               stream_iter_is_ended = true;
-                               break;
-                       }
-
-                       if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       BT_ASSERT(msg);
-
-                       /*
-                        * Get the timestamp in nanoseconds from origin of this
-                        * messsage.
-                        */
-                       live_get_msg_ts_ns(stream_iter, lttng_live_msg_iter,
-                               msg, lttng_live_msg_iter->last_msg_ts_ns,
-                               &curr_msg_ts_ns);
-
-                       /*
-                        * Check if the message of the current live stream
-                        * iterator occured at the exact same time or after the
-                        * last message returned by this component's message
-                        * iterator. If not, we return an error.
-                        */
-                       if (curr_msg_ts_ns >= lttng_live_msg_iter->last_msg_ts_ns) {
-                               stream_iter->current_msg = msg;
-                               stream_iter->current_msg_ts_ns = curr_msg_ts_ns;
-                       } else {
-                               /*
-                                * We received a message in the past. To ensure
-                                * monotonicity, we can't send it forward.
-                                */
-                               BT_LOGE("Message's timestamp is less than "
-                                       "lttng-live's message iterator's last "
-                                       "returned timestamp: "
-                                       "lttng-live-msg-iter-addr=%p, ts=%" PRId64 ", "
-                                       "last-msg-ts=%" PRId64,
-                                       lttng_live_msg_iter, curr_msg_ts_ns,
-                                       lttng_live_msg_iter->last_msg_ts_ns);
-                               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-               }
-
-               if (!stream_iter_is_ended &&
-                               stream_iter->current_msg_ts_ns <= curr_candidate_msg_ts) {
-                       /*
-                        * Update the current best candidate message for the
-                        * stream iterator of thise live trace to be forwarded
-                        * downstream.
-                        */
-                       curr_candidate_msg_ts = stream_iter->current_msg_ts_ns;
-                       curr_candidate_stream_iter = stream_iter;
-               }
-
-               if (stream_iter_is_ended) {
-                       /*
-                        * The live stream iterator is ENDed. We remove that
-                        * iterator from the list and we restart the iteration
-                        * at the beginning of the live stream iterator array
-                        * to because the removal will shuffle the array.
-                        */
-                       g_ptr_array_remove_index_fast(live_trace->stream_iterators,
-                               stream_iter_idx);
-                       stream_iter_idx = 0;
-               } else {
-                       stream_iter_idx++;
-               }
-       }
-
-       if (curr_candidate_stream_iter) {
-               *candidate_stream_iter = curr_candidate_stream_iter;
-               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-       } else {
-               /*
-                * The only case where we don't have a candidate for this trace
-                * is if we reached the end of all the iterators.
-                */
-               BT_ASSERT(live_trace->stream_iterators->len == 0);
-               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_END;
-       }
-
-end:
-       return stream_iter_status;
-}
-
-static
-enum lttng_live_iterator_status next_stream_iterator_for_session(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_session *session,
-               struct lttng_live_stream_iterator **candidate_session_stream_iter)
-{
-       enum lttng_live_iterator_status stream_iter_status;
-       uint64_t trace_idx = 0;
-       int64_t curr_candidate_msg_ts = INT64_MAX;
-       struct lttng_live_stream_iterator *curr_candidate_stream_iter = NULL;
-
-       /*
-        * Make sure we are attached to the session and look for new streams
-        * and metadata.
-        */
-       stream_iter_status = lttng_live_get_session(lttng_live_msg_iter, session);
-       if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK &&
-                       stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_CONTINUE &&
-                       stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_END) {
-               goto end;
-       }
-
-       BT_ASSERT(session->traces);
-
-       /*
-        * Use while loops here rather then for loops so we can restart the
-        * iteration if an element is removed from the array during the
-        * looping.
-        */
-       while (trace_idx < session->traces->len) {
-               bool trace_is_ended = false;
-               struct lttng_live_stream_iterator *stream_iter;
-               struct lttng_live_trace *trace =
-                       g_ptr_array_index(session->traces, trace_idx);
-
-               stream_iter_status = next_stream_iterator_for_trace(
-                       lttng_live_msg_iter, trace, &stream_iter);
-               if (stream_iter_status == LTTNG_LIVE_ITERATOR_STATUS_END) {
-                       /*
-                        * All the live stream iterators for this trace are
-                        * ENDed. Remove the trace from this session.
-                        */
-                       trace_is_ended = true;
-               } else if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-                       goto end;
-               }
-
-               if (!trace_is_ended) {
-                       BT_ASSERT(stream_iter);
-
-                       if (stream_iter->current_msg_ts_ns <= curr_candidate_msg_ts) {
-                               curr_candidate_msg_ts = stream_iter->current_msg_ts_ns;
-                               curr_candidate_stream_iter = stream_iter;
-                       }
-                       trace_idx++;
-               } else {
-                       g_ptr_array_remove_index_fast(session->traces, trace_idx);
-                       trace_idx = 0;
-               }
-       }
-       if (curr_candidate_stream_iter) {
-               *candidate_session_stream_iter = curr_candidate_stream_iter;
-               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-       } else {
-               /*
-                * The only cases where we don't have a candidate for this
-                * trace is:
-                *  1. if we reached the end of all the iterators of all the
-                *  traces of this session,
-                *  2. if we never had live stream iterator in the first place.
-                *
-                * In either cases, we return END.
-                */
-               BT_ASSERT(session->traces->len == 0);
-               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_END;
-       }
-end:
-       return stream_iter_status;
-}
-
-static inline
-void put_messages(bt_message_array_const msgs, uint64_t count)
-{
-       uint64_t i;
-
-       for (i = 0; i < count; i++) {
-               BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
-       }
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status lttng_live_msg_iter_next(
-               bt_self_message_iterator *self_msg_it,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       bt_self_message_iterator_status status;
-       struct lttng_live_msg_iter *lttng_live_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_it);
-       struct lttng_live_component *lttng_live =
-               lttng_live_msg_iter->lttng_live_comp;
-       enum lttng_live_iterator_status stream_iter_status;
-       uint64_t session_idx;
-
-       *count = 0;
-
-       BT_ASSERT(lttng_live_msg_iter);
-
-       /*
-        * Clear all the invalid message reference that might be left over in
-        * the output array.
-        */
-       memset(msgs, 0, capacity * sizeof(*msgs));
-
-       /*
-        * If no session are exposed on the relay found at the url provided by
-        * the user, session count will be 0. In this case, we return status
-        * end to return gracefully.
-        */
-       if (lttng_live_msg_iter->sessions->len == 0) {
-               if (lttng_live->params.sess_not_found_act !=
-                               SESSION_NOT_FOUND_ACTION_CONTINUE) {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-                       goto no_session;
-               } else {
-                       /*
-                        * The are no more active session for this session
-                        * name. Retry to create a viewer session for the
-                        * requested session name.
-                        */
-                       if (lttng_live_create_viewer_session(lttng_live_msg_iter)) {
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto no_session;
-                       }
-               }
-       }
-
-       if (lttng_live_msg_iter->active_stream_iter == 0) {
-               lttng_live_force_new_streams_and_metadata(lttng_live_msg_iter);
-       }
-
-       /*
-        * Here the muxing of message is done.
-        *
-        * We need to iterate over all the streams of all the traces of all the
-        * viewer sessions in order to get the message with the smallest
-        * timestamp. In this case, a session is a viewer session and there is
-        * one viewer session per consumer daemon. (UST 32bit, UST 64bit and/or
-        * kernel). Each viewer session can have multiple traces, for example,
-        * 64bit UST viewer sessions could have multiple per-pid traces.
-        *
-        * We iterate over the streams of each traces to update and see what is
-        * their next message's timestamp. From those timestamps, we select the
-        * message with the smallest timestamp as the best candidate message
-        * for that trace and do the same thing across all the sessions.
-        *
-        * We then compare the timestamp of best candidate message of all the
-        * sessions to pick the message with the smallest timestamp and we
-        * return it.
-        */
-       while (*count < capacity) {
-               struct lttng_live_stream_iterator *next_stream_iter = NULL,
-                                                 *candidate_stream_iter = NULL;
-               int64_t next_msg_ts_ns = INT64_MAX;
-
-               BT_ASSERT(lttng_live_msg_iter->sessions);
-               session_idx = 0;
-               /*
-                * Use a while loop instead of a for loop so we can restart the
-                * iteration if we remove an element. We can safely call
-                * next_stream_iterator_for_session() multiple times on the
-                * same session as we only fetch a new message if there is no
-                * current next message for each live stream iterator.
-                * If all live stream iterator of that session already have a
-                * current next message, the function will simply exit return
-                * the same candidate live stream iterator every time.
-                */
-               while (session_idx < lttng_live_msg_iter->sessions->len) {
-                       struct lttng_live_session *session =
-                               g_ptr_array_index(lttng_live_msg_iter->sessions,
-                                       session_idx);
-
-                       /* Find the best candidate message to send downstream. */
-                       stream_iter_status = next_stream_iterator_for_session(
-                               lttng_live_msg_iter, session,
-                               &candidate_stream_iter);
-
-                       /* If we receive an END status, it means that either:
-                        * - Those traces never had active streams (UST with no
-                        *   data produced yet),
-                        * - All live stream iterators have ENDed.*/
-                       if (stream_iter_status == LTTNG_LIVE_ITERATOR_STATUS_END) {
-                               if (session->closed && session->traces->len == 0) {
-                                       /*
-                                        * Remove the session from the list and restart the
-                                        * iteration at the beginning of the array since the
-                                        * removal shuffle the elements of the array.
-                                        */
-                                       g_ptr_array_remove_index_fast(
-                                               lttng_live_msg_iter->sessions,
-                                               session_idx);
-                                       session_idx = 0;
-                               } else {
-                                       session_idx++;
-                               }
-                               continue;
-                       }
-
-                       if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       if (candidate_stream_iter->current_msg_ts_ns <= next_msg_ts_ns) {
-                               next_msg_ts_ns = candidate_stream_iter->current_msg_ts_ns;
-                               next_stream_iter = candidate_stream_iter;
-                       }
-
-                       session_idx++;
-               }
-
-               if (!next_stream_iter) {
-                       stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-                       goto end;
-               }
-
-               BT_ASSERT(next_stream_iter->current_msg);
-               /* Ensure monotonicity. */
-               BT_ASSERT(lttng_live_msg_iter->last_msg_ts_ns <=
-                       next_stream_iter->current_msg_ts_ns);
-
-               /*
-                * Insert the next message to the message batch. This will set
-                * stream iterator current messsage to NULL so that next time
-                * we fetch the next message of that stream iterator
-                */
-               BT_MESSAGE_MOVE_REF(msgs[*count], next_stream_iter->current_msg);
-               (*count)++;
-
-               /* Update the last timestamp in nanoseconds sent downstream. */
-               lttng_live_msg_iter->last_msg_ts_ns = next_msg_ts_ns;
-               next_stream_iter->current_msg_ts_ns = INT64_MAX;
-
-               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
-       }
-end:
-       switch (stream_iter_status) {
-       case LTTNG_LIVE_ITERATOR_STATUS_OK:
-       case LTTNG_LIVE_ITERATOR_STATUS_AGAIN:
-               if (*count > 0) {
-                       /*
-                        * We received a again status but we have some messages
-                        * to send downstream. We send them and return OK for
-                        * now. On the next call we return again if there are
-                        * still no new message to send.
-                        */
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-               } else {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN;
-               }
-               break;
-       case LTTNG_LIVE_ITERATOR_STATUS_END:
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-               break;
-       case LTTNG_LIVE_ITERATOR_STATUS_NOMEM:
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               break;
-       case LTTNG_LIVE_ITERATOR_STATUS_ERROR:
-       case LTTNG_LIVE_ITERATOR_STATUS_INVAL:
-       case LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED:
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               /* Put all existing messages on error. */
-               put_messages(msgs, *count);
-               break;
-       default:
-               abort();
-       }
-
-no_session:
-       return status;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status lttng_live_msg_iter_init(
-               bt_self_message_iterator *self_msg_it,
-               bt_self_component_source *self_comp_src,
-               bt_self_component_port_output *self_port)
-{
-       bt_self_message_iterator_status ret =
-                       BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       bt_self_component *self_comp =
-                       bt_self_component_source_as_self_component(self_comp_src);
-       struct lttng_live_component *lttng_live;
-       struct lttng_live_msg_iter *lttng_live_msg_iter;
-
-       BT_ASSERT(self_msg_it);
-
-       lttng_live = bt_self_component_get_data(self_comp);
-
-       /* There can be only one downstream iterator at the same time. */
-       BT_ASSERT(!lttng_live->has_msg_iter);
-       lttng_live->has_msg_iter = true;
-
-       lttng_live_msg_iter = g_new0(struct lttng_live_msg_iter, 1);
-       if (!lttng_live_msg_iter) {
-               ret = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       lttng_live_msg_iter->lttng_live_comp = lttng_live;
-       lttng_live_msg_iter->self_msg_iter = self_msg_it;
-
-       lttng_live_msg_iter->active_stream_iter = 0;
-       lttng_live_msg_iter->last_msg_ts_ns = INT64_MIN;
-       lttng_live_msg_iter->sessions = g_ptr_array_new_with_free_func(
-               (GDestroyNotify) lttng_live_destroy_session);
-       BT_ASSERT(lttng_live_msg_iter->sessions);
-
-       lttng_live_msg_iter->viewer_connection =
-               live_viewer_connection_create(lttng_live->params.url->str, false,
-                       lttng_live_msg_iter);
-       if (!lttng_live_msg_iter->viewer_connection) {
-               goto error;
-       }
-
-       if (lttng_live_create_viewer_session(lttng_live_msg_iter)) {
-               goto error;
-       }
-       if (lttng_live_msg_iter->sessions->len == 0) {
-               switch (lttng_live->params.sess_not_found_act) {
-               case SESSION_NOT_FOUND_ACTION_CONTINUE:
-                       BT_LOGI("Unable to connect to the requested live viewer "
-                               "session. Keep trying to connect because of "
-                               "%s=\"%s\" component parameter: url=\"%s\"",
-                               SESS_NOT_FOUND_ACTION_PARAM,
-                               SESS_NOT_FOUND_ACTION_CONTINUE_STR,
-                               lttng_live->params.url->str);
-                       break;
-               case SESSION_NOT_FOUND_ACTION_FAIL:
-                       BT_LOGE("Unable to connect to the requested live viewer "
-                               "session. Fail the message iterator"
-                               "initialization because of %s=\"%s\" "
-                               "component parameter: url =\"%s\"",
-                               SESS_NOT_FOUND_ACTION_PARAM,
-                               SESS_NOT_FOUND_ACTION_FAIL_STR,
-                               lttng_live->params.url->str);
-                       goto error;
-               case SESSION_NOT_FOUND_ACTION_END:
-                       BT_LOGI("Unable to connect to the requested live viewer "
-                               "session. End gracefully at the first _next() "
-                               "call because of %s=\"%s\" component parameter: "
-                               "url=\"%s\"", SESS_NOT_FOUND_ACTION_PARAM,
-                               SESS_NOT_FOUND_ACTION_END_STR,
-                               lttng_live->params.url->str);
-                       break;
-               }
-       }
-
-       bt_self_message_iterator_set_data(self_msg_it, lttng_live_msg_iter);
-
-       goto end;
-error:
-       ret = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-       lttng_live_msg_iter_destroy(lttng_live_msg_iter);
-end:
-       return ret;
-}
-
-static
-bt_query_status lttng_live_query_list_sessions(const bt_value *params,
-               const bt_value **result)
-{
-       bt_query_status status = BT_QUERY_STATUS_OK;
-       const bt_value *url_value = NULL;
-       const char *url;
-       struct live_viewer_connection *viewer_connection = NULL;
-
-       url_value = bt_value_map_borrow_entry_value_const(params, URL_PARAM);
-       if (!url_value) {
-               BT_LOGW("Mandatory `%s` parameter missing", URL_PARAM);
-               status = BT_QUERY_STATUS_INVALID_PARAMS;
-               goto error;
-       }
-
-       if (!bt_value_is_string(url_value)) {
-               BT_LOGW("`%s` parameter is required to be a string value",
-                       URL_PARAM);
-               status = BT_QUERY_STATUS_INVALID_PARAMS;
-               goto error;
-       }
-
-       url = bt_value_string_get(url_value);
-
-       viewer_connection = live_viewer_connection_create(url, true, NULL);
-       if (!viewer_connection) {
-               goto error;
-       }
-
-       status = live_viewer_connection_list_sessions(viewer_connection,
-                       result);
-       if (status != BT_QUERY_STATUS_OK) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(*result);
-
-       if (status >= 0) {
-               status = BT_QUERY_STATUS_ERROR;
-       }
-
-end:
-       if (viewer_connection) {
-               live_viewer_connection_destroy(viewer_connection);
-       }
-       return status;
-}
-
-BT_HIDDEN
-bt_query_status lttng_live_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, "sessions") == 0) {
-               status = lttng_live_query_list_sessions(params, result);
-       } else {
-               BT_LOGW("Unknown query object `%s`", object);
-               status = BT_QUERY_STATUS_INVALID_OBJECT;
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-static
-void lttng_live_component_destroy_data(struct lttng_live_component *lttng_live)
-{
-       if (!lttng_live) {
-               return;
-       }
-       if (lttng_live->params.url) {
-               g_string_free(lttng_live->params.url, TRUE);
-       }
-       g_free(lttng_live);
-}
-
-BT_HIDDEN
-void lttng_live_component_finalize(bt_self_component_source *component)
-{
-       void *data = bt_self_component_get_data(
-                       bt_self_component_source_as_self_component(component));
-
-       if (!data) {
-               return;
-       }
-       lttng_live_component_destroy_data(data);
-}
-
-static
-enum session_not_found_action parse_session_not_found_action_param(
-       const bt_value *no_session_param)
-{
-       enum session_not_found_action action;
-       const char *no_session_act_str;
-       no_session_act_str = bt_value_string_get(no_session_param);
-       if (strcmp(no_session_act_str, SESS_NOT_FOUND_ACTION_CONTINUE_STR) == 0) {
-               action = SESSION_NOT_FOUND_ACTION_CONTINUE;
-       } else if (strcmp(no_session_act_str, SESS_NOT_FOUND_ACTION_FAIL_STR) == 0) {
-               action = SESSION_NOT_FOUND_ACTION_FAIL;
-       } else if (strcmp(no_session_act_str, SESS_NOT_FOUND_ACTION_END_STR) == 0) {
-               action = SESSION_NOT_FOUND_ACTION_END;
-       } else {
-               action = -1;
-       }
-
-       return action;
-}
-
-struct lttng_live_component *lttng_live_component_create(const bt_value *params)
-{
-       struct lttng_live_component *lttng_live;
-       const bt_value *value = NULL;
-       const char *url;
-
-       lttng_live = g_new0(struct lttng_live_component, 1);
-       if (!lttng_live) {
-               goto end;
-       }
-       lttng_live->max_query_size = MAX_QUERY_SIZE;
-       lttng_live->has_msg_iter = false;
-
-       value = bt_value_map_borrow_entry_value_const(params, URL_PARAM);
-       if (!value || !bt_value_is_string(value)) {
-               BT_LOGW("Mandatory `%s` parameter missing or not a string",
-                       URL_PARAM);
-               goto error;
-       }
-       url = bt_value_string_get(value);
-       lttng_live->params.url = g_string_new(url);
-       if (!lttng_live->params.url) {
-               goto error;
-       }
-
-       value = bt_value_map_borrow_entry_value_const(params,
-               SESS_NOT_FOUND_ACTION_PARAM);
-
-       if (value && bt_value_is_string(value)) {
-               lttng_live->params.sess_not_found_act =
-                       parse_session_not_found_action_param(value);
-               if (lttng_live->params.sess_not_found_act == -1) {
-                       BT_LOGE("Unexpected value for `%s` parameter: "
-                               "value=\"%s\"", SESS_NOT_FOUND_ACTION_PARAM,
-                               bt_value_string_get(value));
-                       goto error;
-               }
-       } else {
-               BT_LOGW("Optional `%s` parameter is missing or "
-                       "not a string value. Defaulting to %s=\"%s\".",
-                       SESS_NOT_FOUND_ACTION_PARAM,
-                       SESS_NOT_FOUND_ACTION_PARAM,
-                       SESS_NOT_FOUND_ACTION_CONTINUE_STR);
-               lttng_live->params.sess_not_found_act =
-                       SESSION_NOT_FOUND_ACTION_CONTINUE;
-       }
-
-       goto end;
-
-error:
-       lttng_live_component_destroy_data(lttng_live);
-       lttng_live = NULL;
-end:
-       return lttng_live;
-}
-
-BT_HIDDEN
-bt_self_component_status lttng_live_component_init(
-               bt_self_component_source *self_comp,
-               const bt_value *params, UNUSED_VAR void *init_method_data)
-{
-       struct lttng_live_component *lttng_live;
-       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
-
-       lttng_live = lttng_live_component_create(params);
-       if (!lttng_live) {
-               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto error;
-       }
-       lttng_live->self_comp = self_comp;
-
-       if (lttng_live_graph_is_canceled(lttng_live)) {
-               ret = BT_SELF_COMPONENT_STATUS_END;
-               goto error;
-       }
-
-       ret = bt_self_component_source_add_output_port(
-                               lttng_live->self_comp, "out",
-                               NULL, NULL);
-       if (ret != BT_SELF_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-
-       bt_self_component_set_data(
-                       bt_self_component_source_as_self_component(self_comp),
-                       lttng_live);
-       goto end;
-
-error:
-       lttng_live_component_destroy_data(lttng_live);
-       lttng_live = NULL;
-end:
-       return ret;
-}
diff --git a/plugins/ctf/lttng-live/lttng-live.h b/plugins/ctf/lttng-live/lttng-live.h
deleted file mode 100644 (file)
index 67f021c..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_CTF_LTTNG_LIVE_H
-#define BABELTRACE_PLUGIN_CTF_LTTNG_LIVE_H
-
-/*
- * BabelTrace - LTTng-live client Component
- *
- * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdbool.h>
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "../common/metadata/decoder.h"
-#include "../common/msg-iter/msg-iter.h"
-
-#include "viewer-connection.h"
-
-struct lttng_live_component;
-struct lttng_live_session;
-struct lttng_live_msg_iter;
-
-enum lttng_live_stream_state {
-       /* This stream won't have data until some known time in the future. */
-       LTTNG_LIVE_STREAM_QUIESCENT,
-       /*
-        * This stream won't have data until some known time in the future and
-        * the message iterator inactivity message was already sent downstream.
-        */
-       LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA, /* */
-       /* This stream has data ready to be consumed. */
-       LTTNG_LIVE_STREAM_ACTIVE_DATA,
-       /*
-        * This stream has no data left to consume. We should asked the relay
-        * for more.
-        */
-       LTTNG_LIVE_STREAM_ACTIVE_NO_DATA,
-       /* This stream won't have anymore data, ever. */
-       LTTNG_LIVE_STREAM_EOF,
-};
-
-/* Iterator over a live stream. */
-struct lttng_live_stream_iterator {
-       /* Owned by this. */
-       bt_stream *stream;
-
-       /* Weak reference. */
-       struct lttng_live_trace *trace;
-
-       /*
-        * Since only a single iterator per viewer connection, we have
-        * only a single message iterator per stream.
-        */
-       struct bt_msg_iter *msg_iter;
-
-       uint64_t viewer_stream_id;
-
-       uint64_t ctf_stream_class_id;
-
-       /* base offset in current index. */
-       uint64_t base_offset;
-       /* len to read in current index. */
-       uint64_t len;
-       /* offset in current index. */
-       uint64_t offset;
-
-       /*
-        * Clock Snapshot value of the last message iterator inactivity message
-        * sent downstream.
-        */
-       uint64_t last_inactivity_ts;
-
-       /*
-        * Clock Snapshot value of the current message iterator inactivity
-        * message we might want to send downstream.
-        */
-       uint64_t current_inactivity_ts;
-
-       enum lttng_live_stream_state state;
-
-       /*
-        * The current message produced by this live stream iterator. Owned by
-        * this.
-        */
-       bt_message *current_msg;
-
-       /* Timestamp in nanoseconds of the current message (current_msg). */
-       int64_t current_msg_ts_ns;
-
-       /* Owned by this. */
-       uint8_t *buf;
-       size_t buflen;
-
-       /* Owned by this. */
-       GString *name;
-};
-
-struct lttng_live_metadata {
-       /* Weak reference. */
-       struct lttng_live_trace *trace;
-
-       uint64_t stream_id;
-       /* Weak reference. */
-       struct ctf_metadata_decoder *decoder;
-
-       bool closed;
-};
-
-struct lttng_live_trace {
-       /* Back reference to session. */
-       struct lttng_live_session *session;
-
-       /* ctf trace ID within the session. */
-       uint64_t id;
-
-       /* Owned by this. */
-       bt_trace *trace;
-
-       /* Weak reference. */
-       bt_trace_class *trace_class;
-
-       struct lttng_live_metadata *metadata;
-
-       const bt_clock_class *clock_class;
-
-       /* Array of pointers to struct lttng_live_stream_iterator. */
-       /* Owned by this. */
-       GPtrArray *stream_iterators;
-
-       bool new_metadata_needed;
-};
-
-struct lttng_live_session {
-       /* Weak reference. */
-       struct lttng_live_msg_iter *lttng_live_msg_iter;
-
-       /* Owned by this. */
-       GString *hostname;
-
-       /* Owned by this. */
-       GString *session_name;
-
-       uint64_t id;
-
-       /* Array of pointers to struct lttng_live_trace. */
-       GPtrArray *traces;
-
-       bool attached;
-       bool new_streams_needed;
-       bool lazy_stream_msg_init;
-       bool closed;
-};
-
-enum session_not_found_action {
-       SESSION_NOT_FOUND_ACTION_CONTINUE,
-       SESSION_NOT_FOUND_ACTION_FAIL,
-       SESSION_NOT_FOUND_ACTION_END,
-};
-
-/*
- * A component instance is an iterator on a single session.
- */
-struct lttng_live_component {
-       /* Weak reference. */
-       bt_self_component_source *self_comp;
-
-       struct {
-               GString *url;
-               enum session_not_found_action sess_not_found_act;
-       } params;
-
-       size_t max_query_size;
-
-       /*
-        * Keeps track of whether the downstream component already has a
-        * message iterator on this component.
-        */
-       bool has_msg_iter;
-};
-
-struct lttng_live_msg_iter {
-       /* Weak reference. */
-       struct lttng_live_component *lttng_live_comp;
-
-       /* Weak reference. */
-       bt_self_message_iterator *self_msg_iter;
-
-       /* Owned by this. */
-       struct live_viewer_connection *viewer_connection;
-
-       /* Array of pointers to struct lttng_live_session. */
-       GPtrArray *sessions;
-
-       /* Number of live stream iterator this message iterator has.*/
-       uint64_t active_stream_iter;
-
-       /* Timestamp in nanosecond of the last message sent downstream. */
-       int64_t last_msg_ts_ns;
-};
-
-enum lttng_live_iterator_status {
-       /** Iterator state has progressed. Continue iteration immediately. */
-       LTTNG_LIVE_ITERATOR_STATUS_CONTINUE = 3,
-       /** No message available for now. Try again later. */
-       LTTNG_LIVE_ITERATOR_STATUS_AGAIN = 2,
-       /** No more CTF_LTTNG_LIVEs to be delivered. */
-       LTTNG_LIVE_ITERATOR_STATUS_END = 1,
-       /** No error, okay. */
-       LTTNG_LIVE_ITERATOR_STATUS_OK = 0,
-       /** Invalid arguments. */
-       LTTNG_LIVE_ITERATOR_STATUS_INVAL = -1,
-       /** General error. */
-       LTTNG_LIVE_ITERATOR_STATUS_ERROR = -2,
-       /** Out of memory. */
-       LTTNG_LIVE_ITERATOR_STATUS_NOMEM = -3,
-       /** Unsupported iterator feature. */
-       LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED = -4,
-};
-
-bt_self_component_status lttng_live_component_init(
-               bt_self_component_source *self_comp,
-               const bt_value *params, void *init_method_data);
-
-bt_query_status lttng_live_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);
-
-void lttng_live_component_finalize(bt_self_component_source *component);
-
-bt_self_message_iterator_status lttng_live_msg_iter_next(
-               bt_self_message_iterator *iterator,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count);
-
-bt_self_message_iterator_status lttng_live_msg_iter_init(
-               bt_self_message_iterator *self_msg_it,
-               bt_self_component_source *self_comp,
-               bt_self_component_port_output *self_port);
-
-void lttng_live_msg_iter_finalize(bt_self_message_iterator *it);
-
-int lttng_live_create_viewer_session(struct lttng_live_msg_iter *lttng_live_msg_iter);
-int lttng_live_attach_session(struct lttng_live_session *session);
-int lttng_live_detach_session(struct lttng_live_session *session);
-enum lttng_live_iterator_status lttng_live_get_new_streams(
-               struct lttng_live_session *session);
-
-int lttng_live_add_session(struct lttng_live_msg_iter *lttng_live_msg_iter,
-               uint64_t session_id,
-               const char *hostname,
-               const char *session_name);
-
-ssize_t lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace,
-               FILE *fp);
-enum lttng_live_iterator_status lttng_live_get_next_index(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *stream,
-               struct packet_index *index);
-
-enum bt_msg_iter_medium_status lttng_live_get_stream_bytes(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *stream, uint8_t *buf,
-               uint64_t offset, uint64_t req_len, uint64_t *recv_len);
-void lttng_live_add_stream_iterator(struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *stream_iter);
-void lttng_live_remove_stream_iterator(struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *stream_iter);
-
-struct lttng_live_trace *lttng_live_borrow_trace(
-               struct lttng_live_session *session, uint64_t trace_id);
-void lttng_live_need_new_streams(struct lttng_live_msg_iter *lttng_live_msg_iter);
-
-bool lttng_live_graph_is_canceled(struct lttng_live_component *lttng_live);
-
-#endif /* BABELTRACE_PLUGIN_CTF_LTTNG_LIVE_H */
diff --git a/plugins/ctf/lttng-live/lttng-viewer-abi.h b/plugins/ctf/lttng-live/lttng-viewer-abi.h
deleted file mode 100644 (file)
index a05ed61..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-#ifndef LTTNG_VIEWER_ABI_H
-#define LTTNG_VIEWER_ABI_H
-
-/*
- * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
- *                      Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *                      David Goulet <dgoulet@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/compat/limits-internal.h>
-
-#define LTTNG_VIEWER_PATH_MAX          4096
-#define LTTNG_VIEWER_NAME_MAX          255
-#define LTTNG_VIEWER_HOST_NAME_MAX     64
-
-/* Flags in reply to get_next_index and get_packet. */
-enum {
-       /* New metadata is required to read this packet. */
-       LTTNG_VIEWER_FLAG_NEW_METADATA  = (1 << 0),
-       /* New stream got added to the trace. */
-       LTTNG_VIEWER_FLAG_NEW_STREAM    = (1 << 1),
-};
-
-enum lttng_viewer_command {
-       LTTNG_VIEWER_CONNECT            = 1,
-       LTTNG_VIEWER_LIST_SESSIONS      = 2,
-       LTTNG_VIEWER_ATTACH_SESSION     = 3,
-       LTTNG_VIEWER_GET_NEXT_INDEX     = 4,
-       LTTNG_VIEWER_GET_PACKET         = 5,
-       LTTNG_VIEWER_GET_METADATA       = 6,
-       LTTNG_VIEWER_GET_NEW_STREAMS    = 7,
-       LTTNG_VIEWER_CREATE_SESSION     = 8,
-       LTTNG_VIEWER_DETACH_SESSION     = 9,
-};
-
-enum lttng_viewer_attach_return_code {
-       LTTNG_VIEWER_ATTACH_OK          = 1, /* The attach command succeeded. */
-       LTTNG_VIEWER_ATTACH_ALREADY     = 2, /* A viewer is already attached. */
-       LTTNG_VIEWER_ATTACH_UNK         = 3, /* The session ID is unknown. */
-       LTTNG_VIEWER_ATTACH_NOT_LIVE    = 4, /* The session is not live. */
-       LTTNG_VIEWER_ATTACH_SEEK_ERR    = 5, /* Seek error. */
-       LTTNG_VIEWER_ATTACH_NO_SESSION  = 6, /* No viewer session created. */
-};
-
-enum lttng_viewer_detach_session_return_code {
-       LTTNG_VIEWER_DETACH_SESSION_OK          = 1,
-       LTTNG_VIEWER_DETACH_SESSION_UNK         = 2,
-       LTTNG_VIEWER_DETACH_SESSION_ERR         = 3,
-};
-
-enum lttng_viewer_next_index_return_code {
-       LTTNG_VIEWER_INDEX_OK           = 1, /* Index is available. */
-       LTTNG_VIEWER_INDEX_RETRY        = 2, /* Index not yet available. */
-       LTTNG_VIEWER_INDEX_HUP          = 3, /* Index closed (trace destroyed). */
-       LTTNG_VIEWER_INDEX_ERR          = 4, /* Unknow error. */
-       LTTNG_VIEWER_INDEX_INACTIVE     = 5, /* Inactive stream beacon. */
-       LTTNG_VIEWER_INDEX_EOF          = 6, /* End of index file. */
-};
-
-enum lttng_viewer_get_packet_return_code {
-       LTTNG_VIEWER_GET_PACKET_OK      = 1,
-       LTTNG_VIEWER_GET_PACKET_RETRY   = 2,
-       LTTNG_VIEWER_GET_PACKET_ERR     = 3,
-       LTTNG_VIEWER_GET_PACKET_EOF     = 4,
-};
-
-enum lttng_viewer_get_metadata_return_code {
-       LTTNG_VIEWER_METADATA_OK        = 1,
-       LTTNG_VIEWER_NO_NEW_METADATA    = 2,
-       LTTNG_VIEWER_METADATA_ERR       = 3,
-};
-
-enum lttng_viewer_connection_type {
-       LTTNG_VIEWER_CLIENT_COMMAND             = 1,
-       LTTNG_VIEWER_CLIENT_MESSAGE     = 2,
-};
-
-enum lttng_viewer_seek {
-       /* Receive the trace packets from the beginning. */
-       LTTNG_VIEWER_SEEK_BEGINNING     = 1,
-       /* Receive the trace packets from now. */
-       LTTNG_VIEWER_SEEK_LAST          = 2,
-};
-
-enum lttng_viewer_new_streams_return_code {
-       LTTNG_VIEWER_NEW_STREAMS_OK           = 1, /* If new streams are being sent. */
-       LTTNG_VIEWER_NEW_STREAMS_NO_NEW       = 2, /* If no new streams are available. */
-       LTTNG_VIEWER_NEW_STREAMS_ERR          = 3, /* Error. */
-       LTTNG_VIEWER_NEW_STREAMS_HUP          = 4, /* Session closed. */
-};
-
-enum lttng_viewer_create_session_return_code {
-       LTTNG_VIEWER_CREATE_SESSION_OK          = 1,
-       LTTNG_VIEWER_CREATE_SESSION_ERR         = 2,
-};
-
-struct lttng_viewer_session {
-       uint64_t id;
-       uint32_t live_timer;
-       uint32_t clients;
-       uint32_t streams;
-       char hostname[LTTNG_VIEWER_HOST_NAME_MAX];
-       char session_name[LTTNG_VIEWER_NAME_MAX];
-} __attribute__((__packed__));
-
-struct lttng_viewer_stream {
-       uint64_t id;
-       uint64_t ctf_trace_id;
-       uint32_t metadata_flag;
-       char path_name[LTTNG_VIEWER_PATH_MAX];
-       char channel_name[LTTNG_VIEWER_NAME_MAX];
-} __attribute__((__packed__));
-
-struct lttng_viewer_cmd {
-       uint64_t data_size;     /* data size following this header */
-       uint32_t cmd;           /* enum lttcomm_relayd_command */
-       uint32_t cmd_version;   /* command version */
-} __attribute__((__packed__));
-
-/*
- * LTTNG_VIEWER_CONNECT payload.
- */
-struct lttng_viewer_connect {
-       /* session ID assigned by the relay for command connections */
-       uint64_t viewer_session_id;
-       uint32_t major;
-       uint32_t minor;
-       uint32_t type;          /* enum lttng_viewer_connection_type */
-} __attribute__((__packed__));
-
-/*
- * LTTNG_VIEWER_LIST_SESSIONS payload.
- */
-struct lttng_viewer_list_sessions {
-       uint32_t sessions_count;
-       char session_list[];    /* struct lttng_viewer_session */
-} __attribute__((__packed__));
-
-/*
- * LTTNG_VIEWER_ATTACH_SESSION payload.
- */
-struct lttng_viewer_attach_session_request {
-       uint64_t session_id;
-       uint64_t offset;        /* unused for now */
-       uint32_t seek;          /* enum lttng_viewer_seek */
-} __attribute__((__packed__));
-
-struct lttng_viewer_attach_session_response {
-       /* enum lttng_viewer_attach_return_code */
-       uint32_t status;
-       uint32_t streams_count;
-       /* struct lttng_viewer_stream */
-       char stream_list[];
-} __attribute__((__packed__));
-
-/*
- * LTTNG_VIEWER_GET_NEXT_INDEX payload.
- */
-struct lttng_viewer_get_next_index {
-       uint64_t stream_id;
-} __attribute__ ((__packed__));
-
-struct lttng_viewer_index {
-       uint64_t offset;
-       uint64_t packet_size;
-       uint64_t content_size;
-       uint64_t timestamp_begin;
-       uint64_t timestamp_end;
-       uint64_t events_discarded;
-       uint64_t stream_id;
-       uint32_t status;        /* enum lttng_viewer_next_index_return_code */
-       uint32_t flags;         /* LTTNG_VIEWER_FLAG_* */
-} __attribute__ ((__packed__));
-
-/*
- * LTTNG_VIEWER_GET_PACKET payload.
- */
-struct lttng_viewer_get_packet {
-       uint64_t stream_id;
-       uint64_t offset;
-       uint32_t len;
-} __attribute__((__packed__));
-
-struct lttng_viewer_trace_packet {
-       uint32_t status;        /* enum lttng_viewer_get_packet_return_code */
-       uint32_t len;
-       uint32_t flags;         /* LTTNG_VIEWER_FLAG_* */
-       char data[];
-} __attribute__((__packed__));
-
-/*
- * LTTNG_VIEWER_GET_METADATA payload.
- */
-struct lttng_viewer_get_metadata {
-       uint64_t stream_id;
-} __attribute__((__packed__));
-
-struct lttng_viewer_metadata_packet {
-       uint64_t len;
-       uint32_t status;        /* enum lttng_viewer_get_metadata_return_code */
-       char data[];
-} __attribute__((__packed__));
-
-/*
- * LTTNG_VIEWER_GET_NEW_STREAMS payload.
- */
-struct lttng_viewer_new_streams_request {
-       uint64_t session_id;
-} __attribute__((__packed__));
-
-struct lttng_viewer_new_streams_response {
-       /* enum lttng_viewer_new_streams_return_code */
-       uint32_t status;
-       uint32_t streams_count;
-       /* struct lttng_viewer_stream */
-       char stream_list[];
-} __attribute__((__packed__));
-
-struct lttng_viewer_create_session_response {
-       /* enum lttng_viewer_create_session_return_code */
-       uint32_t status;
-} __attribute__((__packed__));
-
-/*
- * LTTNG_VIEWER_DETACH_SESSION payload.
- */
-struct lttng_viewer_detach_session_request {
-       uint64_t session_id;
-} __attribute__((__packed__));
-
-struct lttng_viewer_detach_session_response {
-       /* enum lttng_viewer_detach_session_return_code */
-       uint32_t status;
-} __attribute__((__packed__));
-
-#endif /* LTTNG_VIEWER_ABI_H */
diff --git a/plugins/ctf/lttng-live/metadata.c b/plugins/ctf/lttng-live/metadata.c
deleted file mode 100644 (file)
index 14088bb..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright 2019 - Francis Deslauriers <francis.deslauriers@efficios.com>
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
- *
- * Some functions are based on older functions written by Mathieu Desnoyers.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-LIVE-SRC-METADATA"
-#include "logging.h"
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <babeltrace2/compat/memstream-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "metadata.h"
-#include "../common/metadata/decoder.h"
-
-#define TSDL_MAGIC     0x75d11d57
-
-struct packet_header {
-       uint32_t magic;
-       uint8_t  uuid[16];
-       uint32_t checksum;
-       uint32_t content_size;
-       uint32_t packet_size;
-       uint8_t  compression_scheme;
-       uint8_t  encryption_scheme;
-       uint8_t  checksum_scheme;
-       uint8_t  major;
-       uint8_t  minor;
-} __attribute__((__packed__));
-
-
-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;
-}
-/*
- * Iterate over the stream classes and returns the first clock class
- * encountered. This is useful to create message iterator inactivity message as
- * we don't need a particular clock class.
- */
-static
-const bt_clock_class *borrow_any_clock_class(bt_trace_class *tc)
-{
-       uint64_t i, sc_count;
-       const bt_clock_class *cc = NULL;
-       const bt_stream_class *sc;
-
-       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) {
-                       goto end;
-               }
-       }
-end:
-       BT_ASSERT(cc);
-       return cc;
-}
-
-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;
-}
-
-BT_HIDDEN
-int lttng_live_metadata_create_stream(struct lttng_live_session *session,
-               uint64_t ctf_trace_id,
-               uint64_t stream_id,
-               const char *trace_name)
-{
-       struct lttng_live_component *lttng_live =
-               session->lttng_live_msg_iter->lttng_live_comp;
-       struct lttng_live_metadata *metadata = NULL;
-       struct lttng_live_trace *trace;
-       const char *match;
-
-       metadata = g_new0(struct lttng_live_metadata, 1);
-       if (!metadata) {
-               return -1;
-       }
-       metadata->stream_id = stream_id;
-
-       match = strstr(trace_name, session->session_name->str);
-       if (!match) {
-               goto error;
-       }
-
-       metadata->decoder = ctf_metadata_decoder_create(
-                               lttng_live->self_comp, NULL);
-       if (!metadata->decoder) {
-               goto error;
-       }
-       trace = lttng_live_borrow_trace(session, ctf_trace_id);
-       if (!trace) {
-               goto error;
-       }
-       metadata->trace = trace;
-       trace->metadata = metadata;
-       return 0;
-
-error:
-       ctf_metadata_decoder_destroy(metadata->decoder);
-       g_free(metadata);
-       return -1;
-}
-
-BT_HIDDEN
-void lttng_live_metadata_fini(struct lttng_live_trace *trace)
-{
-       struct lttng_live_metadata *metadata = trace->metadata;
-
-       if (!metadata) {
-               return;
-       }
-       ctf_metadata_decoder_destroy(metadata->decoder);
-       trace->metadata = NULL;
-       g_free(metadata);
-}
diff --git a/plugins/ctf/lttng-live/metadata.h b/plugins/ctf/lttng-live/metadata.h
deleted file mode 100644 (file)
index 2a81c88..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef LTTNG_LIVE_METADATA_H
-#define LTTNG_LIVE_METADATA_H
-
-/*
- * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include "lttng-live.h"
-
-int lttng_live_metadata_create_stream(struct lttng_live_session *session,
-               uint64_t ctf_trace_id, uint64_t stream_id,
-               const char *trace_name);
-
-enum lttng_live_iterator_status lttng_live_metadata_update(
-               struct lttng_live_trace *trace);
-
-void lttng_live_metadata_fini(struct lttng_live_trace *trace);
-
-#endif /* LTTNG_LIVE_METADATA_H */
diff --git a/plugins/ctf/lttng-live/viewer-connection.c b/plugins/ctf/lttng-live/viewer-connection.c
deleted file mode 100644 (file)
index e11fe7e..0000000
+++ /dev/null
@@ -1,1524 +0,0 @@
-/*
- * Copyright 2019 - Francis Deslauriers <francis.deslauriers@efficios.com>
- * Copyright 2016 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-LIVE-SRC-VIEWER"
-#include "logging.h"
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <glib.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-#include <babeltrace2/compat/socket-internal.h>
-#include <babeltrace2/endian-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "lttng-live.h"
-#include "viewer-connection.h"
-#include "lttng-viewer-abi.h"
-#include "data-stream.h"
-#include "metadata.h"
-
-static
-ssize_t lttng_live_recv(struct live_viewer_connection *viewer_connection,
-               void *buf, size_t len)
-{
-       ssize_t ret;
-       size_t copied = 0, to_copy = len;
-       struct lttng_live_msg_iter *lttng_live_msg_iter =
-               viewer_connection->lttng_live_msg_iter;
-       BT_SOCKET sock = viewer_connection->control_sock;
-
-       do {
-               ret = bt_socket_recv(sock, buf + copied, to_copy, 0);
-               if (ret > 0) {
-                       BT_ASSERT(ret <= to_copy);
-                       copied += ret;
-                       to_copy -= ret;
-               }
-               if (ret == BT_SOCKET_ERROR && bt_socket_interrupted()) {
-                       if (!viewer_connection->in_query &&
-                                       lttng_live_graph_is_canceled(lttng_live_msg_iter->lttng_live_comp)) {
-                               break;
-                       } else {
-                               continue;
-                       }
-               }
-       } while (ret > 0 && to_copy > 0);
-       if (ret > 0)
-               ret = copied;
-       /* ret = 0 means orderly shutdown, ret == BT_SOCKET_ERROR is error. */
-       return ret;
-}
-
-static
-ssize_t lttng_live_send(struct live_viewer_connection *viewer_connection,
-               const void *buf, size_t len)
-{
-       struct lttng_live_msg_iter *lttng_live_msg_iter =
-               viewer_connection->lttng_live_msg_iter;
-       BT_SOCKET sock = viewer_connection->control_sock;
-       ssize_t ret;
-
-       for (;;) {
-               ret = bt_socket_send_nosigpipe(sock, buf, len);
-               if (ret == BT_SOCKET_ERROR && bt_socket_interrupted()) {
-                       if (!viewer_connection->in_query &&
-                                       lttng_live_graph_is_canceled(lttng_live_msg_iter->lttng_live_comp)) {
-                               break;
-                       } else {
-                               continue;
-                       }
-               } else {
-                       break;
-               }
-       }
-       return ret;
-}
-
-static
-int parse_url(struct live_viewer_connection *viewer_connection)
-{
-       char error_buf[256] = { 0 };
-       struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
-       int ret = -1;
-       const char *path = viewer_connection->url->str;
-
-       if (!path) {
-               goto end;
-       }
-
-       lttng_live_url_parts = bt_common_parse_lttng_live_url(path,
-                       error_buf, sizeof(error_buf));
-       if (!lttng_live_url_parts.proto) {
-               BT_LOGW("Invalid LTTng live URL format: %s", error_buf);
-               goto end;
-       }
-
-       viewer_connection->relay_hostname =
-                       lttng_live_url_parts.hostname;
-       lttng_live_url_parts.hostname = NULL;
-
-       if (lttng_live_url_parts.port >= 0) {
-               viewer_connection->port = lttng_live_url_parts.port;
-       } else {
-               viewer_connection->port = LTTNG_DEFAULT_NETWORK_VIEWER_PORT;
-       }
-
-       viewer_connection->target_hostname =
-                       lttng_live_url_parts.target_hostname;
-       lttng_live_url_parts.target_hostname = NULL;
-
-       if (lttng_live_url_parts.session_name) {
-               viewer_connection->session_name =
-                               lttng_live_url_parts.session_name;
-               lttng_live_url_parts.session_name = NULL;
-       }
-
-       BT_LOGD("Connecting to hostname : %s, port : %d, "
-                       "target hostname : %s, session name : %s, "
-                       "proto : %s",
-                       viewer_connection->relay_hostname->str,
-                       viewer_connection->port,
-                       viewer_connection->target_hostname == NULL ?
-                               "<none>" : viewer_connection->target_hostname->str,
-                       viewer_connection->session_name == NULL ?
-                               "<none>" : viewer_connection->session_name->str,
-                       lttng_live_url_parts.proto->str);
-       ret = 0;
-
-end:
-       bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
-       return ret;
-}
-
-static
-int lttng_live_handshake(struct live_viewer_connection *viewer_connection)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_connect connect;
-       const size_t cmd_buf_len = sizeof(cmd) + sizeof(connect);
-       char cmd_buf[cmd_buf_len];
-       int ret;
-       ssize_t ret_len;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT);
-       cmd.data_size = htobe64((uint64_t) sizeof(connect));
-       cmd.cmd_version = htobe32(0);
-
-       connect.viewer_session_id = -1ULL;      /* will be set on recv */
-       connect.major = htobe32(LTTNG_LIVE_MAJOR);
-       connect.minor = htobe32(LTTNG_LIVE_MINOR);
-       connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND);
-
-       /*
-        * Merge the cmd and connection request to prevent a write-write
-        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
-        * second write to be performed quickly in presence of Nagle's algorithm
-        */
-       memcpy(cmd_buf, &cmd, sizeof(cmd));
-       memcpy(cmd_buf + sizeof(cmd), &connect, sizeof(connect));
-       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending version: %s", bt_socket_errormsg());
-               goto error;
-       }
-
-       BT_ASSERT(ret_len == cmd_buf_len);
-
-       ret_len = lttng_live_recv(viewer_connection, &connect, sizeof(connect));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving version: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(connect));
-
-       BT_LOGD("Received viewer session ID : %" PRIu64,
-                       (uint64_t) be64toh(connect.viewer_session_id));
-       BT_LOGD("Relayd version : %u.%u", be32toh(connect.major),
-                       be32toh(connect.minor));
-
-       if (LTTNG_LIVE_MAJOR != be32toh(connect.major)) {
-               BT_LOGE("Incompatible lttng-relayd protocol");
-               goto error;
-       }
-       /* Use the smallest protocol version implemented. */
-       if (LTTNG_LIVE_MINOR > be32toh(connect.minor)) {
-               viewer_connection->minor =  be32toh(connect.minor);
-       } else {
-               viewer_connection->minor =  LTTNG_LIVE_MINOR;
-       }
-       viewer_connection->major = LTTNG_LIVE_MAJOR;
-       ret = 0;
-       return ret;
-
-error:
-       BT_LOGE("Unable to establish connection");
-       return -1;
-}
-
-static
-int lttng_live_connect_viewer(struct live_viewer_connection *viewer_connection)
-{
-       struct hostent *host;
-       struct sockaddr_in server_addr;
-       int ret;
-
-       if (parse_url(viewer_connection)) {
-               goto error;
-       }
-
-       host = gethostbyname(viewer_connection->relay_hostname->str);
-       if (!host) {
-               BT_LOGE("Cannot lookup hostname %s",
-                       viewer_connection->relay_hostname->str);
-               goto error;
-       }
-
-       if ((viewer_connection->control_sock = socket(AF_INET, SOCK_STREAM, 0)) == BT_INVALID_SOCKET) {
-               BT_LOGE("Socket creation failed: %s", bt_socket_errormsg());
-               goto error;
-       }
-
-       server_addr.sin_family = AF_INET;
-       server_addr.sin_port = htons(viewer_connection->port);
-       server_addr.sin_addr = *((struct in_addr *) host->h_addr);
-       memset(&(server_addr.sin_zero), 0, 8);
-
-       if (connect(viewer_connection->control_sock, (struct sockaddr *) &server_addr,
-                               sizeof(struct sockaddr)) == BT_SOCKET_ERROR) {
-               BT_LOGE("Connection failed: %s", bt_socket_errormsg());
-               goto error;
-       }
-       if (lttng_live_handshake(viewer_connection)) {
-               goto error;
-       }
-
-       ret = 0;
-
-       return ret;
-
-error:
-       if (viewer_connection->control_sock != BT_INVALID_SOCKET) {
-               if (bt_socket_close(viewer_connection->control_sock) == BT_SOCKET_ERROR) {
-                       BT_LOGE("Close: %s", bt_socket_errormsg());
-               }
-       }
-       viewer_connection->control_sock = BT_INVALID_SOCKET;
-       return -1;
-}
-
-static
-void lttng_live_disconnect_viewer(
-               struct live_viewer_connection *viewer_connection)
-{
-       if (viewer_connection->control_sock == BT_INVALID_SOCKET) {
-               return;
-       }
-       if (bt_socket_close(viewer_connection->control_sock) == BT_SOCKET_ERROR) {
-               BT_LOGE("Close: %s", bt_socket_errormsg());
-               viewer_connection->control_sock = BT_INVALID_SOCKET;
-       }
-}
-
-static
-void connection_release(bt_object *obj)
-{
-       struct live_viewer_connection *conn =
-               container_of(obj, struct live_viewer_connection, obj);
-
-       live_viewer_connection_destroy(conn);
-}
-
-static
-int list_update_session(bt_value *results,
-               const struct lttng_viewer_session *session,
-               bool *_found)
-{
-       int ret = 0;
-       bt_value *map = NULL;
-       bt_value *hostname = NULL;
-       bt_value *session_name = NULL;
-       bt_value *btval = NULL;
-       int i, len;
-       bool found = false;
-
-       len = bt_value_array_get_size(results);
-       if (len < 0) {
-               BT_LOGE_STR("Error getting size of array.");
-               ret = -1;
-               goto end;
-       }
-       for (i = 0; i < len; i++) {
-               const char *hostname_str = NULL;
-               const char *session_name_str = NULL;
-
-               map = bt_value_array_borrow_element_by_index(results, (size_t) i);
-               if (!map) {
-                       BT_LOGE_STR("Error borrowing map.");
-                       ret = -1;
-                       goto end;
-               }
-               hostname = bt_value_map_borrow_entry_value(map, "target-hostname");
-               if (!hostname) {
-                       BT_LOGE_STR("Error borrowing \"target-hostname\" entry.");
-                       ret = -1;
-                       goto end;
-               }
-               session_name = bt_value_map_borrow_entry_value(map, "session-name");
-               if (!session_name) {
-                       BT_LOGE_STR("Error borrowing \"session-name\" entry.");
-                       ret = -1;
-                       goto end;
-               }
-               hostname_str = bt_value_string_get(hostname);
-               session_name_str = bt_value_string_get(session_name);
-
-               if (!strcmp(session->hostname, hostname_str)
-                               && !strcmp(session->session_name,
-                                       session_name_str)) {
-                       int64_t val;
-                       uint32_t streams = be32toh(session->streams);
-                       uint32_t clients = be32toh(session->clients);
-
-                       found = true;
-
-                       btval = bt_value_map_borrow_entry_value(map, "stream-count");
-                       if (!btval) {
-                               BT_LOGE_STR("Error borrowing \"stream-count\" entry.");
-                               ret = -1;
-                               goto end;
-                       }
-                       val = bt_value_signed_integer_get(btval);
-                       /* sum */
-                       val += streams;
-                       bt_value_signed_integer_set(btval, val);
-
-                       btval = bt_value_map_borrow_entry_value(map, "client-count");
-                       if (!btval) {
-                               BT_LOGE_STR("Error borrowing \"client-count\" entry.");
-                               ret = -1;
-                               goto end;
-                       }
-                       val = bt_value_signed_integer_get(btval);
-                       /* max */
-                       val = max_t(int64_t, clients, val);
-                       bt_value_signed_integer_set(btval, val);
-               }
-
-               if (found) {
-                       break;
-               }
-       }
-end:
-       *_found = found;
-       return ret;
-}
-
-static
-int list_append_session(bt_value *results,
-               GString *base_url,
-               const struct lttng_viewer_session *session)
-{
-       int ret = 0;
-       bt_value_status ret_status;
-       bt_value *map = NULL;
-       GString *url = NULL;
-       bool found = false;
-
-       /*
-        * If the session already exists, add the stream count to it,
-        * and do max of client counts.
-        */
-       ret = list_update_session(results, session, &found);
-       if (ret || found) {
-               goto end;
-       }
-
-       map = bt_value_map_create();
-       if (!map) {
-               BT_LOGE_STR("Error creating map value.");
-               ret = -1;
-               goto end;
-       }
-
-       if (base_url->len < 1) {
-               BT_LOGE_STR("Error: base_url length smaller than 1.");
-               ret = -1;
-               goto end;
-       }
-       /*
-        * key = "url",
-        * value = <string>,
-        */
-       url = g_string_new(base_url->str);
-       g_string_append(url, "/host/");
-       g_string_append(url, session->hostname);
-       g_string_append_c(url, '/');
-       g_string_append(url, session->session_name);
-
-       ret_status = bt_value_map_insert_string_entry(map, "url", url->str);
-       if (ret_status != BT_VALUE_STATUS_OK) {
-               BT_LOGE_STR("Error inserting \"url\" entry.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * key = "target-hostname",
-        * value = <string>,
-        */
-       ret_status = bt_value_map_insert_string_entry(map, "target-hostname",
-               session->hostname);
-       if (ret_status != BT_VALUE_STATUS_OK) {
-               BT_LOGE_STR("Error inserting \"target-hostname\" entry.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * key = "session-name",
-        * value = <string>,
-        */
-       ret_status = bt_value_map_insert_string_entry(map, "session-name",
-               session->session_name);
-       if (ret_status != BT_VALUE_STATUS_OK) {
-               BT_LOGE_STR("Error inserting \"session-name\" entry.");
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * key = "timer-us",
-        * value = <integer>,
-        */
-       {
-               uint32_t live_timer = be32toh(session->live_timer);
-
-               ret_status = bt_value_map_insert_signed_integer_entry(
-                       map, "timer-us", live_timer);
-               if (ret_status != BT_VALUE_STATUS_OK) {
-                       BT_LOGE_STR("Error inserting \"timer-us\" entry.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /*
-        * key = "stream-count",
-        * value = <integer>,
-        */
-       {
-               uint32_t streams = be32toh(session->streams);
-
-               ret_status = bt_value_map_insert_signed_integer_entry(map,
-                       "stream-count", streams);
-               if (ret_status != BT_VALUE_STATUS_OK) {
-                       BT_LOGE_STR("Error inserting \"stream-count\" entry.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       /*
-        * key = "client-count",
-        * value = <integer>,
-        */
-       {
-               uint32_t clients = be32toh(session->clients);
-
-               ret_status = bt_value_map_insert_signed_integer_entry(map,
-                       "client-count", clients);
-               if (ret_status != BT_VALUE_STATUS_OK) {
-                       BT_LOGE_STR("Error inserting \"client-count\" entry.");
-                       ret = -1;
-                       goto end;
-               }
-       }
-
-       ret_status = bt_value_array_append_element(results, map);
-       if (ret_status != BT_VALUE_STATUS_OK) {
-               BT_LOGE_STR("Error appending map to results.");
-               ret = -1;
-       }
-
-end:
-       if (url) {
-               g_string_free(url, true);
-       }
-       BT_VALUE_PUT_REF_AND_RESET(map);
-       return ret;
-}
-
-/*
- * Data structure returned:
- *
- * {
- *   <array> = {
- *     [n] = {
- *       <map> = {
- *         {
- *           key = "url",
- *           value = <string>,
- *         },
- *         {
- *           key = "target-hostname",
- *           value = <string>,
- *         },
- *         {
- *           key = "session-name",
- *           value = <string>,
- *         },
- *         {
- *           key = "timer-us",
- *           value = <integer>,
- *         },
- *         {
- *           key = "stream-count",
- *           value = <integer>,
- *         },
- *         {
- *           key = "client-count",
- *           value = <integer>,
- *         },
- *       },
- *     }
- *   }
- */
-
-BT_HIDDEN
-bt_query_status live_viewer_connection_list_sessions(
-               struct live_viewer_connection *viewer_connection,
-               const bt_value **user_result)
-{
-       bt_query_status status = BT_QUERY_STATUS_OK;
-       bt_value *result = NULL;
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_list_sessions list;
-       uint32_t i, sessions_count;
-       ssize_t ret_len;
-
-       if (lttng_live_handshake(viewer_connection)) {
-               goto error;
-       }
-
-       result = bt_value_array_create();
-       if (!result) {
-               BT_LOGE("Error creating array");
-               status = BT_QUERY_STATUS_NOMEM;
-               goto error;
-       }
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
-       cmd.data_size = htobe64((uint64_t) 0);
-       cmd.cmd_version = htobe32(0);
-
-       ret_len = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending cmd: %s", bt_socket_errormsg());
-               status = BT_QUERY_STATUS_ERROR;
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(cmd));
-
-       ret_len = lttng_live_recv(viewer_connection, &list, sizeof(list));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               status = BT_QUERY_STATUS_ERROR;
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving session list: %s", bt_socket_errormsg());
-               status = BT_QUERY_STATUS_ERROR;
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(list));
-
-       sessions_count = be32toh(list.sessions_count);
-       for (i = 0; i < sessions_count; i++) {
-               struct lttng_viewer_session lsession;
-
-               ret_len = lttng_live_recv(viewer_connection, &lsession,
-                       sizeof(lsession));
-               if (ret_len == 0) {
-                       BT_LOGI("Remote side has closed connection");
-                       status = BT_QUERY_STATUS_ERROR;
-                       goto error;
-               }
-               if (ret_len == BT_SOCKET_ERROR) {
-                       BT_LOGE("Error receiving session: %s", bt_socket_errormsg());
-                       status = BT_QUERY_STATUS_ERROR;
-                       goto error;
-               }
-               BT_ASSERT(ret_len == sizeof(lsession));
-               lsession.hostname[LTTNG_VIEWER_HOST_NAME_MAX - 1] = '\0';
-               lsession.session_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0';
-               if (list_append_session(result, viewer_connection->url,
-                               &lsession)) {
-                       status = BT_QUERY_STATUS_ERROR;
-                       goto error;
-               }
-       }
-
-       *user_result = result;
-       goto end;
-error:
-       BT_VALUE_PUT_REF_AND_RESET(result);
-end:
-       return status;
-}
-
-static
-int lttng_live_query_session_ids(struct lttng_live_msg_iter *lttng_live_msg_iter)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_list_sessions list;
-       struct lttng_viewer_session lsession;
-       uint32_t i, sessions_count;
-       ssize_t ret_len;
-       uint64_t session_id;
-       struct live_viewer_connection *viewer_connection =
-                       lttng_live_msg_iter->viewer_connection;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
-       cmd.data_size = htobe64((uint64_t) 0);
-       cmd.cmd_version = htobe32(0);
-
-       ret_len = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending cmd: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(cmd));
-
-       ret_len = lttng_live_recv(viewer_connection, &list, sizeof(list));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving session list: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(list));
-
-       sessions_count = be32toh(list.sessions_count);
-       for (i = 0; i < sessions_count; i++) {
-               ret_len = lttng_live_recv(viewer_connection,
-                               &lsession, sizeof(lsession));
-               if (ret_len == 0) {
-                       BT_LOGI("Remote side has closed connection");
-                       goto error;
-               }
-               if (ret_len == BT_SOCKET_ERROR) {
-                       BT_LOGE("Error receiving session: %s", bt_socket_errormsg());
-                       goto error;
-               }
-               BT_ASSERT(ret_len == sizeof(lsession));
-               lsession.hostname[LTTNG_VIEWER_HOST_NAME_MAX - 1] = '\0';
-               lsession.session_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0';
-               session_id = be64toh(lsession.id);
-
-               BT_LOGD("Adding session %" PRIu64 " hostname: %s session_name: %s",
-                       session_id, lsession.hostname, lsession.session_name);
-
-               if ((strncmp(lsession.session_name,
-                       viewer_connection->session_name->str,
-                       LTTNG_VIEWER_NAME_MAX) == 0) && (strncmp(lsession.hostname,
-                               viewer_connection->target_hostname->str,
-                               LTTNG_VIEWER_HOST_NAME_MAX) == 0)) {
-                       if (lttng_live_add_session(lttng_live_msg_iter, session_id,
-                                       lsession.hostname,
-                                       lsession.session_name)) {
-                               goto error;
-                       }
-               }
-       }
-
-       return 0;
-
-error:
-       BT_LOGE("Unable to query session ids");
-       return -1;
-}
-
-BT_HIDDEN
-int lttng_live_create_viewer_session(
-               struct lttng_live_msg_iter *lttng_live_msg_iter)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_create_session_response resp;
-       ssize_t ret_len;
-       struct live_viewer_connection *viewer_connection =
-                       lttng_live_msg_iter->viewer_connection;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_CREATE_SESSION);
-       cmd.data_size = htobe64((uint64_t) 0);
-       cmd.cmd_version = htobe32(0);
-
-       ret_len = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending cmd: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(cmd));
-
-       ret_len = lttng_live_recv(viewer_connection, &resp, sizeof(resp));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving create session reply: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(resp));
-
-       if (be32toh(resp.status) != LTTNG_VIEWER_CREATE_SESSION_OK) {
-               BT_LOGE("Error creating viewer session");
-               goto error;
-       }
-       if (lttng_live_query_session_ids(lttng_live_msg_iter)) {
-               goto error;
-       }
-
-       return 0;
-
-error:
-       return -1;
-}
-
-static
-int receive_streams(struct lttng_live_session *session,
-               uint32_t stream_count)
-{
-       ssize_t ret_len;
-       uint32_t i;
-       struct lttng_live_msg_iter *lttng_live_msg_iter =
-                       session->lttng_live_msg_iter;
-       struct live_viewer_connection *viewer_connection =
-                       lttng_live_msg_iter->viewer_connection;
-
-       BT_LOGD("Getting %" PRIu32 " new streams:", stream_count);
-       for (i = 0; i < stream_count; i++) {
-               struct lttng_viewer_stream stream;
-               struct lttng_live_stream_iterator *live_stream;
-               uint64_t stream_id;
-               uint64_t ctf_trace_id;
-
-               ret_len = lttng_live_recv(viewer_connection, &stream, sizeof(stream));
-               if (ret_len == 0) {
-                       BT_LOGI("Remote side has closed connection");
-                       goto error;
-               }
-               if (ret_len == BT_SOCKET_ERROR) {
-                       BT_LOGE("Error receiving stream");
-                       goto error;
-               }
-               BT_ASSERT(ret_len == sizeof(stream));
-               stream.path_name[LTTNG_VIEWER_PATH_MAX - 1] = '\0';
-               stream.channel_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0';
-               stream_id = be64toh(stream.id);
-               ctf_trace_id = be64toh(stream.ctf_trace_id);
-
-               if (stream.metadata_flag) {
-                       BT_LOGD("    metadata stream %" PRIu64 " : %s/%s",
-                                       stream_id, stream.path_name,
-                                       stream.channel_name);
-                       if (lttng_live_metadata_create_stream(session,
-                                       ctf_trace_id, stream_id,
-                                       stream.path_name)) {
-                               BT_LOGE("Error creating metadata stream");
-
-                               goto error;
-                       }
-                       session->lazy_stream_msg_init = true;
-               } else {
-                       BT_LOGD("    stream %" PRIu64 " : %s/%s",
-                                       stream_id, stream.path_name,
-                                       stream.channel_name);
-                       live_stream = lttng_live_stream_iterator_create(session,
-                               ctf_trace_id, stream_id);
-                       if (!live_stream) {
-                               BT_LOGE("Error creating streamn");
-                               goto error;
-                       }
-               }
-       }
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-int lttng_live_attach_session(struct lttng_live_session *session)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_attach_session_request rq;
-       struct lttng_viewer_attach_session_response rp;
-       ssize_t ret_len;
-       struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
-       struct live_viewer_connection *viewer_connection =
-                       lttng_live_msg_iter->viewer_connection;
-       uint64_t session_id = session->id;
-       uint32_t streams_count;
-       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
-       char cmd_buf[cmd_buf_len];
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION);
-       cmd.data_size = htobe64((uint64_t) sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.session_id = htobe64(session_id);
-       // TODO: add cmd line parameter to select seek beginning
-       // rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING);
-       rq.seek = htobe32(LTTNG_VIEWER_SEEK_LAST);
-
-       /*
-        * Merge the cmd and connection request to prevent a write-write
-        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
-        * second write to be performed quickly in presence of Nagle's algorithm.
-        */
-       memcpy(cmd_buf, &cmd, sizeof(cmd));
-       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
-       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending attach request: %s", bt_socket_errormsg());
-               goto error;
-       }
-
-       BT_ASSERT(ret_len == cmd_buf_len);
-       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving attach response: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(rp));
-
-       streams_count = be32toh(rp.streams_count);
-       switch(be32toh(rp.status)) {
-       case LTTNG_VIEWER_ATTACH_OK:
-               break;
-       case LTTNG_VIEWER_ATTACH_UNK:
-               BT_LOGW("Session id %" PRIu64 " is unknown", session_id);
-               goto error;
-       case LTTNG_VIEWER_ATTACH_ALREADY:
-               BT_LOGW("There is already a viewer attached to this session");
-               goto error;
-       case LTTNG_VIEWER_ATTACH_NOT_LIVE:
-               BT_LOGW("Not a live session");
-               goto error;
-       case LTTNG_VIEWER_ATTACH_SEEK_ERR:
-               BT_LOGE("Wrong seek parameter");
-               goto error;
-       default:
-               BT_LOGE("Unknown attach return code %u", be32toh(rp.status));
-               goto error;
-       }
-
-       /* We receive the initial list of streams. */
-       if (receive_streams(session, streams_count)) {
-               goto error;
-       }
-
-       session->attached = true;
-       session->new_streams_needed = false;
-
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-int lttng_live_detach_session(struct lttng_live_session *session)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_detach_session_request rq;
-       struct lttng_viewer_detach_session_response rp;
-       ssize_t ret_len;
-       struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
-       struct live_viewer_connection *viewer_connection =
-                       lttng_live_msg_iter->viewer_connection;
-       uint64_t session_id = session->id;
-       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
-       char cmd_buf[cmd_buf_len];
-
-       if (!session->attached) {
-               return 0;
-       }
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_DETACH_SESSION);
-       cmd.data_size = htobe64((uint64_t) sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.session_id = htobe64(session_id);
-
-       /*
-        * Merge the cmd and connection request to prevent a write-write
-        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
-        * second write to be performed quickly in presence of Nagle's algorithm.
-        */
-       memcpy(cmd_buf, &cmd, sizeof(cmd));
-       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
-       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending detach request: %s", bt_socket_errormsg());
-               goto error;
-       }
-
-       BT_ASSERT(ret_len == cmd_buf_len);
-       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving detach response: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(rp));
-
-       switch(be32toh(rp.status)) {
-       case LTTNG_VIEWER_DETACH_SESSION_OK:
-               break;
-       case LTTNG_VIEWER_DETACH_SESSION_UNK:
-               BT_LOGW("Session id %" PRIu64 " is unknown", session_id);
-               goto error;
-       case LTTNG_VIEWER_DETACH_SESSION_ERR:
-               BT_LOGW("Error detaching session id %" PRIu64 "", session_id);
-               goto error;
-       default:
-               BT_LOGE("Unknown detach return code %u", be32toh(rp.status));
-               goto error;
-       }
-
-       session->attached = false;
-
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-ssize_t lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace,
-               FILE *fp)
-{
-       uint64_t len = 0;
-       int ret;
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_get_metadata rq;
-       struct lttng_viewer_metadata_packet rp;
-       char *data = NULL;
-       ssize_t ret_len;
-       struct lttng_live_session *session = trace->session;
-       struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
-       struct lttng_live_metadata *metadata = trace->metadata;
-       struct live_viewer_connection *viewer_connection =
-                       lttng_live_msg_iter->viewer_connection;
-       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
-       char cmd_buf[cmd_buf_len];
-
-       rq.stream_id = htobe64(metadata->stream_id);
-       cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA);
-       cmd.data_size = htobe64((uint64_t) sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       /*
-        * Merge the cmd and connection request to prevent a write-write
-        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
-        * second write to be performed quickly in presence of Nagle's algorithm.
-        */
-       memcpy(cmd_buf, &cmd, sizeof(cmd));
-       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
-       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending get_metadata request: %s", bt_socket_errormsg());
-               goto error;
-       }
-
-       BT_ASSERT(ret_len == cmd_buf_len);
-       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving get_metadata response: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(rp));
-
-       switch (be32toh(rp.status)) {
-               case LTTNG_VIEWER_METADATA_OK:
-                       BT_LOGD("get_metadata : OK");
-                       break;
-               case LTTNG_VIEWER_NO_NEW_METADATA:
-                       BT_LOGD("get_metadata : NO NEW");
-                       ret = 0;
-                       goto end;
-               case LTTNG_VIEWER_METADATA_ERR:
-                       BT_LOGD("get_metadata : ERR");
-                       goto error;
-               default:
-                       BT_LOGD("get_metadata : UNKNOWN");
-                       goto error;
-       }
-
-       len = be64toh(rp.len);
-       BT_LOGD("Writing %" PRIu64" bytes to metadata", len);
-       if (len <= 0) {
-               goto error;
-       }
-
-       data = zmalloc(len);
-       if (!data) {
-               BT_LOGE("relay data zmalloc: %s", strerror(errno));
-               goto error;
-       }
-       ret_len = lttng_live_recv(viewer_connection, data, len);
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error_free_data;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving trace packet: %s", bt_socket_errormsg());
-               goto error_free_data;
-       }
-       BT_ASSERT(ret_len == len);
-
-       do {
-               ret_len = fwrite(data, 1, len, fp);
-       } while (ret_len < 0 && errno == EINTR);
-       if (ret_len < 0) {
-               BT_LOGE("Writing in the metadata fp");
-               goto error_free_data;
-       }
-       BT_ASSERT(ret_len == len);
-       free(data);
-       ret = len;
-end:
-       return ret;
-
-error_free_data:
-       free(data);
-error:
-       return -1;
-}
-
-/*
- * Assign the fields from a lttng_viewer_index to a packet_index.
- */
-static
-void lttng_index_to_packet_index(struct lttng_viewer_index *lindex,
-               struct packet_index *pindex)
-{
-       BT_ASSERT(lindex);
-       BT_ASSERT(pindex);
-
-       pindex->offset = be64toh(lindex->offset);
-       pindex->packet_size = be64toh(lindex->packet_size);
-       pindex->content_size = be64toh(lindex->content_size);
-       pindex->ts_cycles.timestamp_begin = be64toh(lindex->timestamp_begin);
-       pindex->ts_cycles.timestamp_end = be64toh(lindex->timestamp_end);
-       pindex->events_discarded = be64toh(lindex->events_discarded);
-}
-
-BT_HIDDEN
-enum lttng_live_iterator_status lttng_live_get_next_index(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *stream,
-               struct packet_index *index)
-{
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_get_next_index rq;
-       ssize_t ret_len;
-       struct lttng_viewer_index rp;
-       uint32_t flags, status;
-       enum lttng_live_iterator_status retstatus =
-                       LTTNG_LIVE_ITERATOR_STATUS_OK;
-       struct live_viewer_connection *viewer_connection =
-                       lttng_live_msg_iter->viewer_connection;
-       struct lttng_live_trace *trace = stream->trace;
-       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
-       char cmd_buf[cmd_buf_len];
-       struct lttng_live_component *lttng_live =
-               lttng_live_msg_iter->lttng_live_comp;
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX);
-       cmd.data_size = htobe64((uint64_t) sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-
-       memset(&rq, 0, sizeof(rq));
-       rq.stream_id = htobe64(stream->viewer_stream_id);
-
-       /*
-        * Merge the cmd and connection request to prevent a write-write
-        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
-        * second write to be performed quickly in presence of Nagle's algorithm.
-        */
-       memcpy(cmd_buf, &cmd, sizeof(cmd));
-       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
-       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending get_next_index request: %s",
-                               bt_socket_errormsg());
-               goto error;
-       }
-
-       BT_ASSERT(ret_len == cmd_buf_len);
-       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving get_next_index response: %s",
-                               bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(rp));
-
-       flags = be32toh(rp.flags);
-       status = be32toh(rp.status);
-
-       switch (status) {
-       case LTTNG_VIEWER_INDEX_INACTIVE:
-       {
-               uint64_t ctf_stream_class_id;
-
-               BT_LOGD("get_next_index: inactive");
-               memset(index, 0, sizeof(struct packet_index));
-               index->ts_cycles.timestamp_end = be64toh(rp.timestamp_end);
-               stream->current_inactivity_ts = index->ts_cycles.timestamp_end;
-               ctf_stream_class_id = be64toh(rp.stream_id);
-               if (stream->ctf_stream_class_id != -1ULL) {
-                       BT_ASSERT(stream->ctf_stream_class_id ==
-                               ctf_stream_class_id);
-               } else {
-                       stream->ctf_stream_class_id = ctf_stream_class_id;
-               }
-               stream->state = LTTNG_LIVE_STREAM_QUIESCENT;
-               break;
-       }
-       case LTTNG_VIEWER_INDEX_OK:
-       {
-               uint64_t ctf_stream_class_id;
-
-               BT_LOGD("get_next_index: OK");
-               lttng_index_to_packet_index(&rp, index);
-               ctf_stream_class_id = be64toh(rp.stream_id);
-               if (stream->ctf_stream_class_id != -1ULL) {
-                       BT_ASSERT(stream->ctf_stream_class_id ==
-                               ctf_stream_class_id);
-               } else {
-                       stream->ctf_stream_class_id = ctf_stream_class_id;
-               }
-
-               stream->state = LTTNG_LIVE_STREAM_ACTIVE_DATA;
-
-               if (flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
-                       BT_LOGD("get_next_index: new metadata needed");
-                       trace->new_metadata_needed = true;
-               }
-               if (flags & LTTNG_VIEWER_FLAG_NEW_STREAM) {
-                       BT_LOGD("get_next_index: new streams needed");
-                       lttng_live_need_new_streams(lttng_live_msg_iter);
-               }
-               break;
-       }
-       case LTTNG_VIEWER_INDEX_RETRY:
-               BT_LOGD("get_next_index: retry");
-               memset(index, 0, sizeof(struct packet_index));
-               retstatus = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-               stream->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
-               goto end;
-       case LTTNG_VIEWER_INDEX_HUP:
-               BT_LOGD("get_next_index: stream hung up");
-               memset(index, 0, sizeof(struct packet_index));
-               index->offset = EOF;
-               retstatus = LTTNG_LIVE_ITERATOR_STATUS_END;
-               stream->state = LTTNG_LIVE_STREAM_EOF;
-               break;
-       case LTTNG_VIEWER_INDEX_ERR:
-               BT_LOGE("get_next_index: error");
-               memset(index, 0, sizeof(struct packet_index));
-               stream->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
-               goto error;
-       default:
-               BT_LOGE("get_next_index: unknown value");
-               memset(index, 0, sizeof(struct packet_index));
-               stream->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
-               goto error;
-       }
-end:
-       return retstatus;
-
-error:
-       if (lttng_live_graph_is_canceled(lttng_live)) {
-               retstatus = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-       } else {
-               retstatus = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-       }
-       return retstatus;
-}
-
-BT_HIDDEN
-enum bt_msg_iter_medium_status lttng_live_get_stream_bytes(
-               struct lttng_live_msg_iter *lttng_live_msg_iter,
-               struct lttng_live_stream_iterator *stream, uint8_t *buf,
-               uint64_t offset, uint64_t req_len, uint64_t *recv_len)
-{
-       enum bt_msg_iter_medium_status retstatus = BT_MSG_ITER_MEDIUM_STATUS_OK;
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_get_packet rq;
-       struct lttng_viewer_trace_packet rp;
-       ssize_t ret_len;
-       uint32_t flags, status;
-       struct live_viewer_connection *viewer_connection =
-                       lttng_live_msg_iter->viewer_connection;
-       struct lttng_live_trace *trace = stream->trace;
-       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
-       char cmd_buf[cmd_buf_len];
-       struct lttng_live_component *lttng_live =
-               lttng_live_msg_iter->lttng_live_comp;
-
-       BT_LOGD("lttng_live_get_stream_bytes: offset=%" PRIu64 ", req_len=%" PRIu64,
-                       offset, req_len);
-       cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET);
-       cmd.data_size = htobe64((uint64_t) sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.stream_id = htobe64(stream->viewer_stream_id);
-       rq.offset = htobe64(offset);
-       rq.len = htobe32(req_len);
-
-       /*
-        * Merge the cmd and connection request to prevent a write-write
-        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
-        * second write to be performed quickly in presence of Nagle's algorithm.
-        */
-       memcpy(cmd_buf, &cmd, sizeof(cmd));
-       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
-       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending get_data request: %s", bt_socket_errormsg());
-               goto error;
-       }
-
-       BT_ASSERT(ret_len == cmd_buf_len);
-       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving get_data response: %s", bt_socket_errormsg());
-               goto error;
-       }
-       if (ret_len != sizeof(rp)) {
-               BT_LOGE("get_data_packet: expected %zu"
-                               ", received %zd", sizeof(rp),
-                               ret_len);
-               goto error;
-       }
-
-       flags = be32toh(rp.flags);
-       status = be32toh(rp.status);
-
-       switch (status) {
-       case LTTNG_VIEWER_GET_PACKET_OK:
-               req_len = be32toh(rp.len);
-               BT_LOGD("get_data_packet: Ok, packet size : %" PRIu64 "", req_len);
-               break;
-       case LTTNG_VIEWER_GET_PACKET_RETRY:
-               /* Unimplemented by relay daemon */
-               BT_LOGD("get_data_packet: retry");
-               retstatus = BT_MSG_ITER_MEDIUM_STATUS_AGAIN;
-               goto end;
-       case LTTNG_VIEWER_GET_PACKET_ERR:
-               if (flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
-                       BT_LOGD("get_data_packet: new metadata needed, try again later");
-                       trace->new_metadata_needed = true;
-               }
-               if (flags & LTTNG_VIEWER_FLAG_NEW_STREAM) {
-                       BT_LOGD("get_data_packet: new streams needed, try again later");
-                       lttng_live_need_new_streams(lttng_live_msg_iter);
-               }
-               if (flags & (LTTNG_VIEWER_FLAG_NEW_METADATA
-                               | LTTNG_VIEWER_FLAG_NEW_STREAM)) {
-                       retstatus = BT_MSG_ITER_MEDIUM_STATUS_AGAIN;
-                       goto end;
-               }
-               BT_LOGE("get_data_packet: error");
-               goto error;
-       case LTTNG_VIEWER_GET_PACKET_EOF:
-               retstatus = BT_MSG_ITER_MEDIUM_STATUS_EOF;
-               goto end;
-       default:
-               BT_LOGE("get_data_packet: unknown");
-               goto error;
-       }
-
-       if (req_len == 0) {
-               goto error;
-       }
-
-       ret_len = lttng_live_recv(viewer_connection, buf, req_len);
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving trace packet: %s", bt_socket_errormsg());
-               goto error;
-       }
-       BT_ASSERT(ret_len == req_len);
-       *recv_len = ret_len;
-end:
-       return retstatus;
-
-error:
-       if (lttng_live_graph_is_canceled(lttng_live)) {
-               retstatus = BT_MSG_ITER_MEDIUM_STATUS_AGAIN;
-       } else {
-               retstatus = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
-       }
-       return retstatus;
-}
-
-/*
- * Request new streams for a session.
- */
-BT_HIDDEN
-enum lttng_live_iterator_status lttng_live_get_new_streams(
-               struct lttng_live_session *session)
-{
-       enum lttng_live_iterator_status status =
-               LTTNG_LIVE_ITERATOR_STATUS_OK;
-       struct lttng_viewer_cmd cmd;
-       struct lttng_viewer_new_streams_request rq;
-       struct lttng_viewer_new_streams_response rp;
-       ssize_t ret_len;
-       struct lttng_live_msg_iter *lttng_live_msg_iter =
-               session->lttng_live_msg_iter;
-       struct live_viewer_connection *viewer_connection =
-               lttng_live_msg_iter->viewer_connection;
-       struct lttng_live_component *lttng_live =
-               lttng_live_msg_iter->lttng_live_comp;
-       uint32_t streams_count;
-       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
-       char cmd_buf[cmd_buf_len];
-
-       if (!session->new_streams_needed) {
-               return LTTNG_LIVE_ITERATOR_STATUS_OK;
-       }
-
-       cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEW_STREAMS);
-       cmd.data_size = htobe64((uint64_t) sizeof(rq));
-       cmd.cmd_version = htobe32(0);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.session_id = htobe64(session->id);
-
-       /*
-        * Merge the cmd and connection request to prevent a write-write
-        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
-        * second write to be performed quickly in presence of Nagle's algorithm.
-        */
-       memcpy(cmd_buf, &cmd, sizeof(cmd));
-       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
-       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error sending get_new_streams request: %s",
-                               bt_socket_errormsg());
-               goto error;
-       }
-
-       BT_ASSERT(ret_len == cmd_buf_len);
-       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
-       if (ret_len == 0) {
-               BT_LOGI("Remote side has closed connection");
-               goto error;
-       }
-       if (ret_len == BT_SOCKET_ERROR) {
-               BT_LOGE("Error receiving get_new_streams response");
-               goto error;
-       }
-       BT_ASSERT(ret_len == sizeof(rp));
-
-       streams_count = be32toh(rp.streams_count);
-
-       switch(be32toh(rp.status)) {
-       case LTTNG_VIEWER_NEW_STREAMS_OK:
-               session->new_streams_needed = false;
-               break;
-       case LTTNG_VIEWER_NEW_STREAMS_NO_NEW:
-               session->new_streams_needed = false;
-               goto end;
-       case LTTNG_VIEWER_NEW_STREAMS_HUP:
-               session->new_streams_needed = false;
-               session->closed = true;
-               status = LTTNG_LIVE_ITERATOR_STATUS_END;
-               goto end;
-       case LTTNG_VIEWER_NEW_STREAMS_ERR:
-               BT_LOGE("get_new_streams error");
-               goto error;
-       default:
-               BT_LOGE("Unknown return code %u", be32toh(rp.status));
-               goto error;
-       }
-
-       if (receive_streams(session, streams_count)) {
-               goto error;
-       }
-end:
-       return status;
-
-error:
-       if (lttng_live_graph_is_canceled(lttng_live)) {
-               status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
-       } else {
-               status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
-       }
-       return status;
-}
-
-BT_HIDDEN
-struct live_viewer_connection *live_viewer_connection_create(
-               const char *url, bool in_query,
-               struct lttng_live_msg_iter *lttng_live_msg_iter)
-{
-       struct live_viewer_connection *viewer_connection;
-
-       viewer_connection = g_new0(struct live_viewer_connection, 1);
-
-       if (bt_socket_init() != 0) {
-               goto error;
-       }
-
-       bt_object_init_shared(&viewer_connection->obj, connection_release);
-       viewer_connection->control_sock = BT_INVALID_SOCKET;
-       viewer_connection->port = -1;
-       viewer_connection->in_query = in_query;
-       viewer_connection->lttng_live_msg_iter = lttng_live_msg_iter;
-       viewer_connection->url = g_string_new(url);
-       if (!viewer_connection->url) {
-               goto error;
-       }
-
-       BT_LOGD("Establishing connection to url \"%s\"...", url);
-       if (lttng_live_connect_viewer(viewer_connection)) {
-               goto error_report;
-       }
-       BT_LOGD("Connection to url \"%s\" is established", url);
-       return viewer_connection;
-
-error_report:
-       BT_LOGW("Failure to establish connection to url \"%s\"", url);
-error:
-       g_free(viewer_connection);
-       return NULL;
-}
-
-BT_HIDDEN
-void live_viewer_connection_destroy(
-               struct live_viewer_connection *viewer_connection)
-{
-       BT_LOGD("Closing connection to url \"%s\"", viewer_connection->url->str);
-       lttng_live_disconnect_viewer(viewer_connection);
-       g_string_free(viewer_connection->url, true);
-       if (viewer_connection->relay_hostname) {
-               g_string_free(viewer_connection->relay_hostname, true);
-       }
-       if (viewer_connection->target_hostname) {
-               g_string_free(viewer_connection->target_hostname, true);
-       }
-       if (viewer_connection->session_name) {
-               g_string_free(viewer_connection->session_name, true);
-       }
-       g_free(viewer_connection);
-
-       bt_socket_fini();
-}
diff --git a/plugins/ctf/lttng-live/viewer-connection.h b/plugins/ctf/lttng-live/viewer-connection.h
deleted file mode 100644 (file)
index 752d1a9..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef LTTNG_LIVE_VIEWER_CONNECTION_H
-#define LTTNG_LIVE_VIEWER_CONNECTION_H
-
-/*
- * Copyright 2016 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-#include <glib.h>
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compat/socket-internal.h>
-
-//TODO: this should not be used by plugins. Should copy code into plugin
-//instead.
-#include <babeltrace2/object-internal.h>
-
-#define LTTNG_DEFAULT_NETWORK_VIEWER_PORT      5344
-
-#define LTTNG_LIVE_MAJOR                       2
-#define LTTNG_LIVE_MINOR                       4
-
-struct lttng_live_component;
-
-struct live_viewer_connection {
-       bt_object obj;
-
-       GString *url;
-
-       GString *relay_hostname;
-       GString *target_hostname;
-       GString *session_name;
-
-       BT_SOCKET control_sock;
-       int port;
-
-       int32_t major;
-       int32_t minor;
-
-       bool in_query;
-       struct lttng_live_msg_iter *lttng_live_msg_iter;
-};
-
-struct packet_index_time {
-       uint64_t timestamp_begin;
-       uint64_t timestamp_end;
-};
-
-struct packet_index {
-       off_t offset;           /* offset of the packet in the file, in bytes */
-       int64_t data_offset;    /* offset of data within the packet, in bits */
-       uint64_t packet_size;   /* packet size, in bits */
-       uint64_t content_size;  /* content size, in bits */
-       uint64_t events_discarded;
-       uint64_t events_discarded_len;  /* length of the field, in bits */
-       struct packet_index_time ts_cycles;     /* timestamp in cycles */
-       struct packet_index_time ts_real;       /* realtime timestamp */
-       /* CTF_INDEX 1.0 limit */
-       uint64_t stream_instance_id;    /* ID of the channel instance */
-       uint64_t packet_seq_num;        /* packet sequence number */
-};
-
-struct live_viewer_connection * live_viewer_connection_create(
-               const char *url, bool in_query,
-               struct lttng_live_msg_iter *lttng_live_msg_iter);
-
-void live_viewer_connection_destroy(
-               struct live_viewer_connection *conn);
-
-bt_query_status live_viewer_connection_list_sessions(
-               struct live_viewer_connection *viewer_connection,
-               const bt_value **user_result);
-
-#endif /* LTTNG_LIVE_VIEWER_CONNECTION_H */
diff --git a/plugins/ctf/plugin.c b/plugins/ctf/plugin.c
deleted file mode 100644 (file)
index 9597403..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * plugin.c
- *
- * Babeltrace CTF Plug-in Registration Symbols
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-
-#include "fs-src/fs.h"
-#include "fs-sink/fs-sink.h"
-#include "lttng-live/lttng-live.h"
-
-#ifndef BT_BUILT_IN_PLUGINS
-BT_PLUGIN_MODULE();
-#endif
-
-/* Initialize plug-in description. */
-BT_PLUGIN(ctf);
-BT_PLUGIN_DESCRIPTION("CTF source and sink support");
-BT_PLUGIN_AUTHOR("Julien Desfossez, Mathieu Desnoyers, Jérémie Galarneau, Philippe Proulx");
-BT_PLUGIN_LICENSE("MIT");
-
-/* ctf.fs source */
-BT_PLUGIN_SOURCE_COMPONENT_CLASS(fs, ctf_fs_iterator_next);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION(fs,
-       "Read CTF traces from the file system.");
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_INIT_METHOD(fs, ctf_fs_init);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_QUERY_METHOD(fs, ctf_fs_query);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD(fs, ctf_fs_finalize);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD(fs,
-       ctf_fs_iterator_init);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD(fs,
-       ctf_fs_iterator_finalize);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD(fs,
-       ctf_fs_iterator_seek_beginning);
-
-/* ctf.fs sink */
-BT_PLUGIN_SINK_COMPONENT_CLASS(fs, ctf_fs_sink_consume);
-BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(fs, ctf_fs_sink_init);
-BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(fs, ctf_fs_sink_finalize);
-BT_PLUGIN_SINK_COMPONENT_CLASS_GRAPH_IS_CONFIGURED_METHOD(fs,
-       ctf_fs_sink_graph_is_configured);
-BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(fs, "Write CTF traces to the file system.");
-
-/* ctf.lttng-live source */
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_WITH_ID(auto, lttng_live, "lttng-live",
-       lttng_live_msg_iter_next);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION_WITH_ID(auto, lttng_live,
-       "Connect to an LTTng relay daemon and receive CTF streams.");
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_INIT_METHOD_WITH_ID(auto, lttng_live,
-       lttng_live_component_init);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_QUERY_METHOD_WITH_ID(auto, lttng_live,
-       lttng_live_query);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD_WITH_ID(auto, lttng_live,
-       lttng_live_component_finalize);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD_WITH_ID(auto,
-       lttng_live, lttng_live_msg_iter_init);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD_WITH_ID(auto,
-       lttng_live, lttng_live_msg_iter_finalize);
diff --git a/plugins/ctf/print.h b/plugins/ctf/print.h
deleted file mode 100644 (file)
index eab99d7..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef CTF_PRINT_H
-#define CTF_PRINT_H
-
-/*
- * Define PRINT_PREFIX, PRINT_DBG_CHECK, and PRINT_ERR_STREAM, then
- * include this file.
- *
- * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdio.h>
-
-#define PERR(fmt, ...)                                                 \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "[error " PRINT_PREFIX "] " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PWARN(fmt, ...)                                                        \
-       do {                                                            \
-               if (PRINT_ERR_STREAM) {                                 \
-                       fprintf(PRINT_ERR_STREAM,                       \
-                               "[warning " PRINT_PREFIX "] " fmt,      \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#define PDBG(fmt, ...)                                                 \
-       do {                                                            \
-               if (PRINT_DBG_CHECK) {                                  \
-                       fprintf(stderr,                                 \
-                               "[debug " PRINT_PREFIX "] " fmt,        \
-                               ##__VA_ARGS__);                         \
-               }                                                       \
-       } while (0)
-
-#endif /* CTF_PRINT_H */
diff --git a/plugins/lttng-utils/Makefile.am b/plugins/lttng-utils/Makefile.am
deleted file mode 100644 (file)
index 1d555a5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-SUBDIRS =
-
-babeltrace_plugin_lttng_utils_la_LIBADD =
-
-if ENABLE_DEBUG_INFO
-SUBDIRS += debug-info
-babeltrace_plugin_lttng_utils_la_LIBADD += \
-       debug-info/libdebug-info.la
-endif
-
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-plugindir = "$(PLUGINSDIR)"
-plugin_LTLIBRARIES = babeltrace-plugin-lttng-utils.la
-
-babeltrace_plugin_lttng_utils_la_SOURCES = \
-       plugin.c
-
-babeltrace_plugin_lttng_utils_la_LDFLAGS = \
-       $(LT_NO_UNDEFINED) \
-       -avoid-version -module \
-       $(ELFUTILS_LIBS)
-
-if !ENABLE_BUILT_IN_PLUGINS
-babeltrace_plugin_lttng_utils_la_LIBADD += \
-       $(top_builddir)/lib/libbabeltrace2.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la
-endif
diff --git a/plugins/lttng-utils/debug-info/Makefile.am b/plugins/lttng-utils/debug-info/Makefile.am
deleted file mode 100644 (file)
index 0dea0a4..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-noinst_LTLIBRARIES = libdebug-info.la
-
-libdebug_info_la_LIBADD = \
-       $(top_builddir)/fd-cache/libbabeltrace2-fd-cache.la
-
-libdebug_info_la_SOURCES = \
-       bin-info.c \
-       bin-info.h \
-       crc32.c \
-       crc32.h \
-       debug-info.c \
-       debug-info.h \
-       dwarf.c \
-       dwarf.h \
-       logging.c \
-       logging.h \
-       trace-ir-data-copy.c \
-       trace-ir-data-copy.h \
-       trace-ir-mapping.c \
-       trace-ir-mapping.h \
-       trace-ir-metadata-copy.c \
-       trace-ir-metadata-copy.h \
-       trace-ir-metadata-field-class-copy.c \
-       trace-ir-metadata-field-class-copy.h \
-       utils.c \
-       utils.h
diff --git a/plugins/lttng-utils/debug-info/bin-info.c b/plugins/lttng-utils/debug-info/bin-info.c
deleted file mode 100644 (file)
index bad796d..0000000
+++ /dev/null
@@ -1,1583 +0,0 @@
-/*
- * bin-info.c
- *
- * Babeltrace - Executable and Shared Object Debug Info Reader
- *
- * Copyright 2015 Antoine Busque <abusque@efficios.com>
- *
- * Author: Antoine Busque <abusque@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT-BIN-INFO"
-#include "logging.h"
-
-#include <dwarf.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <glib.h>
-
-#include <babeltrace2/common-internal.h>
-
-#include "bin-info.h"
-#include "crc32.h"
-#include "dwarf.h"
-#include "utils.h"
-
-/*
- * An address printed in hex is at most 20 bytes (16 for 64-bits +
- * leading 0x + optional leading '+' if addr is an offset + null
- * character).
- */
-#define ADDR_STR_LEN 20
-#define BUILD_ID_NOTE_NAME "GNU"
-
-BT_HIDDEN
-int bin_info_init(void)
-{
-       int ret = 0;
-
-       if (elf_version(EV_CURRENT) == EV_NONE) {
-               BT_LOGD("ELF library initialization failed: %s.",
-                       elf_errmsg(-1));
-               ret = -1;
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path,
-               uint64_t low_addr, uint64_t memsz, bool is_pic,
-               const char *debug_info_dir, const char *target_prefix)
-{
-       struct bin_info *bin = NULL;
-
-       BT_ASSERT(fdc);
-
-       if (!path) {
-               goto error;
-       }
-
-       bin = g_new0(struct bin_info, 1);
-       if (!bin) {
-               goto error;
-       }
-
-       if (target_prefix) {
-               bin->elf_path = g_build_filename(target_prefix, path, NULL);
-       } else {
-               bin->elf_path = g_strdup(path);
-       }
-
-       if (!bin->elf_path) {
-               goto error;
-       }
-
-       if (debug_info_dir) {
-               bin->debug_info_dir = g_strdup(debug_info_dir);
-               if (!bin->debug_info_dir) {
-                       goto error;
-               }
-       }
-
-       bin->is_pic = is_pic;
-       bin->memsz = memsz;
-       bin->low_addr = low_addr;
-       bin->high_addr = bin->low_addr + bin->memsz;
-       bin->build_id = NULL;
-       bin->build_id_len = 0;
-       bin->file_build_id_matches = false;
-       bin->fd_cache = fdc;
-
-       return bin;
-
-error:
-       bin_info_destroy(bin);
-       return NULL;
-}
-
-BT_HIDDEN
-void bin_info_destroy(struct bin_info *bin)
-{
-       if (!bin) {
-               return;
-       }
-
-       dwarf_end(bin->dwarf_info);
-
-       g_free(bin->debug_info_dir);
-       g_free(bin->elf_path);
-       g_free(bin->dwarf_path);
-       g_free(bin->build_id);
-       g_free(bin->dbg_link_filename);
-
-       elf_end(bin->elf_file);
-
-       bt_fd_cache_put_handle(bin->fd_cache, bin->elf_handle);
-       bt_fd_cache_put_handle(bin->fd_cache, bin->dwarf_handle);
-
-       g_free(bin);
-}
-
-/**
- * Initialize the ELF file for a given executable.
- *
- * @param bin  bin_info instance
- * @returns    0 on success, negative value on error.
- */
-static
-int bin_info_set_elf_file(struct bin_info *bin)
-{
-       struct bt_fd_cache_handle *elf_handle = NULL;
-       Elf *elf_file = NULL;
-
-       if (!bin) {
-               goto error;
-       }
-
-       elf_handle = bt_fd_cache_get_handle(bin->fd_cache, bin->elf_path);
-       if (!elf_handle) {
-               BT_LOGD("Failed to open %s", bin->elf_path);
-               goto error;
-       }
-       bin->elf_handle = elf_handle;
-
-       elf_file = elf_begin(bt_fd_cache_handle_get_fd(bin->elf_handle),
-               ELF_C_READ, NULL);
-       if (!elf_file) {
-               BT_LOGE("elf_begin failed: %s", elf_errmsg(-1));
-               goto error;
-       }
-
-       bin->elf_file = elf_file;
-
-       if (elf_kind(elf_file) != ELF_K_ELF) {
-               BT_LOGE("Error: %s is not an ELF object", bin->elf_path);
-               goto error;
-       }
-
-       return 0;
-
-error:
-       bt_fd_cache_put_handle(bin->fd_cache, elf_handle);
-       elf_end(elf_file);
-       return -1;
-}
-
-/**
- * From a note section data struct, check if it is a build id note.
- *
- * @param note_data            Pointer to a note section
- *
- * @returns                    1 on match, 0 if `buf` does not contain a
- *                             valid build id note
- */
-static
-int is_build_id_note_section(Elf_Data *note_data)
-{
-       size_t name_offset, desc_offset;
-       GElf_Nhdr note_header;
-       int ret = 0;
-
-       /*
-        * Discard the return value as it contains the size of the note section
-        * and we don't need it.
-        */
-       (void) gelf_getnote(note_data, 0, &note_header, &name_offset,
-               &desc_offset);
-
-       /*
-        * Check the note name length. The name_sz field includes the
-        * terminating null byte.
-        */
-       if (note_header.n_namesz != sizeof(BUILD_ID_NOTE_NAME)) {
-               goto invalid;
-       }
-
-       /* Check the note type. */
-       if (note_header.n_type != NT_GNU_BUILD_ID) {
-               goto invalid;
-       }
-
-       /* Check the note name. */
-       if (memcmp(note_data->d_buf + name_offset, BUILD_ID_NOTE_NAME,
-                       note_header.n_namesz) != 0) {
-               goto invalid;
-       }
-
-       ret = 1;
-
-invalid:
-       return ret;
-}
-
-/**
- *  From a build id note section data struct, check if the build id it contains
- *  is identical to the build id passed as parameter.
- *
- * @param note_data            Pointer to the file build id note section.
- * @param build_id             Pointer to a build id to compare to.
- * @param build_id_len         length of the build id.
- *
- * @returns                    1 on match, 0 otherwise.
- */
-static
-int is_build_id_note_section_matching(Elf_Data *note_data,
-               uint8_t *build_id, size_t build_id_len)
-{
-       size_t name_offset, desc_offset;
-       GElf_Nhdr note_header;
-
-       if (build_id_len <= 0) {
-               goto end;
-       }
-
-       /*
-        * Discard the return value as it contains the size of the note section
-        * and we don't need it.
-        */
-       (void) gelf_getnote(note_data, 0, &note_header, &name_offset,
-               &desc_offset);
-
-       /*
-        * Compare the binary build id with the supplied build id.
-        */
-       if (memcmp(build_id, note_data->d_buf + desc_offset,
-                       build_id_len) == 0) {
-               return 1;
-       }
-end:
-       return 0;
-}
-
-/**
- * Checks if the build id stored in `bin` (bin->build_id) is matching the build
- * id of the ondisk file (bin->elf_file).
- *
- * @param bin                  bin_info instance
- * @param build_id             build id to compare ot the on disk file
- * @param build_id_len         length of the build id
- *
- * @returns                    1 on if the build id of stored in `bin` matches
- *                             the build id of the ondisk file.
- *                             0 on if they are different or an error occured.
- */
-static
-int is_build_id_matching(struct bin_info *bin)
-{
-       int ret, is_build_id, is_matching = 0;
-       Elf_Scn *curr_section = NULL, *next_section = NULL;
-       GElf_Shdr curr_section_hdr;
-
-       if (!bin->build_id) {
-               goto error;
-       }
-
-       /* Set ELF file if it hasn't been accessed yet. */
-       if (!bin->elf_file) {
-               ret = bin_info_set_elf_file(bin);
-               if (ret) {
-                       /* Failed to set ELF file. */
-                       goto error;
-               }
-       }
-
-       next_section = elf_nextscn(bin->elf_file, curr_section);
-       if (!next_section) {
-               goto error;
-       }
-
-       while (next_section) {
-               Elf_Data *note_data = NULL;
-
-               curr_section = next_section;
-               next_section = elf_nextscn(bin->elf_file, curr_section);
-
-               if (!gelf_getshdr(curr_section, &curr_section_hdr)) {
-                       goto error;
-               }
-
-               if (curr_section_hdr.sh_type != SHT_NOTE) {
-                       continue;
-               }
-
-               /*
-                * elf_getdata() translates the data to native byte order.
-                */
-               note_data = elf_getdata(curr_section, NULL);
-               if (!note_data) {
-                       goto error;
-               }
-
-               /* Check if the note is of the build-id type. */
-               is_build_id = is_build_id_note_section(note_data);
-               if (!is_build_id) {
-                       continue;
-               }
-
-               /*
-                * Compare the build id of the on-disk file and
-                * the build id recorded in the trace.
-                */
-               is_matching = is_build_id_note_section_matching(
-                       note_data, bin->build_id, bin->build_id_len);
-               if (!is_matching) {
-                       break;
-               }
-       }
-error:
-       return is_matching;
-}
-
-BT_HIDDEN
-int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id,
-               size_t build_id_len)
-{
-       if (!bin || !build_id) {
-               goto error;
-       }
-
-       /* Set the build id. */
-       bin->build_id = g_new0(uint8_t, build_id_len);
-       if (!bin->build_id) {
-               goto error;
-       }
-
-       memcpy(bin->build_id, build_id, build_id_len);
-       bin->build_id_len = build_id_len;
-
-       /*
-        * Check if the file found on the file system has the same build id
-        * that what was recorded in the trace.
-        */
-       bin->file_build_id_matches = is_build_id_matching(bin);
-       if (!bin->file_build_id_matches) {
-               BT_LOGD_STR("Supplied Build ID does not match Build ID of the "
-                               "binary or library found on the file system.");
-               goto error;
-       }
-
-       /*
-        * Reset the is_elf_only flag in case it had been set
-        * previously, because we might find separate debug info using
-        * the new build id information.
-        */
-       bin->is_elf_only = false;
-
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-int bin_info_set_debug_link(struct bin_info *bin, const char *filename,
-               uint32_t crc)
-{
-       if (!bin || !filename) {
-               goto error;
-       }
-
-       bin->dbg_link_filename = g_strdup(filename);
-       if (!bin->dbg_link_filename) {
-               goto error;
-       }
-
-       bin->dbg_link_crc = crc;
-
-       /*
-        * Reset the is_elf_only flag in case it had been set
-        * previously, because we might find separate debug info using
-        * the new build id information.
-        */
-       bin->is_elf_only = false;
-
-       return 0;
-
-error:
-
-       return -1;
-}
-
-/**
- * Tries to read DWARF info from the location given by path, and
- * attach it to the given bin_info instance if it exists.
- *
- * @param bin  bin_info instance for which to set DWARF info
- * @param path Presumed location of the DWARF info
- * @returns    0 on success, negative value on failure
- */
-static
-int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
-{
-       int ret = 0;
-       struct bt_fd_cache_handle *dwarf_handle = NULL;
-       struct bt_dwarf_cu *cu = NULL;
-       Dwarf *dwarf_info = NULL;
-
-       if (!bin || !path) {
-               goto error;
-       }
-
-       dwarf_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
-       if (!dwarf_handle) {
-               goto error;
-       }
-
-       dwarf_info = dwarf_begin(bt_fd_cache_handle_get_fd(dwarf_handle),
-               DWARF_C_READ);
-       if (!dwarf_info) {
-               goto error;
-       }
-
-       /*
-        * Check if the dwarf info has any CU. If not, the
-        * executable's object file contains no DWARF info.
-        */
-       cu = bt_dwarf_cu_create(dwarf_info);
-       if (!cu) {
-               goto error;
-       }
-
-       ret = bt_dwarf_cu_next(cu);
-       if (ret) {
-               goto error;
-       }
-
-       bin->dwarf_handle = dwarf_handle;
-       bin->dwarf_path = g_strdup(path);
-       if (!bin->dwarf_path) {
-               goto error;
-       }
-       bin->dwarf_info = dwarf_info;
-       free(cu);
-
-       return 0;
-
-error:
-       bt_fd_cache_put_handle(bin->fd_cache, dwarf_handle);
-       dwarf_end(dwarf_info);
-       g_free(dwarf_info);
-       free(cu);
-
-       return -1;
-}
-
-/**
- * Try to set the dwarf_info for a given bin_info instance via the
- * build ID method.
- *
- * @param bin          bin_info instance for which to retrieve the
- *                     DWARF info via build ID
- * @returns            0 on success (i.e. dwarf_info set), -1 on failure
- */
-static
-int bin_info_set_dwarf_info_build_id(struct bin_info *bin)
-{
-       int i = 0, ret = 0;
-       char *path = NULL, *build_id_prefix_dir = NULL, *build_id_file = NULL;
-       const char *dbg_dir = NULL;
-       size_t build_id_char_len, build_id_suffix_char_len, build_id_file_len;
-
-       if (!bin || !bin->build_id) {
-               goto error;
-       }
-
-       dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR;
-
-       /*
-        * The prefix dir is the first byte of the build id, represented in
-        * lowercase hex as two characters per byte, +1 for '\0'.
-        */
-       build_id_prefix_dir = g_new0(gchar, BUILD_ID_PREFIX_DIR_LEN + 1);
-       if (!build_id_prefix_dir) {
-               goto error;
-       }
-       g_snprintf(build_id_prefix_dir, BUILD_ID_PREFIX_DIR_LEN + 1, "%02x", bin->build_id[0]);
-
-       /*
-        * The build id file is the remaining bytes of the build id,
-        * represented in lowercase hex, as two characters per byte.
-        */
-       build_id_char_len = (2 * (bin->build_id_len - 1));
-
-       /* To which the build id suffix is added, +1 for '\0'. */
-       build_id_suffix_char_len = strlen(BUILD_ID_SUFFIX) + 1;
-
-       /*
-        * The resulting filename string is the concatenation of the
-        * hex build id and the suffix.
-        */
-       build_id_file_len =  build_id_char_len + build_id_suffix_char_len;
-       build_id_file = g_new0(gchar, build_id_file_len);
-       if (!build_id_file) {
-               goto error;
-       }
-
-       /*
-        * For each byte, starting at offset 1, append two characters
-        * in lowercase hex.
-        */
-       for (i = 1; i < bin->build_id_len; ++i) {
-               int path_idx = 2 * (i - 1);
-
-               g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]);
-       }
-       /* Append the suffix to the generated string, including the '\0'. */
-       g_snprintf(&build_id_file[build_id_char_len], build_id_suffix_char_len,
-               BUILD_ID_SUFFIX);
-
-       path = g_build_filename(dbg_dir, BUILD_ID_SUBDIR, build_id_prefix_dir, build_id_file, NULL);
-       if (!path) {
-               goto error;
-       }
-
-       ret = bin_info_set_dwarf_info_from_path(bin, path);
-       if (ret) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-end:
-       g_free(build_id_prefix_dir);
-       g_free(build_id_file);
-       g_free(path);
-
-       return ret;
-}
-
-/**
- * Tests whether the file located at path exists and has the expected
- * checksum.
- *
- * This predicate is used when looking up separate debug info via the
- * GNU debuglink method. The expected crc can be found .gnu_debuglink
- * section in the original ELF file, along with the filename for the
- * file containing the debug info.
- *
- * @param path Full path at which to look for the debug file
- * @param crc  Expected checksum for the debug file
- * @returns    1 if the file exists and has the correct checksum,
- *             0 otherwise
- */
-static
-int is_valid_debug_file(struct bin_info *bin, char *path, uint32_t crc)
-{
-       int ret = 0;
-       struct bt_fd_cache_handle *debug_handle = NULL;
-       uint32_t _crc = 0;
-
-       if (!path) {
-               goto end;
-       }
-
-       debug_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
-       if (!debug_handle) {
-               goto end;
-       }
-
-       ret = crc32(bt_fd_cache_handle_get_fd(debug_handle), &_crc);
-       if (ret) {
-               ret = 0;
-               goto end;
-       }
-
-       ret = (crc == _crc);
-
-end:
-       bt_fd_cache_put_handle(bin->fd_cache, debug_handle);
-       return ret;
-}
-
-/**
- * Try to set the dwarf_info for a given bin_info instance via the
- * debug-link method.
- *
- * @param bin          bin_info instance for which to retrieve the
- *                     DWARF info via debug link
- * @returns            0 on success (i.e. dwarf_info set), -1 on failure
- */
-static
-int bin_info_set_dwarf_info_debug_link(struct bin_info *bin)
-{
-       int ret = 0;
-       const gchar *dbg_dir = NULL;
-       gchar *bin_dir = NULL, *path = NULL;
-
-       if (!bin || !bin->dbg_link_filename) {
-               goto error;
-       }
-
-       dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR;
-       bin_dir = g_path_get_dirname(bin->elf_path);
-
-       /* First look in the executable's dir */
-       path = g_build_filename(bin_dir, bin->dbg_link_filename, NULL);
-
-       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
-               goto found;
-       }
-
-       /* If not found, look in .debug subdir */
-       g_free(path);
-       path = g_build_filename(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL);
-
-       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
-               goto found;
-       }
-
-       /* Lastly, look under the global debug directory */
-       g_free(path);
-
-       path = g_build_filename(dbg_dir, bin_dir, bin->dbg_link_filename, NULL);
-       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
-               goto found;
-       }
-
-error:
-       ret = -1;
-end:
-       g_free(bin_dir);
-       g_free(path);
-
-       return ret;
-
-found:
-       ret = bin_info_set_dwarf_info_from_path(bin, path);
-       if (ret) {
-               goto error;
-       }
-
-       goto end;
-}
-
-/**
- * Initialize the DWARF info for a given executable.
- *
- * @param bin  bin_info instance
- * @returns    0 on success, negative value on failure
- */
-static
-int bin_info_set_dwarf_info(struct bin_info *bin)
-{
-       int ret = 0;
-
-       if (!bin) {
-               ret = -1;
-               goto end;
-       }
-
-       /* First try to set the DWARF info from the ELF file */
-       ret = bin_info_set_dwarf_info_from_path(bin, bin->elf_path);
-       if (!ret) {
-               goto end;
-       }
-
-       /*
-        * If that fails, try to find separate debug info via build ID
-        * and debug link.
-        */
-       ret = bin_info_set_dwarf_info_build_id(bin);
-       if (!ret) {
-               goto end;
-       }
-
-       ret = bin_info_set_dwarf_info_debug_link(bin);
-       if (!ret) {
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-void source_location_destroy(struct source_location *src_loc)
-{
-       if (!src_loc) {
-               return;
-       }
-
-       free(src_loc->filename);
-       g_free(src_loc);
-}
-
-/**
- * Append a string representation of an address offset to an existing
- * string.
- *
- * On success, the out parameter `result` will contain the base string
- * followed by the offset string of the form "+0x1234". On failure,
- * `result` remains unchanged.
- *
- * @param base_str     The string to which to append an offset string
- * @param low_addr     The lower virtual memory address, the base from
- *                     which the offset is computed
- * @param high_addr    The higher virtual memory address
- * @param result       Out parameter, the base string followed by the
- *                     offset string
- * @returns            0 on success, -1 on failure
- */
-static
-int bin_info_append_offset_str(const char *base_str, uint64_t low_addr,
-                               uint64_t high_addr, char **result)
-{
-       uint64_t offset;
-       char *_result = NULL;
-
-       if (!base_str || !result) {
-               goto error;
-       }
-
-       offset = high_addr - low_addr;
-
-       _result = g_strdup_printf("%s+%#0" PRIx64, base_str, offset);
-       if (!_result) {
-               goto error;
-       }
-       *result = _result;
-
-       return 0;
-
-error:
-       free(_result);
-       return -1;
-}
-
-/**
- * Try to find the symbol closest to an address within a given ELF
- * section.
- *
- * Only function symbols are taken into account. The symbol's address
- * must precede `addr`. A symbol with a closer address might exist
- * after `addr` but is irrelevant because it cannot encompass `addr`.
- *
- * On success, if found, the out parameters `sym` and `shdr` are
- * set. On failure or if none are found, they remain unchanged.
- *
- * @param scn          ELF section in which to look for the address
- * @param addr         Virtual memory address for which to find the
- *                     nearest function symbol
- * @param sym          Out parameter, the nearest function symbol
- * @param shdr         Out parameter, the section header for scn
- * @returns            0 on success, -1 on failure
- */
-static
-int bin_info_get_nearest_symbol_from_section(Elf_Scn *scn, uint64_t addr,
-               GElf_Sym **sym, GElf_Shdr **shdr)
-{
-       int i;
-       size_t symbol_count;
-       Elf_Data *data = NULL;
-       GElf_Shdr *_shdr = NULL;
-       GElf_Sym *nearest_sym = NULL;
-
-       if (!scn || !sym || !shdr) {
-               goto error;
-       }
-
-       _shdr = g_new0(GElf_Shdr, 1);
-       if (!_shdr) {
-               goto error;
-       }
-
-       _shdr = gelf_getshdr(scn, _shdr);
-       if (!_shdr) {
-               goto error;
-       }
-
-       if (_shdr->sh_type != SHT_SYMTAB) {
-               /*
-                * We are only interested in symbol table (symtab)
-                * sections, skip this one.
-                */
-               goto end;
-       }
-
-       data = elf_getdata(scn, NULL);
-       if (!data) {
-               goto error;
-       }
-
-       symbol_count = _shdr->sh_size / _shdr->sh_entsize;
-
-       for (i = 0; i < symbol_count; ++i) {
-               GElf_Sym *cur_sym = NULL;
-
-               cur_sym = g_new0(GElf_Sym, 1);
-               if (!cur_sym) {
-                       goto error;
-               }
-               cur_sym = gelf_getsym(data, i, cur_sym);
-               if (!cur_sym) {
-                       goto error;
-               }
-               if (GELF_ST_TYPE(cur_sym->st_info) != STT_FUNC) {
-                       /* We're only interested in the functions. */
-                       g_free(cur_sym);
-                       continue;
-               }
-
-               if (cur_sym->st_value <= addr &&
-                               (!nearest_sym ||
-                               cur_sym->st_value > nearest_sym->st_value)) {
-                       g_free(nearest_sym);
-                       nearest_sym = cur_sym;
-               } else {
-                       g_free(cur_sym);
-               }
-       }
-
-end:
-       if (nearest_sym) {
-               *sym = nearest_sym;
-               *shdr = _shdr;
-       } else {
-               g_free(_shdr);
-       }
-
-       return 0;
-
-error:
-       g_free(nearest_sym);
-       g_free(_shdr);
-       return -1;
-}
-
-/**
- * Get the name of the function containing a given address within an
- * executable using ELF symbols.
- *
- * The function name is in fact the name of the nearest ELF symbol,
- * followed by the offset in bytes between the address and the symbol
- * (in hex), separated by a '+' character.
- *
- * If found, the out parameter `func_name` is set on success. On failure,
- * it remains unchanged.
- *
- * @param bin          bin_info instance for the executable containing
- *                     the address
- * @param addr         Virtual memory address for which to find the
- *                     function name
- * @param func_name    Out parameter, the function name
- * @returns            0 on success, -1 on failure
- */
-static
-int bin_info_lookup_elf_function_name(struct bin_info *bin, uint64_t addr,
-               char **func_name)
-{
-       /*
-        * TODO (possible optimisation): if an ELF has no symtab
-        * section, it has been stripped. Therefore, it would be wise
-        * to store a flag indicating the stripped status after the
-        * first iteration to prevent subsequent ones.
-        */
-       int ret = 0;
-       Elf_Scn *scn = NULL;
-       GElf_Sym *sym = NULL;
-       GElf_Shdr *shdr = NULL;
-       char *sym_name = NULL;
-
-       /* Set ELF file if it hasn't been accessed yet. */
-       if (!bin->elf_file) {
-               ret = bin_info_set_elf_file(bin);
-               if (ret) {
-                       /* Failed to set ELF file. */
-                       goto error;
-               }
-       }
-
-       scn = elf_nextscn(bin->elf_file, scn);
-       if (!scn) {
-               goto error;
-       }
-
-       while (scn && !sym) {
-               ret = bin_info_get_nearest_symbol_from_section(
-                               scn, addr, &sym, &shdr);
-               if (ret) {
-                       goto error;
-               }
-
-               scn = elf_nextscn(bin->elf_file, scn);
-       }
-
-       if (sym) {
-               sym_name = elf_strptr(bin->elf_file, shdr->sh_link,
-                               sym->st_name);
-               if (!sym_name) {
-                       goto error;
-               }
-
-               ret = bin_info_append_offset_str(sym_name, sym->st_value, addr,
-                                               func_name);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       g_free(shdr);
-       g_free(sym);
-       return 0;
-
-error:
-       g_free(shdr);
-       g_free(sym);
-       return ret;
-}
-
-/**
- * Get the name of the function containing a given address within a
- * given compile unit (CU).
- *
- * If found, the out parameter `func_name` is set on success. On
- * failure, it remains unchanged.
- *
- * @param cu           bt_dwarf_cu instance which may contain the address
- * @param addr         Virtual memory address for which to find the
- *                     function name
- * @param func_name    Out parameter, the function name
- * @returns            0 on success, -1 on failure
- */
-static
-int bin_info_lookup_cu_function_name(struct bt_dwarf_cu *cu, uint64_t addr,
-               char **func_name)
-{
-       int ret = 0;
-       bool found = false;
-       struct bt_dwarf_die *die = NULL;
-
-       if (!cu || !func_name) {
-               goto error;
-       }
-
-       die = bt_dwarf_die_create(cu);
-       if (!die) {
-               goto error;
-       }
-
-       while (bt_dwarf_die_next(die) == 0) {
-               int tag;
-
-               ret = bt_dwarf_die_get_tag(die, &tag);
-               if (ret) {
-                       goto error;
-               }
-
-               if (tag == DW_TAG_subprogram) {
-                       ret = bt_dwarf_die_contains_addr(die, addr, &found);
-                       if (ret) {
-                               goto error;
-                       }
-
-                       if (found) {
-                               break;
-                       }
-               }
-       }
-
-       if (found) {
-               uint64_t low_addr = 0;
-               char *die_name = NULL;
-
-               ret = bt_dwarf_die_get_name(die, &die_name);
-               if (ret) {
-                       goto error;
-               }
-
-               ret = dwarf_lowpc(die->dwarf_die, &low_addr);
-               if (ret) {
-                       free(die_name);
-                       goto error;
-               }
-
-               ret = bin_info_append_offset_str(die_name, low_addr, addr,
-                                               func_name);
-               free(die_name);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       bt_dwarf_die_destroy(die);
-       return 0;
-
-error:
-       bt_dwarf_die_destroy(die);
-       return -1;
-}
-
-/**
- * Get the name of the function containing a given address within an
- * executable using DWARF debug info.
- *
- * If found, the out parameter `func_name` is set on success. On
- * failure, it remains unchanged.
- *
- * @param bin          bin_info instance for the executable containing
- *                     the address
- * @param addr         Virtual memory address for which to find the
- *                     function name
- * @param func_name    Out parameter, the function name
- * @returns            0 on success, -1 on failure
- */
-static
-int bin_info_lookup_dwarf_function_name(struct bin_info *bin, uint64_t addr,
-               char **func_name)
-{
-       int ret = 0;
-       char *_func_name = NULL;
-       struct bt_dwarf_cu *cu = NULL;
-
-       if (!bin || !func_name) {
-               goto error;
-       }
-
-       cu = bt_dwarf_cu_create(bin->dwarf_info);
-       if (!cu) {
-               goto error;
-       }
-
-       while (bt_dwarf_cu_next(cu) == 0) {
-               ret = bin_info_lookup_cu_function_name(cu, addr, &_func_name);
-               if (ret) {
-                       goto error;
-               }
-
-               if (_func_name) {
-                       break;
-               }
-       }
-
-       if (_func_name) {
-               *func_name = _func_name;
-       } else {
-               goto error;
-       }
-
-       bt_dwarf_cu_destroy(cu);
-       return 0;
-
-error:
-       bt_dwarf_cu_destroy(cu);
-       return -1;
-}
-
-BT_HIDDEN
-int bin_info_lookup_function_name(struct bin_info *bin,
-               uint64_t addr, char **func_name)
-{
-       int ret = 0;
-       char *_func_name = NULL;
-
-       if (!bin || !func_name) {
-               goto error;
-       }
-
-       /*
-        * If the bin_info has a build id but it does not match the build id
-        * that was found on the file system, return an error.
-        */
-       if (bin->build_id && !bin->file_build_id_matches) {
-               goto error;
-       }
-
-       /* Set DWARF info if it hasn't been accessed yet. */
-       if (!bin->dwarf_info && !bin->is_elf_only) {
-               ret = bin_info_set_dwarf_info(bin);
-               if (ret) {
-                       BT_LOGD_STR("Failed to set bin dwarf info, falling "
-                                       "back to ELF lookup.");
-                       /* Failed to set DWARF info, fallback to ELF. */
-                       bin->is_elf_only = true;
-               }
-       }
-
-       if (!bin_info_has_address(bin, addr)) {
-               goto error;
-       }
-
-       /*
-        * Addresses in ELF and DWARF are relative to base address for
-        * PIC, so make the address argument relative too if needed.
-        */
-       if (bin->is_pic) {
-               addr -= bin->low_addr;
-       }
-
-       if (bin->is_elf_only) {
-               ret = bin_info_lookup_elf_function_name(bin, addr,
-                               &_func_name);
-               if (ret) {
-                       BT_LOGD("Failed to lookup function name (ELF): "
-                               "ret=%d", ret);
-               }
-       } else {
-               ret = bin_info_lookup_dwarf_function_name(bin, addr,
-                               &_func_name);
-               if (ret) {
-                       BT_LOGD("Failed to lookup function name (DWARF): "
-                               "ret=%d", ret);
-               }
-       }
-
-       *func_name = _func_name;
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc)
-{
-       gchar *_bin_loc = NULL;
-
-       if (!bin || !bin_loc) {
-               goto error;
-       }
-
-       /*
-        * If the bin_info has a build id but it does not match the build id
-        * that was found on the file system, return an error.
-        */
-       if (bin->build_id && !bin->file_build_id_matches) {
-               goto error;
-       }
-
-       if (bin->is_pic) {
-               addr -= bin->low_addr;
-               _bin_loc = g_strdup_printf("+%#0" PRIx64, addr);
-       } else {
-               _bin_loc = g_strdup_printf("@%#0" PRIx64, addr);
-       }
-
-       if (!_bin_loc) {
-               goto error;
-       }
-
-       *bin_loc = _bin_loc;
-       return 0;
-
-error:
-       return -1;
-}
-
-/**
- * Predicate used to determine whether the children of a given DIE
- * contain a specific address.
- *
- * More specifically, the parameter `die` is expected to be a
- * subprogram (function) DIE, and this predicate tells whether any
- * subroutines are inlined within this function and would contain
- * `addr`.
- *
- * On success, the out parameter `contains` is set with the boolean
- * value indicating whether the DIE's range covers `addr`. On failure,
- * it remains unchanged.
- *
- * Do note that this function advances the position of `die`. If the
- * address is found within one of its children, `die` will be pointing
- * to that child upon returning from the function, allowing to extract
- * the information deemed necessary.
- *
- * @param die          The parent DIE in whose children the address will be
- *                     looked for
- * @param addr         The address for which to look for in the DIEs
- * @param contains     Out parameter, true if addr is contained,
- *                     false if not
- * @returns            Returns 0 on success, -1 on failure
- */
-static
-int bin_info_child_die_has_address(struct bt_dwarf_die *die, uint64_t addr, bool *contains)
-{
-       int ret = 0;
-       bool _contains = false;
-
-       if (!die) {
-               goto error;
-       }
-
-       ret = bt_dwarf_die_child(die);
-       if (ret) {
-               goto error;
-       }
-
-       do {
-               ret = bt_dwarf_die_contains_addr(die, addr, &_contains);
-               if (ret) {
-                       goto error;
-               }
-
-               if (_contains) {
-                       /*
-                        * The address is within the range of the current DIE
-                        * or its children.
-                        */
-                       int tag;
-
-                       ret = bt_dwarf_die_get_tag(die, &tag);
-                       if (ret) {
-                               goto error;
-                       }
-
-                       if (tag == DW_TAG_inlined_subroutine) {
-                               /* Found the tracepoint. */
-                               goto end;
-                       }
-
-                       if (bt_dwarf_die_has_children(die)) {
-                               /*
-                                * Look for the address in the children DIEs.
-                                */
-                               ret = bt_dwarf_die_child(die);
-                               if (ret) {
-                                       goto error;
-                               }
-                       }
-               }
-       } while (bt_dwarf_die_next(die) == 0);
-
-end:
-       *contains = _contains;
-       return 0;
-
-error:
-       return -1;
-}
-
-/**
- * Lookup the source location for a given address within a CU, making
- * the assumption that it is contained within an inline routine in a
- * function.
- *
- * @param cu           bt_dwarf_cu instance in which to look for the address
- * @param addr         The address for which to look for
- * @param src_loc      Out parameter, the source location (filename and
- *                     line number) for the address
- * @returns            0 on success, -1 on failure
- */
-static
-int bin_info_lookup_cu_src_loc_inl(struct bt_dwarf_cu *cu, uint64_t addr,
-               struct source_location **src_loc)
-{
-       int ret = 0;
-       bool found = false;
-       struct bt_dwarf_die *die = NULL;
-       struct source_location *_src_loc = NULL;
-
-       if (!cu || !src_loc) {
-               goto error;
-       }
-
-       die = bt_dwarf_die_create(cu);
-       if (!die) {
-               goto error;
-       }
-
-       while (bt_dwarf_die_next(die) == 0) {
-               int tag;
-
-               ret = bt_dwarf_die_get_tag(die, &tag);
-               if (ret) {
-                       goto error;
-               }
-
-               if (tag == DW_TAG_subprogram) {
-                       bool contains = false;
-
-                       ret = bt_dwarf_die_contains_addr(die, addr, &contains);
-                       if (ret) {
-                               goto error;
-                       }
-
-                       if (contains) {
-                               /*
-                                * Try to find an inlined subroutine
-                                * child of this DIE containing addr.
-                                */
-                               ret = bin_info_child_die_has_address(die, addr,
-                                               &found);
-                               if(ret) {
-                                       goto error;
-                               }
-
-                               goto end;
-                       }
-               }
-       }
-
-end:
-       if (found) {
-               char *filename = NULL;
-               uint64_t line_no;
-
-               _src_loc = g_new0(struct source_location, 1);
-               if (!_src_loc) {
-                       goto error;
-               }
-
-               ret = bt_dwarf_die_get_call_file(die, &filename);
-               if (ret) {
-                       goto error;
-               }
-               ret = bt_dwarf_die_get_call_line(die, &line_no);
-               if (ret) {
-                       free(filename);
-                       goto error;
-               }
-
-               _src_loc->filename = filename;
-               _src_loc->line_no = line_no;
-               *src_loc = _src_loc;
-       }
-
-       bt_dwarf_die_destroy(die);
-       return 0;
-
-error:
-       source_location_destroy(_src_loc);
-       bt_dwarf_die_destroy(die);
-       return -1;
-}
-
-/**
- * Lookup the source location for a given address within a CU,
- * assuming that it is contained within an inlined function.
- *
- * A source location can be found regardless of inlining status for
- * this method, but in the case of an inlined function, the returned
- * source location will point not to the callsite but rather to the
- * definition site of the inline function.
- *
- * @param cu           bt_dwarf_cu instance in which to look for the address
- * @param addr         The address for which to look for
- * @param src_loc      Out parameter, the source location (filename and
- *                     line number) for the address. Set only if the address
- *                     is found and resolved successfully
- *
- * @returns            0 on success, -1 on failure
- */
-static
-int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr,
-               struct source_location **src_loc)
-{
-       struct source_location *_src_loc = NULL;
-       struct bt_dwarf_die *die = NULL;
-       const char *filename = NULL;
-       Dwarf_Line *line = NULL;
-       Dwarf_Addr line_addr;
-       int ret = 0, line_no;
-
-       if (!cu || !src_loc) {
-               goto error;
-       }
-
-       die = bt_dwarf_die_create(cu);
-       if (!die) {
-               goto error;
-       }
-
-       line = dwarf_getsrc_die(die->dwarf_die, addr);
-       if (!line) {
-               /* This is not an error. The caller needs to keep looking. */
-               goto end;
-       }
-
-       ret = dwarf_lineaddr(line, &line_addr);
-       if (ret) {
-               goto error;
-       }
-
-       filename = dwarf_linesrc(line, NULL, NULL);
-       if (!filename) {
-               goto error;
-       }
-
-       if (addr == line_addr) {
-               _src_loc = g_new0(struct source_location, 1);
-               if (!_src_loc) {
-                       goto error;
-               }
-
-               ret = dwarf_lineno(line, &line_no);
-               if (ret) {
-                       goto error;
-               }
-
-               _src_loc->line_no = line_no;
-               _src_loc->filename = g_strdup(filename);
-       }
-
-       if (_src_loc) {
-               *src_loc = _src_loc;
-       }
-
-       goto end;
-
-error:
-       source_location_destroy(_src_loc);
-       ret = -1;
-end:
-       bt_dwarf_die_destroy(die);
-       return ret;
-}
-
-/**
- * Get the source location (file name and line number) for a given
- * address within a compile unit (CU).
- *
- * On success, the out parameter `src_loc` is set if found. On
- * failure, it remains unchanged.
- *
- * @param cu           bt_dwarf_cu instance for the compile unit which
- *                     may contain the address
- * @param addr         Virtual memory address for which to find the
- *                     source location
- * @param src_loc      Out parameter, the source location
- * @returns            0 on success, -1 on failure
- */
-static
-int bin_info_lookup_cu_src_loc(struct bt_dwarf_cu *cu, uint64_t addr,
-               struct source_location **src_loc)
-{
-       int ret = 0;
-       struct source_location *_src_loc = NULL;
-
-       if (!cu || !src_loc) {
-               goto error;
-       }
-
-       ret = bin_info_lookup_cu_src_loc_inl(cu, addr, &_src_loc);
-       if (ret) {
-               goto error;
-       }
-
-       if (_src_loc) {
-               goto end;
-       }
-
-       ret = bin_info_lookup_cu_src_loc_no_inl(cu, addr, &_src_loc);
-       if (ret) {
-               goto error;
-       }
-
-       if (_src_loc) {
-               goto end;
-       }
-
-end:
-       if (_src_loc) {
-               *src_loc = _src_loc;
-       }
-
-       return 0;
-
-error:
-       source_location_destroy(_src_loc);
-       return -1;
-}
-
-BT_HIDDEN
-int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr,
-               struct source_location **src_loc)
-{
-       struct bt_dwarf_cu *cu = NULL;
-       struct source_location *_src_loc = NULL;
-
-       if (!bin || !src_loc) {
-               goto error;
-       }
-
-       /*
-        * If the bin_info has a build id but it does not match the build id
-        * that was found on the file system, return an error.
-        */
-       if (bin->build_id && !bin->file_build_id_matches) {
-               goto error;
-       }
-
-       /* Set DWARF info if it hasn't been accessed yet. */
-       if (!bin->dwarf_info && !bin->is_elf_only) {
-               if (bin_info_set_dwarf_info(bin)) {
-                       /* Failed to set DWARF info. */
-                       bin->is_elf_only = true;
-               }
-       }
-
-       if (bin->is_elf_only) {
-               /* We cannot lookup source location without DWARF info. */
-               goto error;
-       }
-
-       if (!bin_info_has_address(bin, addr)) {
-               goto error;
-       }
-
-       /*
-        * Addresses in ELF and DWARF are relative to base address for
-        * PIC, so make the address argument relative too if needed.
-        */
-       if (bin->is_pic) {
-               addr -= bin->low_addr;
-       }
-
-       cu = bt_dwarf_cu_create(bin->dwarf_info);
-       if (!cu) {
-               goto error;
-       }
-
-       while (bt_dwarf_cu_next(cu) == 0) {
-               int ret;
-
-               ret = bin_info_lookup_cu_src_loc(cu, addr, &_src_loc);
-               if (ret) {
-                       goto error;
-               }
-
-               if (_src_loc) {
-                       break;
-               }
-       }
-
-       bt_dwarf_cu_destroy(cu);
-       if (_src_loc) {
-               *src_loc = _src_loc;
-       }
-
-       return 0;
-
-error:
-       source_location_destroy(_src_loc);
-       bt_dwarf_cu_destroy(cu);
-       return -1;
-}
diff --git a/plugins/lttng-utils/debug-info/bin-info.h b/plugins/lttng-utils/debug-info/bin-info.h
deleted file mode 100644 (file)
index c193a06..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-#ifndef _BABELTRACE_BIN_INFO_H
-#define _BABELTRACE_BIN_INFO_H
-
-/*
- * Babeltrace - Executable and Shared Object Debug Info Reader
- *
- * Copyright 2015 Antoine Busque <abusque@efficios.com>
- *
- * Author: Antoine Busque <abusque@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <gelf.h>
-#include <elfutils/libdw.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/fd-cache-internal.h>
-
-#define DEFAULT_DEBUG_DIR "/usr/lib/debug"
-#define DEBUG_SUBDIR ".debug"
-#define BUILD_ID_SUBDIR ".build-id"
-#define BUILD_ID_SUFFIX ".debug"
-#define BUILD_ID_PREFIX_DIR_LEN 2
-
-struct bin_info {
-       /* Base virtual memory address. */
-       uint64_t low_addr;
-       /* Upper bound of exec address space. */
-       uint64_t high_addr;
-       /* Size of exec address space. */
-       uint64_t memsz;
-       /* Paths to ELF and DWARF files. */
-       gchar *elf_path;
-       gchar *dwarf_path;
-       /* libelf and libdw objects representing the files. */
-       Elf *elf_file;
-       Dwarf *dwarf_info;
-       /* Optional build ID info. */
-       uint8_t *build_id;
-       size_t build_id_len;
-
-       /* Optional debug link info. */
-       gchar *dbg_link_filename;
-       uint32_t dbg_link_crc;
-       /* fd cache handles to ELF and DWARF files. */
-       struct bt_fd_cache_handle *elf_handle;
-       struct bt_fd_cache_handle *dwarf_handle;
-       /* Configuration. */
-       gchar *debug_info_dir;
-       /* Denotes whether the executable is position independent code. */
-       bool is_pic:1;
-       /* Denotes whether the build id in the trace matches to one on disk. */
-       bool file_build_id_matches:1;
-       /*
-        * Denotes whether the executable only has ELF symbols and no
-        * DWARF info.
-        */
-       bool is_elf_only:1;
-       /* Weak ref. Owned by the iterator. */
-       struct bt_fd_cache *fd_cache;
-};
-
-struct source_location {
-       uint64_t line_no;
-       gchar *filename;
-};
-
-/**
- * Initializes the bin_info framework. Call this before calling
- * anything else.
- *
- * @returns            0 on success, -1 on failure
- */
-BT_HIDDEN
-int bin_info_init(void);
-
-/**
- * Instantiate a structure representing an ELF executable, possibly
- * with DWARF info, located at the given path.
- *
- * @param path         Path to the ELF file
- * @param low_addr     Base address of the executable
- * @param memsz        In-memory size of the executable
- * @param is_pic       Whether the executable is position independent
- *                     code (PIC)
- * @param debug_info_dir Directory containing debug info or NULL.
- * @param target_prefix  Path to the root file system of the target
- *                       or NULL.
- * @returns            Pointer to the new bin_info on success,
- *                     NULL on failure.
- */
-BT_HIDDEN
-struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path,
-               uint64_t low_addr, uint64_t memsz, bool is_pic,
-               const char *debug_info_dir, const char *target_prefix);
-
-/**
- * Destroy the given bin_info instance
- *
- * @param bin  bin_info instance to destroy
- */
-BT_HIDDEN
-void bin_info_destroy(struct bin_info *bin);
-
-/**
- * Sets the build ID information for a given bin_info instance.
- *
- * @param bin          The bin_info instance for which to set
- *                     the build ID
- * @param build_id     Array of bytes containing the actual ID
- * @param build_id_len Length in bytes of the build_id
- * @returns            0 on success, -1 on failure
- */
-BT_HIDDEN
-int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id,
-               size_t build_id_len);
-
-/**
- * Sets the debug link information for a given bin_info instance.
- *
- * @param bin          The bin_info instance for which to set
- *                     the debug link
- * @param filename     Name of the separate debug info file
- * @param crc          Checksum for the debug info file
- * @returns            0 on success, -1 on failure
- */
-BT_HIDDEN
-int bin_info_set_debug_link(struct bin_info *bin, const char *filename,
-               uint32_t crc);
-
-/**
- * Returns whether or not the given bin info \p bin contains the
- * address \p addr.
- *
- * @param bin          bin_info instance
- * @param addr         Address to lookup
- * @returns            1 if \p bin contains \p addr, 0 if it does not,
- *                     -1 on failure
- */
-static inline
-int bin_info_has_address(struct bin_info *bin, uint64_t addr)
-{
-       if (!bin) {
-               return -1;
-       }
-
-       return addr >= bin->low_addr && addr < bin->high_addr;
-}
-
-/**
- * Get the name of the function containing a given address within an
- * executable.
- *
- * If no DWARF info is available, the function falls back to ELF
- * symbols and the "function name" is in fact the name of the closest
- * symbol, followed by the offset between the symbol and the address.
- *
- * On success, if found, the out parameter `func_name` is set. The ownership
- * of `func_name` is passed to the caller. On failure, `func_name` remains
- * unchanged.
- *
- * @param bin          bin_info instance for the executable containing
- *                     the address
- * @param addr         Virtual memory address for which to find the
- *                     function name
- * @param func_name    Out parameter, the function name.
- * @returns            0 on success, -1 on failure
- */
-BT_HIDDEN
-int bin_info_lookup_function_name(struct bin_info *bin, uint64_t addr,
-               char **func_name);
-
-/**
- * Get the source location (file name and line number) for a given
- * address within an executable.
- *
- * If no DWARF info is available, the source location cannot be found
- * and the function will return unsuccessfully.
- *
- * On success, if found, the out parameter `src_loc` is set. The ownership
- * of `src_loc` is passed to the caller. On failure, `src_loc` remains
- * unchanged.
- *
- * @param bin          bin_info instance for the executable containing
- *                     the address
- * @param addr         Virtual memory address for which to find the
- *                     source location
- * @param src_loc      Out parameter, the source location
- * @returns            0 on success, -1 on failure
- */
-BT_HIDDEN
-int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr,
-               struct source_location **src_loc);
-/**
- * Get a string representing the location within the binary of a given
- * address.
- *
- * In the  case of a PIC binary, the location is relative (+0x1234).
- * For a non-PIC binary, the location is absolute (@0x1234)
- *
- * On success, the out parameter `bin_loc` is set. The ownership is
- * passed to the caller. On failure, `bin_loc` remains unchanged.
- *
- * @param bin          bin_info instance for the executable containing
- *                     the address
- * @param addr         Virtual memory address for which to find the
- *                     binary location
- * @param bin_loc      Out parameter, the binary location
- * @returns            0 on success, -1 on failure
- */
-BT_HIDDEN
-int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc);
-
-/**
- * Destroy the given source_location instance
- *
- * @param src_loc      source_location instance to destroy
- */
-BT_HIDDEN
-void source_location_destroy(struct source_location *src_loc);
-
-#endif /* _BABELTRACE_BIN_INFO_H */
diff --git a/plugins/lttng-utils/debug-info/crc32.c b/plugins/lttng-utils/debug-info/crc32.c
deleted file mode 100644 (file)
index e68c043..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "crc32.h"
-
-#define CRC(crc, ch)    (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
-
-/* generated using the AUTODIN II polynomial
- *     x^32 + x^26 + x^23 + x^22 + x^16 +
- *     x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
- */
-static const uint32_t crctab[256] = {
-       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
-       0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
-       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
-       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
-       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
-       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
-       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
-       0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
-       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
-       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
-       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
-       0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
-       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
-       0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
-       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
-       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
-       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
-       0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
-       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
-       0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
-       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
-       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
-       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
-       0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
-       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
-       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
-       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
-       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
-       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
-       0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
-       0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
-       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
-       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
-       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
-       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
-       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
-       0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
-       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
-       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
-       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
-       0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
-       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
-       0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
-       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
-       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
-       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
-       0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
-       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
-       0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
-       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
-       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
-       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
-       0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
-       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
-       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
-       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
-       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
-       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
-       0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
-       0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
-       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
-       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-int crc32(int fd, uint32_t *crc)
-{
-       int nr;
-       uint32_t _crc = ~0;
-       char buf[BUFSIZ], *p;
-
-       if (fd < 0 || !crc) {
-               goto error;
-       }
-
-       while ((nr = read(fd, buf, sizeof(buf))) > 0) {
-               for (p = buf; nr--; ++p) {
-                       CRC(_crc, *p);
-               }
-       }
-
-       if (nr < 0) {
-               goto error;
-       }
-
-       *crc = ~_crc;
-       return 0;
-
-error:
-       return -1;
-}
diff --git a/plugins/lttng-utils/debug-info/crc32.h b/plugins/lttng-utils/debug-info/crc32.h
deleted file mode 100644 (file)
index 3cb825e..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _BABELTRACE_CRC32_H
-#define _BABELTRACE_CRC32_H
-
-/*
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by the University of
- *    California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-/**
- * Compute a 32-bit cyclic redundancy checksum for a given file.
- *
- * On success, the out parameter crc is set with the computed checksum
- * value,
- *
- * @param fd   File descriptor for the file for which to compute the CRC
- * @param crc  Out parameter, the computed checksum
- * @returns    0 on success, -1 on failure.
- */
-BT_HIDDEN
-int crc32(int fd, uint32_t *crc);
-
-#endif /* _BABELTRACE_CRC32_H */
diff --git a/plugins/lttng-utils/debug-info/debug-info.c b/plugins/lttng-utils/debug-info/debug-info.c
deleted file mode 100644 (file)
index 1e7a238..0000000
+++ /dev/null
@@ -1,2061 +0,0 @@
-/*
- * Babeltrace - Debug Information State Tracker
- *
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
- * Copyright (c) 2015 Antoine Busque <abusque@efficios.com>
- * Copyright (c) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT"
-#include "logging.h"
-
-#include <glib.h>
-#include <plugins-common.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/fd-cache-internal.h>
-
-#include "bin-info.h"
-#include "debug-info.h"
-#include "trace-ir-data-copy.h"
-#include "trace-ir-mapping.h"
-#include "trace-ir-metadata-copy.h"
-#include "utils.h"
-
-#define DEFAULT_DEBUG_INFO_FIELD_NAME  "debug_info"
-#define LTTNG_UST_STATEDUMP_PREFIX     "lttng_ust"
-#define VPID_FIELD_NAME                        "vpid"
-#define IP_FIELD_NAME                  "ip"
-#define BADDR_FIELD_NAME               "baddr"
-#define CRC32_FIELD_NAME               "crc"
-#define BUILD_ID_FIELD_NAME            "build_id"
-#define FILENAME_FIELD_NAME            "filename"
-#define IS_PIC_FIELD_NAME              "is_pic"
-#define MEMSZ_FIELD_NAME               "memsz"
-#define PATH_FIELD_NAME                        "path"
-
-struct debug_info_component {
-       gchar *arg_debug_dir;
-       gchar *arg_debug_info_field_name;
-       gchar *arg_target_prefix;
-       bt_bool arg_full_path;
-};
-
-struct debug_info_msg_iter {
-       struct debug_info_component *debug_info_component;
-       bt_self_message_iterator *input_iterator;
-       bt_self_component *self_comp;
-       bt_self_component_port_input_message_iterator *msg_iter;
-
-       struct trace_ir_maps *ir_maps;
-       /* in_trace -> debug_info_mapping. */
-       GHashTable *debug_info_map;
-
-       struct bt_fd_cache fd_cache;
-};
-
-struct debug_info_source {
-       /* Strings are owned by debug_info_source. */
-       gchar *func;
-       /*
-        * Store the line number as a string so that the allocation and
-        * conversion to string is only done once.
-        */
-       gchar *line_no;
-       gchar *src_path;
-       /* short_src_path points inside src_path, no need to free. */
-       const gchar *short_src_path;
-       gchar *bin_path;
-       /* short_bin_path points inside bin_path, no need to free. */
-       const gchar *short_bin_path;
-       /*
-        * Location within the binary. Either absolute (@0x1234) or
-        * relative (+0x4321).
-        */
-       gchar *bin_loc;
-};
-
-struct proc_debug_info_sources {
-       /*
-        * Hash table: base address (pointer to uint64_t) to bin info; owned by
-        * proc_debug_info_sources.
-        */
-       GHashTable *baddr_to_bin_info;
-
-       /*
-        * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *);
-        * owned by proc_debug_info_sources.
-        */
-       GHashTable *ip_to_debug_info_src;
-};
-
-struct debug_info {
-       struct debug_info_component *comp;
-       const bt_trace *input_trace;
-       uint64_t destruction_listener_id;
-
-       /*
-        * Hash table of VPIDs (pointer to int64_t) to
-        * (struct proc_debug_info_sources*); owned by debug_info.
-        */
-       GHashTable *vpid_to_proc_dbg_info_src;
-       GQuark q_statedump_bin_info;
-       GQuark q_statedump_debug_link;
-       GQuark q_statedump_build_id;
-       GQuark q_statedump_start;
-       GQuark q_dl_open;
-       GQuark q_lib_load;
-       GQuark q_lib_unload;
-       struct bt_fd_cache *fd_cache; /* Weak ref. Owned by the iterator. */
-};
-
-static
-int debug_info_init(struct debug_info *info)
-{
-       info->q_statedump_bin_info = g_quark_from_string(
-                       "lttng_ust_statedump:bin_info");
-       info->q_statedump_debug_link = g_quark_from_string(
-                       "lttng_ust_statedump:debug_link");
-       info->q_statedump_build_id = g_quark_from_string(
-                       "lttng_ust_statedump:build_id");
-       info->q_statedump_start = g_quark_from_string(
-                       "lttng_ust_statedump:start");
-       info->q_dl_open = g_quark_from_string("lttng_ust_dl:dlopen");
-       info->q_lib_load = g_quark_from_string("lttng_ust_lib:load");
-       info->q_lib_unload = g_quark_from_string("lttng_ust_lib:unload");
-
-       return bin_info_init();
-}
-
-static
-void debug_info_source_destroy(struct debug_info_source *debug_info_src)
-{
-       if (!debug_info_src) {
-               return;
-       }
-
-       g_free(debug_info_src->func);
-       g_free(debug_info_src->line_no);
-       g_free(debug_info_src->src_path);
-       g_free(debug_info_src->bin_path);
-       g_free(debug_info_src->bin_loc);
-       g_free(debug_info_src);
-}
-
-static
-struct debug_info_source *debug_info_source_create_from_bin(
-               struct bin_info *bin, uint64_t ip)
-{
-       int ret;
-       struct debug_info_source *debug_info_src = NULL;
-       struct source_location *src_loc = NULL;
-
-       debug_info_src = g_new0(struct debug_info_source, 1);
-
-       if (!debug_info_src) {
-               goto end;
-       }
-
-       /* Lookup function name */
-       ret = bin_info_lookup_function_name(bin, ip, &debug_info_src->func);
-       if (ret) {
-               goto error;
-       }
-
-       /* Can't retrieve src_loc from ELF, or could not find binary, skip. */
-       if (!bin->is_elf_only || !debug_info_src->func) {
-               /* Lookup source location */
-               ret = bin_info_lookup_source_location(bin, ip, &src_loc);
-               if (ret) {
-                       BT_LOGD("Failed to lookup source location: ret=%d", ret);
-               }
-       }
-
-       if (src_loc) {
-               debug_info_src->line_no =
-                       g_strdup_printf("%"PRId64, src_loc->line_no);
-               if (!debug_info_src->line_no) {
-                       BT_LOGD("Error occured when setting line_no field.");
-                       goto error;
-               }
-
-               if (src_loc->filename) {
-                       debug_info_src->src_path = g_strdup(src_loc->filename);
-                       if (!debug_info_src->src_path) {
-                               goto error;
-                       }
-
-                       debug_info_src->short_src_path = get_filename_from_path(
-                                       debug_info_src->src_path);
-               }
-               source_location_destroy(src_loc);
-       }
-
-       if (bin->elf_path) {
-               debug_info_src->bin_path = g_strdup(bin->elf_path);
-               if (!debug_info_src->bin_path) {
-                       goto error;
-               }
-
-               debug_info_src->short_bin_path = get_filename_from_path(
-                               debug_info_src->bin_path);
-
-               ret = bin_info_get_bin_loc(bin, ip, &(debug_info_src->bin_loc));
-               if (ret) {
-                       goto error;
-               }
-       }
-
-end:
-       return debug_info_src;
-
-error:
-       debug_info_source_destroy(debug_info_src);
-       return NULL;
-}
-
-static
-void proc_debug_info_sources_destroy(
-               struct proc_debug_info_sources *proc_dbg_info_src)
-{
-       if (!proc_dbg_info_src) {
-               return;
-       }
-
-       if (proc_dbg_info_src->baddr_to_bin_info) {
-               g_hash_table_destroy(proc_dbg_info_src->baddr_to_bin_info);
-       }
-
-       if (proc_dbg_info_src->ip_to_debug_info_src) {
-               g_hash_table_destroy(proc_dbg_info_src->ip_to_debug_info_src);
-       }
-
-       g_free(proc_dbg_info_src);
-}
-
-static
-struct proc_debug_info_sources *proc_debug_info_sources_create(void)
-{
-       struct proc_debug_info_sources *proc_dbg_info_src = NULL;
-
-       proc_dbg_info_src = g_new0(struct proc_debug_info_sources, 1);
-       if (!proc_dbg_info_src) {
-               goto end;
-       }
-
-       proc_dbg_info_src->baddr_to_bin_info = g_hash_table_new_full(
-                       g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
-                       (GDestroyNotify) bin_info_destroy);
-       if (!proc_dbg_info_src->baddr_to_bin_info) {
-               goto error;
-       }
-
-       proc_dbg_info_src->ip_to_debug_info_src = g_hash_table_new_full(
-                       g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
-                       (GDestroyNotify) debug_info_source_destroy);
-       if (!proc_dbg_info_src->ip_to_debug_info_src) {
-               goto error;
-       }
-
-end:
-       return proc_dbg_info_src;
-
-error:
-       proc_debug_info_sources_destroy(proc_dbg_info_src);
-       return NULL;
-}
-
-static
-struct proc_debug_info_sources *proc_debug_info_sources_ht_get_entry(
-               GHashTable *ht, int64_t vpid)
-{
-       gpointer key = g_new0(int64_t, 1);
-       struct proc_debug_info_sources *proc_dbg_info_src = NULL;
-
-       if (!key) {
-               goto end;
-       }
-
-       *((int64_t *) key) = vpid;
-
-       /* Exists? Return it */
-       proc_dbg_info_src = g_hash_table_lookup(ht, key);
-       if (proc_dbg_info_src) {
-               goto end;
-       }
-
-       /* Otherwise, create and return it */
-       proc_dbg_info_src = proc_debug_info_sources_create();
-       if (!proc_dbg_info_src) {
-               goto end;
-       }
-
-       g_hash_table_insert(ht, key, proc_dbg_info_src);
-       /* Ownership passed to ht */
-       key = NULL;
-end:
-       g_free(key);
-       return proc_dbg_info_src;
-}
-
-static inline
-const bt_field *event_borrow_payload_field(const bt_event *event,
-               const char *field_name)
-{
-       const bt_field *event_payload, *field;
-
-       event_payload =  bt_event_borrow_payload_field_const(event);
-       BT_ASSERT(event_payload);
-
-       field = bt_field_structure_borrow_member_field_by_name_const(
-                       event_payload, field_name);
-       return field;
-}
-
-static inline
-const bt_field *event_borrow_common_context_field(const bt_event *event,
-               const char *field_name)
-{
-       const bt_field *event_common_ctx, *field = NULL;
-
-       event_common_ctx =  bt_event_borrow_common_context_field_const(event);
-       if (!event_common_ctx) {
-               goto end;
-       }
-
-       field = bt_field_structure_borrow_member_field_by_name_const(
-                       event_common_ctx, field_name);
-
-end:
-       return field;
-}
-
-static inline
-void event_get_common_context_signed_integer_field_value(
-               const bt_event *event, const char *field_name, int64_t *value)
-{
-       *value = bt_field_signed_integer_get_value(
-                       event_borrow_common_context_field(event, field_name));
-}
-
-static inline
-int event_get_payload_build_id_length(const bt_event *event,
-               const char *field_name, uint64_t *build_id_len)
-{
-       const bt_field *build_id_field;
-       const bt_field_class *build_id_field_class;
-
-       build_id_field = event_borrow_payload_field(event, field_name);
-       build_id_field_class = bt_field_borrow_class_const(build_id_field);
-
-       BT_ASSERT(bt_field_class_get_type(build_id_field_class) ==
-                       BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY);
-       BT_ASSERT(bt_field_class_get_type(
-                       bt_field_class_array_borrow_element_field_class_const(
-                               build_id_field_class)) ==
-                       BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER);
-
-       *build_id_len = bt_field_array_get_length(build_id_field);
-
-       return 0;
-}
-
-static inline
-int event_get_payload_build_id_value(const bt_event *event,
-               const char *field_name, uint8_t *build_id)
-{
-       const bt_field *curr_field, *build_id_field;
-       const bt_field_class *build_id_field_class;
-       uint64_t i, build_id_len;
-       int ret;
-
-       ret = 0;
-
-       build_id_field = event_borrow_payload_field(event, field_name);
-       build_id_field_class = bt_field_borrow_class_const(build_id_field);
-
-       BT_ASSERT(bt_field_class_get_type(build_id_field_class) ==
-                       BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY);
-       BT_ASSERT(bt_field_class_get_type(
-                       bt_field_class_array_borrow_element_field_class_const(
-                               build_id_field_class)) ==
-                       BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER);
-
-       build_id_len = bt_field_array_get_length(build_id_field);
-
-       for (i = 0; i < build_id_len; i++) {
-               curr_field =
-                       bt_field_array_borrow_element_field_by_index_const(
-                                       build_id_field, i);
-
-               build_id[i] = bt_field_unsigned_integer_get_value(curr_field);
-       }
-
-       return ret;
-}
-
-static
-void event_get_payload_unsigned_integer_field_value(const bt_event *event,
-               const char *field_name, uint64_t *value)
-{
-       *value = bt_field_unsigned_integer_get_value(
-                       event_borrow_payload_field(event, field_name));
-}
-
-static
-void event_get_payload_string_field_value(const bt_event *event,
-               const char *field_name, const char **value)
-{
-       *value = bt_field_string_get_value(
-                       event_borrow_payload_field(event, field_name));
-}
-
-static inline
-bool event_has_payload_field(const bt_event *event,
-               const char *field_name)
-{
-       return event_borrow_payload_field(event, field_name) != NULL;
-}
-
-static
-struct debug_info_source *proc_debug_info_sources_get_entry(
-               struct proc_debug_info_sources *proc_dbg_info_src, uint64_t ip)
-{
-       struct debug_info_source *debug_info_src = NULL;
-       gpointer key = g_new0(uint64_t, 1);
-       GHashTableIter iter;
-       gpointer baddr, value;
-
-       if (!key) {
-               goto end;
-       }
-
-       *((uint64_t *) key) = ip;
-
-       /* Look in IP to debug infos hash table first. */
-       debug_info_src = g_hash_table_lookup(
-                       proc_dbg_info_src->ip_to_debug_info_src,
-                       key);
-       if (debug_info_src) {
-               goto end;
-       }
-
-       /* Check in all bin_infos. */
-       g_hash_table_iter_init(&iter, proc_dbg_info_src->baddr_to_bin_info);
-
-       while (g_hash_table_iter_next(&iter, &baddr, &value))
-       {
-               struct bin_info *bin = value;
-
-               if (!bin_info_has_address(value, ip)) {
-                       continue;
-               }
-
-               /*
-                * Found; add it to cache.
-                *
-                * FIXME: this should be bounded in size (and implement
-                * a caching policy), and entries should be prunned when
-                * libraries are unmapped.
-                */
-               debug_info_src = debug_info_source_create_from_bin(bin, ip);
-               if (debug_info_src) {
-                       g_hash_table_insert(
-                                       proc_dbg_info_src->ip_to_debug_info_src,
-                                       key, debug_info_src);
-                       /* Ownership passed to ht. */
-                       key = NULL;
-               }
-               break;
-       }
-
-end:
-       free(key);
-       return debug_info_src;
-}
-
-static
-struct debug_info_source *debug_info_query(struct debug_info *debug_info,
-               int64_t vpid, uint64_t ip)
-{
-       struct debug_info_source *dbg_info_src = NULL;
-       struct proc_debug_info_sources *proc_dbg_info_src;
-
-       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
-                       debug_info->vpid_to_proc_dbg_info_src, vpid);
-       if (!proc_dbg_info_src) {
-               goto end;
-       }
-
-       dbg_info_src = proc_debug_info_sources_get_entry(proc_dbg_info_src, ip);
-
-end:
-       return dbg_info_src;
-}
-
-static
-struct debug_info *debug_info_create(struct debug_info_component *comp,
-               const bt_trace *trace, struct bt_fd_cache *fdc)
-{
-       int ret;
-       struct debug_info *debug_info;
-
-       BT_ASSERT(comp);
-       BT_ASSERT(trace);
-       BT_ASSERT(fdc);
-
-       debug_info = g_new0(struct debug_info, 1);
-       if (!debug_info) {
-               goto end;
-       }
-
-       debug_info->vpid_to_proc_dbg_info_src = g_hash_table_new_full(
-                       g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
-                       (GDestroyNotify) proc_debug_info_sources_destroy);
-       if (!debug_info->vpid_to_proc_dbg_info_src) {
-               goto error;
-       }
-
-       debug_info->comp = comp;
-       ret = debug_info_init(debug_info);
-       if (ret) {
-               goto error;
-       }
-
-       debug_info->input_trace = trace;
-       debug_info->fd_cache = fdc;
-
-end:
-       return debug_info;
-error:
-       g_free(debug_info);
-       return NULL;
-}
-
-static
-void debug_info_destroy(struct debug_info *debug_info)
-{
-       bt_trace_status status;
-       if (!debug_info) {
-               goto end;
-       }
-
-       if (debug_info->vpid_to_proc_dbg_info_src) {
-               g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src);
-       }
-
-       status = bt_trace_remove_destruction_listener(debug_info->input_trace,
-                       debug_info->destruction_listener_id);
-       if (status != BT_TRACE_STATUS_OK) {
-               BT_LOGD("Trace destruction listener removal failed.");
-       }
-
-       g_free(debug_info);
-end:
-       return;
-}
-
-static
-void handle_event_statedump_build_id(struct debug_info *debug_info,
-               const bt_event *event)
-{
-       struct proc_debug_info_sources *proc_dbg_info_src;
-       uint64_t build_id_len, baddr;
-       uint8_t *build_id = NULL;
-       struct bin_info *bin;
-       int64_t vpid;
-       int ret = 0;
-
-       event_get_common_context_signed_integer_field_value(event,
-                       VPID_FIELD_NAME, &vpid);
-       event_get_payload_unsigned_integer_field_value(event,
-                       BADDR_FIELD_NAME, &baddr);
-
-       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
-                       debug_info->vpid_to_proc_dbg_info_src, vpid);
-       if (!proc_dbg_info_src) {
-               goto end;
-       }
-
-       bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info,
-                       (gpointer) &baddr);
-       if (!bin) {
-               /*
-                * The build_id event comes after the bin has been
-                * created. If it isn't found, just ignore this event.
-                */
-               goto end;
-       }
-       ret = event_get_payload_build_id_length(event, BUILD_ID_FIELD_NAME,
-                       &build_id_len);
-
-       build_id = g_new0(uint8_t, build_id_len);
-       if (!build_id) {
-               goto end;
-       }
-
-       ret = event_get_payload_build_id_value(event, BUILD_ID_FIELD_NAME,
-                       build_id);
-       if (ret) {
-               goto end;
-       }
-
-       ret = bin_info_set_build_id(bin, build_id, build_id_len);
-       if (ret) {
-               goto end;
-       }
-
-       /*
-        * Reset the is_elf_only flag in case it had been set
-        * previously, because we might find separate debug info using
-        * the new build id information.
-        */
-       bin->is_elf_only = false;
-
-end:
-       g_free(build_id);
-       return;
-}
-
-static
-void handle_event_statedump_debug_link(struct debug_info *debug_info,
-               const bt_event *event)
-{
-       struct proc_debug_info_sources *proc_dbg_info_src;
-       struct bin_info *bin = NULL;
-       int64_t vpid;
-       uint64_t baddr;
-       const char *filename = NULL;
-       uint32_t crc32;
-       uint64_t crc_field_value;
-
-       event_get_common_context_signed_integer_field_value(event,
-                       VPID_FIELD_NAME, &vpid);
-
-       event_get_payload_unsigned_integer_field_value(event,
-                       BADDR_FIELD_NAME, &baddr);
-
-       event_get_payload_unsigned_integer_field_value(event,
-                       CRC32_FIELD_NAME, &crc_field_value);
-
-       crc32 = (uint32_t) crc_field_value;
-
-       event_get_payload_string_field_value(event,
-                       FILENAME_FIELD_NAME, &filename);
-
-       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
-                       debug_info->vpid_to_proc_dbg_info_src, vpid);
-       if (!proc_dbg_info_src) {
-               goto end;
-       }
-
-       bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info,
-                       (gpointer) &baddr);
-       if (!bin) {
-               /*
-                * The debug_link event comes after the bin has been
-                * created. If it isn't found, just ignore this event.
-                */
-               goto end;
-       }
-
-       bin_info_set_debug_link(bin, filename, crc32);
-
-end:
-       return;
-}
-
-static
-void handle_bin_info_event(struct debug_info *debug_info,
-               const bt_event *event, bool has_pic_field)
-{
-       struct proc_debug_info_sources *proc_dbg_info_src;
-       struct bin_info *bin;
-       uint64_t baddr, memsz;
-       int64_t vpid;
-       const char *path;
-       gpointer key = NULL;
-       bool is_pic;
-
-       event_get_payload_unsigned_integer_field_value(event,
-                       MEMSZ_FIELD_NAME, &memsz);
-       if (memsz == 0) {
-               /* Ignore VDSO. */
-               goto end;
-       }
-
-       event_get_payload_unsigned_integer_field_value(event,
-                       BADDR_FIELD_NAME, &baddr);
-
-       /*
-        * This field is not produced by the dlopen event emitted before
-        * lttng-ust 2.9.
-        */
-       if (!event_has_payload_field(event, PATH_FIELD_NAME)) {
-               goto end;
-       }
-       event_get_payload_string_field_value(event, PATH_FIELD_NAME, &path);
-
-       if (has_pic_field) {
-               uint64_t is_pic_field_value;
-
-               event_get_payload_unsigned_integer_field_value(event,
-                       IS_PIC_FIELD_NAME, &is_pic_field_value);
-               is_pic = is_pic_field_value == 1;
-       } else {
-               /*
-                * dlopen has no is_pic field, because the shared
-                * object is always PIC.
-                */
-               is_pic = true;
-       }
-
-       event_get_common_context_signed_integer_field_value(event,
-               VPID_FIELD_NAME, &vpid);
-
-       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
-               debug_info->vpid_to_proc_dbg_info_src, vpid);
-       if (!proc_dbg_info_src) {
-               goto end;
-       }
-
-       key = g_new0(uint64_t, 1);
-       if (!key) {
-               goto end;
-       }
-
-       *((uint64_t *) key) = baddr;
-
-       bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, key);
-       if (bin) {
-               goto end;
-       }
-
-       bin = bin_info_create(debug_info->fd_cache, path, baddr, memsz, is_pic,
-               debug_info->comp->arg_debug_dir,
-               debug_info->comp->arg_target_prefix);
-       if (!bin) {
-               goto end;
-       }
-
-       g_hash_table_insert(proc_dbg_info_src->baddr_to_bin_info, key, bin);
-       /* Ownership passed to ht. */
-       key = NULL;
-
-end:
-       g_free(key);
-       return;
-}
-
-static inline
-void handle_event_statedump_bin_info(struct debug_info *debug_info,
-               const bt_event *event)
-{
-       handle_bin_info_event(debug_info, event, true);
-}
-
-static inline
-void handle_event_lib_load(struct debug_info *debug_info,
-               const bt_event *event)
-{
-       handle_bin_info_event(debug_info, event, false);
-}
-
-static
-void handle_event_lib_unload(struct debug_info *debug_info,
-               const bt_event *event)
-{
-       gboolean ret;
-       struct proc_debug_info_sources *proc_dbg_info_src;
-       uint64_t baddr;
-       int64_t vpid;
-
-       event_get_payload_unsigned_integer_field_value(event, BADDR_FIELD_NAME,
-                       &baddr);
-
-       event_get_common_context_signed_integer_field_value(event,
-                       VPID_FIELD_NAME, &vpid);
-
-       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
-                       debug_info->vpid_to_proc_dbg_info_src, vpid);
-       if (!proc_dbg_info_src) {
-               /*
-                * It's an unload event for a library for which no load event
-                * was previously received.
-                */
-               goto end;
-       }
-
-       ret = g_hash_table_remove(proc_dbg_info_src->baddr_to_bin_info,
-                       (gpointer) &baddr);
-       BT_ASSERT(ret);
-end:
-       return;
-}
-
-static
-void handle_event_statedump_start(struct debug_info *debug_info,
-               const bt_event *event)
-{
-       struct proc_debug_info_sources *proc_dbg_info_src;
-       int64_t vpid;
-
-       event_get_common_context_signed_integer_field_value(
-                       event, VPID_FIELD_NAME, &vpid);
-
-       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
-                       debug_info->vpid_to_proc_dbg_info_src, vpid);
-       if (!proc_dbg_info_src) {
-               goto end;
-       }
-
-       g_hash_table_remove_all(proc_dbg_info_src->baddr_to_bin_info);
-       g_hash_table_remove_all(proc_dbg_info_src->ip_to_debug_info_src);
-
-end:
-       return;
-}
-
-void trace_debug_info_remove_func(const bt_trace *in_trace, void *data)
-{
-       struct debug_info_msg_iter *debug_it = data;
-       if (debug_it->debug_info_map) {
-               gboolean ret;
-               ret = g_hash_table_remove(debug_it->debug_info_map,
-                               (gpointer) in_trace);
-               BT_ASSERT(ret);
-       }
-}
-
-static
-void handle_event_statedump(struct debug_info_msg_iter *debug_it,
-               const bt_event *event)
-{
-       const bt_event_class *event_class;
-       const char *event_name;
-       GQuark q_event_name;
-       const bt_trace *trace;
-       struct debug_info *debug_info;
-
-       BT_ASSERT(debug_it);
-       BT_ASSERT(event);
-
-       event_class = bt_event_borrow_class_const(event);
-
-       event_name = bt_event_class_get_name(event_class);
-
-       trace = bt_stream_borrow_trace_const(
-                       bt_event_borrow_stream_const(event));
-
-       debug_info = g_hash_table_lookup(debug_it->debug_info_map, trace);
-       if (!debug_info) {
-               debug_info = debug_info_create(debug_it->debug_info_component,
-                               trace, &debug_it->fd_cache);
-               g_hash_table_insert(debug_it->debug_info_map, (gpointer) trace,
-                               debug_info);
-               bt_trace_add_destruction_listener(trace,
-                               trace_debug_info_remove_func, debug_it,
-                               &debug_info->destruction_listener_id);
-       }
-
-       q_event_name = g_quark_try_string(event_name);
-
-       if (q_event_name == debug_info->q_statedump_bin_info) {
-               /* State dump */
-               handle_event_statedump_bin_info(debug_info, event);
-       } else if (q_event_name == debug_info->q_dl_open ||
-                       q_event_name == debug_info->q_lib_load) {
-               /*
-                * dl_open and lib_load events are both checked for since
-                * only dl_open was produced as of lttng-ust 2.8.
-                *
-                * lib_load, which is produced from lttng-ust 2.9+, is a lot
-                * more reliable since it will be emitted when other functions
-                * of the dlopen family are called (e.g. dlmopen) and when
-                * library are transitively loaded.
-                */
-               handle_event_lib_load(debug_info, event);
-       } else if (q_event_name == debug_info->q_statedump_start) {
-               /* Start state dump */
-               handle_event_statedump_start(debug_info, event);
-       } else if (q_event_name == debug_info->q_statedump_debug_link) {
-               /* Debug link info */
-               handle_event_statedump_debug_link(debug_info, event);
-       } else if (q_event_name == debug_info->q_statedump_build_id) {
-               /* Build ID info */
-               handle_event_statedump_build_id(debug_info, event);
-       } else if (q_event_name == debug_info-> q_lib_unload) {
-               handle_event_lib_unload(debug_info, event);
-       }
-
-       return;
-}
-
-static
-void destroy_debug_info_comp(struct debug_info_component *debug_info)
-{
-       if (!debug_info) {
-               return;
-       }
-
-       g_free(debug_info->arg_debug_dir);
-       g_free(debug_info->arg_debug_info_field_name);
-       g_free(debug_info->arg_target_prefix);
-       g_free(debug_info);
-}
-
-static
-void fill_debug_info_bin_field(struct debug_info_source *dbg_info_src,
-               bool full_path, bt_field *curr_field)
-{
-       bt_field_status status;
-
-       BT_ASSERT(bt_field_get_class_type(curr_field) ==
-                       BT_FIELD_CLASS_TYPE_STRING);
-
-       if (dbg_info_src) {
-               if (full_path) {
-                       status = bt_field_string_set_value(curr_field,
-                                       dbg_info_src->bin_path);
-               } else {
-                       status = bt_field_string_set_value(curr_field,
-                                       dbg_info_src->short_bin_path);
-               }
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot set path component of \"bin\" "
-                               "curr_field field's value: str-fc-addr=%p",
-                               curr_field);
-               }
-
-               status = bt_field_string_append(curr_field, dbg_info_src->bin_loc);
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot set bin location component of \"bin\" "
-                               "curr_field field's value: str-fc-addr=%p",
-                               curr_field);
-               }
-       } else {
-               status = bt_field_string_set_value(curr_field, "");
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot set \"bin\" curr_field field's value: "
-                               "str-fc-addr=%p", curr_field);
-               }
-       }
-}
-
-static
-void fill_debug_info_func_field(struct debug_info_source *dbg_info_src,
-               bt_field *curr_field)
-{
-       bt_field_status status;
-
-       BT_ASSERT(bt_field_get_class_type(curr_field) ==
-                       BT_FIELD_CLASS_TYPE_STRING);
-       if (dbg_info_src && dbg_info_src->func) {
-               status = bt_field_string_set_value(curr_field,
-                               dbg_info_src->func);
-       } else {
-               status = bt_field_string_set_value(curr_field, "");
-       }
-       if (status != BT_FIELD_STATUS_OK) {
-               BT_LOGE("Cannot set \"func\" curr_field field's value: "
-                       "str-fc-addr=%p", curr_field);
-       }
-}
-
-static
-void fill_debug_info_src_field(struct debug_info_source *dbg_info_src,
-               bool full_path, bt_field *curr_field)
-{
-       bt_field_status status;
-
-       BT_ASSERT(bt_field_get_class_type(curr_field) ==
-                       BT_FIELD_CLASS_TYPE_STRING);
-
-       if (dbg_info_src && dbg_info_src->src_path) {
-               if (full_path) {
-                       status = bt_field_string_set_value(curr_field,
-                                       dbg_info_src->src_path);
-               } else {
-                       status = bt_field_string_set_value(curr_field,
-                                       dbg_info_src->short_src_path);
-               }
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot set path component of \"src\" "
-                               "curr_field field's value: str-fc-addr=%p",
-                               curr_field);
-               }
-
-               status = bt_field_string_append(curr_field, ":");
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot set colon component of \"src\" "
-                               "curr_field field's value: str-fc-addr=%p",
-                               curr_field);
-               }
-
-               status = bt_field_string_append(curr_field, dbg_info_src->line_no);
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot set line number component of \"src\" "
-                               "curr_field field's value: str-fc-addr=%p",
-                               curr_field);
-               }
-       } else {
-               status = bt_field_string_set_value(curr_field, "");
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot set \"src\" curr_field field's value: "
-                               "str-fc-addr=%p", curr_field);
-               }
-       }
-}
-
-void fill_debug_info_field_empty(bt_field *debug_info_field)
-{
-       bt_field_status status;
-       bt_field *bin_field, *func_field, *src_field;
-
-       BT_ASSERT(bt_field_get_class_type(debug_info_field) ==
-                       BT_FIELD_CLASS_TYPE_STRUCTURE);
-
-       bin_field = bt_field_structure_borrow_member_field_by_name(
-                       debug_info_field, "bin");
-       func_field = bt_field_structure_borrow_member_field_by_name(
-                       debug_info_field, "func");
-       src_field = bt_field_structure_borrow_member_field_by_name(
-                       debug_info_field, "src");
-
-       BT_ASSERT(bt_field_get_class_type(bin_field) ==
-                       BT_FIELD_CLASS_TYPE_STRING);
-       BT_ASSERT(bt_field_get_class_type(func_field) ==
-                       BT_FIELD_CLASS_TYPE_STRING);
-       BT_ASSERT(bt_field_get_class_type(src_field) ==
-                       BT_FIELD_CLASS_TYPE_STRING);
-
-       status = bt_field_string_set_value(bin_field, "");
-       if (status != BT_FIELD_STATUS_OK) {
-               BT_LOGE("Cannot set \"bin\" bin_field field's value: "
-                       "str-fc-addr=%p", bin_field);
-       }
-
-       status = bt_field_string_set_value(func_field, "");
-       if (status != BT_FIELD_STATUS_OK) {
-               BT_LOGE("Cannot set \"func\" func_field field's value: "
-                       "str-fc-addr=%p", func_field);
-       }
-
-       status = bt_field_string_set_value(src_field, "");
-       if (status != BT_FIELD_STATUS_OK) {
-               BT_LOGE("Cannot set \"src\" src_field field's value: "
-                       "str-fc-addr=%p", src_field);
-       }
-}
-static
-void fill_debug_info_field(struct debug_info *debug_info, int64_t vpid,
-               uint64_t ip, bt_field *debug_info_field)
-{
-       struct debug_info_source *dbg_info_src;
-       const bt_field_class *debug_info_fc;
-
-       BT_ASSERT(bt_field_get_class_type(debug_info_field) ==
-                       BT_FIELD_CLASS_TYPE_STRUCTURE);
-
-       debug_info_fc = bt_field_borrow_class_const(debug_info_field);
-
-       BT_ASSERT(bt_field_class_structure_get_member_count(debug_info_fc) == 3);
-
-       dbg_info_src = debug_info_query(debug_info, vpid, ip);
-
-       fill_debug_info_bin_field(dbg_info_src, debug_info->comp->arg_full_path,
-                       bt_field_structure_borrow_member_field_by_name(
-                               debug_info_field, "bin"));
-       fill_debug_info_func_field(dbg_info_src,
-                       bt_field_structure_borrow_member_field_by_name(
-                               debug_info_field, "func"));
-       fill_debug_info_src_field(dbg_info_src, debug_info->comp->arg_full_path,
-                       bt_field_structure_borrow_member_field_by_name(
-                               debug_info_field, "src"));
-}
-
-static
-void fill_debug_info_event_if_needed(struct debug_info_msg_iter *debug_it,
-               const bt_event *in_event, bt_event *out_event)
-{
-       bt_field *out_common_ctx_field, *out_debug_info_field;
-       const bt_field *vpid_field, *ip_field, *in_common_ctx_field;
-       const bt_field_class *in_common_ctx_fc;
-       struct debug_info *debug_info;
-       uint64_t vpid;
-       int64_t ip;
-       gchar *debug_info_field_name =
-               debug_it->debug_info_component->arg_debug_info_field_name;
-
-       in_common_ctx_field = bt_event_borrow_common_context_field_const(
-                       in_event);
-       if (!in_common_ctx_field) {
-               /*
-                * There is no event common context so no need to add debug
-                * info field.
-                */
-               goto end;
-       }
-
-       in_common_ctx_fc = bt_field_borrow_class_const(in_common_ctx_field);
-       if (!is_event_common_ctx_dbg_info_compatible(in_common_ctx_fc,
-                               debug_it->ir_maps->debug_info_field_class_name)) {
-               /*
-                * The input event common context does not have the necessary
-                * fields to resolve debug information.
-                */
-               goto end;
-       }
-
-       /* Borrow the debug-info field. */
-       out_common_ctx_field = bt_event_borrow_common_context_field(out_event);
-       if (!out_common_ctx_field) {
-               goto end;
-       }
-
-       out_debug_info_field = bt_field_structure_borrow_member_field_by_name(
-                               out_common_ctx_field, debug_info_field_name);
-
-       vpid_field = bt_field_structure_borrow_member_field_by_name_const(
-                       out_common_ctx_field, VPID_FIELD_NAME);
-       ip_field = bt_field_structure_borrow_member_field_by_name_const(
-                       out_common_ctx_field, IP_FIELD_NAME);
-
-       vpid = bt_field_signed_integer_get_value(vpid_field);
-       ip = bt_field_unsigned_integer_get_value(ip_field);
-
-       /*
-        * Borrow the debug_info structure needed for the source
-        * resolving.
-        */
-       debug_info = g_hash_table_lookup(debug_it->debug_info_map,
-                       bt_stream_borrow_trace_const(
-                               bt_event_borrow_stream_const(in_event)));
-
-       if (debug_info) {
-               /*
-                * Perform the debug-info resolving and set the event fields
-                * accordingly.
-                */
-               fill_debug_info_field(debug_info, vpid, ip, out_debug_info_field);
-       } else {
-               BT_LOGD("No debug information for this trace. Setting debug "
-                       "info fields to empty strings.");
-               fill_debug_info_field_empty(out_debug_info_field);
-       }
-end:
-       return;
-}
-
-static
-void update_event_statedump_if_needed(struct debug_info_msg_iter *debug_it,
-               const bt_event *in_event)
-{
-       const bt_field *event_common_ctx;
-       const bt_field_class *event_common_ctx_fc;
-       const bt_event_class *in_event_class = bt_event_borrow_class_const(in_event);
-
-       /*
-        * If the event is an lttng_ust_statedump event AND has the right event
-        * common context fields update the debug-info view for this process.
-        */
-       event_common_ctx = bt_event_borrow_common_context_field_const(in_event);
-       if (!event_common_ctx) {
-               goto end;
-       }
-
-       event_common_ctx_fc = bt_field_borrow_class_const(event_common_ctx);
-       if (is_event_common_ctx_dbg_info_compatible(event_common_ctx_fc,
-                               debug_it->ir_maps->debug_info_field_class_name)) {
-               /* Checkout if it might be a one of lttng ust statedump events. */
-               const char *in_event_name = bt_event_class_get_name(in_event_class);
-               if (strncmp(in_event_name, LTTNG_UST_STATEDUMP_PREFIX,
-                               strlen(LTTNG_UST_STATEDUMP_PREFIX)) == 0) {
-                       /* Handle statedump events. */
-                       handle_event_statedump(debug_it, in_event);
-               }
-       }
-end:
-       return;
-}
-
-static
-bt_message *handle_event_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       const bt_clock_snapshot *cs;
-       const bt_clock_class *default_cc;
-       const bt_packet *in_packet;
-       bt_event_class *out_event_class;
-       bt_packet *out_packet;
-       bt_event *out_event;
-
-       bt_message *out_message = NULL;
-
-       /* Borrow the input event and its event class. */
-       const bt_event *in_event =
-               bt_message_event_borrow_event_const(in_message);
-       const bt_event_class *in_event_class =
-               bt_event_borrow_class_const(in_event);
-
-       update_event_statedump_if_needed(debug_it, in_event);
-
-       out_event_class = trace_ir_mapping_borrow_mapped_event_class(
-                       debug_it->ir_maps, in_event_class);
-       if (!out_event_class) {
-               out_event_class = trace_ir_mapping_create_new_mapped_event_class(
-                                       debug_it->ir_maps, in_event_class);
-       }
-       BT_ASSERT(out_event_class);
-
-       /* Borrow the input and output packets. */
-       in_packet = bt_event_borrow_packet_const(in_event);
-       out_packet = trace_ir_mapping_borrow_mapped_packet(debug_it->ir_maps,
-                       in_packet);
-
-       default_cc = bt_stream_class_borrow_default_clock_class_const(
-                       bt_event_class_borrow_stream_class_const(in_event_class));
-       if (default_cc) {
-               /* Borrow event clock snapshot. */
-               cs = bt_message_event_borrow_default_clock_snapshot_const(
-                               in_message);
-
-               /* Create an output event message. */
-               out_message = bt_message_event_create_with_default_clock_snapshot(
-                                       debug_it->input_iterator,
-                                       out_event_class, out_packet,
-                                       bt_clock_snapshot_get_value(cs));
-       } else {
-               out_message = bt_message_event_create(debug_it->input_iterator,
-                               out_event_class, out_packet);
-       }
-
-       if (!out_message) {
-               BT_LOGE("Error creating output event message.");
-               goto error;
-       }
-
-       out_event = bt_message_event_borrow_event(out_message);
-
-       /* Copy the original fields to the output event. */
-       copy_event_content(in_event, out_event);
-
-       /*
-        * Try to set the debug-info fields based on debug information that is
-        * gathered so far.
-        */
-       fill_debug_info_event_if_needed(debug_it, in_event, out_event);
-
-error:
-       return out_message;
-}
-
-static
-bt_message *handle_stream_begin_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       const bt_stream *in_stream;
-       bt_message *out_message;
-       bt_stream *out_stream;
-
-       in_stream = bt_message_stream_beginning_borrow_stream_const(in_message);
-       BT_ASSERT(in_stream);
-
-       /* Create a duplicated output stream. */
-       out_stream = trace_ir_mapping_create_new_mapped_stream(
-                       debug_it->ir_maps, in_stream);
-       if (!out_stream) {
-               out_message = NULL;
-               goto error;
-       }
-
-       /* Create an output stream beginning message. */
-       out_message = bt_message_stream_beginning_create(
-                       debug_it->input_iterator, out_stream);
-       if (!out_message) {
-               BT_LOGE("Error creating output stream beginning message: "
-                       "out-s-addr=%p", out_stream);
-       }
-error:
-       return out_message;
-}
-
-static
-bt_message *handle_stream_end_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       const bt_stream *in_stream;
-       bt_message *out_message = NULL;
-       bt_stream *out_stream;
-
-       in_stream = bt_message_stream_end_borrow_stream_const(in_message);
-       BT_ASSERT(in_stream);
-
-       out_stream = trace_ir_mapping_borrow_mapped_stream(
-                       debug_it->ir_maps, in_stream);
-       BT_ASSERT(out_stream);
-
-       /* Create an output stream end message. */
-       out_message = bt_message_stream_end_create(debug_it->input_iterator,
-                       out_stream);
-       if (!out_message) {
-               BT_LOGE("Error creating output stream end message: out-s-addr=%p",
-                               out_stream);
-       }
-
-       /* Remove stream from trace mapping hashtable. */
-       trace_ir_mapping_remove_mapped_stream(debug_it->ir_maps, in_stream);
-
-       return out_message;
-}
-
-static
-bt_message *handle_packet_begin_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       bool has_default_clock_snapshot;
-       const bt_clock_snapshot *cs;
-       bt_message *out_message = NULL;
-       bt_packet *out_packet;
-
-       const bt_packet *in_packet =
-               bt_message_packet_beginning_borrow_packet_const(in_message);
-       BT_ASSERT(in_packet);
-
-       /* This packet should not be already mapped. */
-       BT_ASSERT(!trace_ir_mapping_borrow_mapped_packet(
-                               debug_it->ir_maps, in_packet));
-
-       out_packet = trace_ir_mapping_create_new_mapped_packet(debug_it->ir_maps,
-                       in_packet);
-
-       BT_ASSERT(out_packet);
-
-       has_default_clock_snapshot =
-               bt_stream_class_packets_have_beginning_default_clock_snapshot(
-                       bt_stream_borrow_class_const(
-                               bt_packet_borrow_stream_const(in_packet)));
-       if (has_default_clock_snapshot) {
-               /* Borrow clock snapshot. */
-               cs = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
-                                       in_message);
-
-               /* Create an output packet beginning message. */
-               out_message = bt_message_packet_beginning_create_with_default_clock_snapshot(
-                               debug_it->input_iterator, out_packet,
-                               bt_clock_snapshot_get_value(cs));
-       } else {
-               out_message = bt_message_packet_beginning_create(
-                               debug_it->input_iterator, out_packet);
-       }
-       if (!out_message) {
-               BT_LOGE("Error creating output packet beginning message: "
-                       "out-p-addr=%p", out_packet);
-       }
-
-       return out_message;
-}
-
-static
-bt_message *handle_packet_end_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       bool has_default_clock_snapshot;
-       const bt_clock_snapshot *cs;
-       const bt_packet *in_packet;
-       bt_message *out_message = NULL;
-       bt_packet *out_packet;
-
-       in_packet = bt_message_packet_end_borrow_packet_const(in_message);
-       BT_ASSERT(in_packet);
-
-       out_packet = trace_ir_mapping_borrow_mapped_packet(debug_it->ir_maps, in_packet);
-       BT_ASSERT(out_packet);
-
-       has_default_clock_snapshot =
-               bt_stream_class_packets_have_end_default_clock_snapshot(
-                       bt_stream_borrow_class_const(
-                               bt_packet_borrow_stream_const(in_packet)));
-       if (has_default_clock_snapshot) {
-               /* Borrow clock snapshot. */
-               cs = bt_message_packet_end_borrow_default_clock_snapshot_const(
-                                       in_message);
-
-               /* Create an outpute packet end message. */
-               out_message = bt_message_packet_end_create_with_default_clock_snapshot(
-                               debug_it->input_iterator, out_packet,
-                               bt_clock_snapshot_get_value(cs));
-       } else {
-               out_message = bt_message_packet_end_create(
-                               debug_it->input_iterator, out_packet);
-       }
-
-       if (!out_message) {
-               BT_LOGE("Error creating output packet end message: "
-                       "out-p-addr=%p", out_packet);
-       }
-
-       /* Remove packet from data mapping hashtable. */
-       trace_ir_mapping_remove_mapped_packet(debug_it->ir_maps, in_packet);
-
-       return out_message;
-}
-
-static
-bt_message *handle_msg_iterator_inactivity(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       /*
-        * This message type can be forwarded directly because it does
-        * not refer to any objects in the trace class.
-        */
-       bt_message_get_ref(in_message);
-       return (bt_message*) in_message;
-}
-
-static
-bt_message *handle_stream_act_begin_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       const bt_clock_snapshot *cs;
-       const bt_clock_class *default_cc;
-       bt_message *out_message = NULL;
-       bt_stream *out_stream;
-       uint64_t cs_value;
-       bt_message_stream_activity_clock_snapshot_state cs_state;
-
-       const bt_stream *in_stream =
-               bt_message_stream_activity_beginning_borrow_stream_const(
-                       in_message);
-       BT_ASSERT(in_stream);
-
-       out_stream = trace_ir_mapping_borrow_mapped_stream(debug_it->ir_maps,
-                       in_stream);
-       BT_ASSERT(out_stream);
-
-       out_message = bt_message_stream_activity_beginning_create(
-                       debug_it->input_iterator, out_stream);
-       if (!out_message) {
-               BT_LOGE("Error creating output stream activity beginning "
-                       "message: out-s-addr=%p", out_stream);
-               goto error;
-       }
-
-       default_cc = bt_stream_class_borrow_default_clock_class_const(
-                       bt_stream_borrow_class_const(in_stream));
-       if (default_cc) {
-               /* Borrow clock snapshot. */
-               cs_state =
-                       bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
-                                       in_message, &cs);
-
-               if (cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
-                       cs_value = bt_clock_snapshot_get_value(cs);
-                       bt_message_stream_activity_beginning_set_default_clock_snapshot(
-                                       out_message, cs_value);
-               } else {
-                       bt_message_stream_activity_beginning_set_default_clock_snapshot_state(
-                                       out_message, cs_state);
-               }
-       }
-
-error:
-       return out_message;
-}
-
-static
-bt_message *handle_stream_act_end_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       const bt_clock_snapshot *cs;
-       const bt_clock_class *default_cc;
-       const bt_stream *in_stream;
-       bt_message *out_message;
-       bt_stream *out_stream;
-       uint64_t cs_value;
-       bt_message_stream_activity_clock_snapshot_state cs_state;
-
-       in_stream = bt_message_stream_activity_end_borrow_stream_const(
-                       in_message);
-       BT_ASSERT(in_stream);
-
-       out_stream = trace_ir_mapping_borrow_mapped_stream(debug_it->ir_maps,
-               in_stream);
-       BT_ASSERT(out_stream);
-
-       out_message = bt_message_stream_activity_end_create(
-                       debug_it->input_iterator, out_stream);
-       if (!out_message) {
-               BT_LOGE("Error creating output stream activity end message: "
-                       "out-s-addr=%p", out_stream);
-               goto error;
-       }
-
-       default_cc = bt_stream_class_borrow_default_clock_class_const(
-                       bt_stream_borrow_class_const(in_stream));
-
-       if (default_cc) {
-               cs_state =
-                       bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
-                                       in_message, &cs);
-
-               if (cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN ) {
-                       cs_value = bt_clock_snapshot_get_value(cs);
-                       bt_message_stream_activity_end_set_default_clock_snapshot(
-                                       out_message, cs_value);
-               } else {
-                       bt_message_stream_activity_end_set_default_clock_snapshot_state(
-                                       out_message, cs_state);
-               }
-       }
-
-error:
-       return out_message;
-}
-
-static
-bt_message *handle_discarded_events_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       const bt_clock_snapshot *begin_cs, *end_cs;
-       const bt_stream *in_stream;
-       bool has_default_clock_snapshots;
-       uint64_t discarded_events, begin_cs_value, end_cs_value;
-       bt_property_availability prop_avail;
-       bt_message *out_message = NULL;
-       bt_stream *out_stream;
-
-       in_stream = bt_message_discarded_events_borrow_stream_const(
-                       in_message);
-       BT_ASSERT(in_stream);
-
-       out_stream = trace_ir_mapping_borrow_mapped_stream(
-                               debug_it->ir_maps, in_stream);
-       BT_ASSERT(out_stream);
-
-       has_default_clock_snapshots =
-               bt_stream_class_discarded_events_have_default_clock_snapshots(
-                       bt_stream_borrow_class_const(in_stream));
-       if (has_default_clock_snapshots) {
-               begin_cs =
-                       bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-                               in_message);
-               end_cs =
-                       bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
-                               in_message);
-
-               begin_cs_value = bt_clock_snapshot_get_value(begin_cs);
-               end_cs_value = bt_clock_snapshot_get_value(end_cs);
-
-               out_message =
-                       bt_message_discarded_events_create_with_default_clock_snapshots(
-                                       debug_it->input_iterator, out_stream,
-                                       begin_cs_value, end_cs_value);
-       } else {
-               out_message = bt_message_discarded_events_create(
-                               debug_it->input_iterator, out_stream);
-       }
-       if (!out_message) {
-               BT_LOGE("Error creating output discarded events message: "
-                       "out-s-addr=%p", out_stream);
-               goto error;
-       }
-
-       prop_avail = bt_message_discarded_events_get_count(in_message,
-                       &discarded_events);
-
-       if (prop_avail == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
-               bt_message_discarded_events_set_count(out_message,
-                               discarded_events);
-       }
-
-error:
-       return out_message;
-}
-
-static
-bt_message *handle_discarded_packets_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       const bt_clock_snapshot *begin_cs, *end_cs;
-       bool has_default_clock_snapshots;
-       const bt_stream *in_stream;
-       uint64_t discarded_packets, begin_cs_value, end_cs_value;
-       bt_property_availability prop_avail;
-       bt_message *out_message = NULL;
-       bt_stream *out_stream;
-
-       in_stream = bt_message_discarded_packets_borrow_stream_const(
-                       in_message);
-       BT_ASSERT(in_stream);
-
-       out_stream = trace_ir_mapping_borrow_mapped_stream(
-                       debug_it->ir_maps, in_stream);
-       BT_ASSERT(out_stream);
-
-       has_default_clock_snapshots =
-               bt_stream_class_discarded_packets_have_default_clock_snapshots(
-                       bt_stream_borrow_class_const(in_stream));
-       if (has_default_clock_snapshots) {
-               begin_cs =
-                       bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-                               in_message);
-
-               end_cs =
-                       bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
-                               in_message);
-
-               begin_cs_value = bt_clock_snapshot_get_value(begin_cs);
-               end_cs_value = bt_clock_snapshot_get_value(end_cs);
-
-               out_message = bt_message_discarded_packets_create_with_default_clock_snapshots(
-                                       debug_it->input_iterator, out_stream,
-                                       begin_cs_value, end_cs_value);
-       } else {
-               out_message = bt_message_discarded_packets_create(
-                               debug_it->input_iterator, out_stream);
-       }
-       if (!out_message) {
-               BT_LOGE("Error creating output discarded packet message: "
-                       "out-s-addr=%p", out_stream);
-               goto error;
-       }
-
-       prop_avail = bt_message_discarded_packets_get_count(in_message,
-                       &discarded_packets);
-       if (prop_avail == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
-               bt_message_discarded_packets_set_count(out_message,
-                               discarded_packets);
-       }
-
-error:
-       return out_message;
-}
-
-static
-const bt_message *handle_message(struct debug_info_msg_iter *debug_it,
-               const bt_message *in_message)
-{
-       bt_message *out_message = NULL;
-
-       switch (bt_message_get_type(in_message)) {
-       case BT_MESSAGE_TYPE_EVENT:
-               out_message = handle_event_message(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-               out_message = handle_packet_begin_message(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_PACKET_END:
-               out_message = handle_packet_end_message(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
-               out_message = handle_stream_begin_message(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_END:
-               out_message = handle_stream_end_message(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-               out_message = handle_msg_iterator_inactivity(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-               out_message = handle_stream_act_begin_message(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-               out_message = handle_stream_act_end_message(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-               out_message = handle_discarded_events_message(debug_it,
-                               in_message);
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-               out_message = handle_discarded_packets_message(debug_it,
-                               in_message);
-               break;
-       default:
-               abort();
-               break;
-       }
-
-       return out_message;
-}
-
-static
-int init_from_params(struct debug_info_component *debug_info_component,
-               const bt_value *params)
-{
-       const bt_value *value = NULL;
-       int ret = 0;
-
-       BT_ASSERT(params);
-
-       value = bt_value_map_borrow_entry_value_const(params,
-                       "debug-info-field-name");
-       if (value) {
-               debug_info_component->arg_debug_info_field_name =
-                       g_strdup(bt_value_string_get(value));
-       } else {
-               debug_info_component->arg_debug_info_field_name =
-                       g_strdup(DEFAULT_DEBUG_INFO_FIELD_NAME);
-       }
-
-       value = bt_value_map_borrow_entry_value_const(params, "debug-info-dir");
-       if (value) {
-               debug_info_component->arg_debug_dir =
-                       g_strdup(bt_value_string_get(value));
-       } else {
-               debug_info_component->arg_debug_dir = NULL;
-       }
-
-
-       value = bt_value_map_borrow_entry_value_const(params, "target-prefix");
-       if (value) {
-               debug_info_component->arg_target_prefix =
-                       g_strdup(bt_value_string_get(value));
-       } else {
-               debug_info_component->arg_target_prefix = NULL;
-       }
-
-       value = bt_value_map_borrow_entry_value_const(params, "full-path");
-       if (value) {
-               debug_info_component->arg_full_path = bt_value_bool_get(value);
-       } else {
-               debug_info_component->arg_full_path = BT_FALSE;
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-bt_self_component_status debug_info_comp_init(
-               bt_self_component_filter *self_comp,
-               const bt_value *params, UNUSED_VAR void *init_method_data)
-{
-       int ret;
-       struct debug_info_component *debug_info_comp;
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-
-       BT_LOGD("Initializing debug_info component: "
-               "comp-addr=%p, params-addr=%p", self_comp, params);
-
-       debug_info_comp = g_new0(struct debug_info_component, 1);
-       if (!debug_info_comp) {
-               BT_LOGE_STR("Failed to allocate one debug_info component.");
-               goto error;
-       }
-
-       bt_self_component_set_data(
-                       bt_self_component_filter_as_self_component(self_comp),
-                       debug_info_comp);
-
-       status = bt_self_component_filter_add_input_port(self_comp, "in",
-                       NULL, NULL);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-
-       status = bt_self_component_filter_add_output_port(self_comp, "out",
-                       NULL, NULL);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-
-       ret = init_from_params(debug_info_comp, params);
-       if (ret) {
-               BT_LOGE("Cannot configure debug_info component: "
-                       "debug_info-comp-addr=%p, params-addr=%p",
-                       debug_info_comp, params);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       destroy_debug_info_comp(debug_info_comp);
-       bt_self_component_set_data(
-               bt_self_component_filter_as_self_component(self_comp),
-               NULL);
-
-       if (status == BT_SELF_COMPONENT_STATUS_OK) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-       }
-end:
-       return status;
-}
-
-BT_HIDDEN
-void debug_info_comp_finalize(bt_self_component_filter *self_comp)
-{
-       struct debug_info_component *debug_info =
-               bt_self_component_get_data(
-                               bt_self_component_filter_as_self_component(
-                                       self_comp));
-       BT_LOGD("Finalizing debug_info self_component: comp-addr=%p",
-               self_comp);
-
-       destroy_debug_info_comp(debug_info);
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status debug_info_msg_iter_next(
-               bt_self_message_iterator *self_msg_iter,
-               const bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       bt_self_component_port_input_message_iterator *upstream_iterator = NULL;
-       bt_message_iterator_status upstream_iterator_ret_status;
-       struct debug_info_msg_iter *debug_info_msg_iter;
-       struct debug_info_component *debug_info = NULL;
-       bt_self_message_iterator_status status;
-       bt_self_component *self_comp = NULL;
-       bt_message_array_const input_msgs;
-       const bt_message *out_message;
-       uint64_t curr_msg_idx, i;
-
-       status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       self_comp = bt_self_message_iterator_borrow_component(self_msg_iter);
-       BT_ASSERT(self_comp);
-
-       debug_info = bt_self_component_get_data(self_comp);
-       BT_ASSERT(debug_info);
-
-       debug_info_msg_iter = bt_self_message_iterator_get_data(self_msg_iter);
-       BT_ASSERT(debug_info_msg_iter);
-
-       upstream_iterator = debug_info_msg_iter->msg_iter;
-       BT_ASSERT(upstream_iterator);
-
-       upstream_iterator_ret_status =
-               bt_self_component_port_input_message_iterator_next(
-                               upstream_iterator, &input_msgs, count);
-       if (upstream_iterator_ret_status != BT_MESSAGE_ITERATOR_STATUS_OK) {
-               /*
-                * No messages were returned. Not necessarily an error. Convert
-                * the upstream message iterator status to a self status.
-                */
-               status = bt_common_message_iterator_status_to_self(
-                               upstream_iterator_ret_status);
-               goto end;
-       }
-
-       /*
-        * There should never be more received messages than the capacity we
-        * provided.
-        */
-       BT_ASSERT(*count <= capacity);
-
-       for (curr_msg_idx = 0; curr_msg_idx < *count; curr_msg_idx++) {
-               out_message = handle_message(debug_info_msg_iter,
-                               input_msgs[curr_msg_idx]);
-               if (!out_message) {
-                       goto handle_msg_error;
-               }
-
-               msgs[curr_msg_idx] = out_message;
-               /*
-                * Drop our reference of the input message as we are done with
-                * it and created a output copy.
-                */
-               bt_message_put_ref(input_msgs[curr_msg_idx]);
-       }
-
-       goto end;
-
-handle_msg_error:
-       /*
-        * Drop references of all the output messages created before the
-        * failure.
-        */
-       for (i = 0; i < curr_msg_idx; i++) {
-               bt_message_put_ref(msgs[i]);
-       }
-
-       status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-end:
-       return status;
-}
-
-static
-void debug_info_msg_iter_destroy(struct debug_info_msg_iter *debug_info_msg_iter)
-{
-       if (!debug_info_msg_iter) {
-               goto end;
-       }
-
-       if (debug_info_msg_iter->msg_iter) {
-               bt_self_component_port_input_message_iterator_put_ref(
-                               debug_info_msg_iter->msg_iter);
-       }
-
-       if (debug_info_msg_iter->ir_maps) {
-               trace_ir_maps_destroy(debug_info_msg_iter->ir_maps);
-       }
-
-       if (debug_info_msg_iter->debug_info_map) {
-               g_hash_table_destroy(debug_info_msg_iter->debug_info_map);
-       }
-
-       bt_fd_cache_fini(&debug_info_msg_iter->fd_cache);
-       g_free(debug_info_msg_iter);
-
-end:
-       return;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status debug_info_msg_iter_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_filter *self_comp,
-               bt_self_component_port_output *self_port)
-{
-       bt_self_message_iterator_status status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       struct bt_self_component_port_input *input_port = NULL;
-       bt_self_component_port_input_message_iterator *upstream_iterator = NULL;
-       struct debug_info_msg_iter *debug_info_msg_iter = NULL;
-       gchar *debug_info_field_name;
-       int ret;
-
-       /* Borrow the upstream input port. */
-       input_port = bt_self_component_filter_borrow_input_port_by_name(
-               self_comp, "in");
-       if (!input_port) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto error;
-       }
-
-       debug_info_msg_iter = g_new0(struct debug_info_msg_iter, 1);
-       if (!debug_info_msg_iter) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto error;
-       }
-
-       /* Create an iterator on the upstream component. */
-       upstream_iterator = bt_self_component_port_input_message_iterator_create(
-               input_port);
-       if (!upstream_iterator) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto error;
-       }
-
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF(
-               debug_info_msg_iter->msg_iter, upstream_iterator);
-
-       /* Create hashtable that will contain debug info mapping. */
-       debug_info_msg_iter->debug_info_map = g_hash_table_new_full(
-               g_direct_hash, g_direct_equal, (GDestroyNotify) NULL,
-               (GDestroyNotify) debug_info_destroy);
-       if (!debug_info_msg_iter->debug_info_map) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto error;
-       }
-
-       debug_info_msg_iter->self_comp =
-               bt_self_component_filter_as_self_component(self_comp);
-
-       debug_info_msg_iter->debug_info_component = bt_self_component_get_data(
-               bt_self_component_filter_as_self_component(
-                       self_comp));
-
-       debug_info_field_name =
-               debug_info_msg_iter->debug_info_component->arg_debug_info_field_name;
-
-       debug_info_msg_iter->ir_maps = trace_ir_maps_create(
-               bt_self_component_filter_as_self_component(self_comp),
-               debug_info_field_name);
-       if (!debug_info_msg_iter->ir_maps) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto error;
-       }
-
-       ret = bt_fd_cache_init(&debug_info_msg_iter->fd_cache);
-       if (ret) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto error;
-       }
-
-       bt_self_message_iterator_set_data(self_msg_iter, debug_info_msg_iter);
-       debug_info_msg_iter->input_iterator = self_msg_iter;
-
-       goto end;
-
-error:
-       debug_info_msg_iter_destroy(debug_info_msg_iter);
-end:
-       return status;
-}
-
-BT_HIDDEN
-bt_bool debug_info_msg_iter_can_seek_beginning(
-               bt_self_message_iterator *self_msg_iter)
-{
-       struct debug_info_msg_iter *debug_info_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_iter);
-       BT_ASSERT(debug_info_msg_iter);
-
-       return bt_self_component_port_input_message_iterator_can_seek_beginning(
-                       debug_info_msg_iter->msg_iter);
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status debug_info_msg_iter_seek_beginning(
-               bt_self_message_iterator *self_msg_iter)
-{
-       struct debug_info_msg_iter *debug_info_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_iter);
-       bt_message_iterator_status status = BT_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_ASSERT(debug_info_msg_iter);
-
-       /* Ask the upstream component to seek to the beginning. */
-       status = bt_self_component_port_input_message_iterator_seek_beginning(
-               debug_info_msg_iter->msg_iter);
-       if (status != BT_MESSAGE_ITERATOR_STATUS_OK) {
-               goto end;
-       }
-
-       /* Clear this iterator data. */
-       trace_ir_maps_clear(debug_info_msg_iter->ir_maps);
-       g_hash_table_remove_all(debug_info_msg_iter->debug_info_map);
-end:
-       return bt_common_message_iterator_status_to_self(status);
-}
-
-BT_HIDDEN
-void debug_info_msg_iter_finalize(bt_self_message_iterator *it)
-{
-       struct debug_info_msg_iter *debug_info_msg_iter;
-
-       debug_info_msg_iter = bt_self_message_iterator_get_data(it);
-       BT_ASSERT(debug_info_msg_iter);
-
-       debug_info_msg_iter_destroy(debug_info_msg_iter);
-}
diff --git a/plugins/lttng-utils/debug-info/debug-info.h b/plugins/lttng-utils/debug-info/debug-info.h
deleted file mode 100644 (file)
index f97d32d..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_H
-#define BABELTRACE_PLUGIN_DEBUG_INFO_H
-
-/*
- * Babeltrace - Debug information Plugin
- *
- * Copyright (c) 2015-2019 EfficiOS Inc.
- * Copyright (c) 2015 Antoine Busque <abusque@efficios.com>
- * Copyright (c) 2019 Francis Deslauriers francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-#define VPID_FIELD_NAME                "vpid"
-#define IP_FIELD_NAME          "ip"
-
-BT_HIDDEN
-bt_self_component_status debug_info_comp_init(
-               bt_self_component_filter *self_comp,
-               const bt_value *params, void *init_method_data);
-
-BT_HIDDEN
-void debug_info_comp_finalize(bt_self_component_filter *self_comp);
-
-BT_HIDDEN
-bt_self_message_iterator_status debug_info_msg_iter_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_filter *self_comp,
-               bt_self_component_port_output *self_port);
-
-BT_HIDDEN
-bt_self_message_iterator_status debug_info_msg_iter_next(
-               bt_self_message_iterator *self_msg_iter,
-               const bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count);
-
-BT_HIDDEN
-bt_bool debug_info_msg_iter_can_seek_beginning(
-               bt_self_message_iterator *message_iterator);
-
-BT_HIDDEN
-bt_self_message_iterator_status debug_info_msg_iter_seek_beginning(
-               bt_self_message_iterator *message_iterator);
-
-BT_HIDDEN
-void debug_info_msg_iter_finalize(bt_self_message_iterator *it);
-
-#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_H */
diff --git a/plugins/lttng-utils/debug-info/dwarf.c b/plugins/lttng-utils/debug-info/dwarf.c
deleted file mode 100644 (file)
index 534d288..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * dwarf.c
- *
- * Babeltrace - DWARF Information Reader
- *
- * Copyright 2015 Antoine Busque <abusque@efficios.com>
- *
- * Author: Antoine Busque <abusque@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include "dwarf.h"
-
-BT_HIDDEN
-struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info)
-{
-       struct bt_dwarf_cu *cu;
-
-       if (!dwarf_info) {
-               goto error;
-       }
-
-       cu = g_new0(struct bt_dwarf_cu, 1);
-       if (!cu) {
-               goto error;
-       }
-       cu->dwarf_info = dwarf_info;
-       return cu;
-
-error:
-       return NULL;
-}
-
-BT_HIDDEN
-void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu)
-{
-       g_free(cu);
-}
-
-BT_HIDDEN
-int bt_dwarf_cu_next(struct bt_dwarf_cu *cu)
-{
-       int ret;
-       Dwarf_Off next_offset;
-       size_t cu_header_size;
-
-       if (!cu) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = dwarf_nextcu(cu->dwarf_info, cu->next_offset, &next_offset,
-                       &cu_header_size, NULL, NULL, NULL);
-       if (ret) {
-               /* ret is -1 on error, 1 if no next CU. */
-               goto end;
-       }
-
-       cu->offset = cu->next_offset;
-       cu->next_offset = next_offset;
-       cu->header_size = cu_header_size;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-struct bt_dwarf_die *bt_dwarf_die_create(struct bt_dwarf_cu *cu)
-{
-       Dwarf_Die *dwarf_die = NULL;
-       struct bt_dwarf_die *die = NULL;
-
-       if (!cu) {
-               goto error;
-       }
-
-       dwarf_die = g_new0(Dwarf_Die, 1);
-       if (!dwarf_die) {
-               goto error;
-       }
-
-       dwarf_die = dwarf_offdie(cu->dwarf_info, cu->offset + cu->header_size,
-                       dwarf_die);
-       if (!dwarf_die) {
-               goto error;
-       }
-
-       die = g_new0(struct bt_dwarf_die, 1);
-       if (!die) {
-               goto error;
-       }
-
-       die->cu = cu;
-       die->dwarf_die = dwarf_die;
-       die->depth = 0;
-
-       return die;
-
-error:
-       g_free(dwarf_die);
-       g_free(die);
-       return NULL;
-}
-
-BT_HIDDEN
-void bt_dwarf_die_destroy(struct bt_dwarf_die *die)
-{
-       if (!die) {
-               return;
-       }
-
-       g_free(die->dwarf_die);
-       g_free(die);
-}
-
-BT_HIDDEN
-int bt_dwarf_die_has_children(struct bt_dwarf_die *die)
-{
-       return dwarf_haschildren(die->dwarf_die);
-}
-
-BT_HIDDEN
-int bt_dwarf_die_child(struct bt_dwarf_die *die)
-{
-       int ret;
-       Dwarf_Die *child_die = NULL;
-
-       if (!die) {
-               ret = -1;
-               goto error;
-       }
-
-       child_die = g_new0(Dwarf_Die, 1);
-       if (!child_die) {
-               ret = -1;
-               goto error;
-       }
-
-       ret = dwarf_child(die->dwarf_die, child_die);
-       if (ret) {
-               /* ret is -1 on error, 1 if no child DIE. */
-               goto error;
-       }
-
-       g_free(die->dwarf_die);
-       die->dwarf_die = child_die;
-       die->depth++;
-       return 0;
-
-error:
-       g_free(child_die);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_dwarf_die_next(struct bt_dwarf_die *die)
-{
-       int ret;
-       Dwarf_Die *next_die = NULL;
-
-       if (!die) {
-               ret = -1;
-               goto error;
-       }
-
-       next_die = g_new0(Dwarf_Die, 1);
-       if (!next_die) {
-               ret = -1;
-               goto error;
-       }
-
-       if (die->depth == 0) {
-               ret = dwarf_child(die->dwarf_die, next_die);
-               if (ret) {
-                       /* ret is -1 on error, 1 if no child DIE. */
-                       goto error;
-               }
-
-               die->depth = 1;
-       } else {
-               ret = dwarf_siblingof(die->dwarf_die, next_die);
-               if (ret) {
-                       /* ret is -1 on error, 1 if we reached end of
-                        * DIEs at this depth. */
-                       goto error;
-               }
-       }
-
-       g_free(die->dwarf_die);
-       die->dwarf_die = next_die;
-       return 0;
-
-error:
-       g_free(next_die);
-       return ret;
-}
-
-BT_HIDDEN
-int bt_dwarf_die_get_tag(struct bt_dwarf_die *die, int *tag)
-{
-       int _tag;
-
-       if (!die || !tag) {
-               goto error;
-       }
-
-       _tag = dwarf_tag(die->dwarf_die);
-       if (_tag == DW_TAG_invalid) {
-               goto error;
-       }
-
-       *tag = _tag;
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-int bt_dwarf_die_get_name(struct bt_dwarf_die *die, char **name)
-{
-       const char *_name;
-
-       if (!die || !name) {
-               goto error;
-       }
-
-       _name = dwarf_diename(die->dwarf_die);
-       if (!_name) {
-               goto error;
-       }
-
-       *name = g_strdup(_name);
-       if (!*name) {
-               goto error;
-       }
-
-       return 0;
-
-error:
-       return -1;
-}
-
-BT_HIDDEN
-int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename)
-{
-       int ret;
-       Dwarf_Sword file_no;
-       const char *_filename = NULL;
-       Dwarf_Files *src_files = NULL;
-       Dwarf_Attribute *file_attr = NULL;
-       struct bt_dwarf_die *cu_die = NULL;
-
-       if (!die || !filename) {
-               goto error;
-       }
-
-       file_attr = g_new0(Dwarf_Attribute, 1);
-       if (!file_attr) {
-               goto error;
-       }
-
-       file_attr = dwarf_attr(die->dwarf_die, DW_AT_call_file, file_attr);
-       if (!file_attr) {
-               goto error;
-       }
-
-       ret = dwarf_formsdata(file_attr, &file_no);
-       if (ret) {
-               goto error;
-       }
-
-       cu_die = bt_dwarf_die_create(die->cu);
-       if (!cu_die) {
-               goto error;
-       }
-
-       ret = dwarf_getsrcfiles(cu_die->dwarf_die, &src_files, NULL);
-       if (ret) {
-               goto error;
-       }
-
-       _filename = dwarf_filesrc(src_files, file_no, NULL, NULL);
-       if (!_filename) {
-               goto error;
-       }
-
-       *filename = g_strdup(_filename);
-
-       bt_dwarf_die_destroy(cu_die);
-       g_free(file_attr);
-
-       return 0;
-
-error:
-       bt_dwarf_die_destroy(cu_die);
-       g_free(file_attr);
-
-       return -1;
-}
-
-BT_HIDDEN
-int bt_dwarf_die_get_call_line(struct bt_dwarf_die *die,
-               uint64_t *line_no)
-{
-       int ret = 0;
-       Dwarf_Attribute *line_attr = NULL;
-       uint64_t _line_no;
-
-       if (!die || !line_no) {
-               goto error;
-       }
-
-       line_attr = g_new0(Dwarf_Attribute, 1);
-       if (!line_attr) {
-               goto error;
-       }
-
-       line_attr = dwarf_attr(die->dwarf_die, DW_AT_call_line, line_attr);
-       if (!line_attr) {
-               goto error;
-       }
-
-       ret = dwarf_formudata(line_attr, &_line_no);
-       if (ret) {
-               goto error;
-       }
-
-       *line_no = _line_no;
-       g_free(line_attr);
-
-       return 0;
-
-error:
-       g_free(line_attr);
-
-       return -1;
-}
-
-BT_HIDDEN
-int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr,
-               bool *contains)
-{
-       int ret;
-
-       ret = dwarf_haspc(die->dwarf_die, addr);
-       if (ret == -1) {
-               goto error;
-       }
-
-       *contains = (ret == 1);
-
-       return 0;
-
-error:
-       return -1;
-}
diff --git a/plugins/lttng-utils/debug-info/dwarf.h b/plugins/lttng-utils/debug-info/dwarf.h
deleted file mode 100644 (file)
index 72bb8d2..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-#ifndef _BABELTRACE_DWARF_H
-#define _BABELTRACE_DWARF_H
-
-/*
- * Babeltrace - DWARF Information Reader
- *
- * Copyright 2015 Antoine Busque <abusque@efficios.com>
- *
- * Author: Antoine Busque <abusque@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <dwarf.h>
-#include <elfutils/libdw.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-/*
- * bt_dwarf is a wrapper over libdw providing a nicer, higher-level
- * interface, to access basic debug information.
- */
-
-/*
- * This structure corresponds to a single compilation unit (CU) for a
- * given set of debug information (Dwarf type).
- */
-struct bt_dwarf_cu {
-       Dwarf *dwarf_info;
-       /* Offset in bytes in the DWARF file to current CU header. */
-       Dwarf_Off offset;
-       /* Offset in bytes in the DWARF file to next CU header. */
-       Dwarf_Off next_offset;
-       /* Size in bytes of CU header */
-       size_t header_size;
-};
-
-/*
- * This structure represents a single debug information entry (DIE),
- * within a compilation unit (CU).
- */
-struct bt_dwarf_die {
-       struct bt_dwarf_cu *cu;
-       Dwarf_Die *dwarf_die;
-       /*
-        * A depth of 0 represents a root DIE, located in the DWARF
-        * layout on the same level as its corresponding CU entry. Its
-        * children DIEs will have a depth of 1, and so forth.
-        */
-       unsigned int depth;
-};
-
-/**
- * Instantiate a structure to access compile units (CU) from a given
- * `dwarf_info`.
- *
- * @param dwarf_info   Dwarf instance
- * @returns            Pointer to the new bt_dwarf_cu on success,
- *                     NULL on failure.
- */
-BT_HIDDEN
-struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info);
-
-/**
- * Destroy the given bt_dwarf_cu instance.
- *
- * @param cu   bt_dwarf_cu instance
- */
-BT_HIDDEN
-void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu);
-
-/**
- * Advance the compile unit `cu` to the next one.
- *
- * On success, `cu`'s offset is set to that of the current compile
- * unit in the executable. On failure, `cu` remains unchanged.
- *
- * @param cu   bt_dwarf_cu instance
- * @returns    0 on success, 1 if no next CU is available,
- *             -1 on failure
- */
-BT_HIDDEN
-int bt_dwarf_cu_next(struct bt_dwarf_cu *cu);
-
-/**
- * Instantiate a structure to access debug information entries (DIE)
- * for the given compile unit `cu`.
- *
- * @param cu   bt_dwarf_cu instance
- * @returns    Pointer to the new bt_dwarf_die on success,
- *             NULL on failure.
- */
-BT_HIDDEN
-struct bt_dwarf_die *bt_dwarf_die_create(struct bt_dwarf_cu *cu);
-
-/**
- * Destroy the given bt_dwarf_die instance.
- *
- * @param die  bt_dwarf_die instance
- */
-BT_HIDDEN
-void bt_dwarf_die_destroy(struct bt_dwarf_die *die);
-
-/**
- * Indicates if the debug information entry `die` has children DIEs.
- *
- * @param die  bt_dwarf_die instance
- * @returns    0 if the die no child, 1 otherwise
- */
-BT_HIDDEN
-int bt_dwarf_die_has_children(struct bt_dwarf_die *die);
-
-/**
- * Advance the debug information entry `die` to its first child, if
- * any.
- *
- * @param die  bt_dwarf_die instance
- * @returns    0 on success, 1 if no child DIE is available,
- *             -1 on failure
- */
-BT_HIDDEN
-int bt_dwarf_die_child(struct bt_dwarf_die *die);
-
-/**
- * Advance the debug information entry `die` to the next one.
- *
- * The next DIE is considered to be its sibling on the same level. The
- * only exception is when the depth of the given DIE is 0, i.e. a
- * newly created bt_dwarf_die, in which case next returns the first
- * DIE at depth 1.
- *
- * The reason for staying at a depth of 1 is that this is where all
- * the function DIEs (those with a tag value of DW_TAG_subprogram) are
- * located, from which more specific child DIEs can then be accessed
- * if needed via bt_dwarf_die_child.
- *
- * @param die  bt_dwarf_die instance
- * @returns    0 on success, 1 if no other siblings are available, -1 on
- *             failure
- */
-BT_HIDDEN
-int bt_dwarf_die_next(struct bt_dwarf_die *die);
-
-/**
- * Get a DIE's tag.
- *
- * On success, the `tag` out parameter is set to the `die`'s tag's
- * value. It remains unchanged on failure.
- *
- * @param die  bt_dwarf_die instance
- * @param tag  Out parameter, the DIE's tag value
- * @returns    0 on success, -1 on failure.
- */
-BT_HIDDEN
-int bt_dwarf_die_get_tag(struct bt_dwarf_die *die, int *tag);
-
-/**
- * Get a DIE's name.
- *
- * On success, the `name` out parameter is set to the DIE's name. It
- * remains unchanged on failure.
- *
- * @param die  bt_dwarf_die instance
- * @param name Out parameter, the DIE's name
- * @returns    0 on success, -1 on failure
- */
-BT_HIDDEN
-int bt_dwarf_die_get_name(struct bt_dwarf_die *die, char **name);
-
-/**
- * Get the full path to the DIE's callsite file.
- *
- * Only applies to DW_TAG_inlined_subroutine entries. The out
- * parameter `filename` is set on success, unchanged on failure.
- *
- * @param die          bt_dwarf_die instance
- * @param filename     Out parameter, the filename for the subroutine's
- *                     callsite
- * @returns            0 on success, -1 on failure
- */
-BT_HIDDEN
-int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename);
-
-/**
- * Get line number for the DIE's callsite.
- *
- * Only applies to DW_TAG_inlined_subroutine entries. The out
- * parameter `line_no` is set on success, unchanged on failure.
- *
- * @param die          bt_dwarf_die instance
- * @param line_no      Out parameter, the line number for the
- *                     subroutine's callsite
- * @returns            0 on success, -1 on failure
- */
-BT_HIDDEN
-int bt_dwarf_die_get_call_line(struct bt_dwarf_die *die,
-               uint64_t *line_no);
-
-/**
- * Verifies whether a given DIE contains the virtual memory address
- * `addr`.
- *
- * On success, the out parameter `contains` is set with the boolean
- * value indicating whether the DIE's range covers `addr`. On failure,
- * it remains unchanged.
- *
- * @param die          bt_dwarf_die instance
- * @param addr         The memory address to verify
- * @param contains     Out parameter, true if addr is contained,
- *                     false if not
- * @returns            0 on succes, -1 on failure
- */
-BT_HIDDEN
-int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr,
-               bool *contains);
-
-#endif /* _BABELTRACE_DWARF_H */
diff --git a/plugins/lttng-utils/debug-info/logging.c b/plugins/lttng-utils/debug-info/logging.c
deleted file mode 100644 (file)
index d7befe9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_lttng_utils_debug_info_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_plugin_lttng_utils_debug_info_log_level,
-       "BABELTRACE_FLT_LTTNG_UTILS_DEBUG_INFO_LOG_LEVEL");
diff --git a/plugins/lttng-utils/debug-info/logging.h b/plugins/lttng-utils/debug-info/logging.h
deleted file mode 100644 (file)
index 154ca0f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H
-#define PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_lttng_utils_debug_info_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_lttng_utils_debug_info_log_level);
-
-#endif /* PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H */
diff --git a/plugins/lttng-utils/debug-info/trace-ir-data-copy.c b/plugins/lttng-utils/debug-info/trace-ir-data-copy.c
deleted file mode 100644 (file)
index 8eb2edd..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Babeltrace - Trace IR data object copy
- *
- * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-DATA-COPY"
-#include "logging.h"
-
-#include <inttypes.h>
-#include <stdint.h>
-
-#include <babeltrace2/assert-internal.h>
-
-#include "trace-ir-data-copy.h"
-
-BT_HIDDEN
-void copy_trace_content(const bt_trace *in_trace, bt_trace *out_trace)
-{
-       bt_trace_status status;
-       const char *trace_name;
-
-       BT_LOGD("Copying content of trace: in-t-addr=%p, out-t-addr=%p",
-                       in_trace, out_trace);
-
-       trace_name = bt_trace_get_name(in_trace);
-       /* Copy the trace name. */
-       if (trace_name) {
-               status = bt_trace_set_name(out_trace, trace_name);
-               if (status != BT_TRACE_STATUS_OK) {
-                       BT_LOGE("Cannot set trace's name: trace-addr=%p, name=\"%s\"",
-                                       out_trace, trace_name);
-                       goto end;
-               }
-       }
-
-       BT_LOGD("Copied content of trace: in-t-addr=%p, out-t-addr=%p",
-                       in_trace, out_trace);
-end:
-       return;
-}
-
-BT_HIDDEN
-void copy_stream_content(const bt_stream *in_stream, bt_stream *out_stream)
-{
-       const char *stream_name;
-       bt_stream_status status;
-
-       BT_LOGD("Copying content of stream: in-s-addr=%p, out-s-addr=%p",
-                       in_stream, out_stream);
-
-       stream_name = bt_stream_get_name(in_stream);
-       if (stream_name) {
-               status = bt_stream_set_name(out_stream, stream_name);
-               if (status != BT_STREAM_STATUS_OK) {
-                       BT_LOGE("Cannot set stream's name: stream-addr=%p, "
-                               "name=%s", out_stream, stream_name);
-                       goto end;
-               }
-       }
-
-       BT_LOGD("Copied content of stream: in-s-addr=%p, out-s-addr=%p",
-                       in_stream, out_stream);
-end:
-       return;
-}
-
-BT_HIDDEN
-void copy_packet_content(const bt_packet *in_packet, bt_packet *out_packet)
-{
-       const bt_field *in_context_field;
-       bt_field *out_context_field;
-
-       BT_LOGD("Copying content of packet: in-p-addr=%p, out-p-addr=%p",
-                       in_packet, out_packet);
-
-       /* Copy context field. */
-       in_context_field = bt_packet_borrow_context_field_const(in_packet);
-       if (in_context_field) {
-               out_context_field = bt_packet_borrow_context_field(out_packet);
-               BT_ASSERT(out_context_field);
-               copy_field_content(in_context_field, out_context_field);
-       }
-
-       BT_LOGD("Copied content of packet: in-p-addr=%p, out-p-addr=%p",
-                       in_packet, out_packet);
-       return;
-}
-
-BT_HIDDEN
-void copy_event_content(const bt_event *in_event, bt_event *out_event)
-{
-       const bt_field *in_common_ctx_field, *in_specific_ctx_field,
-             *in_payload_field;
-       bt_field *out_common_ctx_field, *out_specific_ctx_field,
-                *out_payload_field;
-
-       BT_LOGD("Copying content of event: in-e-addr=%p, out-e-addr=%p",
-                       in_event, out_event);
-       in_common_ctx_field =
-               bt_event_borrow_common_context_field_const(in_event);
-       if (in_common_ctx_field) {
-               out_common_ctx_field =
-                       bt_event_borrow_common_context_field(out_event);
-               BT_ASSERT(out_common_ctx_field);
-               copy_field_content(in_common_ctx_field,
-                               out_common_ctx_field);
-       }
-
-       in_specific_ctx_field =
-               bt_event_borrow_specific_context_field_const(in_event);
-       if (in_specific_ctx_field) {
-               out_specific_ctx_field =
-                       bt_event_borrow_specific_context_field(out_event);
-               BT_ASSERT(out_specific_ctx_field);
-               copy_field_content(in_specific_ctx_field,
-                               out_specific_ctx_field);
-       }
-
-       in_payload_field = bt_event_borrow_payload_field_const(in_event);
-       if (in_payload_field) {
-               out_payload_field = bt_event_borrow_payload_field(out_event);
-               BT_ASSERT(out_payload_field);
-               copy_field_content(in_payload_field,
-                               out_payload_field);
-       }
-
-       BT_LOGD("Copied content of event: in-e-addr=%p, out-e-addr=%p",
-                       in_event, out_event);
-}
-
-BT_HIDDEN
-void copy_field_content(const bt_field *in_field, bt_field *out_field)
-{
-       bt_field_class_type in_fc_type, out_fc_type;
-
-       in_fc_type = bt_field_get_class_type(in_field);
-       out_fc_type = bt_field_get_class_type(out_field);
-       BT_ASSERT(in_fc_type == out_fc_type);
-
-       BT_LOGD("Copying content of field: in-f-addr=%p, out-f-addr=%p",
-                       in_field, out_field);
-       switch (in_fc_type) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-               bt_field_unsigned_integer_set_value(out_field,
-                               bt_field_unsigned_integer_get_value(in_field));
-               break;
-       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-               bt_field_signed_integer_set_value(out_field,
-                               bt_field_signed_integer_get_value(in_field));
-               break;
-       case BT_FIELD_CLASS_TYPE_REAL:
-               bt_field_real_set_value(out_field,
-                               bt_field_real_get_value(in_field));
-               break;
-       case BT_FIELD_CLASS_TYPE_STRING:
-       {
-               const char *str = bt_field_string_get_value(in_field);
-               bt_field_status status = bt_field_string_set_value(out_field, str);
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot set string field's value: "
-                               "str-field-addr=%p, str=%s" PRId64,
-                               out_field, str);
-               }
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-       {
-               uint64_t i, nb_member_struct;
-               const bt_field *in_member_field;
-               bt_field *out_member_field;
-               const bt_field_class *in_field_class;
-               const char *in_member_name;
-
-               in_field_class = bt_field_borrow_class_const(in_field);
-               nb_member_struct = bt_field_class_structure_get_member_count(
-                               in_field_class);
-
-               /*
-                * Iterate over the fields by names in the input field to avoid
-                * problem if the struct fields are not in the same order after
-                * the debug-info was added.
-                */
-               for (i = 0; i < nb_member_struct; i++) {
-                       const bt_field_class_structure_member *member =
-                               bt_field_class_structure_borrow_member_by_index_const(
-                                       in_field_class, i);
-
-                       in_member_name =
-                               bt_field_class_structure_member_get_name(
-                                       member);
-                       in_member_field =
-                               bt_field_structure_borrow_member_field_by_name_const(
-                                               in_field, in_member_name);
-                       out_member_field =
-                               bt_field_structure_borrow_member_field_by_name(
-                                               out_field, in_member_name);
-
-                       copy_field_content(in_member_field,
-                                       out_member_field);
-               }
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-               /* fall through */
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       {
-               const bt_field *in_element_field;
-               bt_field *out_element_field;
-               uint64_t i, array_len;
-               bt_field_status status;
-
-               array_len = bt_field_array_get_length(in_field);
-
-               if (in_fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY) {
-                       status = bt_field_dynamic_array_set_length(out_field,
-                                       array_len);
-                       if (status != BT_FIELD_STATUS_OK) {
-                               BT_LOGE("Cannot set dynamic array field's "
-                                       "length field: field-addr=%p, "
-                                       "length=%" PRIu64, out_field, array_len);
-                       }
-               }
-
-               for (i = 0; i < array_len; i++) {
-                       in_element_field =
-                               bt_field_array_borrow_element_field_by_index_const(
-                                               in_field, i);
-                       out_element_field =
-                               bt_field_array_borrow_element_field_by_index(
-                                               out_field, i);
-                       copy_field_content(in_element_field, out_element_field);
-               }
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-       {
-               bt_field_status status;
-               uint64_t in_selected_option_idx;
-               const bt_field *in_option_field;
-               bt_field *out_option_field;
-
-               in_selected_option_idx =
-                       bt_field_variant_get_selected_option_field_index(
-                                       in_field);
-               status = bt_field_variant_select_option_field(out_field,
-                               in_selected_option_idx);
-               if (status != BT_FIELD_STATUS_OK) {
-                       BT_LOGE("Cannot select variant field's option field: "
-                               "var-field-addr=%p, opt-index=%" PRId64,
-                               out_field, in_selected_option_idx);
-               }
-
-               in_option_field = bt_field_variant_borrow_selected_option_field_const(in_field);
-               out_option_field = bt_field_variant_borrow_selected_option_field(out_field);
-
-               copy_field_content(in_option_field, out_option_field);
-
-               break;
-       }
-       default:
-               abort();
-       }
-       BT_LOGD("Copied content of field: in-f-addr=%p, out-f-addr=%p",
-                       in_field, out_field);
-}
diff --git a/plugins/lttng-utils/debug-info/trace-ir-data-copy.h b/plugins/lttng-utils/debug-info/trace-ir-data-copy.h
deleted file mode 100644 (file)
index b925976..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H
-#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H
-
-/*
- * Babeltrace - Trace IR data object copy
- *
- * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-
-#include "trace-ir-mapping.h"
-
-BT_HIDDEN
-void copy_trace_content(const bt_trace *in_trace, bt_trace *out_trace);
-BT_HIDDEN
-void copy_stream_content(const bt_stream *in_stream, bt_stream *out_stream);
-BT_HIDDEN
-void copy_packet_content(const bt_packet *in_packet, bt_packet *out_packet);
-BT_HIDDEN
-void copy_event_content(const bt_event *in_event, bt_event *out_event);
-BT_HIDDEN
-void copy_field_content(const bt_field *in_field, bt_field *out_field);
-
-#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H */
diff --git a/plugins/lttng-utils/debug-info/trace-ir-mapping.c b/plugins/lttng-utils/debug-info/trace-ir-mapping.c
deleted file mode 100644 (file)
index 61bfb01..0000000
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * Babeltrace - Mapping of IR metadata and data object between input and output
- *             trace
- *
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-MAPPING"
-#include "logging.h"
-
-#include <stdbool.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace.h>
-/* For bt_property_availability */
-#include <babeltrace2/property.h>
-
-#include "debug-info.h"
-#include "trace-ir-data-copy.h"
-#include "trace-ir-mapping.h"
-#include "trace-ir-metadata-copy.h"
-
-static
-bt_trace_class *create_new_mapped_trace_class(struct trace_ir_maps *ir_maps,
-               const bt_trace_class *in_trace_class)
-{
-       int ret;
-       bt_trace_class *out_trace_class;
-
-       BT_LOGD("Creating new mapped trace class: in-tc-addr=%p", in_trace_class);
-
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_trace_class);
-
-       /* Create the ouput trace class. */
-       out_trace_class = bt_trace_class_create(ir_maps->self_comp);
-       if (!out_trace_class) {
-               BT_LOGE_STR("Error create output trace class");
-               goto end;
-       }
-
-       /* If not, create a new one and add it to the mapping. */
-       ret = copy_trace_class_content(in_trace_class, out_trace_class);
-       if (ret) {
-               BT_LOGE_STR("Error copy content to output trace class");
-               out_trace_class = NULL;
-               goto end;
-       }
-
-       BT_LOGD("Created new mapped trace class: in-tc-addr=%p, out-tc-addr=%p",
-                       in_trace_class, out_trace_class);
-
-end:
-       return out_trace_class;
-}
-
-static
-bt_trace *create_new_mapped_trace(struct trace_ir_maps *ir_maps,
-               const bt_trace *in_trace)
-{
-       bt_trace *out_trace;
-       const bt_trace_class *in_trace_class;
-       struct trace_ir_metadata_maps *metadata_maps;
-
-       BT_LOGD("Creating new mapped trace: in-t-addr=%p", in_trace);
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_trace);
-
-       in_trace_class = bt_trace_borrow_class_const(in_trace);
-       metadata_maps = borrow_metadata_maps_from_input_trace_class(ir_maps,
-                       in_trace_class);
-
-       if (!metadata_maps->output_trace_class) {
-               metadata_maps->output_trace_class =
-                       create_new_mapped_trace_class(ir_maps, in_trace_class);
-               if (!metadata_maps->output_trace_class) {
-                       out_trace = NULL;
-                       goto end;
-               }
-       }
-
-       out_trace = bt_trace_create(metadata_maps->output_trace_class);
-       if (!out_trace) {
-               BT_LOGE_STR("Error create output trace");
-               goto end;
-       }
-
-       /* If not, create a new one and add it to the mapping. */
-       copy_trace_content(in_trace, out_trace);
-
-       BT_LOGD("Created new mapped trace: in-t-addr=%p, out-t-addr=%p",
-                       in_trace, out_trace);
-end:
-       return out_trace;
-}
-
-static
-bt_stream_class *borrow_mapped_stream_class(struct trace_ir_metadata_maps *md_maps,
-               const bt_stream_class *in_stream_class)
-{
-       BT_ASSERT(md_maps);
-       BT_ASSERT(in_stream_class);
-
-       return g_hash_table_lookup(md_maps->stream_class_map,
-                       (gpointer) in_stream_class);
-}
-
-static
-bt_stream_class *create_new_mapped_stream_class(struct trace_ir_maps *ir_maps,
-               const bt_stream_class *in_stream_class)
-{
-       int ret;
-       bt_stream_class *out_stream_class;
-       struct trace_ir_metadata_maps *md_maps;
-
-       BT_LOGD("Creating new mapped stream class: in-sc-addr=%p",
-                       in_stream_class);
-
-       md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps,
-                       in_stream_class);
-
-       BT_ASSERT(md_maps);
-       BT_ASSERT(in_stream_class);
-       BT_ASSERT(!borrow_mapped_stream_class(md_maps, in_stream_class));
-
-       /* Create an out_stream_class. */
-       out_stream_class = bt_stream_class_create_with_id(
-                       md_maps->output_trace_class,
-                       bt_stream_class_get_id(in_stream_class));
-       if (!out_stream_class) {
-               BT_LOGE_STR("Error create output stream class");
-               goto end;
-       }
-
-       /* If not, create a new one and add it to the mapping. */
-       ret = copy_stream_class_content(ir_maps, in_stream_class,
-                       out_stream_class);
-       if (ret) {
-               BT_LOGE_STR("Error copy content to output stream class");
-               out_stream_class = NULL;
-               goto end;
-       }
-
-       g_hash_table_insert(md_maps->stream_class_map,
-                       (gpointer) in_stream_class, out_stream_class);
-
-       BT_LOGD("Created new mapped stream class: in-sc-addr=%p, out-sc-addr=%p",
-                       in_stream_class, out_stream_class);
-
-end:
-       return out_stream_class;
-}
-
-static
-bt_stream *borrow_mapped_stream(struct trace_ir_data_maps *d_maps,
-               const bt_stream *in_stream)
-{
-       BT_ASSERT(d_maps);
-       BT_ASSERT(in_stream);
-
-       return g_hash_table_lookup(d_maps->stream_map, (gpointer) in_stream);
-}
-
-BT_HIDDEN
-bt_stream *trace_ir_mapping_create_new_mapped_stream(
-               struct trace_ir_maps *ir_maps,
-               const bt_stream *in_stream)
-{
-       struct trace_ir_data_maps *d_maps;
-       struct trace_ir_metadata_maps *md_maps;
-       const bt_stream_class *in_stream_class;
-       const bt_trace *in_trace;
-       bt_stream_class *out_stream_class;
-       bt_stream *out_stream = NULL;
-
-       BT_LOGD("Creating new mapped stream: in-s-addr=%p", in_stream);
-
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_stream);
-
-       in_trace = bt_stream_borrow_trace_const(in_stream);
-
-       d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace);
-       if (!d_maps->output_trace) {
-               d_maps->output_trace = create_new_mapped_trace(ir_maps, in_trace);
-               if (!d_maps->output_trace) {
-                       goto end;
-               }
-       }
-
-       BT_ASSERT(d_maps->output_trace);
-       BT_ASSERT(!borrow_mapped_stream(d_maps, in_stream));
-
-       in_stream_class = bt_stream_borrow_class_const(in_stream);
-       md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class);
-       out_stream_class = borrow_mapped_stream_class(md_maps, in_stream_class);
-       if (!out_stream_class) {
-               out_stream_class = create_new_mapped_stream_class(ir_maps,
-                               in_stream_class);
-               if (!out_stream_class) {
-                       goto end;
-               }
-       }
-       BT_ASSERT(out_stream_class);
-
-       out_stream = bt_stream_create_with_id(out_stream_class,
-                       d_maps->output_trace, bt_stream_get_id(in_stream));
-       if (!out_stream) {
-               BT_LOGE_STR("Error creating output stream");
-               goto end;
-       }
-       /*
-        * Release our ref since the trace object will be managing the life
-        * time of the stream objects.
-        */
-
-       copy_stream_content(in_stream, out_stream);
-
-       g_hash_table_insert(d_maps->stream_map, (gpointer) in_stream,
-                       out_stream);
-
-       BT_LOGD("Created new mapped stream: in-s-addr=%p, out-s-addr=%p",
-                       in_stream, out_stream);
-
-end:
-       return out_stream;
-}
-
-BT_HIDDEN
-bt_stream *trace_ir_mapping_borrow_mapped_stream(struct trace_ir_maps *ir_maps,
-               const bt_stream *in_stream)
-{
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_stream);
-       struct trace_ir_data_maps *d_maps;
-
-       d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream);
-       /* Return the mapped stream. */
-       return borrow_mapped_stream(d_maps, in_stream);
-}
-
-static inline
-bt_event_class *borrow_mapped_event_class(struct trace_ir_metadata_maps *md_maps,
-               const bt_event_class *in_event_class)
-{
-       return g_hash_table_lookup(md_maps->event_class_map,
-                       (gpointer) in_event_class);
-}
-
-BT_HIDDEN
-bt_event_class *trace_ir_mapping_create_new_mapped_event_class(
-               struct trace_ir_maps *ir_maps,
-               const bt_event_class *in_event_class)
-{
-       bt_event_class *out_event_class;
-       const bt_trace_class *in_trace_class;
-       const bt_stream_class *in_stream_class;
-       bt_stream_class *out_stream_class;
-       struct trace_ir_metadata_maps *md_maps;
-       int ret;
-
-       BT_LOGD("Creating new mapped event class: in-ec-addr=%p",
-                       in_event_class);
-
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_event_class);
-
-       in_trace_class = bt_stream_class_borrow_trace_class_const(
-                               bt_event_class_borrow_stream_class_const(
-                                       in_event_class));
-
-       md_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, in_trace_class);
-
-       BT_ASSERT(!borrow_mapped_event_class(md_maps, in_event_class));
-
-       in_stream_class =
-               bt_event_class_borrow_stream_class_const(in_event_class);
-       BT_ASSERT(in_stream_class);
-
-       /* Get the right output stream class to add the new event class to. */
-       out_stream_class = borrow_mapped_stream_class(md_maps, in_stream_class);
-       BT_ASSERT(out_stream_class);
-
-       /* Create an output event class. */
-       out_event_class = bt_event_class_create_with_id(out_stream_class,
-                       bt_event_class_get_id(in_event_class));
-       if (!out_event_class) {
-               BT_LOGE_STR("Error creating output event class");
-               goto end;
-       }
-
-       /* If not, create a new one and add it to the mapping. */
-       ret = copy_event_class_content(ir_maps, in_event_class,
-                       out_event_class);
-       if (ret) {
-               BT_LOGE_STR("Error copy content to output event class");
-               out_event_class = NULL;
-               goto end;
-       }
-
-       g_hash_table_insert(md_maps->event_class_map,
-                       (gpointer) in_event_class, out_event_class);
-
-       BT_LOGD("Created new mapped event class: in-ec-addr=%p, out-ec-addr=%p",
-                       in_event_class, out_event_class);
-
-end:
-       return out_event_class;
-}
-
-BT_HIDDEN
-bt_event_class *trace_ir_mapping_borrow_mapped_event_class(
-               struct trace_ir_maps *ir_maps,
-               const bt_event_class *in_event_class)
-{
-       struct trace_ir_metadata_maps *md_maps;
-
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_event_class);
-
-       md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, in_event_class);
-
-       /* Return the mapped event_class. */
-       return borrow_mapped_event_class(md_maps, in_event_class);
-}
-
-static inline
-bt_packet *borrow_mapped_packet(struct trace_ir_data_maps *d_maps,
-               const bt_packet *in_packet)
-{
-       BT_ASSERT(d_maps);
-       BT_ASSERT(in_packet);
-
-       return g_hash_table_lookup(d_maps->packet_map,
-                       (gpointer) in_packet);
-}
-
-BT_HIDDEN
-bt_packet *trace_ir_mapping_create_new_mapped_packet(
-               struct trace_ir_maps *ir_maps,
-               const bt_packet *in_packet)
-{
-       struct trace_ir_data_maps *d_maps;
-       const bt_trace *in_trace;
-       const bt_stream *in_stream;
-       bt_packet *out_packet;
-       bt_stream *out_stream;
-
-       BT_LOGD("Creating new mapped packet: in-p-addr=%p", in_packet);
-
-       in_stream = bt_packet_borrow_stream_const(in_packet);
-       in_trace = bt_stream_borrow_trace_const(in_stream);
-       d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace);
-
-       /* There should never be a mapped packet. */
-       BT_ASSERT(!borrow_mapped_packet(d_maps, in_packet));
-
-       BT_ASSERT(in_stream);
-
-       /* Get output stream corresponding to this input stream. */
-       out_stream = borrow_mapped_stream(d_maps, in_stream);
-       BT_ASSERT(out_stream);
-
-       /* Create the output packet. */
-       out_packet = bt_packet_create(out_stream);
-       if (!out_packet) {
-               BT_LOGE_STR("Error create output packet");
-               goto end;
-       }
-
-       /*
-        * Release our ref since the stream object will be managing the life
-        * time of the packet objects.
-        */
-       copy_packet_content(in_packet, out_packet);
-
-       g_hash_table_insert(d_maps->packet_map,
-                       (gpointer) in_packet, out_packet);
-
-       BT_LOGD("Created new mapped packet: in-p-addr=%p, out-p-addr=%p",
-                       in_packet, out_packet);
-
-end:
-       return out_packet;
-}
-
-BT_HIDDEN
-bt_packet *trace_ir_mapping_borrow_mapped_packet(struct trace_ir_maps *ir_maps,
-               const bt_packet *in_packet)
-{
-       struct trace_ir_data_maps *d_maps;
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_packet);
-
-       d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet);
-
-       return borrow_mapped_packet(d_maps, in_packet);
-}
-
-BT_HIDDEN
-void trace_ir_mapping_remove_mapped_packet(struct trace_ir_maps *ir_maps,
-               const bt_packet *in_packet)
-{
-       gboolean ret;
-
-       struct trace_ir_data_maps *d_maps;
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_packet);
-
-       d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet);
-
-       ret = g_hash_table_remove(d_maps->packet_map, in_packet);
-
-       BT_ASSERT(ret);
-}
-
-BT_HIDDEN
-void trace_ir_mapping_remove_mapped_stream(struct trace_ir_maps *ir_maps,
-               const bt_stream *in_stream)
-{
-       gboolean ret;
-       struct trace_ir_data_maps *d_maps;
-
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_stream);
-
-       d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream);
-
-       ret = g_hash_table_remove(d_maps->stream_map, in_stream);
-
-       BT_ASSERT(ret);
-}
-
-static
-void trace_ir_metadata_maps_remove_func(const bt_trace_class *in_trace_class,
-               void *data)
-{
-       struct trace_ir_maps *maps = (struct trace_ir_maps *) data;
-       if (maps->metadata_maps) {
-               gboolean ret;
-               ret = g_hash_table_remove(maps->metadata_maps,
-                               (gpointer) in_trace_class);
-               BT_ASSERT(ret);
-       }
-}
-
-static
-void trace_ir_data_maps_remove_func(const bt_trace *in_trace, void *data)
-{
-       struct trace_ir_maps *maps = (struct trace_ir_maps *) data;
-       if (maps->data_maps) {
-               gboolean ret;
-               ret = g_hash_table_remove(maps->data_maps, (gpointer) in_trace);
-               BT_ASSERT(ret);
-       }
-}
-
-struct trace_ir_data_maps *trace_ir_data_maps_create(struct trace_ir_maps *ir_maps,
-               const bt_trace *in_trace)
-{
-       struct trace_ir_data_maps *d_maps =
-               g_new0(struct trace_ir_data_maps, 1);
-       if (!d_maps) {
-               BT_LOGE_STR("Error allocating trace_ir_maps");
-               goto error;
-       }
-
-       d_maps->input_trace = in_trace;
-
-       /* Create the hashtables used to map data objects. */
-       d_maps->stream_map = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, NULL,(GDestroyNotify) bt_stream_put_ref);
-       d_maps->packet_map = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, NULL,(GDestroyNotify) bt_packet_put_ref);
-
-       bt_trace_add_destruction_listener(in_trace, trace_ir_data_maps_remove_func,
-                       ir_maps, &d_maps->destruction_listener_id);
-error:
-       return d_maps;
-}
-
-struct trace_ir_metadata_maps *trace_ir_metadata_maps_create(
-               struct trace_ir_maps *ir_maps,
-               const bt_trace_class *in_trace_class)
-{
-       struct trace_ir_metadata_maps *md_maps =
-               g_new0(struct trace_ir_metadata_maps, 1);
-       if (!md_maps) {
-               BT_LOGE_STR("Error allocating trace_ir_maps");
-               goto error;
-       }
-
-       md_maps->input_trace_class = in_trace_class;
-       /*
-        * Create the field class resolving context. This is needed to keep
-        * track of the field class already copied in order to do the field
-        * path resolution correctly.
-        */
-       md_maps->fc_resolving_ctx =
-               g_new0(struct field_class_resolving_context, 1);
-       if (!md_maps->fc_resolving_ctx) {
-               BT_LOGE_STR("Error allocating field_class_resolving_context");
-               goto error;
-       }
-
-       /* Create the hashtables used to map metadata objects. */
-       md_maps->stream_class_map = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, NULL, (GDestroyNotify) bt_stream_class_put_ref);
-       md_maps->event_class_map = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, NULL, (GDestroyNotify) bt_event_class_put_ref);
-       md_maps->field_class_map = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, NULL, (GDestroyNotify) bt_field_class_put_ref);
-       md_maps->clock_class_map = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, NULL, (GDestroyNotify) bt_clock_class_put_ref);
-
-       bt_trace_class_add_destruction_listener(in_trace_class,
-                       trace_ir_metadata_maps_remove_func,
-                       ir_maps, &md_maps->destruction_listener_id);
-error:
-       return md_maps;
-}
-
-BT_HIDDEN
-void trace_ir_data_maps_destroy(struct trace_ir_data_maps *maps)
-{
-       bt_trace_status status;
-       if (!maps) {
-               return;
-       }
-
-       if (maps->packet_map) {
-               g_hash_table_destroy(maps->packet_map);
-       }
-
-       if (maps->stream_map) {
-               g_hash_table_destroy(maps->stream_map);
-       }
-
-       if (maps->output_trace) {
-               bt_trace_put_ref(maps->output_trace);
-       }
-
-       status = bt_trace_remove_destruction_listener(maps->input_trace,
-                       maps->destruction_listener_id);
-       if (status != BT_TRACE_STATUS_OK) {
-               BT_LOGD("Trace destruction listener removal failed.");
-       }
-
-       g_free(maps);
-}
-
-BT_HIDDEN
-void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *maps)
-{
-       bt_trace_class_status status;
-       if (!maps) {
-               return;
-       }
-
-       if (maps->stream_class_map) {
-               g_hash_table_destroy(maps->stream_class_map);
-       }
-
-       if (maps->event_class_map) {
-               g_hash_table_destroy(maps->event_class_map);
-       }
-
-       if (maps->field_class_map) {
-               g_hash_table_destroy(maps->field_class_map);
-       }
-
-       if (maps->clock_class_map) {
-               g_hash_table_destroy(maps->clock_class_map);
-       }
-
-       if (maps->fc_resolving_ctx) {
-               g_free(maps->fc_resolving_ctx);
-       }
-
-       if (maps->output_trace_class) {
-               bt_trace_class_put_ref(maps->output_trace_class);
-       }
-
-       status = bt_trace_class_remove_destruction_listener(maps->input_trace_class,
-                       maps->destruction_listener_id);
-       if (status != BT_TRACE_CLASS_STATUS_OK) {
-               BT_LOGD("Trace destruction listener removal failed.");
-       }
-
-       g_free(maps);
-}
-
-void trace_ir_maps_clear(struct trace_ir_maps *maps)
-{
-       if (maps->data_maps) {
-               g_hash_table_remove_all(maps->data_maps);
-       }
-
-       if (maps->metadata_maps) {
-               g_hash_table_remove_all(maps->metadata_maps);
-       }
-}
-
-BT_HIDDEN
-void trace_ir_maps_destroy(struct trace_ir_maps *maps)
-{
-       if (!maps) {
-               return;
-       }
-
-       if (maps->debug_info_field_class_name) {
-               g_free(maps->debug_info_field_class_name);
-       }
-
-       if (maps->data_maps) {
-               g_hash_table_destroy(maps->data_maps);
-               maps->data_maps = NULL;
-       }
-
-       if (maps->metadata_maps) {
-               g_hash_table_destroy(maps->metadata_maps);
-               maps->metadata_maps = NULL;
-       }
-
-       g_free(maps);
-}
-
-BT_HIDDEN
-struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp,
-               const char *debug_info_field_name)
-{
-       struct trace_ir_maps *trace_ir_maps =
-               g_new0(struct trace_ir_maps, 1);
-       if (!trace_ir_maps) {
-               BT_LOGE_STR("Error allocating trace_ir_maps");
-               goto error;
-       }
-
-       /* Copy debug info field name received from the user. */
-       trace_ir_maps->debug_info_field_class_name =
-               g_strdup(debug_info_field_name);
-       if (!trace_ir_maps->debug_info_field_class_name) {
-               BT_LOGE_STR("Cannot copy debug info field name");
-               goto error;
-       }
-
-       trace_ir_maps->self_comp = self_comp;
-
-       trace_ir_maps->data_maps = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, (GDestroyNotify) NULL,
-                       (GDestroyNotify) trace_ir_data_maps_destroy);
-
-       trace_ir_maps->metadata_maps = g_hash_table_new_full(g_direct_hash,
-                       g_direct_equal, (GDestroyNotify) NULL,
-                       (GDestroyNotify) trace_ir_metadata_maps_destroy);
-
-       goto end;
-error:
-       trace_ir_maps_destroy(trace_ir_maps);
-       trace_ir_maps = NULL;
-end:
-       return trace_ir_maps;
-}
diff --git a/plugins/lttng-utils/debug-info/trace-ir-mapping.h b/plugins/lttng-utils/debug-info/trace-ir-mapping.h
deleted file mode 100644 (file)
index 0f29e23..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H
-#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H
-/*
- * Copyright 2019 Francis Deslauriers francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "debug-info.h"
-
-/* Used to resolve field paths for dynamic arrays and variant field classes. */
-struct field_class_resolving_context {
-       /* Weak reference. Owned by input stream class. */
-       const bt_field_class *packet_context;
-       /* Weak reference. Owned by input stream class. */
-       const bt_field_class *event_common_context;
-       /* Weak reference. Owned by input event class. */
-       const bt_field_class *event_specific_context;
-       /* Weak reference. Owned by input event class. */
-       const bt_field_class *event_payload;
-};
-
-struct trace_ir_metadata_maps {
-       const bt_trace_class *input_trace_class;
-       bt_trace_class *output_trace_class;
-
-       /*
-        * Map between input stream class and its corresponding output stream
-        * class.
-        * input stream class: weak reference. Owned by an upstream
-        * component.
-        * output stream class: owned by this structure.
-        */
-       GHashTable *stream_class_map;
-
-       /*
-        * Map between input event class and its corresponding output event
-        * class.
-        * input event class: weak reference. Owned by an upstream component.
-        * output event class: owned by this structure.
-        */
-       GHashTable *event_class_map;
-
-       /*
-        * Map between input field class and its corresponding output field
-        * class.
-        * input field class: weak reference. Owned by an upstream component.
-        * output field class: owned by this structure.
-        */
-       GHashTable *field_class_map;
-
-       /*
-        * Map between input clock class and its corresponding output clock
-        * class.
-        * input clock class: weak reference. Owned by an upstream component.
-        * output clock class: owned by this structure.
-        */
-       GHashTable *clock_class_map;
-
-       struct field_class_resolving_context *fc_resolving_ctx;
-
-       uint64_t destruction_listener_id;
-};
-
-struct trace_ir_data_maps {
-       const bt_trace *input_trace;
-       bt_trace *output_trace;
-
-       /*
-        * Map between input stream its corresponding output stream.
-        * input stream: weak reference. Owned by an upstream component.
-        * output stream: owned by this structure.
-        */
-       GHashTable *stream_map;
-
-       /*
-        * Map between input packet its corresponding output packet.
-        * input packet: weak reference. Owned by an upstream packet component.
-        * output packet: owned by this structure.
-        */
-       GHashTable *packet_map;
-
-       uint64_t destruction_listener_id;
-};
-
-struct trace_ir_maps {
-       /*
-        * input trace -> trace_ir_data_maps.
-        * input trace: weak reference. Owned by an upstream component.
-        * trace_ir_data_maps: Owned by this structure.
-        */
-       GHashTable *data_maps;
-
-       /*
-        * input trace class -> trace_ir_metadata_maps.
-        * input trace class: weak reference. Owned by an upstream component.
-        * trace_ir_metadata_maps: Owned by this structure.
-        */
-       GHashTable *metadata_maps;
-
-       char *debug_info_field_class_name;
-
-       bt_self_component *self_comp;
-};
-
-BT_HIDDEN
-struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp,
-               const char *debug_info_field_name);
-
-BT_HIDDEN
-void trace_ir_maps_clear(struct trace_ir_maps *maps);
-
-BT_HIDDEN
-void trace_ir_maps_destroy(struct trace_ir_maps *maps);
-
-BT_HIDDEN
-struct trace_ir_data_maps *trace_ir_data_maps_create(
-               struct trace_ir_maps *ir_maps,
-               const bt_trace *in_trace);
-
-BT_HIDDEN
-void trace_ir_data_maps_destroy(struct trace_ir_data_maps *d_maps);
-
-BT_HIDDEN
-struct trace_ir_metadata_maps *trace_ir_metadata_maps_create(
-               struct trace_ir_maps *ir_maps,
-               const bt_trace_class *in_trace_class);
-
-BT_HIDDEN
-void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *md_maps);
-
-BT_HIDDEN
-bt_stream *trace_ir_mapping_create_new_mapped_stream(
-               struct trace_ir_maps *ir_maps,
-               const bt_stream *in_stream);
-
-BT_HIDDEN
-bt_stream *trace_ir_mapping_borrow_mapped_stream(
-               struct trace_ir_maps *ir_maps,
-               const bt_stream *in_stream);
-
-BT_HIDDEN
-void trace_ir_mapping_remove_mapped_stream(
-               struct trace_ir_maps *ir_maps,
-               const bt_stream *in_stream);
-
-BT_HIDDEN
-bt_event_class *trace_ir_mapping_create_new_mapped_event_class(
-               struct trace_ir_maps *ir_maps,
-               const bt_event_class *in_event_class);
-
-BT_HIDDEN
-bt_event_class *trace_ir_mapping_borrow_mapped_event_class(
-               struct trace_ir_maps *ir_maps,
-               const bt_event_class *in_event_class);
-
-BT_HIDDEN
-bt_packet *trace_ir_mapping_create_new_mapped_packet(
-               struct trace_ir_maps *ir_maps,
-               const bt_packet *in_packet);
-
-BT_HIDDEN
-bt_packet *trace_ir_mapping_borrow_mapped_packet(
-               struct trace_ir_maps *ir_maps,
-               const bt_packet *in_packet);
-
-BT_HIDDEN
-void trace_ir_mapping_remove_mapped_packet(
-               struct trace_ir_maps *ir_maps,
-               const bt_packet *in_packet);
-
-static inline
-struct trace_ir_data_maps *borrow_data_maps_from_input_trace(
-               struct trace_ir_maps *ir_maps, const bt_trace *in_trace)
-{
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_trace);
-
-       struct trace_ir_data_maps *d_maps =
-               g_hash_table_lookup(ir_maps->data_maps, (gpointer) in_trace);
-       if (!d_maps) {
-               d_maps = trace_ir_data_maps_create(ir_maps, in_trace);
-               g_hash_table_insert(ir_maps->data_maps, (gpointer) in_trace, d_maps);
-       }
-
-       return d_maps;
-}
-
-static inline
-struct trace_ir_data_maps *borrow_data_maps_from_input_stream(
-               struct trace_ir_maps *ir_maps, const bt_stream *in_stream)
-{
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_stream);
-
-       return borrow_data_maps_from_input_trace(ir_maps,
-                       bt_stream_borrow_trace_const(in_stream));
-}
-
-static inline
-struct trace_ir_data_maps *borrow_data_maps_from_input_packet(
-               struct trace_ir_maps *ir_maps, const bt_packet *in_packet)
-{
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_packet);
-
-       return borrow_data_maps_from_input_stream(ir_maps,
-                       bt_packet_borrow_stream_const(in_packet));
-}
-
-static inline
-struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_trace_class(
-               struct trace_ir_maps *ir_maps,
-               const bt_trace_class *in_trace_class)
-{
-       BT_ASSERT(ir_maps);
-       BT_ASSERT(in_trace_class);
-
-       struct trace_ir_metadata_maps *md_maps =
-               g_hash_table_lookup(ir_maps->metadata_maps,
-                               (gpointer) in_trace_class);
-       if (!md_maps) {
-               md_maps = trace_ir_metadata_maps_create(ir_maps, in_trace_class);
-               g_hash_table_insert(ir_maps->metadata_maps,
-                               (gpointer) in_trace_class, md_maps);
-       }
-
-       return md_maps;
-}
-
-static inline
-struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_stream_class(
-               struct trace_ir_maps *ir_maps,
-               const bt_stream_class *in_stream_class) {
-
-       BT_ASSERT(in_stream_class);
-
-       return borrow_metadata_maps_from_input_trace_class(ir_maps,
-                       bt_stream_class_borrow_trace_class_const(in_stream_class));
-}
-
-static inline
-struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_event_class(
-               struct trace_ir_maps *ir_maps,
-               const bt_event_class *in_event_class) {
-
-       BT_ASSERT(in_event_class);
-
-       return borrow_metadata_maps_from_input_stream_class(ir_maps,
-                       bt_event_class_borrow_stream_class_const(in_event_class));
-}
-
-#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H */
diff --git a/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c b/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c
deleted file mode 100644 (file)
index 55bb953..0000000
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Babeltrace - Trace IR metadata object copy
- *
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-METADATA-COPY"
-#include "logging.h"
-
-#include <inttypes.h>
-#include <stdint.h>
-
-#include <babeltrace2/assert-internal.h>
-
-#include "trace-ir-metadata-copy.h"
-#include "trace-ir-metadata-field-class-copy.h"
-#include "utils.h"
-
-BT_HIDDEN
-int copy_trace_class_content(const bt_trace_class *in_trace_class,
-               bt_trace_class *out_trace_class)
-{
-       int ret = 0;
-       uint64_t i, env_field_count;
-       const char *in_trace_class_name;
-
-       BT_LOGD("Copying content of trace class: in-tc-addr=%p, out-tc-addr=%p",
-                       in_trace_class, out_trace_class);
-
-       /* Use the same stream class ids as in the origin trace class. */
-       bt_trace_class_set_assigns_automatic_stream_class_id(out_trace_class,
-                       BT_FALSE);
-
-       in_trace_class_name = bt_trace_class_get_name(in_trace_class);
-       if (in_trace_class_name) {
-               bt_trace_class_set_name(out_trace_class, in_trace_class_name);
-       }
-
-       /*
-        * Do not copy the trace class UUID as it may be modified and should no
-        * longer have the same UUID.
-        */
-
-       /*
-        * Go over all the entries in the environment section of the trace class
-        * and copy the content to the new trace class.
-        */
-       env_field_count = bt_trace_class_get_environment_entry_count(in_trace_class);
-       for (i = 0; i < env_field_count; i++) {
-               const char *value_name;
-               const bt_value *value = NULL;
-               bt_trace_class_status trace_class_status;
-
-               bt_trace_class_borrow_environment_entry_by_index_const(
-                       in_trace_class, i, &value_name, &value);
-
-               BT_LOGD("Copying trace class environnement entry: "
-                       "index=%" PRId64 ", value-addr=%p, value-name=%s",
-                       i, value, value_name);
-
-               BT_ASSERT(value_name);
-               BT_ASSERT(value);
-
-               if (bt_value_is_signed_integer(value)) {
-                       trace_class_status =
-                               bt_trace_class_set_environment_entry_integer(
-                                               out_trace_class, value_name,
-                                               bt_value_signed_integer_get(
-                                                       value));
-               } else if (bt_value_is_string(value)) {
-                       trace_class_status =
-                               bt_trace_class_set_environment_entry_string(
-                                       out_trace_class, value_name,
-                                       bt_value_string_get(value));
-               } else {
-                       abort();
-               }
-
-               if (trace_class_status != BT_TRACE_CLASS_STATUS_OK) {
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Copied content of trace class: in-tc-addr=%p, out-tc-addr=%p",
-                       in_trace_class, out_trace_class);
-error:
-       return ret;
-}
-
-static
-int copy_clock_class_content(const bt_clock_class *in_clock_class,
-               bt_clock_class *out_clock_class)
-{
-       bt_clock_class_status status;
-       const char *clock_class_name, *clock_class_description;
-       int64_t seconds;
-       uint64_t cycles;
-       bt_uuid in_uuid;
-       int ret = 0;
-
-       BT_LOGD("Copying content of clock class: in-cc-addr=%p, out-cc-addr=%p",
-                       in_clock_class, out_clock_class);
-
-       clock_class_name = bt_clock_class_get_name(in_clock_class);
-
-       if (clock_class_name) {
-               status = bt_clock_class_set_name(out_clock_class, clock_class_name);
-               if (status != BT_CLOCK_CLASS_STATUS_OK) {
-                       BT_LOGE("Error setting clock class' name cc-addr=%p, name=%p",
-                               out_clock_class, clock_class_name);
-                       out_clock_class = NULL;
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       clock_class_description = bt_clock_class_get_description(in_clock_class);
-
-       if (clock_class_description) {
-               status = bt_clock_class_set_description(out_clock_class,
-                               clock_class_description);
-               if (status != BT_CLOCK_CLASS_STATUS_OK) {
-                       BT_LOGE("Error setting clock class' description cc-addr=%p, "
-                               "name=%p", out_clock_class, clock_class_description);
-                       out_clock_class = NULL;
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       in_uuid = bt_clock_class_get_uuid(in_clock_class);
-       if (in_uuid) {
-               bt_clock_class_set_uuid(out_clock_class, in_uuid);
-       }
-
-       bt_clock_class_set_frequency(out_clock_class,
-                       bt_clock_class_get_frequency(in_clock_class));
-       bt_clock_class_set_precision(out_clock_class,
-                       bt_clock_class_get_precision(in_clock_class));
-       bt_clock_class_get_offset(in_clock_class, &seconds, &cycles);
-       bt_clock_class_set_offset(out_clock_class, seconds, cycles);
-       bt_clock_class_set_origin_is_unix_epoch(out_clock_class,
-                       bt_clock_class_origin_is_unix_epoch(in_clock_class));
-
-       BT_LOGD("Copied content of clock class: in-cc-addr=%p, out-cc-addr=%p",
-                       in_clock_class, out_clock_class);
-
-error:
-       return ret;
-}
-
-static
-bt_clock_class *borrow_mapped_clock_class(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_clock_class *in_clock_class)
-{
-       BT_ASSERT(md_maps);
-       BT_ASSERT(in_clock_class);
-
-       return g_hash_table_lookup(md_maps->clock_class_map,
-                       (gpointer) in_clock_class);
-}
-
-static
-bt_clock_class *create_new_mapped_clock_class(
-               bt_self_component *self_comp,
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_clock_class *in_clock_class)
-{
-       bt_clock_class *out_clock_class;
-       int ret;
-
-       BT_LOGD("Creating new mapped clock class: in-cc-addr=%p",
-                       in_clock_class);
-
-       BT_ASSERT(md_maps);
-       BT_ASSERT(in_clock_class);
-
-       BT_ASSERT(!borrow_mapped_clock_class(md_maps, in_clock_class));
-
-       out_clock_class = bt_clock_class_create(self_comp);
-       if (!out_clock_class) {
-               BT_LOGE_STR("Cannot create clock class");
-               goto end;
-       }
-       /* If not, create a new one and add it to the mapping. */
-       ret = copy_clock_class_content(in_clock_class, out_clock_class);
-       if (ret) {
-               BT_LOGE_STR("Cannot copy clock class");
-               goto end;
-       }
-
-       g_hash_table_insert(md_maps->clock_class_map,
-                       (gpointer) in_clock_class, out_clock_class);
-
-       BT_LOGD("Created new mapped clock class: in-cc-addr=%p, out-cc-addr=%p",
-                       in_clock_class, out_clock_class);
-end:
-       return out_clock_class;
-}
-
-BT_HIDDEN
-int copy_stream_class_content(struct trace_ir_maps *ir_maps,
-               const bt_stream_class *in_stream_class,
-               bt_stream_class *out_stream_class)
-{
-       struct trace_ir_metadata_maps *md_maps;
-       const bt_clock_class *in_clock_class;
-       bt_clock_class *out_clock_class;
-       const bt_field_class *in_packet_context_fc, *in_common_context_fc;
-       bt_field_class *out_packet_context_fc, *out_common_context_fc;
-       bt_stream_class_status status;
-       const char *in_name;
-       int ret = 0;
-
-       BT_LOGD("Copying content of stream class: in-sc-addr=%p, out-sc-addr=%p",
-                       in_stream_class, out_stream_class);
-
-       md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class);
-       in_clock_class = bt_stream_class_borrow_default_clock_class_const(
-                               in_stream_class);
-
-       if (in_clock_class) {
-               /* Copy the clock class. */
-               out_clock_class =
-                       borrow_mapped_clock_class(md_maps, in_clock_class);
-               if (!out_clock_class) {
-                       out_clock_class = create_new_mapped_clock_class(
-                                       ir_maps->self_comp, md_maps,
-                                       in_clock_class);
-               }
-               bt_stream_class_set_default_clock_class(out_stream_class,
-                               out_clock_class);
-
-       }
-
-       bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
-               out_stream_class,
-               bt_stream_class_packets_have_beginning_default_clock_snapshot(
-                       in_stream_class));
-       bt_stream_class_set_packets_have_end_default_clock_snapshot(
-               out_stream_class,
-               bt_stream_class_packets_have_end_default_clock_snapshot(
-                       in_stream_class));
-       bt_stream_class_set_supports_discarded_events(
-               out_stream_class,
-               bt_stream_class_supports_discarded_events(in_stream_class),
-               bt_stream_class_discarded_events_have_default_clock_snapshots(
-                       in_stream_class));
-       bt_stream_class_set_supports_discarded_packets(
-               out_stream_class,
-               bt_stream_class_supports_discarded_packets(in_stream_class),
-               bt_stream_class_discarded_packets_have_default_clock_snapshots(
-                       in_stream_class));
-
-       in_name = bt_stream_class_get_name(in_stream_class);
-       if (in_name) {
-               status = bt_stream_class_set_name(out_stream_class, in_name);
-               if (status != BT_STREAM_CLASS_STATUS_OK) {
-                       BT_LOGE("Error set stream class name: out-sc-addr=%p, "
-                               "name=%s", out_stream_class, in_name);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       bt_stream_class_set_assigns_automatic_stream_id(out_stream_class,
-                       BT_FALSE);
-       bt_stream_class_set_assigns_automatic_event_class_id(out_stream_class,
-                       BT_FALSE);
-
-       /*
-        * Add the input packet context field class to the context to
-        * resolution in the further steps.
-        */
-       in_packet_context_fc =
-               bt_stream_class_borrow_packet_context_field_class_const(
-                               in_stream_class);
-       md_maps->fc_resolving_ctx->packet_context =
-               in_packet_context_fc;
-
-       if (in_packet_context_fc) {
-               /* Copy packet context. */
-               out_packet_context_fc = create_field_class_copy(
-                               md_maps, in_packet_context_fc);
-
-               ret = copy_field_class_content(md_maps,
-                       in_packet_context_fc, out_packet_context_fc);
-               if (ret) {
-                       ret = -1;
-                       goto error;
-               }
-
-               status = bt_stream_class_set_packet_context_field_class(
-                               out_stream_class, out_packet_context_fc);
-               if (status !=  BT_STREAM_CLASS_STATUS_OK) {
-                       BT_LOGE("Error setting stream class' packet context "
-                               "field class: sc-addr=%p, packet-fc-addr=%p",
-                               out_stream_class, out_packet_context_fc);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       /*
-        * Add the input common context field class to the context to
-        * resolution in the further steps.
-        */
-       in_common_context_fc =
-               bt_stream_class_borrow_event_common_context_field_class_const(
-                               in_stream_class);
-       md_maps->fc_resolving_ctx->event_common_context =
-               in_common_context_fc;
-
-       if (in_common_context_fc) {
-               /* Copy common context. */
-               /* TODO: I find it a bit awkward to have this special function
-                * here to add the debug-info field class. I would like to
-                * abstract that.*/
-               out_common_context_fc = create_field_class_copy(
-                               md_maps, in_common_context_fc);
-
-               ret = copy_event_common_context_field_class_content(
-                               md_maps, ir_maps->debug_info_field_class_name,
-                               in_common_context_fc, out_common_context_fc);
-               if (ret) {
-                       goto error;
-               }
-
-               status = bt_stream_class_set_event_common_context_field_class(
-                               out_stream_class, out_common_context_fc);
-               if (status !=  BT_STREAM_CLASS_STATUS_OK) {
-                       BT_LOGE("Error setting stream class' packet context "
-                               "field class: sc-addr=%p, packet-fc-addr=%p",
-                               out_stream_class, out_common_context_fc);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       /* Set packet snapshot boolean fields. */
-       BT_LOGD("Copied content of stream class: in-sc-addr=%p, out-sc-addr=%p",
-                       in_stream_class, out_stream_class);
-error:
-       return ret;
-}
-
-BT_HIDDEN
-int copy_event_class_content(struct trace_ir_maps *ir_maps,
-               const bt_event_class *in_event_class,
-               bt_event_class *out_event_class)
-{
-       struct trace_ir_metadata_maps *md_maps;
-       const char *in_event_class_name, *in_emf_uri;
-       bt_property_availability prop_avail;
-       bt_event_class_log_level log_level;
-       bt_event_class_status status;
-       bt_field_class *out_specific_context_fc, *out_payload_fc;
-       const bt_field_class *in_event_specific_context, *in_event_payload;
-       int ret = 0;
-
-       BT_LOGD("Copying content of event class: in-ec-addr=%p, out-ec-addr=%p",
-                       in_event_class, out_event_class);
-
-       /* Copy event class name. */
-       in_event_class_name = bt_event_class_get_name(in_event_class);
-       if (in_event_class_name) {
-               status = bt_event_class_set_name(out_event_class, in_event_class_name);
-               if (status != BT_EVENT_CLASS_STATUS_OK) {
-                       BT_LOGE("Error setting event class' name: ec-addr=%p, "
-                               "name=%s", out_event_class, in_event_class_name);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       /* Copy event class loglevel. */
-       prop_avail = bt_event_class_get_log_level(in_event_class, &log_level);
-       if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
-               bt_event_class_set_log_level(out_event_class,
-                               log_level);
-       }
-
-       /* Copy event class emf uri. */
-       in_emf_uri = bt_event_class_get_emf_uri(in_event_class);
-       if (in_emf_uri) {
-               status = bt_event_class_set_emf_uri(out_event_class, in_emf_uri);
-               if (status != BT_EVENT_CLASS_STATUS_OK) {
-                       BT_LOGE("Error setting event class' emf uri: ec-addr=%p, "
-                               "emf uri=%s", out_event_class, in_emf_uri);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, in_event_class);
-       /*
-        * Add the input event class' specific ctx to te
-        * context.
-        */
-       in_event_specific_context =
-               bt_event_class_borrow_specific_context_field_class_const(
-                               in_event_class);
-
-       md_maps->fc_resolving_ctx->event_specific_context =
-               in_event_specific_context;
-
-       if (in_event_specific_context) {
-               /* Copy the specific context of this event class. */
-               out_specific_context_fc = create_field_class_copy(md_maps,
-                               in_event_specific_context);
-
-               ret = copy_field_class_content(md_maps,
-                               in_event_specific_context, out_specific_context_fc);
-               if (ret) {
-                       goto error;
-               }
-               /*
-                * Add the output specific context to the output event
-                * class.
-                */
-               status = bt_event_class_set_specific_context_field_class(
-                               out_event_class, out_specific_context_fc);
-               if (status != BT_EVENT_CLASS_STATUS_OK) {
-                       BT_LOGE("Error setting event class' specific context "
-                               "field class: ec-addr=%p, ctx-fc-addr=%p",
-                               out_event_class, out_specific_context_fc);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       /*
-        * Add the input event class' payload field class to
-        * the context.
-        */
-       in_event_payload = bt_event_class_borrow_payload_field_class_const(
-                               in_event_class);
-
-       md_maps->fc_resolving_ctx->event_payload = in_event_payload;
-
-       if (in_event_payload) {
-       /* Copy the payload of this event class. */
-               out_payload_fc = create_field_class_copy(md_maps,
-                               in_event_payload);
-               ret = copy_field_class_content(md_maps,
-                               in_event_payload, out_payload_fc);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Add the output payload to the output event class. */
-               status = bt_event_class_set_payload_field_class(
-                               out_event_class, out_payload_fc);
-               if (status != BT_EVENT_CLASS_STATUS_OK) {
-                       BT_LOGE("Error setting event class' payload "
-                               "field class: ec-addr=%p, payload-fc-addr=%p",
-                               out_event_class, out_payload_fc);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Copied content of event class: in-ec-addr=%p, out-ec-addr=%p",
-                       in_event_class, out_event_class);
-error:
-       return ret;
-}
-
-BT_HIDDEN
-int copy_event_common_context_field_class_content(
-               struct trace_ir_metadata_maps *md_maps,
-               const char *debug_info_fc_name,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       bt_field_class_status status;
-       bt_field_class *debug_field_class = NULL, *bin_field_class = NULL,
-                      *func_field_class = NULL, *src_field_class = NULL;
-       int ret = 0;
-
-       BT_LOGD("Copying content of event common context field class: "
-               "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class);
-
-       /* Copy the content of the input common context. */
-       ret = copy_field_class_content(md_maps, in_field_class, out_field_class);
-       if (ret) {
-               goto error;
-       }
-
-       /*
-        * If this event common context has the necessary fields to compute the
-        * debug information append the debug-info field class to the event
-        * common context.
-        */
-       if (is_event_common_ctx_dbg_info_compatible(in_field_class, debug_info_fc_name)) {
-               /*
-                * The struct field and 3 sub-fields are not stored in the
-                * field class map because they don't have input equivalent.
-                * We need to put our reference each of these field classes
-                * once they are added to their respective containing field
-                * classes.
-                */
-               debug_field_class = bt_field_class_structure_create(
-                               md_maps->output_trace_class);
-               if (!debug_field_class) {
-                       BT_LOGE_STR("Failed to create debug_info structure.");
-                       ret = -1;
-                       goto error;
-               }
-
-               bin_field_class = bt_field_class_string_create(
-                               md_maps->output_trace_class);
-               if (!bin_field_class) {
-                       BT_LOGE_STR("Failed to create string for field=bin.");
-                       ret = -1;
-                       goto error;
-               }
-
-               func_field_class = bt_field_class_string_create(
-                               md_maps->output_trace_class);
-               if (!func_field_class) {
-                       BT_LOGE_STR("Failed to create string for field=func.");
-                       ret = -1;
-                       goto error;
-               }
-
-               src_field_class = bt_field_class_string_create(
-                               md_maps->output_trace_class);
-               if (!src_field_class) {
-                       BT_LOGE_STR("Failed to create string for field=src.");
-                       ret = -1;
-                       goto error;
-               }
-
-               status = bt_field_class_structure_append_member(
-                               debug_field_class, "bin", bin_field_class);
-               if (status != BT_FIELD_CLASS_STATUS_OK) {
-                       BT_LOGE_STR("Failed to add a field to debug_info "
-                                       "struct: field=bin.");
-                       ret = -1;
-                       goto error;
-               }
-               BT_FIELD_CLASS_PUT_REF_AND_RESET(bin_field_class);
-
-               status = bt_field_class_structure_append_member(
-                               debug_field_class, "func", func_field_class);
-               if (status != BT_FIELD_CLASS_STATUS_OK) {
-                       BT_LOGE_STR("Failed to add a field to debug_info "
-                                       "struct: field=func.");
-                       ret = -1;
-                       goto error;
-               }
-               BT_FIELD_CLASS_PUT_REF_AND_RESET(func_field_class);
-
-               status = bt_field_class_structure_append_member(
-                               debug_field_class, "src", src_field_class);
-               if (status != BT_FIELD_CLASS_STATUS_OK) {
-                       BT_LOGE_STR("Failed to add a field to debug_info "
-                                       "struct: field=src.");
-                       ret = -1;
-                       goto error;
-               }
-               BT_FIELD_CLASS_PUT_REF_AND_RESET(src_field_class);
-
-               /*Add the filled debug-info field class to the common context. */
-               status = bt_field_class_structure_append_member(out_field_class,
-                               debug_info_fc_name,
-                               debug_field_class);
-               if (status != BT_FIELD_CLASS_STATUS_OK) {
-                       BT_LOGE_STR("Failed to add debug_info field to "
-                                       "event common context.");
-                       ret = -1;
-                       goto error;
-               }
-               BT_FIELD_CLASS_PUT_REF_AND_RESET(debug_field_class);
-       }
-       BT_LOGD("Copied content of event common context field class: "
-               "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class);
-       goto end;
-
-error:
-       if (debug_field_class) {
-               bt_field_class_put_ref(debug_field_class);
-       }
-       if (bin_field_class) {
-               bt_field_class_put_ref(bin_field_class);
-       }
-       if (func_field_class) {
-               bt_field_class_put_ref(func_field_class);
-       }
-       if (src_field_class) {
-               bt_field_class_put_ref(src_field_class);
-       }
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_field_class *create_field_class_copy(struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class)
-{
-       return create_field_class_copy_internal(md_maps, in_field_class);
-}
-
-BT_HIDDEN
-int copy_field_class_content(struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       return copy_field_class_content_internal(md_maps, in_field_class,
-                       out_field_class);
-}
diff --git a/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h b/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h
deleted file mode 100644 (file)
index 9330546..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H
-#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H
-
-/*
- * Babeltrace - Trace IR metadata object copy
- *
- * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include "trace-ir-mapping.h"
-
-BT_HIDDEN
-int copy_trace_class_content(const bt_trace_class *in_trace_class,
-               bt_trace_class *out_trace_class);
-
-BT_HIDDEN
-int copy_stream_class_content(struct trace_ir_maps *trace_ir_maps,
-               const bt_stream_class *in_stream_class,
-               bt_stream_class *out_stream_class);
-
-BT_HIDDEN
-int copy_event_class_content(struct trace_ir_maps *trace_ir_maps,
-               const bt_event_class *in_event_class,
-               bt_event_class *out_event_class);
-
-BT_HIDDEN
-int copy_field_class_content(struct trace_ir_metadata_maps *trace_ir_metadata_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class);
-
-BT_HIDDEN
-int copy_event_common_context_field_class_content(
-               struct trace_ir_metadata_maps *trace_ir_metadata_maps,
-               const char *debug_info_field_class_name,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class);
-
-BT_HIDDEN
-bt_field_class *create_field_class_copy(
-               struct trace_ir_metadata_maps *trace_ir_metadata_maps,
-               const bt_field_class *in_field_class);
-
-#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H */
diff --git a/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c b/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c
deleted file mode 100644 (file)
index 1247e59..0000000
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- * Babeltrace - Trace IR field copy
- *
- * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-METADATA-FC-COPY"
-#include "logging.h"
-
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-#include "trace-ir-metadata-copy.h"
-#include "trace-ir-metadata-field-class-copy.h"
-
-/*
- * This fonction walks througth the nested structures field class to resolve a
- * field path object. A field path is made of indexes inside possibly nested
- * structures ultimately leading to a field class.
- */
-static
-const bt_field_class *walk_field_path(const bt_field_path *fp,
-               const bt_field_class *fc)
-{
-       uint64_t i, fp_item_count;
-       const bt_field_class *curr_fc;
-
-       BT_ASSERT(bt_field_class_get_type(fc) == BT_FIELD_CLASS_TYPE_STRUCTURE);
-       BT_LOGD("Walking field path on field class: fp-addr=%p, fc-addr=%p",
-                       fp, fc);
-
-       fp_item_count = bt_field_path_get_item_count(fp);
-       curr_fc = fc;
-       for (i = 0; i < fp_item_count; i++) {
-               bt_field_class_type fc_type = bt_field_class_get_type(curr_fc);
-               const bt_field_path_item *fp_item =
-                       bt_field_path_borrow_item_by_index_const(fp, i);
-
-               switch (fc_type) {
-               case BT_FIELD_CLASS_TYPE_STRUCTURE:
-               {
-                       const bt_field_class_structure_member *member;
-
-                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
-                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
-                       member = bt_field_class_structure_borrow_member_by_index_const(
-                               curr_fc,
-                               bt_field_path_item_index_get_index(fp_item));
-                       curr_fc = bt_field_class_structure_member_borrow_field_class_const(
-                               member);
-                       break;
-               }
-               case BT_FIELD_CLASS_TYPE_VARIANT:
-               {
-                       const bt_field_class_variant_option *option;
-
-                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
-                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
-                       option = bt_field_class_variant_borrow_option_by_index_const(
-                               curr_fc,
-                               bt_field_path_item_index_get_index(fp_item));
-                       curr_fc = bt_field_class_variant_option_borrow_field_class_const(
-                               option);
-                       break;
-               }
-               case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-               case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-               {
-                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
-                               BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
-                       curr_fc = bt_field_class_array_borrow_element_field_class_const(
-                               curr_fc);
-                       break;
-               }
-               default:
-                       abort();
-               }
-       }
-
-       return curr_fc;
-}
-
-static
-const bt_field_class *resolve_field_path_to_field_class(const bt_field_path *fp,
-               struct trace_ir_metadata_maps *md_maps)
-{
-       struct field_class_resolving_context *fc_resolving_ctx;
-       const bt_field_class *fc;
-       bt_scope fp_scope;
-
-       BT_LOGD("Resolving field path: fp-addr=%p", fp);
-
-       fc_resolving_ctx = md_maps->fc_resolving_ctx;
-       fp_scope = bt_field_path_get_root_scope(fp);
-
-       switch (fp_scope) {
-       case BT_SCOPE_PACKET_CONTEXT:
-               fc = walk_field_path(fp, fc_resolving_ctx->packet_context);
-               break;
-       case BT_SCOPE_EVENT_COMMON_CONTEXT:
-               fc = walk_field_path(fp, fc_resolving_ctx->event_common_context);
-               break;
-       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
-               fc = walk_field_path(fp, fc_resolving_ctx->event_specific_context);
-               break;
-       case BT_SCOPE_EVENT_PAYLOAD:
-               fc = walk_field_path(fp, fc_resolving_ctx->event_payload);
-               break;
-       default:
-               abort();
-       }
-
-       return fc;
-}
-
-static inline
-void field_class_integer_set_props(const bt_field_class *input_fc,
-               bt_field_class *output_fc)
-{
-       bt_field_class_integer_set_preferred_display_base(output_fc,
-                       bt_field_class_integer_get_preferred_display_base(input_fc));
-       bt_field_class_integer_set_field_value_range(output_fc,
-                       bt_field_class_integer_get_field_value_range(input_fc));
-}
-
-static inline
-int field_class_unsigned_integer_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       BT_LOGD("Copying content of unsigned integer field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-       field_class_integer_set_props(in_field_class, out_field_class);
-
-       BT_LOGD("Copied content of unsigned integer field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-       return 0;
-}
-
-static inline
-int field_class_signed_integer_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       BT_LOGD("Copying content of signed integer field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-       field_class_integer_set_props(in_field_class, out_field_class);
-
-       BT_LOGD("Copied content of signed integer field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-       return 0;
-}
-
-BT_HIDDEN
-int field_class_unsigned_enumeration_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       uint64_t i, enum_mapping_count;
-       int ret = 0;
-
-       BT_LOGD("Copying content of unsigned enumeration field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-       /* Copy properties of the inner integer. */
-       field_class_integer_set_props(in_field_class, out_field_class);
-
-       /* Copy all enumeration entries. */
-       enum_mapping_count = bt_field_class_enumeration_get_mapping_count(in_field_class);
-       for (i = 0; i < enum_mapping_count; i++) {
-               const char *label;
-               const bt_field_class_unsigned_enumeration_mapping *u_mapping;
-               const bt_field_class_enumeration_mapping *mapping;
-               uint64_t range_index, range_count;
-
-               /* Get the ranges and the range count. */
-               u_mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
-                               in_field_class, i);
-               mapping = bt_field_class_unsigned_enumeration_mapping_as_mapping_const(
-                       u_mapping);
-               range_count =
-                       bt_field_class_enumeration_mapping_get_range_count(
-                               mapping);
-               label = bt_field_class_enumeration_mapping_get_label(
-                       mapping);
-
-               /*
-                * Iterate over all the ranges to add them to copied field
-                * class.
-                */
-               for (range_index = 0; range_index < range_count; range_index++) {
-                       uint64_t lower, upper;
-                       bt_field_class_status status;
-                       bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
-                                       u_mapping, range_index, &lower, &upper);
-
-                       BT_LOGD("Copying range in enumeration field class: "
-                                       "label=%s, lower=%"PRId64", upper=%"PRId64,
-                                       label, lower, upper);
-
-                       /* Add the label and its range to the copy field class. */
-                       status = bt_field_class_unsigned_enumeration_map_range(
-                                       out_field_class, label, lower, upper);
-
-                       if (status != BT_FIELD_CLASS_STATUS_OK) {
-                               BT_LOGE_STR("Failed to add range to unsigned "
-                                               "enumeration.");
-                               BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class);
-                               ret = -1;
-                               goto error;
-                       }
-               }
-       }
-
-       BT_LOGD("Copied content of unsigned enumeration field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-error:
-       return ret;
-}
-
-static inline
-int field_class_signed_enumeration_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       uint64_t i, enum_mapping_count;
-       int ret = 0;
-
-       BT_LOGD("Copying content of signed enumeration field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-       /* Copy properties of the inner integer. */
-       field_class_integer_set_props(in_field_class, out_field_class);
-
-       /* Copy all enumeration entries. */
-       enum_mapping_count =
-               bt_field_class_enumeration_get_mapping_count(in_field_class);
-       for (i = 0; i < enum_mapping_count; i++) {
-               const char *label;
-               const bt_field_class_signed_enumeration_mapping *i_mapping;
-               const bt_field_class_enumeration_mapping *mapping;
-               uint64_t range_index, range_count;
-
-               /* Get the ranges and the range count. */
-               i_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
-                               in_field_class, i);
-               mapping = bt_field_class_signed_enumeration_mapping_as_mapping_const(
-                       i_mapping);
-               range_count =
-                       bt_field_class_enumeration_mapping_get_range_count(
-                               mapping);
-               label = bt_field_class_enumeration_mapping_get_label(
-                       mapping);
-
-               /*
-                * Iterate over all the ranges to add them to copied field
-                * class.
-                */
-               for (range_index = 0; range_index < range_count; range_index++) {
-                       int64_t lower, upper;
-                       bt_field_class_status status;
-                       bt_field_class_signed_enumeration_mapping_get_range_by_index(
-                                       i_mapping, range_index, &lower, &upper);
-
-                       BT_LOGD("Copying range in enumeration field class: "
-                                       "label=%s, lower=%"PRId64", upper=%"PRId64,
-                                       label, lower, upper);
-
-                       /* Add the label and its range to the copy field class. */
-                       status = bt_field_class_signed_enumeration_map_range(
-                                       out_field_class, label, lower, upper);
-                       if (status != BT_FIELD_CLASS_STATUS_OK) {
-                               BT_LOGE_STR("Failed to add range to signed "
-                                               "enumeration.");
-                               BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class);
-                               ret = -1;
-                               goto error;
-                       }
-               }
-       }
-
-       BT_LOGD("Copied content of signed enumeration field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-error:
-       return ret;
-}
-
-static inline
-int field_class_real_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       BT_LOGD("Copying content of real field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-       bt_field_class_real_set_is_single_precision(out_field_class,
-                       bt_field_class_real_is_single_precision(in_field_class));
-
-       BT_LOGD("Copied content real field class: in-fc-addr=%p, "
-                       "out-fc-addr=%p", in_field_class, out_field_class);
-
-       return 0;
-}
-
-static inline
-int field_class_structure_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       uint64_t i, struct_member_count;
-       bt_field_class_status status;
-       int ret = 0;
-
-       BT_LOGD("Copying content of structure field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-       /* Get the number of member in that struct. */
-       struct_member_count =
-               bt_field_class_structure_get_member_count(in_field_class);
-
-       /* Iterate over all the members of the struct. */
-       for (i = 0; i < struct_member_count; i++) {
-               const bt_field_class_structure_member *member;
-               const char *member_name;
-               const bt_field_class *member_fc;
-               bt_field_class *out_member_field_class;
-
-               member = bt_field_class_structure_borrow_member_by_index_const(
-                       in_field_class, i);
-               member_fc = bt_field_class_structure_member_borrow_field_class_const(
-                       member);
-               member_name = bt_field_class_structure_member_get_name(member);
-               BT_LOGD("Copying structure field class's field: "
-                       "index=%" PRId64 ", "
-                       "member-fc-addr=%p, field-name=\"%s\"",
-                       i, member_fc, member_name);
-
-               out_member_field_class = create_field_class_copy(md_maps,
-                               member_fc);
-               if (!out_member_field_class) {
-                       BT_LOGE("Cannot copy structure field class's field: "
-                               "index=%" PRId64 ", "
-                               "field-fc-addr=%p, field-name=\"%s\"",
-                               i, member_fc, member_name);
-                       ret = -1;
-                       goto error;
-               }
-               ret = copy_field_class_content(md_maps, member_fc,
-                               out_member_field_class);
-               if (ret) {
-                       goto error;
-               }
-
-               status = bt_field_class_structure_append_member(out_field_class,
-                               member_name, out_member_field_class);
-               if (status != BT_FIELD_CLASS_STATUS_OK) {
-                       BT_LOGE("Cannot append structure field class's field: "
-                               "index=%" PRId64 ", "
-                               "field-fc-addr=%p, field-name=\"%s\"",
-                               i, member_fc, member_name);
-                       BT_FIELD_CLASS_PUT_REF_AND_RESET(out_member_field_class);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Copied structure field class: original-fc-addr=%p, copy-fc-addr=%p",
-               in_field_class, out_field_class);
-
-error:
-       return ret;
-}
-
-static inline
-int field_class_variant_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       bt_field_class *out_tag_field_class = NULL;
-       uint64_t i, variant_option_count;
-       const bt_field_path *tag_fp;
-       const bt_field_class *tag_fc;
-       int ret = 0;
-
-       BT_LOGD("Copying content of variant field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-       tag_fp = bt_field_class_variant_borrow_selector_field_path_const(
-                       in_field_class);
-       if (tag_fp) {
-               tag_fc = resolve_field_path_to_field_class(tag_fp,
-                               md_maps);
-
-               out_tag_field_class = g_hash_table_lookup(
-                               md_maps->field_class_map, tag_fc);
-               if (!out_tag_field_class) {
-                       BT_LOGE_STR("Cannot find the tag field class.");
-                       ret = -1;
-                       goto error;
-               }
-               bt_field_class_variant_set_selector_field_class(out_field_class,
-                               out_tag_field_class);
-       }
-
-       variant_option_count =
-               bt_field_class_variant_get_option_count(in_field_class);
-       for (i = 0; i < variant_option_count; i++) {
-               const bt_field_class *option_fc;
-               const char *option_name;
-               bt_field_class *out_option_field_class;
-               bt_field_class_status status;
-               const bt_field_class_variant_option *option;
-
-               option = bt_field_class_variant_borrow_option_by_index_const(
-                       in_field_class, i);
-               option_fc = bt_field_class_variant_option_borrow_field_class_const(
-                       option);
-               option_name = bt_field_class_variant_option_get_name(option);
-               out_option_field_class = create_field_class_copy_internal(
-                               md_maps, option_fc);
-               if (!out_option_field_class) {
-                       BT_LOGE_STR("Cannot copy field class.");
-                       ret = -1;
-                       goto error;
-               }
-               ret = copy_field_class_content_internal(md_maps, option_fc,
-                               out_option_field_class);
-               if (ret) {
-                       BT_LOGE_STR("Error copying content of option variant "
-                                       "field class'");
-                       goto error;
-               }
-
-               status = bt_field_class_variant_append_option(
-                               out_field_class, option_name,
-                               out_option_field_class);
-               if (status != BT_FIELD_CLASS_STATUS_OK) {
-                       BT_LOGE_STR("Cannot append option to variant field class'");
-                       BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Copied content of variant field class: in-fc-addr=%p, "
-               "out-fc-addr=%p", in_field_class, out_field_class);
-
-error:
-       return ret;
-}
-
-static inline
-int field_class_static_array_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       BT_LOGD("Copying content of static array field class: in-fc-addr=%p, "
-                       "out-fc-addr=%p", in_field_class, out_field_class);
-       /*
-        * There is no content to copy. Keep this function call anyway for
-        * logging purposes.
-        */
-       BT_LOGD("Copied content of static array field class: in-fc-addr=%p, "
-                       "out-fc-addr=%p", in_field_class, out_field_class);
-
-       return 0;
-}
-
-static inline
-int field_class_dynamic_array_copy(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       const bt_field_class *len_fc;
-       const bt_field_path *len_fp;
-       bt_field_class_status status;
-       bt_field_class *out_len_field_class;
-       int ret = 0;
-
-       BT_LOGD("Copying content of dynamic array field class: "
-                       "in-fc-addr=%p, out-fc-addr=%p",
-                       in_field_class, out_field_class);
-
-       len_fp = bt_field_class_dynamic_array_borrow_length_field_path_const(
-                       in_field_class);
-
-       if (len_fp) {
-               BT_LOGD("Copying dynamic array length field class using "
-                               "field path: in-len-fp=%p", len_fp);
-               len_fc = resolve_field_path_to_field_class(
-                               len_fp, md_maps);
-               out_len_field_class = g_hash_table_lookup(
-                               md_maps->field_class_map, len_fc);
-               if (!out_len_field_class) {
-                       BT_LOGE_STR("Cannot find the output matching length"
-                                       "field class.");
-                       ret = -1;
-                       goto error;
-               }
-
-               status = bt_field_class_dynamic_array_set_length_field_class(
-                               out_field_class, out_len_field_class);
-               if (status != BT_FIELD_CLASS_STATUS_OK) {
-                       BT_LOGE_STR("Cannot set dynamic array field class' "
-                                       "length field class.");
-                       BT_FIELD_CLASS_PUT_REF_AND_RESET(out_len_field_class);
-                       ret = -1;
-                       goto error;
-               }
-       }
-
-       BT_LOGD("Copied dynamic array field class: in-fc-addr=%p, "
-                       "out-fc-addr=%p", in_field_class, out_field_class);
-
-error:
-       return ret;
-}
-
-static inline
-int field_class_string_copy(struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       BT_LOGD("Copying content of string field class: in-fc-addr=%p, "
-                       "out-fc-addr=%p", in_field_class, out_field_class);
-       /*
-        * There is no content to copy. Keep this function call anyway for
-        * logging purposes.
-        */
-       BT_LOGD("Copied content of string field class: in-fc-addr=%p, "
-                       "out-fc-addr=%p", in_field_class, out_field_class);
-
-       return 0;
-}
-
-static
-bt_field_class *copy_field_class_array_element(struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_elem_fc)
-{
-       int ret;
-       bt_field_class *out_elem_fc =
-               create_field_class_copy_internal(md_maps, in_elem_fc);
-       if (!out_elem_fc) {
-               BT_LOGE("Error creating output elem field class "
-                               "from input elem field class for static array: "
-                               "in-fc-addr=%p", in_elem_fc);
-               goto error;
-       }
-
-       ret = copy_field_class_content_internal(md_maps, in_elem_fc, out_elem_fc);
-       if (ret) {
-               BT_LOGE("Error creating output elem field class "
-                               "from input elem field class for static array: "
-                               "in-fc-addr=%p", in_elem_fc);
-               BT_FIELD_CLASS_PUT_REF_AND_RESET(out_elem_fc);
-               goto error;
-       }
-
-error:
-       return out_elem_fc;
-}
-
-BT_HIDDEN
-bt_field_class *create_field_class_copy_internal(struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class)
-{
-       bt_field_class *out_field_class = NULL;
-
-       BT_LOGD("Creating bare field class based on field class: in-fc-addr=%p",
-                       in_field_class);
-
-       switch(bt_field_class_get_type(in_field_class)) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
-               out_field_class = bt_field_class_unsigned_integer_create(
-                               md_maps->output_trace_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
-               out_field_class = bt_field_class_signed_integer_create(
-                               md_maps->output_trace_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-               out_field_class = bt_field_class_unsigned_enumeration_create(
-                               md_maps->output_trace_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-               out_field_class = bt_field_class_signed_enumeration_create(
-                               md_maps->output_trace_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_REAL:
-               out_field_class = bt_field_class_real_create(
-                               md_maps->output_trace_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_STRING:
-               out_field_class = bt_field_class_string_create(
-                               md_maps->output_trace_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-               out_field_class = bt_field_class_structure_create(
-                               md_maps->output_trace_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-       {
-               const bt_field_class *in_elem_fc =
-                       bt_field_class_array_borrow_element_field_class_const(
-                                       in_field_class);
-               uint64_t array_len =
-                       bt_field_class_static_array_get_length(in_field_class);
-
-               bt_field_class *out_elem_fc = copy_field_class_array_element(
-                               md_maps, in_elem_fc);
-               if (!out_elem_fc) {
-                       out_field_class = NULL;
-                       goto error;
-               }
-
-               out_field_class = bt_field_class_static_array_create(
-                               md_maps->output_trace_class,
-                               out_elem_fc, array_len);
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-       {
-               const bt_field_class *in_elem_fc =
-                       bt_field_class_array_borrow_element_field_class_const(
-                                       in_field_class);
-
-               bt_field_class *out_elem_fc = copy_field_class_array_element(
-                               md_maps, in_elem_fc);
-               if (!out_elem_fc) {
-                       out_field_class = NULL;
-                       goto error;
-               }
-
-               out_field_class = bt_field_class_dynamic_array_create(
-                               md_maps->output_trace_class,
-                               out_elem_fc);
-               break;
-       }
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-               out_field_class = bt_field_class_variant_create(
-                               md_maps->output_trace_class);
-               break;
-       default:
-               abort();
-       }
-
-       /*
-        * Add mapping from in_field_class to out_field_class. This simplifies
-        * the resolution of field paths in variant and dynamic array field
-        * classes.
-        */
-       g_hash_table_insert(md_maps->field_class_map,
-                       (gpointer) in_field_class, out_field_class);
-
-error:
-       if(out_field_class){
-               BT_LOGD("Created bare field class based on field class: in-fc-addr=%p, "
-                               "out-fc-addr=%p", in_field_class, out_field_class);
-       } else {
-               BT_LOGE("Error creating output field class from input field "
-                       "class: in-fc-addr=%p", in_field_class);
-       }
-
-       return out_field_class;
-}
-
-BT_HIDDEN
-int copy_field_class_content_internal(
-               struct trace_ir_metadata_maps *md_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class)
-{
-       int ret = 0;
-       switch(bt_field_class_get_type(in_field_class)) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
-               ret = field_class_unsigned_integer_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
-               ret = field_class_signed_integer_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-               ret = field_class_unsigned_enumeration_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-               ret = field_class_signed_enumeration_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_REAL:
-               ret = field_class_real_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_STRING:
-               ret = field_class_string_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-               ret = field_class_structure_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-               ret = field_class_static_array_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-               ret = field_class_dynamic_array_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-               ret = field_class_variant_copy(md_maps,
-                               in_field_class, out_field_class);
-               break;
-       default:
-               abort();
-       }
-
-       return ret;
-}
diff --git a/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h b/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h
deleted file mode 100644 (file)
index 3bd5b80..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H
-#define BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H
-
-/*
- * Babeltrace - Trace IR metadata field class copy
- *
- * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include "trace-ir-mapping.h"
-
-BT_HIDDEN
-int copy_field_class_content_internal(struct trace_ir_metadata_maps *trace_ir_metadata_maps,
-               const bt_field_class *in_field_class,
-               bt_field_class *out_field_class);
-
-BT_HIDDEN
-bt_field_class *create_field_class_copy_internal(
-               struct trace_ir_metadata_maps *trace_ir_metadata_maps,
-               const bt_field_class *in_field_class);
-
-#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H */
diff --git a/plugins/lttng-utils/debug-info/utils.c b/plugins/lttng-utils/debug-info/utils.c
deleted file mode 100644 (file)
index 8f1bdde..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Babeltrace - Debug info utilities
- *
- * Copyright (c) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "utils.h"
-
-BT_HIDDEN
-const char *get_filename_from_path(const char *path)
-{
-       size_t i = strlen(path);
-
-       if (i == 0) {
-               goto end;
-       }
-
-       if (path[i - 1] == '/') {
-               /*
-                * Path ends with a trailing slash, no filename to return.
-                * Return the original path.
-                */
-               goto end;
-       }
-
-       while (i-- > 0) {
-               if (path[i] == '/') {
-                       path = &path[i + 1];
-                       goto end;
-               }
-       }
-end:
-       return path;
-}
-
-BT_HIDDEN
-bt_bool is_event_common_ctx_dbg_info_compatible(const bt_field_class *in_field_class,
-               const char *debug_info_field_class_name)
-{
-       const bt_field_class_structure_member *member;
-       const bt_field_class *ip_fc, *vpid_fc;
-       bt_bool match = BT_FALSE;
-
-       /*
-        * If the debug info field is already present in the event common
-        * context. Do not try to add it.
-        */
-       member =
-               bt_field_class_structure_borrow_member_by_name_const(
-                       in_field_class, debug_info_field_class_name);
-       if (member) {
-               goto end;
-       }
-
-       /*
-        * Verify that the ip and vpid field are present and of the right field
-        * class.
-        */
-       member = bt_field_class_structure_borrow_member_by_name_const(
-                       in_field_class, IP_FIELD_NAME);
-       if (!member) {
-               goto end;
-       }
-
-       ip_fc = bt_field_class_structure_member_borrow_field_class_const(
-               member);
-       if (bt_field_class_get_type(ip_fc) !=
-                       BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER) {
-               match = BT_FALSE;
-               goto end;
-       }
-
-       member = bt_field_class_structure_borrow_member_by_name_const(
-                       in_field_class, VPID_FIELD_NAME);
-       if (!member) {
-               goto end;
-       }
-
-       vpid_fc = bt_field_class_structure_member_borrow_field_class_const(
-               member);
-
-       if (bt_field_class_get_type(vpid_fc) !=
-                       BT_FIELD_CLASS_TYPE_SIGNED_INTEGER) {
-               goto end;
-       }
-
-       if (bt_field_class_integer_get_field_value_range(vpid_fc) != 32) {
-               goto end;
-       }
-
-       match = BT_TRUE;
-
-end:
-       return match;
-}
diff --git a/plugins/lttng-utils/debug-info/utils.h b/plugins/lttng-utils/debug-info/utils.h
deleted file mode 100644 (file)
index 82820fc..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H
-#define BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H
-/*
- * Babeltrace - Debug Info Utilities
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace-internal.h>
-#include "trace-ir-mapping.h"
-
-/*
- * Return the location of a path's file (the last element of the path).
- * Returns the original path on error.
- */
-BT_HIDDEN
-const char *get_filename_from_path(const char *path);
-
-BT_HIDDEN
-bt_bool is_event_common_ctx_dbg_info_compatible(
-               const bt_field_class *in_field_class,
-               const char *debug_info_field_class_name);
-
-#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H */
diff --git a/plugins/lttng-utils/plugin.c b/plugins/lttng-utils/plugin.c
deleted file mode 100644 (file)
index 8d50b0e..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * plugin.c
- *
- * Babeltrace Debug Info Plug-in
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include "debug-info/debug-info.h"
-
-#ifndef BT_BUILT_IN_PLUGINS
-BT_PLUGIN_MODULE();
-#endif
-
-/* Initialize plug-in entry points. */
-BT_PLUGIN_WITH_ID(lttng_utils, "lttng-utils");
-BT_PLUGIN_DESCRIPTION_WITH_ID(lttng_utils, "LTTng utilities");
-BT_PLUGIN_AUTHOR_WITH_ID(lttng_utils, "Julien Desfossez");
-BT_PLUGIN_LICENSE_WITH_ID(lttng_utils, "MIT");
-
-BT_PLUGIN_FILTER_COMPONENT_CLASS_WITH_ID(lttng_utils, debug_info, "debug-info",
-       debug_info_msg_iter_next);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION_WITH_ID(lttng_utils, debug_info,
-       "Augment compatible events with debugging information.");
-BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD_WITH_ID(lttng_utils,
-       debug_info, debug_info_comp_init);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD_WITH_ID(lttng_utils,
-       debug_info, debug_info_comp_finalize);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD_WITH_ID(
-       lttng_utils, debug_info, debug_info_msg_iter_init);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD_WITH_ID(
-       lttng_utils, debug_info, debug_info_msg_iter_seek_beginning);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CAN_SEEK_BEGINNING_METHOD_WITH_ID(
-       lttng_utils, debug_info, debug_info_msg_iter_can_seek_beginning);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD_WITH_ID(
-       lttng_utils, debug_info, debug_info_msg_iter_finalize);
diff --git a/plugins/plugins-common.h b/plugins/plugins-common.h
deleted file mode 100644 (file)
index c7377bf..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef PLUGINS_COMMON_H
-#define PLUGINS_COMMON_H
-
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * UNUSED_VAR: tag a variable or parameter as explicitly unused so that
- *             the compiler does not warn.
- */
-#define UNUSED_VAR __attribute__((unused))
-
-#endif /* PLUGINS_COMMON_H */
diff --git a/plugins/text/Makefile.am b/plugins/text/Makefile.am
deleted file mode 100644 (file)
index c9b26c2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-SUBDIRS = pretty dmesg
-
-plugindir = "$(PLUGINSDIR)"
-plugin_LTLIBRARIES = babeltrace-plugin-text.la
-
-babeltrace_plugin_text_la_SOURCES = plugin.c
-babeltrace_plugin_text_la_LDFLAGS = \
-       $(LT_NO_UNDEFINED) \
-       -avoid-version -module
-
-babeltrace_plugin_text_la_LIBADD = \
-       pretty/libbabeltrace2-plugin-text-pretty-cc.la \
-       dmesg/libbabeltrace2-plugin-text-dmesg-cc.la
-
-if !ENABLE_BUILT_IN_PLUGINS
-babeltrace_plugin_text_la_LIBADD += \
-       $(top_builddir)/lib/libbabeltrace2.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(top_builddir)/compat/libcompat.la
-endif
diff --git a/plugins/text/dmesg/Makefile.am b/plugins/text/dmesg/Makefile.am
deleted file mode 100644 (file)
index 6e0f12a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-text-dmesg-cc.la
-
-# ctf-text plugin
-libbabeltrace2_plugin_text_dmesg_cc_la_SOURCES = \
-       dmesg.c \
-       dmesg.h \
-       logging.h \
-       logging.c
diff --git a/plugins/text/dmesg/dmesg.c b/plugins/text/dmesg/dmesg.c
deleted file mode 100644 (file)
index b10c942..0000000
+++ /dev/null
@@ -1,927 +0,0 @@
-/*
- * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-TEXT-DMESG-SRC"
-#include "logging.h"
-
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/compat/utc-internal.h>
-#include <babeltrace2/compat/stdio-internal.h>
-#include <glib.h>
-
-#define NSEC_PER_USEC 1000UL
-#define NSEC_PER_MSEC 1000000UL
-#define NSEC_PER_SEC 1000000000ULL
-#define USEC_PER_SEC 1000000UL
-
-struct dmesg_component;
-
-struct dmesg_msg_iter {
-       struct dmesg_component *dmesg_comp;
-       bt_self_message_iterator *pc_msg_iter; /* Weak */
-       char *linebuf;
-       size_t linebuf_len;
-       FILE *fp;
-       bt_message *tmp_event_msg;
-       uint64_t last_clock_value;
-
-       enum {
-               STATE_EMIT_STREAM_BEGINNING,
-               STATE_EMIT_STREAM_ACTIVITY_BEGINNING,
-               STATE_EMIT_PACKET_BEGINNING,
-               STATE_EMIT_EVENT,
-               STATE_EMIT_PACKET_END,
-               STATE_EMIT_STREAM_ACTIVITY_END,
-               STATE_EMIT_STREAM_END,
-               STATE_DONE,
-       } state;
-};
-
-struct dmesg_component {
-       struct {
-               GString *path;
-               bt_bool read_from_stdin;
-               bt_bool no_timestamp;
-       } params;
-
-       bt_self_component_source *self_comp;
-       bt_trace_class *trace_class;
-       bt_stream_class *stream_class;
-       bt_event_class *event_class;
-       bt_trace *trace;
-       bt_stream *stream;
-       bt_packet *packet;
-       bt_clock_class *clock_class;
-};
-
-static
-bt_field_class *create_event_payload_fc(bt_trace_class *trace_class)
-{
-       bt_field_class *root_fc = NULL;
-       bt_field_class *fc = NULL;
-       int ret;
-
-       root_fc = bt_field_class_structure_create(trace_class);
-       if (!root_fc) {
-               BT_LOGE_STR("Cannot create an empty structure field class object.");
-               goto error;
-       }
-
-       fc = bt_field_class_string_create(trace_class);
-       if (!fc) {
-               BT_LOGE_STR("Cannot create a string field class object.");
-               goto error;
-       }
-
-       ret = bt_field_class_structure_append_member(root_fc,
-               "str", fc);
-       if (ret) {
-               BT_LOGE("Cannot add `str` member to structure field class: "
-                       "ret=%d", ret);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_FIELD_CLASS_PUT_REF_AND_RESET(root_fc);
-
-end:
-       bt_field_class_put_ref(fc);
-       return root_fc;
-}
-
-static
-int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
-{
-       bt_field_class *fc = NULL;
-       int ret = 0;
-
-       dmesg_comp->trace_class = bt_trace_class_create(
-               bt_self_component_source_as_self_component(
-                       dmesg_comp->self_comp));
-       if (!dmesg_comp->trace_class) {
-               BT_LOGE_STR("Cannot create an empty trace class object.");
-               goto error;
-       }
-
-       dmesg_comp->stream_class = bt_stream_class_create(
-               dmesg_comp->trace_class);
-       if (!dmesg_comp->stream_class) {
-               BT_LOGE_STR("Cannot create a stream class object.");
-               goto error;
-       }
-
-       if (has_ts) {
-               dmesg_comp->clock_class = bt_clock_class_create(
-                               bt_self_component_source_as_self_component(
-                                       dmesg_comp->self_comp));
-               if (!dmesg_comp->clock_class) {
-                       BT_LOGE_STR("Cannot create clock class.");
-                       goto error;
-               }
-
-               /*
-                * The `dmesg` timestamp's origin is not the Unix epoch,
-                * it's the boot time.
-                */
-               bt_clock_class_set_origin_is_unix_epoch(dmesg_comp->clock_class,
-                       BT_FALSE);
-
-               ret = bt_stream_class_set_default_clock_class(
-                       dmesg_comp->stream_class, dmesg_comp->clock_class);
-               if (ret) {
-                       BT_LOGE_STR("Cannot set stream class's default clock class.");
-                       goto error;
-               }
-
-               bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
-                       dmesg_comp->stream_class, BT_TRUE);
-               bt_stream_class_set_packets_have_end_default_clock_snapshot(
-                       dmesg_comp->stream_class, BT_TRUE);
-       }
-
-       dmesg_comp->event_class = bt_event_class_create(
-               dmesg_comp->stream_class);
-       if (!dmesg_comp->event_class) {
-               BT_LOGE_STR("Cannot create an event class object.");
-               goto error;
-       }
-
-       ret = bt_event_class_set_name(dmesg_comp->event_class, "string");
-       if (ret) {
-               BT_LOGE_STR("Cannot set event class's name.");
-               goto error;
-       }
-
-       fc = create_event_payload_fc(dmesg_comp->trace_class);
-       if (!fc) {
-               BT_LOGE_STR("Cannot create event payload field class.");
-               goto error;
-       }
-
-       ret = bt_event_class_set_payload_field_class(dmesg_comp->event_class, fc);
-       if (ret) {
-               BT_LOGE_STR("Cannot set event class's event payload field class.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       bt_field_class_put_ref(fc);
-       return ret;
-}
-
-static
-int handle_params(struct dmesg_component *dmesg_comp,
-               const bt_value *params)
-{
-       const bt_value *no_timestamp = NULL;
-       const bt_value *path = NULL;
-       const char *path_str;
-       int ret = 0;
-
-       no_timestamp = bt_value_map_borrow_entry_value_const(params,
-               "no-extract-timestamp");
-       if (no_timestamp) {
-               if (!bt_value_is_bool(no_timestamp)) {
-                       BT_LOGE("Expecting a boolean value for the `no-extract-timestamp` parameter: "
-                               "type=%s",
-                               bt_common_value_type_string(
-                                       bt_value_get_type(no_timestamp)));
-                       goto error;
-               }
-
-               dmesg_comp->params.no_timestamp =
-                       bt_value_bool_get(no_timestamp);
-       }
-
-       path = bt_value_map_borrow_entry_value_const(params, "path");
-       if (path) {
-               if (dmesg_comp->params.read_from_stdin) {
-                       BT_LOGE_STR("Cannot specify both `read-from-stdin` and `path` parameters.");
-                       goto error;
-               }
-
-               if (!bt_value_is_string(path)) {
-                       BT_LOGE("Expecting a string value for the `path` parameter: "
-                               "type=%s",
-                               bt_common_value_type_string(
-                                       bt_value_get_type(path)));
-                       goto error;
-               }
-
-               path_str = bt_value_string_get(path);
-               g_string_assign(dmesg_comp->params.path, path_str);
-       } else {
-               dmesg_comp->params.read_from_stdin = true;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int create_packet_and_stream_and_trace(struct dmesg_component *dmesg_comp)
-{
-       int ret = 0;
-       const char *trace_name = NULL;
-       gchar *basename = NULL;
-
-       dmesg_comp->trace = bt_trace_create(dmesg_comp->trace_class);
-       if (!dmesg_comp->trace) {
-               BT_LOGE_STR("Cannot create trace object.");
-               goto error;
-       }
-
-       if (dmesg_comp->params.read_from_stdin) {
-               trace_name = "STDIN";
-       } else {
-               basename = g_path_get_basename(dmesg_comp->params.path->str);
-               BT_ASSERT(basename);
-
-               if (strcmp(basename, G_DIR_SEPARATOR_S) != 0 &&
-                               strcmp(basename, ".") != 0) {
-                       trace_name = basename;
-               }
-       }
-
-       if (trace_name) {
-               ret = bt_trace_set_name(dmesg_comp->trace, trace_name);
-               if (ret) {
-                       BT_LOGE("Cannot set trace's name: name=\"%s\"",
-                               trace_name);
-                       goto error;
-               }
-       }
-
-       dmesg_comp->stream = bt_stream_create(dmesg_comp->stream_class,
-               dmesg_comp->trace);
-       if (!dmesg_comp->stream) {
-               BT_LOGE_STR("Cannot create stream object.");
-               goto error;
-       }
-
-       dmesg_comp->packet = bt_packet_create(dmesg_comp->stream);
-       if (!dmesg_comp->packet) {
-               BT_LOGE_STR("Cannot create packet object.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       if (basename) {
-               g_free(basename);
-       }
-
-       return ret;
-}
-
-static
-int try_create_meta_stream_packet(struct dmesg_component *dmesg_comp,
-               bool has_ts)
-{
-       int ret = 0;
-
-       if (dmesg_comp->trace) {
-               /* Already created */
-               goto end;
-       }
-
-       ret = create_meta(dmesg_comp, has_ts);
-       if (ret) {
-               BT_LOGE("Cannot create metadata objects: dmesg-comp-addr=%p",
-                       dmesg_comp);
-               goto error;
-       }
-
-       ret = create_packet_and_stream_and_trace(dmesg_comp);
-       if (ret) {
-               BT_LOGE("Cannot create packet and stream objects: "
-                       "dmesg-comp-addr=%p", dmesg_comp);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-void destroy_dmesg_component(struct dmesg_component *dmesg_comp)
-{
-       if (!dmesg_comp) {
-               return;
-       }
-
-       if (dmesg_comp->params.path) {
-               g_string_free(dmesg_comp->params.path, TRUE);
-       }
-
-       bt_packet_put_ref(dmesg_comp->packet);
-       bt_trace_put_ref(dmesg_comp->trace);
-       bt_stream_class_put_ref(dmesg_comp->stream_class);
-       bt_event_class_put_ref(dmesg_comp->event_class);
-       bt_stream_put_ref(dmesg_comp->stream);
-       bt_clock_class_put_ref(dmesg_comp->clock_class);
-       bt_trace_class_put_ref(dmesg_comp->trace_class);
-       g_free(dmesg_comp);
-}
-
-static
-bt_self_component_status create_port(
-               bt_self_component_source *self_comp)
-{
-       return bt_self_component_source_add_output_port(self_comp,
-               "out", NULL, NULL);
-}
-
-BT_HIDDEN
-bt_self_component_status dmesg_init(
-               bt_self_component_source *self_comp,
-               bt_value *params, void *init_method_data)
-{
-       int ret = 0;
-       struct dmesg_component *dmesg_comp = g_new0(struct dmesg_component, 1);
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-
-       if (!dmesg_comp) {
-               BT_LOGE_STR("Failed to allocate one dmesg component structure.");
-               goto error;
-       }
-
-       dmesg_comp->self_comp = self_comp;
-       dmesg_comp->params.path = g_string_new(NULL);
-       if (!dmesg_comp->params.path) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               goto error;
-       }
-
-       ret = handle_params(dmesg_comp, params);
-       if (ret) {
-               BT_LOGE("Invalid parameters: comp-addr=%p", self_comp);
-               goto error;
-       }
-
-       if (!dmesg_comp->params.read_from_stdin &&
-                       !g_file_test(dmesg_comp->params.path->str,
-                       G_FILE_TEST_IS_REGULAR)) {
-               BT_LOGE("Input path is not a regular file: "
-                       "comp-addr=%p, path=\"%s\"", self_comp,
-                       dmesg_comp->params.path->str);
-               goto error;
-       }
-
-       status = create_port(self_comp);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-
-       bt_self_component_set_data(
-               bt_self_component_source_as_self_component(self_comp),
-               dmesg_comp);
-       goto end;
-
-error:
-       destroy_dmesg_component(dmesg_comp);
-       bt_self_component_set_data(
-               bt_self_component_source_as_self_component(self_comp),
-               NULL);
-
-       if (status >= 0) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-       }
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-void dmesg_finalize(bt_self_component_source *self_comp)
-{
-       destroy_dmesg_component(bt_self_component_get_data(
-               bt_self_component_source_as_self_component(self_comp)));
-}
-
-static
-bt_message *create_init_event_msg_from_line(
-               struct dmesg_msg_iter *msg_iter,
-               const char *line, const char **new_start)
-{
-       bt_event *event;
-       bt_message *msg = NULL;
-       bool has_timestamp = false;
-       unsigned long sec, usec, msec;
-       unsigned int year, mon, mday, hour, min;
-       uint64_t ts = 0;
-       int ret = 0;
-       struct dmesg_component *dmesg_comp = msg_iter->dmesg_comp;
-
-       *new_start = line;
-
-       if (dmesg_comp->params.no_timestamp) {
-               goto skip_ts;
-       }
-
-       /* Extract time from input line */
-       if (sscanf(line, "[%lu.%lu] ", &sec, &usec) == 2) {
-               ts = (uint64_t) sec * USEC_PER_SEC + (uint64_t) usec;
-
-               /*
-                * The clock class we use has a 1 GHz frequency: convert
-                * from µs to ns.
-                */
-               ts *= NSEC_PER_USEC;
-               has_timestamp = true;
-       } else if (sscanf(line, "[%u-%u-%u %u:%u:%lu.%lu] ",
-                       &year, &mon, &mday, &hour, &min,
-                       &sec, &msec) == 7) {
-               time_t ep_sec;
-               struct tm ti;
-
-               memset(&ti, 0, sizeof(ti));
-               ti.tm_year = year - 1900;       /* From 1900 */
-               ti.tm_mon = mon - 1;            /* 0 to 11 */
-               ti.tm_mday = mday;
-               ti.tm_hour = hour;
-               ti.tm_min = min;
-               ti.tm_sec = sec;
-
-               ep_sec = bt_timegm(&ti);
-               if (ep_sec != (time_t) -1) {
-                       ts = (uint64_t) ep_sec * NSEC_PER_SEC
-                               + (uint64_t) msec * NSEC_PER_MSEC;
-               }
-
-               has_timestamp = true;
-       }
-
-       if (has_timestamp) {
-               /* Set new start for the message portion of the line */
-               *new_start = strchr(line, ']');
-               BT_ASSERT(*new_start);
-               (*new_start)++;
-
-               if ((*new_start)[0] == ' ') {
-                       (*new_start)++;
-               }
-       }
-
-skip_ts:
-       /*
-        * At this point, we know if the stream class's event header
-        * field class should have a timestamp or not, so we can lazily
-        * create the metadata, stream, and packet objects.
-        */
-       ret = try_create_meta_stream_packet(dmesg_comp, has_timestamp);
-       if (ret) {
-               /* try_create_meta_stream_packet() logs errors */
-               goto error;
-       }
-
-       if (dmesg_comp->clock_class) {
-               msg = bt_message_event_create_with_default_clock_snapshot(
-                       msg_iter->pc_msg_iter,
-                       dmesg_comp->event_class, dmesg_comp->packet, ts);
-               msg_iter->last_clock_value = ts;
-       } else {
-               msg = bt_message_event_create(msg_iter->pc_msg_iter,
-                       dmesg_comp->event_class, dmesg_comp->packet);
-       }
-
-       if (!msg) {
-               BT_LOGE_STR("Cannot create event message.");
-               goto error;
-       }
-
-       event = bt_message_event_borrow_event(msg);
-       BT_ASSERT(event);
-       goto end;
-
-error:
-       BT_MESSAGE_PUT_REF_AND_RESET(msg);
-
-end:
-       return msg;
-}
-
-static
-int fill_event_payload_from_line(const char *line,
-               bt_event *event)
-{
-       bt_field *ep_field = NULL;
-       bt_field *str_field = NULL;
-       size_t len;
-       int ret;
-
-       ep_field = bt_event_borrow_payload_field(event);
-       BT_ASSERT(ep_field);
-       str_field = bt_field_structure_borrow_member_field_by_index(
-               ep_field, 0);
-       if (!str_field) {
-               BT_LOGE_STR("Cannot borrow `timestamp` field from event payload structure field.");
-               goto error;
-       }
-
-       len = strlen(line);
-       if (line[len - 1] == '\n') {
-               /* Do not include the newline character in the payload */
-               len--;
-       }
-
-       ret = bt_field_string_clear(str_field);
-       if (ret) {
-               BT_LOGE_STR("Cannot clear string field object.");
-               goto error;
-       }
-
-       ret = bt_field_string_append_with_length(str_field, line, len);
-       if (ret) {
-               BT_LOGE("Cannot append value to string field object: "
-                       "len=%zu", len);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-bt_message *create_msg_from_line(
-               struct dmesg_msg_iter *dmesg_msg_iter, const char *line)
-{
-       bt_event *event = NULL;
-       bt_message *msg = NULL;
-       const char *new_start;
-       int ret;
-
-       msg = create_init_event_msg_from_line(dmesg_msg_iter,
-               line, &new_start);
-       if (!msg) {
-               BT_LOGE_STR("Cannot create and initialize event message from line.");
-               goto error;
-       }
-
-       event = bt_message_event_borrow_event(msg);
-       BT_ASSERT(event);
-       ret = fill_event_payload_from_line(new_start, event);
-       if (ret) {
-               BT_LOGE("Cannot fill event payload field from line: "
-                       "ret=%d", ret);
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_MESSAGE_PUT_REF_AND_RESET(msg);
-
-end:
-       return msg;
-}
-
-static
-void destroy_dmesg_msg_iter(struct dmesg_msg_iter *dmesg_msg_iter)
-{
-       if (!dmesg_msg_iter) {
-               return;
-       }
-
-       if (dmesg_msg_iter->fp && dmesg_msg_iter->fp != stdin) {
-               if (fclose(dmesg_msg_iter->fp)) {
-                       BT_LOGE_ERRNO("Cannot close input file", ".");
-               }
-       }
-
-       bt_message_put_ref(dmesg_msg_iter->tmp_event_msg);
-       free(dmesg_msg_iter->linebuf);
-       g_free(dmesg_msg_iter);
-}
-
-
-
-BT_HIDDEN
-bt_self_message_iterator_status dmesg_msg_iter_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_source *self_comp,
-               bt_self_component_port_output *self_port)
-{
-       struct dmesg_component *dmesg_comp;
-       struct dmesg_msg_iter *dmesg_msg_iter =
-               g_new0(struct dmesg_msg_iter, 1);
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       if (!dmesg_msg_iter) {
-               BT_LOGE_STR("Failed to allocate on dmesg message iterator structure.");
-               goto error;
-       }
-
-       dmesg_comp = bt_self_component_get_data(
-               bt_self_component_source_as_self_component(self_comp));
-       BT_ASSERT(dmesg_comp);
-       dmesg_msg_iter->dmesg_comp = dmesg_comp;
-       dmesg_msg_iter->pc_msg_iter = self_msg_iter;
-
-       if (dmesg_comp->params.read_from_stdin) {
-               dmesg_msg_iter->fp = stdin;
-       } else {
-               dmesg_msg_iter->fp = fopen(dmesg_comp->params.path->str, "r");
-               if (!dmesg_msg_iter->fp) {
-                       BT_LOGE_ERRNO("Cannot open input file in read mode", ": path=\"%s\"",
-                               dmesg_comp->params.path->str);
-                       goto error;
-               }
-       }
-
-       bt_self_message_iterator_set_data(self_msg_iter,
-               dmesg_msg_iter);
-       goto end;
-
-error:
-       destroy_dmesg_msg_iter(dmesg_msg_iter);
-       bt_self_message_iterator_set_data(self_msg_iter, NULL);
-       if (status >= 0) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-       }
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-void dmesg_msg_iter_finalize(
-               bt_self_message_iterator *priv_msg_iter)
-{
-       destroy_dmesg_msg_iter(bt_self_message_iterator_get_data(
-               priv_msg_iter));
-}
-
-static
-bt_self_message_iterator_status dmesg_msg_iter_next_one(
-               struct dmesg_msg_iter *dmesg_msg_iter,
-               bt_message **msg)
-{
-       ssize_t len;
-       struct dmesg_component *dmesg_comp;
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_ASSERT(dmesg_msg_iter);
-       dmesg_comp = dmesg_msg_iter->dmesg_comp;
-       BT_ASSERT(dmesg_comp);
-
-       if (dmesg_msg_iter->state == STATE_DONE) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-               goto end;
-       }
-
-       if (dmesg_msg_iter->tmp_event_msg ||
-                       dmesg_msg_iter->state == STATE_EMIT_PACKET_END ||
-                       dmesg_msg_iter->state == STATE_EMIT_STREAM_ACTIVITY_END ||
-                       dmesg_msg_iter->state == STATE_EMIT_STREAM_END) {
-               goto handle_state;
-       }
-
-       while (true) {
-               const char *ch;
-               bool only_spaces = true;
-
-               len = bt_getline(&dmesg_msg_iter->linebuf,
-                       &dmesg_msg_iter->linebuf_len, dmesg_msg_iter->fp);
-               if (len < 0) {
-                       if (errno == EINVAL) {
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                       } else if (errno == ENOMEM) {
-                               status =
-                                       BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-                       } else {
-                               if (dmesg_msg_iter->state == STATE_EMIT_STREAM_BEGINNING) {
-                                       /* Stream did not even begin */
-                                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-                                       goto end;
-                               } else {
-                                       /* End current packet now */
-                                       dmesg_msg_iter->state =
-                                               STATE_EMIT_PACKET_END;
-                                       goto handle_state;
-                               }
-                       }
-
-                       goto end;
-               }
-
-               BT_ASSERT(dmesg_msg_iter->linebuf);
-
-               /* Ignore empty lines, once trimmed */
-               for (ch = dmesg_msg_iter->linebuf; *ch != '\0'; ch++) {
-                       if (!isspace(*ch)) {
-                               only_spaces = false;
-                               break;
-                       }
-               }
-
-               if (!only_spaces) {
-                       break;
-               }
-       }
-
-       dmesg_msg_iter->tmp_event_msg = create_msg_from_line(
-               dmesg_msg_iter, dmesg_msg_iter->linebuf);
-       if (!dmesg_msg_iter->tmp_event_msg) {
-               BT_LOGE("Cannot create event message from line: "
-                       "dmesg-comp-addr=%p, line=\"%s\"", dmesg_comp,
-                       dmesg_msg_iter->linebuf);
-               goto end;
-       }
-
-handle_state:
-       BT_ASSERT(dmesg_comp->trace);
-
-       switch (dmesg_msg_iter->state) {
-       case STATE_EMIT_STREAM_BEGINNING:
-               BT_ASSERT(dmesg_msg_iter->tmp_event_msg);
-               *msg = bt_message_stream_beginning_create(
-                       dmesg_msg_iter->pc_msg_iter, dmesg_comp->stream);
-               dmesg_msg_iter->state = STATE_EMIT_STREAM_ACTIVITY_BEGINNING;
-               break;
-       case STATE_EMIT_STREAM_ACTIVITY_BEGINNING:
-               BT_ASSERT(dmesg_msg_iter->tmp_event_msg);
-               *msg = bt_message_stream_activity_beginning_create(
-                       dmesg_msg_iter->pc_msg_iter, dmesg_comp->stream);
-               dmesg_msg_iter->state = STATE_EMIT_PACKET_BEGINNING;
-               break;
-       case STATE_EMIT_PACKET_BEGINNING:
-               BT_ASSERT(dmesg_msg_iter->tmp_event_msg);
-
-               if (dmesg_comp->clock_class) {
-                       *msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
-                               dmesg_msg_iter->pc_msg_iter, dmesg_comp->packet,
-                               dmesg_msg_iter->last_clock_value);
-               } else {
-                       *msg = bt_message_packet_beginning_create(
-                               dmesg_msg_iter->pc_msg_iter, dmesg_comp->packet);
-               }
-
-               dmesg_msg_iter->state = STATE_EMIT_EVENT;
-               break;
-       case STATE_EMIT_EVENT:
-               BT_ASSERT(dmesg_msg_iter->tmp_event_msg);
-               *msg = dmesg_msg_iter->tmp_event_msg;
-               dmesg_msg_iter->tmp_event_msg = NULL;
-               break;
-       case STATE_EMIT_PACKET_END:
-               if (dmesg_comp->clock_class) {
-                       *msg = bt_message_packet_end_create_with_default_clock_snapshot(
-                               dmesg_msg_iter->pc_msg_iter, dmesg_comp->packet,
-                               dmesg_msg_iter->last_clock_value);
-               } else {
-                       *msg = bt_message_packet_end_create(
-                               dmesg_msg_iter->pc_msg_iter, dmesg_comp->packet);
-               }
-
-               dmesg_msg_iter->state = STATE_EMIT_STREAM_ACTIVITY_END;
-               break;
-       case STATE_EMIT_STREAM_ACTIVITY_END:
-               *msg = bt_message_stream_activity_end_create(
-                       dmesg_msg_iter->pc_msg_iter, dmesg_comp->stream);
-               dmesg_msg_iter->state = STATE_EMIT_STREAM_END;
-               break;
-       case STATE_EMIT_STREAM_END:
-               *msg = bt_message_stream_end_create(
-                       dmesg_msg_iter->pc_msg_iter, dmesg_comp->stream);
-               dmesg_msg_iter->state = STATE_DONE;
-               break;
-       default:
-               break;
-       }
-
-       if (!*msg) {
-               BT_LOGE("Cannot create message: dmesg-comp-addr=%p",
-                       dmesg_comp);
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-       }
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status dmesg_msg_iter_next(
-               bt_self_message_iterator *self_msg_iter,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       struct dmesg_msg_iter *dmesg_msg_iter =
-               bt_self_message_iterator_get_data(
-                       self_msg_iter);
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       uint64_t i = 0;
-
-       while (i < capacity &&
-                       status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-               bt_message *priv_msg = NULL;
-
-               status = dmesg_msg_iter_next_one(dmesg_msg_iter,
-                       &priv_msg);
-               msgs[i] = priv_msg;
-               if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                       i++;
-               }
-       }
-
-       if (i > 0) {
-               /*
-                * Even if dmesg_msg_iter_next_one() returned
-                * something else than
-                * BT_SELF_MESSAGE_ITERATOR_STATUS_OK, we
-                * accumulated message objects in the output
-                * message array, so we need to return
-                * BT_SELF_MESSAGE_ITERATOR_STATUS_OK so that they
-                * are transfered to downstream. This other status
-                * occurs again the next time muxer_msg_iter_do_next()
-                * is called, possibly without any accumulated
-                * message, in which case we'll return it.
-                */
-               *count = i;
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-bt_bool dmesg_msg_iter_can_seek_beginning(
-               bt_self_message_iterator *self_msg_iter)
-{
-       struct dmesg_msg_iter *dmesg_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_iter);
-
-       /* Can't seek the beginning of the standard input stream */
-       return !dmesg_msg_iter->dmesg_comp->params.read_from_stdin;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status dmesg_msg_iter_seek_beginning(
-               bt_self_message_iterator *self_msg_iter)
-{
-       struct dmesg_msg_iter *dmesg_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_iter);
-
-       BT_ASSERT(!dmesg_msg_iter->dmesg_comp->params.read_from_stdin);
-
-       BT_MESSAGE_PUT_REF_AND_RESET(dmesg_msg_iter->tmp_event_msg);
-       dmesg_msg_iter->last_clock_value = 0;
-       dmesg_msg_iter->state = STATE_EMIT_STREAM_BEGINNING;
-       return BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-}
diff --git a/plugins/text/dmesg/dmesg.h b/plugins/text/dmesg/dmesg.h
deleted file mode 100644 (file)
index 6e75ea4..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H
-#define BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H
-
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdbool.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-BT_HIDDEN
-bt_self_component_status dmesg_init(
-               bt_self_component_source *self_comp,
-               const bt_value *params, void *init_method_data);
-
-BT_HIDDEN
-void dmesg_finalize(bt_self_component_source *self_comp);
-
-BT_HIDDEN
-bt_self_message_iterator_status dmesg_msg_iter_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_source *self_comp,
-               bt_self_component_port_output *self_port);
-
-BT_HIDDEN
-void dmesg_msg_iter_finalize(
-               bt_self_message_iterator *self_msg_iter);
-
-BT_HIDDEN
-bt_self_message_iterator_status dmesg_msg_iter_next(
-               bt_self_message_iterator *self_msg_iter,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count);
-
-BT_HIDDEN
-bt_bool dmesg_msg_iter_can_seek_beginning(
-               bt_self_message_iterator *message_iterator);
-
-BT_HIDDEN
-bt_self_message_iterator_status dmesg_msg_iter_seek_beginning(
-               bt_self_message_iterator *message_iterator);
-
-#endif /* BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H */
diff --git a/plugins/text/dmesg/logging.c b/plugins/text/dmesg/logging.c
deleted file mode 100644 (file)
index 3df7f49..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_text_dmesg_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_plugin_text_dmesg_log_level,
-       "BABELTRACE_SRC_TEXT_DMESG_LOG_LEVEL");
diff --git a/plugins/text/dmesg/logging.h b/plugins/text/dmesg/logging.h
deleted file mode 100644 (file)
index 564479d..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef PLUGINS_TEXT_DMESG_LOG_LEVEL
-#define PLUGINS_TEXT_DMESG_LOG_LEVEL
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_text_dmesg_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_text_dmesg_log_level);
-
-#endif /* PLUGINS_TEXT_DMESG_LOG_LEVEL */
diff --git a/plugins/text/plugin.c b/plugins/text/plugin.c
deleted file mode 100644 (file)
index 17f814b..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include "pretty/pretty.h"
-#include "dmesg/dmesg.h"
-
-#ifndef BT_BUILT_IN_PLUGINS
-BT_PLUGIN_MODULE();
-#endif
-
-BT_PLUGIN(text);
-BT_PLUGIN_DESCRIPTION("Plain text component classes");
-BT_PLUGIN_AUTHOR("Julien Desfossez, Mathieu Desnoyers, Philippe Proulx");
-BT_PLUGIN_LICENSE("MIT");
-
-/* pretty sink */
-BT_PLUGIN_SINK_COMPONENT_CLASS(pretty, pretty_consume);
-BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(pretty, pretty_init);
-BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(pretty, pretty_finalize);
-BT_PLUGIN_SINK_COMPONENT_CLASS_GRAPH_IS_CONFIGURED_METHOD(pretty,
-       pretty_graph_is_configured);
-BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(pretty,
-       "Pretty-print messages (`text` format of Babeltrace 1).");
-
-/* dmesg source */
-BT_PLUGIN_SOURCE_COMPONENT_CLASS(dmesg, dmesg_msg_iter_next);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION(dmesg,
-       "Read a dmesg output from a file or from standard input.");
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_INIT_METHOD(dmesg, dmesg_init);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD(dmesg, dmesg_finalize);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD(dmesg,
-       dmesg_msg_iter_init);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD(dmesg,
-       dmesg_msg_iter_finalize);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD(dmesg,
-       dmesg_msg_iter_seek_beginning);
-BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_CAN_SEEK_BEGINNING_METHOD(dmesg,
-       dmesg_msg_iter_can_seek_beginning);
diff --git a/plugins/text/pretty/Makefile.am b/plugins/text/pretty/Makefile.am
deleted file mode 100644 (file)
index 72c0ab1..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-text-pretty-cc.la
-
-# ctf-text plugin
-libbabeltrace2_plugin_text_pretty_cc_la_SOURCES = \
-       logging.c \
-       logging.h \
-       pretty.c \
-       pretty.h \
-       print.c
diff --git a/plugins/text/pretty/logging.c b/plugins/text/pretty/logging.c
deleted file mode 100644 (file)
index 37beb6d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_text_pretty_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_plugin_text_pretty_log_level,
-       "BABELTRACE_SINK_TEXT_PRETTY_LOG_LEVEL");
diff --git a/plugins/text/pretty/logging.h b/plugins/text/pretty/logging.h
deleted file mode 100644 (file)
index 5ac1f7b..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef PLUGINS_TEXT_PRETTY_LOG_LEVEL
-#define PLUGINS_TEXT_PRETTY_LOG_LEVEL
-
-/*
- * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_text_pretty_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_text_pretty_log_level);
-
-#endif /* PLUGINS_TEXT_PRETTY_LOG_LEVEL */
diff --git a/plugins/text/pretty/pretty.c b/plugins/text/pretty/pretty.c
deleted file mode 100644 (file)
index 7c54839..0000000
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-TEXT-PRETTY-SINK"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <plugins-common.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <glib.h>
-#include <babeltrace2/assert-internal.h>
-
-#include "pretty.h"
-
-GQuark stream_packet_context_quarks[STREAM_PACKET_CONTEXT_QUARKS_LEN];
-
-static
-const char *plugin_options[] = {
-       "color",
-       "path",
-       "no-delta",
-       "clock-cycles",
-       "clock-seconds",
-       "clock-date",
-       "clock-gmt",
-       "verbose",
-       "name-default",         /* show/hide */
-       "name-payload",
-       "name-context",
-       "name-scope",
-       "name-header",
-       "field-default",        /* show/hide */
-       "field-trace",
-       "field-trace:hostname",
-       "field-trace:domain",
-       "field-trace:procname",
-       "field-trace:vpid",
-       "field-loglevel",
-       "field-emf",
-       "field-callsite",
-};
-
-static
-const char * const in_port_name = "in";
-
-static
-void destroy_pretty_data(struct pretty_component *pretty)
-{
-       bt_self_component_port_input_message_iterator_put_ref(pretty->iterator);
-
-       if (pretty->string) {
-               (void) g_string_free(pretty->string, TRUE);
-       }
-
-       if (pretty->tmp_string) {
-               (void) g_string_free(pretty->tmp_string, TRUE);
-       }
-
-       if (pretty->out != stdout) {
-               int ret;
-
-               ret = fclose(pretty->out);
-               if (ret) {
-                       perror("close output file");
-               }
-       }
-       g_free(pretty->options.output_path);
-       g_free(pretty);
-}
-
-static
-struct pretty_component *create_pretty(void)
-{
-       struct pretty_component *pretty;
-
-       pretty = g_new0(struct pretty_component, 1);
-       if (!pretty) {
-               goto end;
-       }
-       pretty->string = g_string_new("");
-       if (!pretty->string) {
-               goto error;
-       }
-       pretty->tmp_string = g_string_new("");
-       if (!pretty->tmp_string) {
-               goto error;
-       }
-end:
-       return pretty;
-
-error:
-       g_free(pretty);
-       return NULL;
-}
-
-BT_HIDDEN
-void pretty_finalize(bt_self_component_sink *comp)
-{
-       destroy_pretty_data(
-               bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(comp)));
-}
-
-static
-bt_self_component_status handle_message(
-               struct pretty_component *pretty,
-               const bt_message *message)
-{
-       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
-
-       BT_ASSERT(pretty);
-
-       switch (bt_message_get_type(message)) {
-       case BT_MESSAGE_TYPE_EVENT:
-               if (pretty_print_event(pretty, message)) {
-                       ret = BT_SELF_COMPONENT_STATUS_ERROR;
-               }
-               break;
-       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-               BT_LOGD_STR("Message iterator inactivity message.");
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-               if (pretty_print_discarded_items(pretty, message)) {
-                       ret = BT_SELF_COMPONENT_STATUS_ERROR;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-bt_self_component_status pretty_graph_is_configured(
-               bt_self_component_sink *comp)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct pretty_component *pretty;
-
-       pretty = bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(comp));
-       BT_ASSERT(pretty);
-       BT_ASSERT(!pretty->iterator);
-       pretty->iterator = bt_self_component_port_input_message_iterator_create(
-               bt_self_component_sink_borrow_input_port_by_name(comp,
-                       in_port_name));
-       if (!pretty->iterator) {
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-bt_self_component_status pretty_consume(
-               bt_self_component_sink *comp)
-{
-       bt_self_component_status ret;
-       bt_message_array_const msgs;
-       bt_self_component_port_input_message_iterator *it;
-       struct pretty_component *pretty = bt_self_component_get_data(
-               bt_self_component_sink_as_self_component(comp));
-       bt_message_iterator_status it_ret;
-       uint64_t count = 0;
-       uint64_t i = 0;
-
-       it = pretty->iterator;
-       it_ret = bt_self_component_port_input_message_iterator_next(it,
-               &msgs, &count);
-
-       switch (it_ret) {
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               ret = BT_SELF_COMPONENT_STATUS_AGAIN;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_END:
-               ret = BT_SELF_COMPONENT_STATUS_END;
-               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
-                       pretty->iterator);
-               goto end;
-       default:
-               ret = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       BT_ASSERT(it_ret == BT_MESSAGE_ITERATOR_STATUS_OK);
-
-       for (i = 0; i < count; i++) {
-               ret = handle_message(pretty, msgs[i]);
-               if (ret) {
-                       goto end;
-               }
-
-               bt_message_put_ref(msgs[i]);
-       }
-
-end:
-       for (; i < count; i++) {
-               bt_message_put_ref(msgs[i]);
-       }
-
-       return ret;
-}
-
-static
-int add_params_to_map(bt_value *plugin_opt_map)
-{
-       int ret = 0;
-       unsigned int i;
-
-       for (i = 0; i < BT_ARRAY_SIZE(plugin_options); i++) {
-               const char *key = plugin_options[i];
-               bt_value_status status;
-
-               status = bt_value_map_insert_entry(plugin_opt_map, key,
-                       bt_value_null);
-               switch (status) {
-               case BT_VALUE_STATUS_OK:
-                       break;
-               default:
-                       ret = -1;
-                       goto end;
-               }
-       }
-end:
-       return ret;
-}
-
-static
-bt_bool check_param_exists(const char *key, const bt_value *object,
-               void *data)
-{
-       struct pretty_component *pretty = data;
-
-       if (!bt_value_map_has_entry(pretty->plugin_opt_map,
-                                   key)) {
-               fprintf(pretty->err,
-                       "[warning] Parameter \"%s\" unknown to \"text.pretty\" sink component\n", key);
-       }
-       return BT_TRUE;
-}
-
-static
-void apply_one_string(const char *key, const bt_value *params, char **option)
-{
-       const bt_value *value = NULL;
-       const char *str;
-
-       value = bt_value_map_borrow_entry_value_const(params, key);
-       if (!value) {
-               goto end;
-       }
-       if (bt_value_is_null(value)) {
-               goto end;
-       }
-       str = bt_value_string_get(value);
-       *option = g_strdup(str);
-
-end:
-       return;
-}
-
-static
-void apply_one_bool(const char *key, const bt_value *params, bool *option,
-               bool *found)
-{
-       const bt_value *value = NULL;
-       bt_bool bool_val;
-
-       value = bt_value_map_borrow_entry_value_const(params, key);
-       if (!value) {
-               goto end;
-       }
-       bool_val = bt_value_bool_get(value);
-       *option = (bool) bool_val;
-       if (found) {
-               *found = true;
-       }
-
-end:
-       return;
-}
-
-static
-void warn_wrong_color_param(struct pretty_component *pretty)
-{
-       fprintf(pretty->err,
-               "[warning] Accepted values for the \"color\" parameter are:\n    \"always\", \"auto\", \"never\"\n");
-}
-
-static
-int open_output_file(struct pretty_component *pretty)
-{
-       int ret = 0;
-
-       if (!pretty->options.output_path) {
-               goto end;
-       }
-
-       pretty->out = fopen(pretty->options.output_path, "w");
-       if (!pretty->out) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-int apply_params(struct pretty_component *pretty, const bt_value *params)
-{
-       int ret = 0;
-       bt_value_status status;
-       bool value, found;
-       char *str = NULL;
-
-       pretty->plugin_opt_map = bt_value_map_create();
-       if (!pretty->plugin_opt_map) {
-               ret = -1;
-               goto end;
-       }
-       ret = add_params_to_map(pretty->plugin_opt_map);
-       if (ret) {
-               goto end;
-       }
-       /* Report unknown parameters. */
-       status = bt_value_map_foreach_entry_const(params,
-               check_param_exists, pretty);
-       switch (status) {
-       case BT_VALUE_STATUS_OK:
-               break;
-       default:
-               ret = -1;
-               goto end;
-       }
-       /* Known parameters. */
-       pretty->options.color = PRETTY_COLOR_OPT_AUTO;
-       if (bt_value_map_has_entry(params, "color")) {
-               const bt_value *color_value;
-               const char *color;
-
-               color_value = bt_value_map_borrow_entry_value_const(params,
-                       "color");
-               if (!color_value) {
-                       goto end;
-               }
-
-               color = bt_value_string_get(color_value);
-
-               if (strcmp(color, "never") == 0) {
-                       pretty->options.color = PRETTY_COLOR_OPT_NEVER;
-               } else if (strcmp(color, "auto") == 0) {
-                       pretty->options.color = PRETTY_COLOR_OPT_AUTO;
-               } else if (strcmp(color, "always") == 0) {
-                       pretty->options.color = PRETTY_COLOR_OPT_ALWAYS;
-               } else {
-                       warn_wrong_color_param(pretty);
-               }
-       }
-
-       apply_one_string("path", params, &pretty->options.output_path);
-       ret = open_output_file(pretty);
-       if (ret) {
-               goto end;
-       }
-
-       value = false;          /* Default. */
-       apply_one_bool("no-delta", params, &value, NULL);
-       pretty->options.print_delta_field = !value;     /* Reverse logic. */
-
-       value = false;          /* Default. */
-       apply_one_bool("clock-cycles", params, &value, NULL);
-       pretty->options.print_timestamp_cycles = value;
-
-       value = false;          /* Default. */
-       apply_one_bool("clock-seconds", params, &value, NULL);
-       pretty->options.clock_seconds = value;
-
-       value = false;          /* Default. */
-       apply_one_bool("clock-date", params, &value, NULL);
-       pretty->options.clock_date = value;
-
-       value = false;          /* Default. */
-       apply_one_bool("clock-gmt", params, &value, NULL);
-       pretty->options.clock_gmt = value;
-
-       value = false;          /* Default. */
-       apply_one_bool("verbose", params, &value, NULL);
-       pretty->options.verbose = value;
-
-       /* Names. */
-       apply_one_string("name-default", params, &str);
-       if (!str) {
-               pretty->options.name_default = PRETTY_DEFAULT_UNSET;
-       } else if (!strcmp(str, "show")) {
-               pretty->options.name_default = PRETTY_DEFAULT_SHOW;
-       } else if (!strcmp(str, "hide")) {
-               pretty->options.name_default = PRETTY_DEFAULT_HIDE;
-       } else {
-               ret = -1;
-               goto end;
-       }
-       g_free(str);
-       str = NULL;
-
-       switch (pretty->options.name_default) {
-       case PRETTY_DEFAULT_UNSET:
-               pretty->options.print_payload_field_names = true;
-               pretty->options.print_context_field_names = true;
-               pretty->options.print_header_field_names = false;
-               pretty->options.print_scope_field_names = false;
-               break;
-       case PRETTY_DEFAULT_SHOW:
-               pretty->options.print_payload_field_names = true;
-               pretty->options.print_context_field_names = true;
-               pretty->options.print_header_field_names = true;
-               pretty->options.print_scope_field_names = true;
-               break;
-       case PRETTY_DEFAULT_HIDE:
-               pretty->options.print_payload_field_names = false;
-               pretty->options.print_context_field_names = false;
-               pretty->options.print_header_field_names = false;
-               pretty->options.print_scope_field_names = false;
-               break;
-       default:
-               ret = -1;
-               goto end;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("name-payload", params, &value, &found);
-       if (found) {
-               pretty->options.print_payload_field_names = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("name-context", params, &value, &found);
-       if (found) {
-               pretty->options.print_context_field_names = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("name-header", params, &value, &found);
-       if (found) {
-               pretty->options.print_header_field_names = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("name-scope", params, &value, &found);
-       if (found) {
-               pretty->options.print_scope_field_names = value;
-       }
-
-       /* Fields. */
-       apply_one_string("field-default", params, &str);
-       if (!str) {
-               pretty->options.field_default = PRETTY_DEFAULT_UNSET;
-       } else if (!strcmp(str, "show")) {
-               pretty->options.field_default = PRETTY_DEFAULT_SHOW;
-       } else if (!strcmp(str, "hide")) {
-               pretty->options.field_default = PRETTY_DEFAULT_HIDE;
-       } else {
-               ret = -1;
-               goto end;
-       }
-       g_free(str);
-       str = NULL;
-
-       switch (pretty->options.field_default) {
-       case PRETTY_DEFAULT_UNSET:
-               pretty->options.print_trace_field = false;
-               pretty->options.print_trace_hostname_field = true;
-               pretty->options.print_trace_domain_field = false;
-               pretty->options.print_trace_procname_field = true;
-               pretty->options.print_trace_vpid_field = true;
-               pretty->options.print_loglevel_field = false;
-               pretty->options.print_emf_field = false;
-               pretty->options.print_callsite_field = false;
-               break;
-       case PRETTY_DEFAULT_SHOW:
-               pretty->options.print_trace_field = true;
-               pretty->options.print_trace_hostname_field = true;
-               pretty->options.print_trace_domain_field = true;
-               pretty->options.print_trace_procname_field = true;
-               pretty->options.print_trace_vpid_field = true;
-               pretty->options.print_loglevel_field = true;
-               pretty->options.print_emf_field = true;
-               pretty->options.print_callsite_field = true;
-               break;
-       case PRETTY_DEFAULT_HIDE:
-               pretty->options.print_trace_field = false;
-               pretty->options.print_trace_hostname_field = false;
-               pretty->options.print_trace_domain_field = false;
-               pretty->options.print_trace_procname_field = false;
-               pretty->options.print_trace_vpid_field = false;
-               pretty->options.print_loglevel_field = false;
-               pretty->options.print_emf_field = false;
-               pretty->options.print_callsite_field = false;
-               break;
-       default:
-               ret = -1;
-               goto end;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("field-trace", params, &value, &found);
-       if (found) {
-               pretty->options.print_trace_field = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("field-trace:hostname", params, &value, &found);
-       if (found) {
-               pretty->options.print_trace_hostname_field = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("field-trace:domain", params, &value, &found);
-       if (found) {
-               pretty->options.print_trace_domain_field = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("field-trace:procname", params, &value, &found);
-       if (found) {
-               pretty->options.print_trace_procname_field = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("field-trace:vpid", params, &value, &found);
-       if (found) {
-               pretty->options.print_trace_vpid_field = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("field-loglevel", params, &value, &found);
-       if (found) {
-               pretty->options.print_loglevel_field = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("field-emf", params, &value, &found);
-       if (found) {
-               pretty->options.print_emf_field = value;
-       }
-
-       value = false;
-       found = false;
-       apply_one_bool("field-callsite", params, &value, &found);
-       if (found) {
-               pretty->options.print_callsite_field = value;
-       }
-
-end:
-       bt_value_put_ref(pretty->plugin_opt_map);
-       pretty->plugin_opt_map = NULL;
-       g_free(str);
-       return ret;
-}
-
-static
-void set_use_colors(struct pretty_component *pretty)
-{
-       switch (pretty->options.color) {
-       case PRETTY_COLOR_OPT_ALWAYS:
-               pretty->use_colors = true;
-               break;
-       case PRETTY_COLOR_OPT_AUTO:
-               pretty->use_colors = pretty->out == stdout &&
-                       bt_common_colors_supported();
-               break;
-       case PRETTY_COLOR_OPT_NEVER:
-               pretty->use_colors = false;
-               break;
-       }
-}
-
-static
-void init_stream_packet_context_quarks(void)
-{
-       stream_packet_context_quarks[Q_TIMESTAMP_BEGIN] =
-               g_quark_from_string("timestamp_begin");
-       stream_packet_context_quarks[Q_TIMESTAMP_BEGIN] =
-               g_quark_from_string("timestamp_begin");
-       stream_packet_context_quarks[Q_TIMESTAMP_END] =
-               g_quark_from_string("timestamp_end");
-       stream_packet_context_quarks[Q_EVENTS_DISCARDED] =
-               g_quark_from_string("events_discarded");
-       stream_packet_context_quarks[Q_CONTENT_SIZE] =
-               g_quark_from_string("content_size");
-       stream_packet_context_quarks[Q_PACKET_SIZE] =
-               g_quark_from_string("packet_size");
-       stream_packet_context_quarks[Q_PACKET_SEQ_NUM] =
-               g_quark_from_string("packet_seq_num");
-}
-
-BT_HIDDEN
-bt_self_component_status pretty_init(
-               bt_self_component_sink *comp,
-               const bt_value *params,
-               UNUSED_VAR void *init_method_data)
-{
-       bt_self_component_status ret;
-       struct pretty_component *pretty = create_pretty();
-
-       if (!pretty) {
-               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       ret = bt_self_component_sink_add_input_port(comp, in_port_name,
-               NULL, NULL);
-       if (ret != BT_SELF_COMPONENT_STATUS_OK) {
-               goto end;
-       }
-
-       pretty->out = stdout;
-       pretty->err = stderr;
-
-       pretty->delta_cycles = -1ULL;
-       pretty->last_cycles_timestamp = -1ULL;
-
-       pretty->delta_real_timestamp = -1ULL;
-       pretty->last_real_timestamp = -1ULL;
-
-       if (apply_params(pretty, params)) {
-               ret = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto error;
-       }
-
-       set_use_colors(pretty);
-       bt_self_component_set_data(
-               bt_self_component_sink_as_self_component(comp), pretty);
-       init_stream_packet_context_quarks();
-
-end:
-       return ret;
-
-error:
-       destroy_pretty_data(pretty);
-       return ret;
-}
diff --git a/plugins/text/pretty/pretty.h b/plugins/text/pretty/pretty.h
deleted file mode 100644 (file)
index 4ebf54b..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-#ifndef BABELTRACE_PLUGIN_TEXT_PRETTY_PRETTY_H
-#define BABELTRACE_PLUGIN_TEXT_PRETTY_PRETTY_H
-
-/*
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdbool.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-enum pretty_default {
-       PRETTY_DEFAULT_UNSET,
-       PRETTY_DEFAULT_SHOW,
-       PRETTY_DEFAULT_HIDE,
-};
-
-enum pretty_color_option {
-       PRETTY_COLOR_OPT_NEVER,
-       PRETTY_COLOR_OPT_AUTO,
-       PRETTY_COLOR_OPT_ALWAYS,
-};
-
-struct pretty_options {
-       char *output_path;
-
-       enum pretty_default name_default;
-       enum pretty_default field_default;
-
-       bool print_scope_field_names;
-       bool print_header_field_names;
-       bool print_context_field_names;
-       bool print_payload_field_names;
-
-       bool print_delta_field;
-       bool print_loglevel_field;
-       bool print_emf_field;
-       bool print_callsite_field;
-       bool print_trace_field;
-       bool print_trace_domain_field;
-       bool print_trace_procname_field;
-       bool print_trace_vpid_field;
-       bool print_trace_hostname_field;
-
-       bool print_timestamp_cycles;
-       bool clock_seconds;
-       bool clock_date;
-       bool clock_gmt;
-       enum pretty_color_option color;
-       bool verbose;
-};
-
-struct pretty_component {
-       struct pretty_options options;
-       bt_self_component_port_input_message_iterator *iterator;
-       FILE *out, *err;
-       int depth;      /* nesting, used for tabulation alignment. */
-       bool start_line;
-       GString *string;
-       GString *tmp_string;
-       bt_value *plugin_opt_map; /* Temporary parameter map. */
-       bool use_colors;
-
-       uint64_t last_cycles_timestamp;
-       uint64_t delta_cycles;
-
-       uint64_t last_real_timestamp;
-       uint64_t delta_real_timestamp;
-
-       bool negative_timestamp_warning_done;
-};
-
-enum stream_packet_context_quarks_enum {
-       Q_TIMESTAMP_BEGIN,
-       Q_TIMESTAMP_END,
-       Q_EVENTS_DISCARDED,
-       Q_CONTENT_SIZE,
-       Q_PACKET_SIZE,
-       Q_PACKET_SEQ_NUM,
-       STREAM_PACKET_CONTEXT_QUARKS_LEN, /* Always the last one of this enum. */
-};
-
-extern
-GQuark stream_packet_context_quarks[STREAM_PACKET_CONTEXT_QUARKS_LEN];
-
-BT_HIDDEN
-bt_self_component_status pretty_init(
-               bt_self_component_sink *component,
-               const bt_value *params,
-               void *init_method_data);
-
-BT_HIDDEN
-bt_self_component_status pretty_consume(
-               bt_self_component_sink *component);
-
-BT_HIDDEN
-bt_self_component_status pretty_graph_is_configured(
-               bt_self_component_sink *component);
-
-BT_HIDDEN
-void pretty_finalize(bt_self_component_sink *component);
-
-BT_HIDDEN
-int pretty_print_event(struct pretty_component *pretty,
-               const bt_message *event_msg);
-
-BT_HIDDEN
-int pretty_print_discarded_items(struct pretty_component *pretty,
-               const bt_message *msg);
-
-#endif /* BABELTRACE_PLUGIN_TEXT_PRETTY_PRETTY_H */
diff --git a/plugins/text/pretty/print.c b/plugins/text/pretty/print.c
deleted file mode 100644 (file)
index a30f3a3..0000000
+++ /dev/null
@@ -1,1390 +0,0 @@
-/*
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/bitfield-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <babeltrace2/compat/time-internal.h>
-#include <babeltrace2/assert-internal.h>
-#include <inttypes.h>
-#include <ctype.h>
-#include "pretty.h"
-
-#define NSEC_PER_SEC 1000000000LL
-
-#define COLOR_NAME             BT_COMMON_COLOR_BOLD
-#define COLOR_FIELD_NAME       BT_COMMON_COLOR_FG_CYAN
-#define COLOR_RST              BT_COMMON_COLOR_RESET
-#define COLOR_STRING_VALUE     BT_COMMON_COLOR_BOLD
-#define COLOR_NUMBER_VALUE     BT_COMMON_COLOR_BOLD
-#define COLOR_ENUM_MAPPING_NAME        BT_COMMON_COLOR_BOLD
-#define COLOR_UNKNOWN          BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_RED
-#define COLOR_EVENT_NAME       BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_MAGENTA
-#define COLOR_TIMESTAMP                BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_YELLOW
-
-struct timestamp {
-       int64_t real_timestamp; /* Relative to UNIX epoch. */
-       uint64_t clock_snapshot;        /* In cycles. */
-};
-
-static
-int print_field(struct pretty_component *pretty,
-               const bt_field *field, bool print_names,
-               GQuark *filters_fields, int filter_array_len);
-
-static
-void print_name_equal(struct pretty_component *pretty, const char *name)
-{
-       if (pretty->use_colors) {
-               g_string_append_printf(pretty->string, "%s%s%s = ", COLOR_NAME,
-                       name, COLOR_RST);
-       } else {
-               g_string_append_printf(pretty->string, "%s = ", name);
-       }
-}
-
-static
-void print_field_name_equal(struct pretty_component *pretty, const char *name)
-{
-       if (pretty->use_colors) {
-               g_string_append_printf(pretty->string, "%s%s%s = ",
-                       COLOR_FIELD_NAME, name, COLOR_RST);
-       } else {
-               g_string_append_printf(pretty->string, "%s = ", name);
-       }
-}
-
-static
-void print_timestamp_cycles(struct pretty_component *pretty,
-               const bt_clock_snapshot *clock_snapshot, bool update_last)
-{
-       uint64_t cycles;
-
-       cycles = bt_clock_snapshot_get_value(clock_snapshot);
-       g_string_append_printf(pretty->string, "%020" PRIu64, cycles);
-
-       if (update_last) {
-               if (pretty->last_cycles_timestamp != -1ULL) {
-                       pretty->delta_cycles = cycles - pretty->last_cycles_timestamp;
-               }
-
-               pretty->last_cycles_timestamp = cycles;
-       }
-}
-
-static
-void print_timestamp_wall(struct pretty_component *pretty,
-               const bt_clock_snapshot *clock_snapshot, bool update_last)
-{
-       int ret;
-       int64_t ts_nsec = 0;    /* add configurable offset */
-       int64_t ts_sec = 0;     /* add configurable offset */
-       uint64_t ts_sec_abs, ts_nsec_abs;
-       bool is_negative;
-
-       if (!clock_snapshot) {
-               g_string_append(pretty->string, "??:??:??.?????????");
-               return;
-       }
-
-       ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot, &ts_nsec);
-       if (ret) {
-               // TODO: log, this is unexpected
-               g_string_append(pretty->string, "Error");
-               return;
-       }
-
-       if (update_last) {
-               if (pretty->last_real_timestamp != -1ULL) {
-                       pretty->delta_real_timestamp = ts_nsec - pretty->last_real_timestamp;
-               }
-
-               pretty->last_real_timestamp = ts_nsec;
-       }
-
-       ts_sec += ts_nsec / NSEC_PER_SEC;
-       ts_nsec = ts_nsec % NSEC_PER_SEC;
-
-       if (ts_sec >= 0 && ts_nsec >= 0) {
-               is_negative = false;
-               ts_sec_abs = ts_sec;
-               ts_nsec_abs = ts_nsec;
-       } else if (ts_sec > 0 && ts_nsec < 0) {
-               is_negative = false;
-               ts_sec_abs = ts_sec - 1;
-               ts_nsec_abs = NSEC_PER_SEC + ts_nsec;
-       } else if (ts_sec == 0 && ts_nsec < 0) {
-               is_negative = true;
-               ts_sec_abs = ts_sec;
-               ts_nsec_abs = -ts_nsec;
-       } else if (ts_sec < 0 && ts_nsec > 0) {
-               is_negative = true;
-               ts_sec_abs = -(ts_sec + 1);
-               ts_nsec_abs = NSEC_PER_SEC - ts_nsec;
-       } else if (ts_sec < 0 && ts_nsec == 0) {
-               is_negative = true;
-               ts_sec_abs = -ts_sec;
-               ts_nsec_abs = ts_nsec;
-       } else {        /* (ts_sec < 0 && ts_nsec < 0) */
-               is_negative = true;
-               ts_sec_abs = -ts_sec;
-               ts_nsec_abs = -ts_nsec;
-       }
-
-       if (!pretty->options.clock_seconds) {
-               struct tm tm;
-               time_t time_s = (time_t) ts_sec_abs;
-
-               if (is_negative && !pretty->negative_timestamp_warning_done) {
-                       // TODO: log instead
-                       fprintf(stderr, "[warning] Fallback to [sec.ns] to print negative time value. Use --clock-seconds.\n");
-                       pretty->negative_timestamp_warning_done = true;
-                       goto seconds;
-               }
-
-               if (!pretty->options.clock_gmt) {
-                       struct tm *res;
-
-                       res = bt_localtime_r(&time_s, &tm);
-                       if (!res) {
-                               // TODO: log instead
-                               fprintf(stderr, "[warning] Unable to get localtime.\n");
-                               goto seconds;
-                       }
-               } else {
-                       struct tm *res;
-
-                       res = bt_gmtime_r(&time_s, &tm);
-                       if (!res) {
-                               // TODO: log instead
-                               fprintf(stderr, "[warning] Unable to get gmtime.\n");
-                               goto seconds;
-                       }
-               }
-               if (pretty->options.clock_date) {
-                       char timestr[26];
-                       size_t res;
-
-                       /* Print date and time */
-                       res = strftime(timestr, sizeof(timestr),
-                                       "%Y-%m-%d ", &tm);
-                       if (!res) {
-                               // TODO: log instead
-                               fprintf(stderr, "[warning] Unable to print ascii time.\n");
-                               goto seconds;
-                       }
-
-                       g_string_append(pretty->string, timestr);
-               }
-
-               /* Print time in HH:MM:SS.ns */
-               g_string_append_printf(pretty->string,
-                       "%02d:%02d:%02d.%09" PRIu64, tm.tm_hour, tm.tm_min,
-                       tm.tm_sec, ts_nsec_abs);
-               goto end;
-       }
-seconds:
-       g_string_append_printf(pretty->string, "%s%" PRId64 ".%09" PRIu64,
-               is_negative ? "-" : "", ts_sec_abs, ts_nsec_abs);
-end:
-       return;
-}
-
-static
-int print_event_timestamp(struct pretty_component *pretty,
-               const bt_message *event_msg, bool *start_line)
-{
-       bool print_names = pretty->options.print_header_field_names;
-       int ret = 0;
-       const bt_clock_snapshot *clock_snapshot = NULL;
-
-       if (!bt_message_event_borrow_stream_class_default_clock_class_const(
-                       event_msg)) {
-               /* No default clock class: skip the timestamp without an error */
-               goto end;
-       }
-
-       clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(event_msg);
-
-       if (print_names) {
-               print_name_equal(pretty, "timestamp");
-       } else {
-               g_string_append(pretty->string, "[");
-       }
-       if (pretty->use_colors) {
-               g_string_append(pretty->string, COLOR_TIMESTAMP);
-       }
-       if (pretty->options.print_timestamp_cycles) {
-               print_timestamp_cycles(pretty, clock_snapshot, true);
-       } else {
-               print_timestamp_wall(pretty, clock_snapshot, true);
-       }
-       if (pretty->use_colors) {
-               g_string_append(pretty->string, COLOR_RST);
-       }
-
-       if (!print_names)
-               g_string_append(pretty->string, "] ");
-
-       if (pretty->options.print_delta_field) {
-               if (print_names) {
-                       g_string_append(pretty->string, ", ");
-                       print_name_equal(pretty, "delta");
-               } else {
-                       g_string_append(pretty->string, "(");
-               }
-               if (pretty->options.print_timestamp_cycles) {
-                       if (pretty->delta_cycles == -1ULL) {
-                               g_string_append(pretty->string,
-                                       "+??????????\?\?"); /* Not a trigraph. */
-                       } else {
-                               g_string_append_printf(pretty->string,
-                                       "+%012" PRIu64, pretty->delta_cycles);
-                       }
-               } else {
-                       if (pretty->delta_real_timestamp != -1ULL) {
-                               uint64_t delta_sec, delta_nsec, delta;
-
-                               delta = pretty->delta_real_timestamp;
-                               delta_sec = delta / NSEC_PER_SEC;
-                               delta_nsec = delta % NSEC_PER_SEC;
-                               g_string_append_printf(pretty->string,
-                                       "+%" PRIu64 ".%09" PRIu64,
-                                       delta_sec, delta_nsec);
-                       } else {
-                               g_string_append(pretty->string, "+?.?????????");
-                       }
-               }
-               if (!print_names) {
-                       g_string_append(pretty->string, ") ");
-               }
-       }
-       *start_line = !print_names;
-
-end:
-       return ret;
-}
-
-static
-int print_event_header(struct pretty_component *pretty,
-               const bt_message *event_msg)
-{
-       bool print_names = pretty->options.print_header_field_names;
-       int ret = 0;
-       const bt_event_class *event_class = NULL;
-       const bt_stream_class *stream_class = NULL;
-       const bt_trace_class *trace_class = NULL;
-       const bt_packet *packet = NULL;
-       const bt_stream *stream = NULL;
-       const bt_trace *trace = NULL;
-       const bt_event *event = bt_message_event_borrow_event_const(event_msg);
-       int dom_print = 0;
-       bt_property_availability prop_avail;
-
-       event_class = bt_event_borrow_class_const(event);
-       stream_class = bt_event_class_borrow_stream_class_const(event_class);
-       trace_class = bt_stream_class_borrow_trace_class_const(stream_class);
-       packet = bt_event_borrow_packet_const(event);
-       stream = bt_packet_borrow_stream_const(packet);
-       trace = bt_stream_borrow_trace_const(stream);
-       ret = print_event_timestamp(pretty, event_msg, &pretty->start_line);
-       if (ret) {
-               goto end;
-       }
-       if (pretty->options.print_trace_field) {
-               const char *name;
-
-               name = bt_trace_get_name(trace);
-               if (name) {
-                       if (!pretty->start_line) {
-                               g_string_append(pretty->string, ", ");
-                       }
-                       if (print_names) {
-                               print_name_equal(pretty, "trace");
-                       }
-
-                       g_string_append(pretty->string, name);
-
-                       if (print_names) {
-                               g_string_append(pretty->string, ", ");
-                       }
-               }
-       }
-       if (pretty->options.print_trace_hostname_field) {
-               const bt_value *hostname_str;
-
-               hostname_str = bt_trace_class_borrow_environment_entry_value_by_name_const(
-                       trace_class, "hostname");
-               if (hostname_str) {
-                       const char *str;
-
-                       if (!pretty->start_line) {
-                               g_string_append(pretty->string, ", ");
-                       }
-                       if (print_names) {
-                               print_name_equal(pretty, "trace:hostname");
-                       }
-                       str = bt_value_string_get(hostname_str);
-                       g_string_append(pretty->string, str);
-                       dom_print = 1;
-               }
-       }
-       if (pretty->options.print_trace_domain_field) {
-               const bt_value *domain_str;
-
-               domain_str = bt_trace_class_borrow_environment_entry_value_by_name_const(
-                       trace_class, "domain");
-               if (domain_str) {
-                       const char *str;
-
-                       if (!pretty->start_line) {
-                               g_string_append(pretty->string, ", ");
-                       }
-                       if (print_names) {
-                               print_name_equal(pretty, "trace:domain");
-                       } else if (dom_print) {
-                               g_string_append(pretty->string, ":");
-                       }
-                       str = bt_value_string_get(domain_str);
-                       g_string_append(pretty->string, str);
-                       dom_print = 1;
-               }
-       }
-       if (pretty->options.print_trace_procname_field) {
-               const bt_value *procname_str;
-
-               procname_str = bt_trace_class_borrow_environment_entry_value_by_name_const(
-                       trace_class, "procname");
-               if (procname_str) {
-                       const char *str;
-
-                       if (!pretty->start_line) {
-                               g_string_append(pretty->string, ", ");
-                       }
-                       if (print_names) {
-                               print_name_equal(pretty, "trace:procname");
-                       } else if (dom_print) {
-                               g_string_append(pretty->string, ":");
-                       }
-                       str = bt_value_string_get(procname_str);
-                       g_string_append(pretty->string, str);
-                       dom_print = 1;
-               }
-       }
-       if (pretty->options.print_trace_vpid_field) {
-               const bt_value *vpid_value;
-
-               vpid_value = bt_trace_class_borrow_environment_entry_value_by_name_const(
-                       trace_class, "vpid");
-               if (vpid_value) {
-                       int64_t value;
-
-                       if (!pretty->start_line) {
-                               g_string_append(pretty->string, ", ");
-                       }
-                       if (print_names) {
-                               print_name_equal(pretty, "trace:vpid");
-                       } else if (dom_print) {
-                               g_string_append(pretty->string, ":");
-                       }
-                       value = bt_value_signed_integer_get(vpid_value);
-                       g_string_append_printf(pretty->string,
-                               "(%" PRId64 ")", value);
-                       dom_print = 1;
-               }
-       }
-       if (pretty->options.print_loglevel_field) {
-               static const char *log_level_names[] = {
-                       [ BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY ] = "TRACE_EMERG",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_ALERT ] = "TRACE_ALERT",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_CRITICAL ] = "TRACE_CRIT",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_ERROR ] = "TRACE_ERR",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_WARNING ] = "TRACE_WARNING",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_NOTICE ] = "TRACE_NOTICE",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_INFO ] = "TRACE_INFO",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM ] = "TRACE_DEBUG_SYSTEM",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM ] = "TRACE_DEBUG_PROGRAM",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS ] = "TRACE_DEBUG_PROCESS",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE ] = "TRACE_DEBUG_MODULE",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT ] = "TRACE_DEBUG_UNIT",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION ] = "TRACE_DEBUG_FUNCTION",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE ] = "TRACE_DEBUG_LINE",
-                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG ] = "TRACE_DEBUG",
-               };
-               bt_event_class_log_level log_level;
-               const char *log_level_str = NULL;
-
-               prop_avail = bt_event_class_get_log_level(event_class,
-                       &log_level);
-               if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
-                       log_level_str = log_level_names[log_level];
-                       BT_ASSERT(log_level_str);
-
-                       if (!pretty->start_line) {
-                               g_string_append(pretty->string, ", ");
-                       }
-                       if (print_names) {
-                               print_name_equal(pretty, "loglevel");
-                       } else if (dom_print) {
-                               g_string_append(pretty->string, ":");
-                       }
-
-                       g_string_append(pretty->string, log_level_str);
-                       g_string_append_printf(
-                               pretty->string, " (%d)", (int) log_level);
-                       dom_print = 1;
-               }
-       }
-       if (pretty->options.print_emf_field) {
-               const char *uri_str;
-
-               uri_str = bt_event_class_get_emf_uri(event_class);
-               if (uri_str) {
-                       if (!pretty->start_line) {
-                               g_string_append(pretty->string, ", ");
-                       }
-                       if (print_names) {
-                               print_name_equal(pretty, "model.emf.uri");
-                       } else if (dom_print) {
-                               g_string_append(pretty->string, ":");
-                       }
-
-                       g_string_append(pretty->string, uri_str);
-                       dom_print = 1;
-               }
-       }
-       if (dom_print && !print_names) {
-               g_string_append(pretty->string, " ");
-       }
-       if (!pretty->start_line) {
-               g_string_append(pretty->string, ", ");
-       }
-       pretty->start_line = true;
-       if (print_names) {
-               print_name_equal(pretty, "name");
-       }
-       if (pretty->use_colors) {
-               g_string_append(pretty->string, COLOR_EVENT_NAME);
-       }
-       g_string_append(pretty->string, bt_event_class_get_name(event_class));
-       if (pretty->use_colors) {
-               g_string_append(pretty->string, COLOR_RST);
-       }
-       if (!print_names) {
-               g_string_append(pretty->string, ": ");
-       } else {
-               g_string_append(pretty->string, ", ");
-       }
-
-end:
-       return ret;
-}
-
-static
-int print_integer(struct pretty_component *pretty,
-               const bt_field *field)
-{
-       int ret = 0;
-       bt_field_class_integer_preferred_display_base base;
-       const bt_field_class *int_fc;
-       union {
-               uint64_t u;
-               int64_t s;
-       } v;
-       bool rst_color = false;
-       bt_field_class_type ft_type;
-
-       int_fc = bt_field_borrow_class_const(field);
-       BT_ASSERT(int_fc);
-       ft_type = bt_field_get_class_type(field);
-       if (ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
-                       ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
-               v.u = bt_field_unsigned_integer_get_value(field);
-       } else {
-               v.s = bt_field_signed_integer_get_value(field);
-       }
-
-       if (pretty->use_colors) {
-               g_string_append(pretty->string, COLOR_NUMBER_VALUE);
-               rst_color = true;
-       }
-
-       base = bt_field_class_integer_get_preferred_display_base(int_fc);
-       switch (base) {
-       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
-       {
-               int bitnr, len;
-
-               len = bt_field_class_integer_get_field_value_range(int_fc);
-               g_string_append(pretty->string, "0b");
-               _bt_safe_lshift(v.u, 64 - len);
-               for (bitnr = 0; bitnr < len; bitnr++) {
-                       g_string_append_printf(pretty->string, "%u", (v.u & (1ULL << 63)) ? 1 : 0);
-                       _bt_safe_lshift(v.u, 1);
-               }
-               break;
-       }
-       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
-       {
-               if (ft_type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
-                               ft_type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
-                       int len;
-
-                       len = bt_field_class_integer_get_field_value_range(
-                               int_fc);
-                       if (len < 64) {
-                               size_t rounded_len;
-
-                               BT_ASSERT(len != 0);
-                               /* Round length to the nearest 3-bit */
-                               rounded_len = (((len - 1) / 3) + 1) * 3;
-                               v.u &= ((uint64_t) 1 << rounded_len) - 1;
-                       }
-               }
-
-               g_string_append_printf(pretty->string, "0%" PRIo64, v.u);
-               break;
-       }
-       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
-               if (ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
-                               ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
-                       g_string_append_printf(pretty->string, "%" PRIu64, v.u);
-               } else {
-                       g_string_append_printf(pretty->string, "%" PRId64, v.s);
-               }
-               break;
-       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
-       {
-               int len;
-
-               len = bt_field_class_integer_get_field_value_range(int_fc);
-               if (len < 64) {
-                       /* Round length to the nearest nibble */
-                       uint8_t rounded_len = ((len + 3) & ~0x3);
-
-                       v.u &= ((uint64_t) 1 << rounded_len) - 1;
-               }
-
-               g_string_append_printf(pretty->string, "0x%" PRIX64, v.u);
-               break;
-       }
-       default:
-               ret = -1;
-               goto end;
-       }
-end:
-       if (rst_color) {
-               g_string_append(pretty->string, COLOR_RST);
-       }
-       return ret;
-}
-
-static
-void print_escape_string(struct pretty_component *pretty, const char *str)
-{
-       int i;
-
-       g_string_append_c(pretty->string, '"');
-
-       for (i = 0; i < strlen(str); i++) {
-               /* Escape sequences not recognized by iscntrl(). */
-               switch (str[i]) {
-               case '\\':
-                       g_string_append(pretty->string, "\\\\");
-                       continue;
-               case '\'':
-                       g_string_append(pretty->string, "\\\'");
-                       continue;
-               case '\"':
-                       g_string_append(pretty->string, "\\\"");
-                       continue;
-               case '\?':
-                       g_string_append(pretty->string, "\\\?");
-                       continue;
-               }
-
-               /* Standard characters. */
-               if (!iscntrl(str[i])) {
-                       g_string_append_c(pretty->string, str[i]);
-                       continue;
-               }
-
-               switch (str[i]) {
-               case '\0':
-                       g_string_append(pretty->string, "\\0");
-                       break;
-               case '\a':
-                       g_string_append(pretty->string, "\\a");
-                       break;
-               case '\b':
-                       g_string_append(pretty->string, "\\b");
-                       break;
-               case '\e':
-                       g_string_append(pretty->string, "\\e");
-                       break;
-               case '\f':
-                       g_string_append(pretty->string, "\\f");
-                       break;
-               case '\n':
-                       g_string_append(pretty->string, "\\n");
-                       break;
-               case '\r':
-                       g_string_append(pretty->string, "\\r");
-                       break;
-               case '\t':
-                       g_string_append(pretty->string, "\\t");
-                       break;
-               case '\v':
-                       g_string_append(pretty->string, "\\v");
-                       break;
-               default:
-                       /* Unhandled control-sequence, print as hex. */
-                       g_string_append_printf(pretty->string, "\\x%02x", str[i]);
-                       break;
-               }
-       }
-
-       g_string_append_c(pretty->string, '"');
-}
-
-static
-int print_enum(struct pretty_component *pretty,
-               const bt_field *field)
-{
-       int ret = 0;
-       const bt_field_class *enumeration_field_class = NULL;
-       bt_field_class_enumeration_mapping_label_array label_array;
-       uint64_t label_count;
-       uint64_t i;
-
-       enumeration_field_class = bt_field_borrow_class_const(field);
-       if (!enumeration_field_class) {
-               ret = -1;
-               goto end;
-       }
-
-       switch (bt_field_get_class_type(field)) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-               ret = bt_field_unsigned_enumeration_get_mapping_labels(field,
-                       &label_array, &label_count);
-               break;
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-               ret = bt_field_signed_enumeration_get_mapping_labels(field,
-                       &label_array, &label_count);
-               break;
-       default:
-               abort();
-       }
-
-       if (ret) {
-               ret = -1;
-               goto end;
-       }
-
-       g_string_append(pretty->string, "( ");
-       if (label_count == 0) {
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_UNKNOWN);
-               }
-               g_string_append(pretty->string, "<unknown>");
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_RST);
-               }
-               goto skip_loop;
-       }
-       for (i = 0; i < label_count; i++) {
-               const char *mapping_name = label_array[i];
-
-               if (i != 0) {
-                       g_string_append(pretty->string, ", ");
-               }
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_ENUM_MAPPING_NAME);
-               }
-               print_escape_string(pretty, mapping_name);
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_RST);
-               }
-       }
-skip_loop:
-       g_string_append(pretty->string, " : container = ");
-       ret = print_integer(pretty, field);
-       if (ret != 0) {
-               goto end;
-       }
-       g_string_append(pretty->string, " )");
-end:
-       return ret;
-}
-
-static
-int filter_field_name(struct pretty_component *pretty, const char *field_name,
-               GQuark *filter_fields, int filter_array_len)
-{
-       int i;
-       GQuark field_quark = g_quark_try_string(field_name);
-
-       if (!field_quark || pretty->options.verbose) {
-               return 1;
-       }
-
-       for (i = 0; i < filter_array_len; i++) {
-               if (field_quark == filter_fields[i]) {
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-static
-int print_struct_field(struct pretty_component *pretty,
-               const bt_field *_struct,
-               const bt_field_class *struct_class,
-               uint64_t i, bool print_names, uint64_t *nr_printed_fields,
-               GQuark *filter_fields, int filter_array_len)
-{
-       int ret = 0;
-       const char *field_name;
-       const bt_field *field = NULL;
-       const bt_field_class_structure_member *member;
-
-       field = bt_field_structure_borrow_member_field_by_index_const(_struct, i);
-       if (!field) {
-               ret = -1;
-               goto end;
-       }
-
-       member = bt_field_class_structure_borrow_member_by_index_const(
-               struct_class, i);
-       field_name = bt_field_class_structure_member_get_name(member);
-
-       if (filter_fields && !filter_field_name(pretty, field_name,
-                               filter_fields, filter_array_len)) {
-               ret = 0;
-               goto end;
-       }
-
-       if (*nr_printed_fields > 0) {
-               g_string_append(pretty->string, ", ");
-       } else {
-               g_string_append(pretty->string, " ");
-       }
-       if (print_names) {
-               print_field_name_equal(pretty, field_name);
-       }
-       ret = print_field(pretty, field, print_names, NULL, 0);
-       *nr_printed_fields += 1;
-
-end:
-       return ret;
-}
-
-static
-int print_struct(struct pretty_component *pretty,
-               const bt_field *_struct, bool print_names,
-               GQuark *filter_fields, int filter_array_len)
-{
-       int ret = 0;
-       const bt_field_class *struct_class = NULL;
-       uint64_t nr_fields, i, nr_printed_fields;
-
-       struct_class = bt_field_borrow_class_const(_struct);
-       if (!struct_class) {
-               ret = -1;
-               goto end;
-       }
-
-       nr_fields = bt_field_class_structure_get_member_count(struct_class);
-
-       g_string_append(pretty->string, "{");
-       pretty->depth++;
-       nr_printed_fields = 0;
-       for (i = 0; i < nr_fields; i++) {
-               ret = print_struct_field(pretty, _struct, struct_class, i,
-                               print_names, &nr_printed_fields, filter_fields,
-                               filter_array_len);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-       pretty->depth--;
-       g_string_append(pretty->string, " }");
-
-end:
-       return ret;
-}
-
-static
-int print_array_field(struct pretty_component *pretty,
-               const bt_field *array, uint64_t i, bool print_names)
-{
-       const bt_field *field = NULL;
-
-       if (i != 0) {
-               g_string_append(pretty->string, ", ");
-       } else {
-               g_string_append(pretty->string, " ");
-       }
-       if (print_names) {
-               g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
-       }
-
-       field = bt_field_array_borrow_element_field_by_index_const(array, i);
-       BT_ASSERT(field);
-       return print_field(pretty, field, print_names, NULL, 0);
-}
-
-static
-int print_array(struct pretty_component *pretty,
-               const bt_field *array, bool print_names)
-{
-       int ret = 0;
-       const bt_field_class *array_class = NULL;
-       uint64_t len;
-       uint64_t i;
-
-       array_class = bt_field_borrow_class_const(array);
-       if (!array_class) {
-               ret = -1;
-               goto end;
-       }
-       len = bt_field_array_get_length(array);
-       g_string_append(pretty->string, "[");
-       pretty->depth++;
-       for (i = 0; i < len; i++) {
-               ret = print_array_field(pretty, array, i, print_names);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-       pretty->depth--;
-       g_string_append(pretty->string, " ]");
-
-end:
-       return ret;
-}
-
-static
-int print_sequence_field(struct pretty_component *pretty,
-               const bt_field *seq, uint64_t i, bool print_names)
-{
-       const bt_field *field = NULL;
-
-       if (i != 0) {
-               g_string_append(pretty->string, ", ");
-       } else {
-               g_string_append(pretty->string, " ");
-       }
-       if (print_names) {
-               g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
-       }
-
-       field = bt_field_array_borrow_element_field_by_index_const(seq, i);
-       BT_ASSERT(field);
-       return print_field(pretty, field, print_names, NULL, 0);
-}
-
-static
-int print_sequence(struct pretty_component *pretty,
-               const bt_field *seq, bool print_names)
-{
-       int ret = 0;
-       uint64_t len;
-       uint64_t i;
-
-       len = bt_field_array_get_length(seq);
-       g_string_append(pretty->string, "[");
-
-       pretty->depth++;
-       for (i = 0; i < len; i++) {
-               ret = print_sequence_field(pretty, seq, i, print_names);
-               if (ret != 0) {
-                       goto end;
-               }
-       }
-       pretty->depth--;
-       g_string_append(pretty->string, " ]");
-
-end:
-       return ret;
-}
-
-static
-int print_variant(struct pretty_component *pretty,
-               const bt_field *variant, bool print_names)
-{
-       int ret = 0;
-       const bt_field *field = NULL;
-
-       field = bt_field_variant_borrow_selected_option_field_const(variant);
-       BT_ASSERT(field);
-       g_string_append(pretty->string, "{ ");
-       pretty->depth++;
-       if (print_names) {
-               // TODO: find tag's name using field path
-               // print_field_name_equal(pretty, tag_choice);
-       }
-       ret = print_field(pretty, field, print_names, NULL, 0);
-       if (ret != 0) {
-               goto end;
-       }
-       pretty->depth--;
-       g_string_append(pretty->string, " }");
-
-end:
-       return ret;
-}
-
-static
-int print_field(struct pretty_component *pretty,
-               const bt_field *field, bool print_names,
-               GQuark *filter_fields, int filter_array_len)
-{
-       bt_field_class_type class_id;
-
-       class_id = bt_field_get_class_type(field);
-       switch (class_id) {
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
-       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
-               return print_integer(pretty, field);
-       case BT_FIELD_CLASS_TYPE_REAL:
-       {
-               double v;
-
-               v = bt_field_real_get_value(field);
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_NUMBER_VALUE);
-               }
-               g_string_append_printf(pretty->string, "%g", v);
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_RST);
-               }
-               return 0;
-       }
-       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
-       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
-               return print_enum(pretty, field);
-       case BT_FIELD_CLASS_TYPE_STRING:
-       {
-               const char *str;
-
-               str = bt_field_string_get_value(field);
-               if (!str) {
-                       return -1;
-               }
-
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_STRING_VALUE);
-               }
-               print_escape_string(pretty, str);
-               if (pretty->use_colors) {
-                       g_string_append(pretty->string, COLOR_RST);
-               }
-               return 0;
-       }
-       case BT_FIELD_CLASS_TYPE_STRUCTURE:
-               return print_struct(pretty, field, print_names, filter_fields,
-                               filter_array_len);
-       case BT_FIELD_CLASS_TYPE_VARIANT:
-               return print_variant(pretty, field, print_names);
-       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
-               return print_array(pretty, field, print_names);
-       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
-               return print_sequence(pretty, field, print_names);
-       default:
-               // TODO: log instead
-               fprintf(pretty->err, "[error] Unknown type id: %d\n", (int) class_id);
-               return -1;
-       }
-}
-
-static
-int print_stream_packet_context(struct pretty_component *pretty,
-               const bt_event *event)
-{
-       int ret = 0;
-       const bt_packet *packet = NULL;
-       const bt_field *main_field = NULL;
-
-       packet = bt_event_borrow_packet_const(event);
-       if (!packet) {
-               ret = -1;
-               goto end;
-       }
-       main_field = bt_packet_borrow_context_field_const(packet);
-       if (!main_field) {
-               goto end;
-       }
-       if (!pretty->start_line) {
-               g_string_append(pretty->string, ", ");
-       }
-       pretty->start_line = false;
-       if (pretty->options.print_scope_field_names) {
-               print_name_equal(pretty, "stream.packet.context");
-       }
-       ret = print_field(pretty, main_field,
-                       pretty->options.print_context_field_names,
-                       stream_packet_context_quarks,
-                       STREAM_PACKET_CONTEXT_QUARKS_LEN);
-
-end:
-       return ret;
-}
-
-static
-int print_stream_event_context(struct pretty_component *pretty,
-               const bt_event *event)
-{
-       int ret = 0;
-       const bt_field *main_field = NULL;
-
-       main_field = bt_event_borrow_common_context_field_const(event);
-       if (!main_field) {
-               goto end;
-       }
-       if (!pretty->start_line) {
-               g_string_append(pretty->string, ", ");
-       }
-       pretty->start_line = false;
-       if (pretty->options.print_scope_field_names) {
-               print_name_equal(pretty, "stream.event.context");
-       }
-       ret = print_field(pretty, main_field,
-                       pretty->options.print_context_field_names, NULL, 0);
-
-end:
-       return ret;
-}
-
-static
-int print_event_context(struct pretty_component *pretty,
-               const bt_event *event)
-{
-       int ret = 0;
-       const bt_field *main_field = NULL;
-
-       main_field = bt_event_borrow_specific_context_field_const(event);
-       if (!main_field) {
-               goto end;
-       }
-       if (!pretty->start_line) {
-               g_string_append(pretty->string, ", ");
-       }
-       pretty->start_line = false;
-       if (pretty->options.print_scope_field_names) {
-               print_name_equal(pretty, "event.context");
-       }
-       ret = print_field(pretty, main_field,
-                       pretty->options.print_context_field_names, NULL, 0);
-
-end:
-       return ret;
-}
-
-static
-int print_event_payload(struct pretty_component *pretty,
-               const bt_event *event)
-{
-       int ret = 0;
-       const bt_field *main_field = NULL;
-
-       main_field = bt_event_borrow_payload_field_const(event);
-       if (!main_field) {
-               goto end;
-       }
-       if (!pretty->start_line) {
-               g_string_append(pretty->string, ", ");
-       }
-       pretty->start_line = false;
-       if (pretty->options.print_scope_field_names) {
-               print_name_equal(pretty, "event.fields");
-       }
-       ret = print_field(pretty, main_field,
-                       pretty->options.print_payload_field_names, NULL, 0);
-
-end:
-       return ret;
-}
-
-static
-int flush_buf(FILE *stream, struct pretty_component *pretty)
-{
-       int ret = 0;
-
-       if (pretty->string->len == 0) {
-               goto end;
-       }
-
-       if (fwrite(pretty->string->str, pretty->string->len, 1, stream) != 1) {
-               ret = -1;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-int pretty_print_event(struct pretty_component *pretty,
-               const bt_message *event_msg)
-{
-       int ret;
-       const bt_event *event =
-               bt_message_event_borrow_event_const(event_msg);
-
-       BT_ASSERT(event);
-       pretty->start_line = true;
-       g_string_assign(pretty->string, "");
-       ret = print_event_header(pretty, event_msg);
-       if (ret != 0) {
-               goto end;
-       }
-
-       ret = print_stream_packet_context(pretty, event);
-       if (ret != 0) {
-               goto end;
-       }
-
-       ret = print_stream_event_context(pretty, event);
-       if (ret != 0) {
-               goto end;
-       }
-
-       ret = print_event_context(pretty, event);
-       if (ret != 0) {
-               goto end;
-       }
-
-       ret = print_event_payload(pretty, event);
-       if (ret != 0) {
-               goto end;
-       }
-
-       g_string_append_c(pretty->string, '\n');
-       if (flush_buf(pretty->out, pretty)) {
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int print_discarded_elements_msg(struct pretty_component *pretty,
-               const bt_stream *stream,
-               const bt_clock_snapshot *begin_clock_snapshot,
-               const bt_clock_snapshot *end_clock_snapshot,
-               uint64_t count, const char *elem_type)
-{
-       int ret = 0;
-       const bt_stream_class *stream_class = NULL;
-       const bt_trace *trace = NULL;
-       const char *stream_name;
-       const char *trace_name;
-       bt_uuid trace_uuid;
-       int64_t stream_class_id;
-       int64_t stream_id;
-       const char *init_msg;
-
-       /* Stream name */
-       stream_name = bt_stream_get_name(stream);
-       if (!stream_name) {
-               stream_name = "(unknown)";
-       }
-
-       /* Stream class ID */
-       stream_class = bt_stream_borrow_class_const(stream);
-       BT_ASSERT(stream_class);
-       stream_class_id = bt_stream_class_get_id(stream_class);
-
-       /* Stream ID */
-       stream_id = bt_stream_get_id(stream);
-
-       /* Trace name */
-       trace = bt_stream_borrow_trace_const(stream);
-       BT_ASSERT(trace);
-       trace_name = bt_trace_get_name(trace);
-       if (!trace_name) {
-               trace_name = "(unknown)";
-       }
-
-       /* Trace UUID */
-       trace_uuid = bt_trace_class_get_uuid(
-               bt_trace_borrow_class_const(trace));
-
-       /* Format message */
-       g_string_assign(pretty->string, "");
-
-       if (count == UINT64_C(-1)) {
-               init_msg = "Tracer may have discarded";
-       } else {
-               init_msg = "Tracer discarded";
-       }
-
-       g_string_append_printf(pretty->string,
-               "%s%sWARNING%s%s: %s ",
-               bt_common_color_fg_yellow(),
-               bt_common_color_bold(),
-               bt_common_color_reset(),
-               bt_common_color_fg_yellow(), init_msg);
-
-       if (count == UINT64_C(-1)) {
-               g_string_append_printf(pretty->string, "%ss", elem_type);
-       } else {
-               g_string_append_printf(pretty->string,
-                       "%" PRIu64 " %s%s", count, elem_type,
-                       count == 1 ? "" : "s");
-       }
-
-       g_string_append_c(pretty->string, ' ');
-
-       if (begin_clock_snapshot && end_clock_snapshot) {
-               g_string_append(pretty->string, "between [");
-               print_timestamp_wall(pretty, begin_clock_snapshot, false);
-               g_string_append(pretty->string, "] and [");
-               print_timestamp_wall(pretty, end_clock_snapshot, false);
-               g_string_append(pretty->string, "]");
-       } else {
-               g_string_append(pretty->string, "(unknown time range)");
-       }
-
-       g_string_append_printf(pretty->string, " in trace \"%s\" ", trace_name);
-
-       if (trace_uuid) {
-               g_string_append_printf(pretty->string,
-                       "(UUID: %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x) ",
-                       trace_uuid[0],
-                       trace_uuid[1],
-                       trace_uuid[2],
-                       trace_uuid[3],
-                       trace_uuid[4],
-                       trace_uuid[5],
-                       trace_uuid[6],
-                       trace_uuid[7],
-                       trace_uuid[8],
-                       trace_uuid[9],
-                       trace_uuid[10],
-                       trace_uuid[11],
-                       trace_uuid[12],
-                       trace_uuid[13],
-                       trace_uuid[14],
-                       trace_uuid[15]);
-       } else {
-               g_string_append(pretty->string, "(no UUID) ");
-       }
-
-       g_string_append_printf(pretty->string,
-               "within stream \"%s\" (stream class ID: %" PRIu64 ", ",
-               stream_name, stream_class_id);
-
-       if (stream_id >= 0) {
-               g_string_append_printf(pretty->string,
-                       "stream ID: %" PRIu64, stream_id);
-       } else {
-               g_string_append(pretty->string, "no stream ID");
-       }
-
-       g_string_append_printf(pretty->string, ").%s\n",
-               bt_common_color_reset());
-
-       /*
-        * Print to standard error stream to remain backward compatible
-        * with Babeltrace 1.
-        */
-       if (flush_buf(stderr, pretty)) {
-               ret = -1;
-       }
-
-       return ret;
-}
-
-BT_HIDDEN
-int pretty_print_discarded_items(struct pretty_component *pretty,
-               const bt_message *msg)
-{
-       const bt_clock_snapshot *begin = NULL;
-       const bt_clock_snapshot *end = NULL;
-       const bt_stream *stream;
-       const bt_stream_class *stream_class;
-       uint64_t count = UINT64_C(-1);
-       const char *elem_type;
-
-       switch (bt_message_get_type(msg)) {
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-               stream = bt_message_discarded_events_borrow_stream_const(msg);
-
-               if (bt_message_discarded_events_get_count(msg, &count) ==
-                               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
-                       count = UINT64_C(-1);
-               }
-
-               elem_type = "event";
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-               stream = bt_message_discarded_packets_borrow_stream_const(msg);
-
-               if (bt_message_discarded_packets_get_count(msg, &count) ==
-                               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
-                       count = UINT64_C(-1);
-               }
-
-               elem_type = "packet";
-               break;
-       default:
-               abort();
-       }
-
-       BT_ASSERT(stream);
-       stream_class = bt_stream_borrow_class_const(stream);
-
-       switch (bt_message_get_type(msg)) {
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-               if (bt_stream_class_discarded_events_have_default_clock_snapshots(
-                               stream_class)) {
-                       begin = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-                               msg);
-                       end = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
-                               msg);
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-               if (bt_stream_class_discarded_packets_have_default_clock_snapshots(
-                               stream_class)) {
-                       begin = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-                               msg);
-                       end = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
-                               msg);
-               }
-
-               break;
-       default:
-               abort();
-       }
-
-       print_discarded_elements_msg(pretty, stream, begin, end,
-               count, elem_type);
-       return 0;
-}
diff --git a/plugins/utils/Makefile.am b/plugins/utils/Makefile.am
deleted file mode 100644 (file)
index 9211dd9..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-SUBDIRS = dummy muxer counter trimmer .
-
-plugindir = "$(PLUGINSDIR)"
-plugin_LTLIBRARIES = babeltrace-plugin-utils.la
-
-babeltrace_plugin_utils_la_SOURCES = plugin.c
-babeltrace_plugin_utils_la_LDFLAGS = \
-       $(LT_NO_UNDEFINED) \
-       -avoid-version -module
-babeltrace_plugin_utils_la_LIBADD = \
-       dummy/libbabeltrace2-plugin-dummy-cc.la \
-       muxer/libbabeltrace2-plugin-muxer.la \
-       counter/libbabeltrace2-plugin-counter-cc.la \
-       trimmer/libbabeltrace2-plugin-trimmer.la
-
-if !ENABLE_BUILT_IN_PLUGINS
-babeltrace_plugin_utils_la_LIBADD += \
-       $(top_builddir)/lib/libbabeltrace2.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la
-endif
diff --git a/plugins/utils/counter/Makefile.am b/plugins/utils/counter/Makefile.am
deleted file mode 100644 (file)
index 67d1656..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-counter-cc.la
-libbabeltrace2_plugin_counter_cc_la_SOURCES = \
-       counter.c \
-       counter.h \
-       logging.c \
-       logging.h
diff --git a/plugins/utils/counter/counter.c b/plugins/utils/counter/counter.c
deleted file mode 100644 (file)
index 5a6eada..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-UTILS-COUNTER-FLT"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <plugins-common.h>
-#include <babeltrace2/assert-internal.h>
-#include <inttypes.h>
-#include <stdint.h>
-
-#include "counter.h"
-
-#define PRINTF_COUNT(_what, _var, args...)                             \
-       do {                                                            \
-               if (counter->count._var != 0 || !counter->hide_zero) {  \
-                       printf("%15" PRIu64 " %s message%s\n",          \
-                               counter->count._var,                    \
-                               (_what),                                \
-                               counter->count._var == 1 ? "" : "s");   \
-               }                                                       \
-       } while (0)
-
-static
-const char * const in_port_name = "in";
-
-static
-uint64_t get_total_count(struct counter *counter)
-{
-       return counter->count.event +
-               counter->count.stream_begin +
-               counter->count.stream_end +
-               counter->count.stream_activity_begin +
-               counter->count.stream_activity_end +
-               counter->count.packet_begin +
-               counter->count.packet_end +
-               counter->count.disc_events +
-               counter->count.disc_packets +
-               counter->count.msg_iter_inactivity +
-               counter->count.other;
-}
-
-static
-void print_count(struct counter *counter)
-{
-       uint64_t total = get_total_count(counter);
-
-       PRINTF_COUNT("Event", event);
-       PRINTF_COUNT("Stream beginning", stream_begin);
-       PRINTF_COUNT("Stream end", stream_end);
-       PRINTF_COUNT("Stream activity beginning", stream_activity_begin);
-       PRINTF_COUNT("Stream activity end", stream_activity_end);
-       PRINTF_COUNT("Packet beginning", packet_begin);
-       PRINTF_COUNT("Packet end", packet_end);
-       PRINTF_COUNT("Discarded event", disc_events);
-       PRINTF_COUNT("Discarded packet", disc_packets);
-       PRINTF_COUNT("Message iterator inactivity", msg_iter_inactivity);
-
-       if (counter->count.other > 0) {
-               PRINTF_COUNT("Other (unknown)", other);
-       }
-
-       printf("%s%15" PRIu64 " message%s (TOTAL)%s\n",
-               bt_common_color_bold(), total, total == 1 ? "" : "s",
-               bt_common_color_reset());
-       counter->last_printed_total = total;
-}
-
-static
-void try_print_count(struct counter *counter, uint64_t msg_count)
-{
-       if (counter->step == 0) {
-               /* No update */
-               return;
-       }
-
-       counter->at += msg_count;
-
-       if (counter->at >= counter->step) {
-               counter->at = 0;
-               print_count(counter);
-               putchar('\n');
-       }
-}
-
-static
-void try_print_last(struct counter *counter)
-{
-       const uint64_t total = get_total_count(counter);
-
-       if (total != counter->last_printed_total) {
-               print_count(counter);
-       }
-}
-
-void destroy_private_counter_data(struct counter *counter)
-{
-       bt_self_component_port_input_message_iterator_put_ref(counter->msg_iter);
-       g_free(counter);
-}
-
-BT_HIDDEN
-void counter_finalize(bt_self_component_sink *comp)
-{
-       struct counter *counter;
-
-       BT_ASSERT(comp);
-       counter = bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(comp));
-       BT_ASSERT(counter);
-       try_print_last(counter);
-       bt_self_component_port_input_message_iterator_put_ref(counter->msg_iter);
-       g_free(counter);
-}
-
-BT_HIDDEN
-bt_self_component_status counter_init(
-               bt_self_component_sink *component,
-               const bt_value *params,
-               UNUSED_VAR void *init_method_data)
-{
-       bt_self_component_status ret;
-       struct counter *counter = g_new0(struct counter, 1);
-       const bt_value *step = NULL;
-       const bt_value *hide_zero = NULL;
-
-       if (!counter) {
-               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto error;
-       }
-
-       ret = bt_self_component_sink_add_input_port(component,
-               "in", NULL, NULL);
-       if (ret != BT_SELF_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-
-       counter->last_printed_total = -1ULL;
-       counter->step = 10000;
-       step = bt_value_map_borrow_entry_value_const(params, "step");
-       if (step) {
-               if (!bt_value_is_unsigned_integer(step)) {
-                       BT_LOGE("`step` parameter: expecting an unsigned integer value: "
-                               "type=%s", bt_common_value_type_string(
-                                       bt_value_get_type(step)));
-                       goto error;
-               }
-
-               counter->step = bt_value_unsigned_integer_get(step);
-       }
-
-       hide_zero = bt_value_map_borrow_entry_value_const(params, "hide-zero");
-       if (hide_zero) {
-               if (!bt_value_is_bool(hide_zero)) {
-                       BT_LOGE("`hide-zero` parameter: expecting a boolean value: "
-                               "type=%s", bt_common_value_type_string(
-                                       bt_value_get_type(hide_zero)));
-                       goto error;
-               }
-
-               counter->hide_zero = (bool) bt_value_bool_get(hide_zero);
-       }
-
-       bt_self_component_set_data(
-               bt_self_component_sink_as_self_component(component),
-               counter);
-       goto end;
-
-error:
-       destroy_private_counter_data(counter);
-       ret = BT_SELF_COMPONENT_STATUS_ERROR;
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_self_component_status counter_graph_is_configured(
-               bt_self_component_sink *comp)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct counter *counter;
-       bt_self_component_port_input_message_iterator *iterator;
-
-       counter = bt_self_component_get_data(
-               bt_self_component_sink_as_self_component(comp));
-       BT_ASSERT(counter);
-       iterator = bt_self_component_port_input_message_iterator_create(
-               bt_self_component_sink_borrow_input_port_by_name(comp,
-                       in_port_name));
-       if (!iterator) {
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF(
-               counter->msg_iter, iterator);
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-bt_self_component_status counter_consume(
-               bt_self_component_sink *comp)
-{
-       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
-       struct counter *counter;
-       bt_message_iterator_status it_ret;
-       uint64_t msg_count;
-       bt_message_array_const msgs;
-
-       counter = bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(comp));
-       BT_ASSERT(counter);
-
-       if (unlikely(!counter->msg_iter)) {
-               try_print_last(counter);
-               ret = BT_SELF_COMPONENT_STATUS_END;
-               goto end;
-       }
-
-       /* Consume messages */
-       it_ret = bt_self_component_port_input_message_iterator_next(
-               counter->msg_iter, &msgs, &msg_count);
-       if (it_ret < 0) {
-               ret = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       }
-
-       switch (it_ret) {
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-       {
-               uint64_t i;
-
-               for (i = 0; i < msg_count; i++) {
-                       const bt_message *msg = msgs[i];
-
-                       BT_ASSERT(msg);
-                       switch (bt_message_get_type(msg)) {
-                       case BT_MESSAGE_TYPE_EVENT:
-                               counter->count.event++;
-                               break;
-                       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-                               counter->count.packet_begin++;
-                               break;
-                       case BT_MESSAGE_TYPE_PACKET_END:
-                               counter->count.packet_end++;
-                               break;
-                       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-                               counter->count.msg_iter_inactivity++;
-                               break;
-                       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
-                               counter->count.stream_begin++;
-                               break;
-                       case BT_MESSAGE_TYPE_STREAM_END:
-                               counter->count.stream_end++;
-                               break;
-                       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-                               counter->count.stream_activity_begin++;
-                               break;
-                       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-                               counter->count.stream_activity_end++;
-                               break;
-                       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-                               counter->count.disc_events++;
-                               break;
-                       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-                               counter->count.disc_packets++;
-                               break;
-                       default:
-                               counter->count.other++;
-                       }
-
-                       bt_message_put_ref(msg);
-               }
-
-               ret = BT_SELF_COMPONENT_STATUS_OK;
-               break;
-       }
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               ret = BT_SELF_COMPONENT_STATUS_AGAIN;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_END:
-               try_print_last(counter);
-               ret = BT_SELF_COMPONENT_STATUS_END;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       default:
-               break;
-       }
-
-       try_print_count(counter, msg_count);
-
-end:
-       return ret;
-}
diff --git a/plugins/utils/counter/counter.h b/plugins/utils/counter/counter.h
deleted file mode 100644 (file)
index c29f0fd..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef BABELTRACE_PLUGINS_UTILS_COUNTER_H
-#define BABELTRACE_PLUGINS_UTILS_COUNTER_H
-
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include <babeltrace2/babeltrace.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-struct counter {
-       bt_self_component_port_input_message_iterator *msg_iter;
-       struct {
-               uint64_t event;
-               uint64_t stream_begin;
-               uint64_t stream_end;
-               uint64_t stream_activity_begin;
-               uint64_t stream_activity_end;
-               uint64_t packet_begin;
-               uint64_t packet_end;
-               uint64_t disc_events;
-               uint64_t disc_packets;
-               uint64_t msg_iter_inactivity;
-               uint64_t other;
-       } count;
-       uint64_t last_printed_total;
-       uint64_t at;
-       uint64_t step;
-       bool hide_zero;
-};
-
-BT_HIDDEN
-bt_self_component_status counter_init(
-               bt_self_component_sink *component,
-               const bt_value *params, void *init_method_data);
-
-BT_HIDDEN
-void counter_finalize(bt_self_component_sink *component);
-
-BT_HIDDEN
-bt_self_component_status counter_graph_is_configured(
-               bt_self_component_sink *component);
-
-BT_HIDDEN
-bt_self_component_status counter_consume(bt_self_component_sink *component);
-
-#endif /* BABELTRACE_PLUGINS_UTILS_COUNTER_H */
diff --git a/plugins/utils/counter/logging.c b/plugins/utils/counter/logging.c
deleted file mode 100644 (file)
index 42de03f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_counter_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_plugin_utils_counter_log_level,
-       "BABELTRACE_FLT_UTILS_COUNTER_LOG_LEVEL");
diff --git a/plugins/utils/counter/logging.h b/plugins/utils/counter/logging.h
deleted file mode 100644 (file)
index 176122f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef PLUGINS_UTILS_MUXER_LOGGING_H
-#define PLUGINS_UTILS_MUXER_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_muxer_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_utils_muxer_log_level);
-
-#endif /* PLUGINS_UTILS_MUXER_LOGGING_H */
diff --git a/plugins/utils/dummy/Makefile.am b/plugins/utils/dummy/Makefile.am
deleted file mode 100644 (file)
index 197aaa1..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-dummy-cc.la
-libbabeltrace2_plugin_dummy_cc_la_SOURCES = dummy.c dummy.h
diff --git a/plugins/utils/dummy/dummy.c b/plugins/utils/dummy/dummy.c
deleted file mode 100644 (file)
index 59d8515..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <plugins-common.h>
-#include <babeltrace2/assert-internal.h>
-#include "dummy.h"
-
-static
-const char * const in_port_name = "in";
-
-void destroy_private_dummy_data(struct dummy *dummy)
-{
-       bt_self_component_port_input_message_iterator_put_ref(dummy->msg_iter);
-       g_free(dummy);
-
-}
-
-BT_HIDDEN
-void dummy_finalize(bt_self_component_sink *comp)
-{
-       struct dummy *dummy;
-
-       BT_ASSERT(comp);
-       dummy = bt_self_component_get_data(
-                       bt_self_component_sink_as_self_component(comp));
-       BT_ASSERT(dummy);
-       destroy_private_dummy_data(dummy);
-}
-
-BT_HIDDEN
-bt_self_component_status dummy_init(
-               bt_self_component_sink *component,
-               const bt_value *params,
-               UNUSED_VAR void *init_method_data)
-{
-       bt_self_component_status ret;
-       struct dummy *dummy = g_new0(struct dummy, 1);
-
-       if (!dummy) {
-               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       ret = bt_self_component_sink_add_input_port(component,
-               "in", NULL, NULL);
-       if (ret != BT_SELF_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-
-       bt_self_component_set_data(
-               bt_self_component_sink_as_self_component(component), dummy);
-       goto end;
-
-error:
-       destroy_private_dummy_data(dummy);
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_self_component_status dummy_graph_is_configured(
-               bt_self_component_sink *comp)
-{
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct dummy *dummy;
-       bt_self_component_port_input_message_iterator *iterator;
-
-       dummy = bt_self_component_get_data(
-               bt_self_component_sink_as_self_component(comp));
-       BT_ASSERT(dummy);
-       iterator = bt_self_component_port_input_message_iterator_create(
-               bt_self_component_sink_borrow_input_port_by_name(comp,
-                       in_port_name));
-       if (!iterator) {
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF(
-               dummy->msg_iter, iterator);
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-bt_self_component_status dummy_consume(
-               bt_self_component_sink *component)
-{
-       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
-       bt_message_array_const msgs;
-       uint64_t count;
-       struct dummy *dummy;
-       bt_message_iterator_status it_ret;
-       uint64_t i;
-
-       dummy = bt_self_component_get_data(
-               bt_self_component_sink_as_self_component(component));
-       BT_ASSERT(dummy);
-
-       if (unlikely(!dummy->msg_iter)) {
-               ret = BT_SELF_COMPONENT_STATUS_END;
-               goto end;
-       }
-
-       /* Consume one message  */
-       it_ret = bt_self_component_port_input_message_iterator_next(
-               dummy->msg_iter, &msgs, &count);
-       switch (it_ret) {
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-               ret = BT_SELF_COMPONENT_STATUS_OK;
-
-               for (i = 0; i < count; i++) {
-                       bt_message_put_ref(msgs[i]);
-               }
-
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               ret = BT_SELF_COMPONENT_STATUS_AGAIN;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_END:
-               ret = BT_SELF_COMPONENT_STATUS_END;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_ERROR:
-               ret = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto end;
-       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
-               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       default:
-               break;
-       }
-
-end:
-       return ret;
-}
diff --git a/plugins/utils/dummy/dummy.h b/plugins/utils/dummy/dummy.h
deleted file mode 100644 (file)
index dfe21d1..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef BABELTRACE_PLUGINS_UTILS_DUMMY_H
-#define BABELTRACE_PLUGINS_UTILS_DUMMY_H
-
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <glib.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <stdbool.h>
-
-struct dummy {
-       bt_self_component_port_input_message_iterator *msg_iter;
-};
-
-BT_HIDDEN
-bt_self_component_status dummy_init(
-               bt_self_component_sink *component,
-               const bt_value *params, void *init_method_data);
-
-BT_HIDDEN
-void dummy_finalize(bt_self_component_sink *component);
-
-BT_HIDDEN
-bt_self_component_status dummy_graph_is_configured(
-               bt_self_component_sink *comp);
-
-BT_HIDDEN
-bt_self_component_status dummy_consume(
-               bt_self_component_sink *component);
-
-#endif /* BABELTRACE_PLUGINS_UTILS_DUMMY_H */
diff --git a/plugins/utils/muxer/Makefile.am b/plugins/utils/muxer/Makefile.am
deleted file mode 100644 (file)
index 9c305bc..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-muxer.la
-libbabeltrace2_plugin_muxer_la_SOURCES = muxer.c muxer.h logging.c logging.h
diff --git a/plugins/utils/muxer/logging.c b/plugins/utils/muxer/logging.c
deleted file mode 100644 (file)
index 3f16b97..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_muxer_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_plugin_utils_muxer_log_level,
-       "BABELTRACE_FLT_UTILS_MUXER_LOG_LEVEL");
diff --git a/plugins/utils/muxer/logging.h b/plugins/utils/muxer/logging.h
deleted file mode 100644 (file)
index 176122f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef PLUGINS_UTILS_MUXER_LOGGING_H
-#define PLUGINS_UTILS_MUXER_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_muxer_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_utils_muxer_log_level);
-
-#endif /* PLUGINS_UTILS_MUXER_LOGGING_H */
diff --git a/plugins/utils/muxer/muxer.c b/plugins/utils/muxer/muxer.c
deleted file mode 100644 (file)
index 626c437..0000000
+++ /dev/null
@@ -1,1534 +0,0 @@
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-UTILS-MUXER-FLT"
-#include "logging.h"
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compat/uuid-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/value-internal.h>
-#include <babeltrace2/graph/component-internal.h>
-#include <babeltrace2/graph/message-iterator-internal.h>
-#include <babeltrace2/graph/connection-internal.h>
-#include <plugins-common.h>
-#include <glib.h>
-#include <stdbool.h>
-#include <inttypes.h>
-#include <babeltrace2/assert-internal.h>
-#include <babeltrace2/common-internal.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "muxer.h"
-
-#define ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME       "assume-absolute-clock-classes"
-
-struct muxer_comp {
-       /* Weak ref */
-       bt_self_component_filter *self_comp;
-
-       unsigned int next_port_num;
-       size_t available_input_ports;
-       bool initializing_muxer_msg_iter;
-       bool assume_absolute_clock_classes;
-};
-
-struct muxer_upstream_msg_iter {
-       /* Owned by this, NULL if ended */
-       bt_self_component_port_input_message_iterator *msg_iter;
-
-       /* Contains `const bt_message *`, owned by this */
-       GQueue *msgs;
-};
-
-enum muxer_msg_iter_clock_class_expectation {
-       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ANY = 0,
-       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NONE,
-       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE,
-       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID,
-       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID,
-};
-
-struct muxer_msg_iter {
-       /*
-        * Array of struct muxer_upstream_msg_iter * (owned by this).
-        *
-        * NOTE: This array is searched in linearly to find the youngest
-        * current message. Keep this until benchmarks confirm that
-        * another data structure is faster than this for our typical
-        * use cases.
-        */
-       GPtrArray *active_muxer_upstream_msg_iters;
-
-       /*
-        * Array of struct muxer_upstream_msg_iter * (owned by this).
-        *
-        * We move ended message iterators from
-        * `active_muxer_upstream_msg_iters` to this array so as to be
-        * able to restore them when seeking.
-        */
-       GPtrArray *ended_muxer_upstream_msg_iters;
-
-       /* Last time returned in a message */
-       int64_t last_returned_ts_ns;
-
-       /* Clock class expectation state */
-       enum muxer_msg_iter_clock_class_expectation clock_class_expectation;
-
-       /*
-        * Expected clock class UUID, only valid when
-        * clock_class_expectation is
-        * MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID.
-        */
-       unsigned char expected_clock_class_uuid[BABELTRACE_UUID_LEN];
-};
-
-static
-void empty_message_queue(struct muxer_upstream_msg_iter *upstream_msg_iter)
-{
-       const bt_message *msg;
-
-       while ((msg = g_queue_pop_head(upstream_msg_iter->msgs))) {
-               bt_message_put_ref(msg);
-       }
-}
-
-static
-void destroy_muxer_upstream_msg_iter(
-               struct muxer_upstream_msg_iter *muxer_upstream_msg_iter)
-{
-       if (!muxer_upstream_msg_iter) {
-               return;
-       }
-
-       BT_LOGD("Destroying muxer's upstream message iterator wrapper: "
-               "addr=%p, msg-iter-addr=%p, queue-len=%u",
-               muxer_upstream_msg_iter,
-               muxer_upstream_msg_iter->msg_iter,
-               muxer_upstream_msg_iter->msgs->length);
-       bt_self_component_port_input_message_iterator_put_ref(
-               muxer_upstream_msg_iter->msg_iter);
-
-       if (muxer_upstream_msg_iter->msgs) {
-               empty_message_queue(muxer_upstream_msg_iter);
-               g_queue_free(muxer_upstream_msg_iter->msgs);
-       }
-
-       g_free(muxer_upstream_msg_iter);
-}
-
-static
-int muxer_msg_iter_add_upstream_msg_iter(struct muxer_msg_iter *muxer_msg_iter,
-               bt_self_component_port_input_message_iterator *self_msg_iter)
-{
-       int ret = 0;
-       struct muxer_upstream_msg_iter *muxer_upstream_msg_iter =
-               g_new0(struct muxer_upstream_msg_iter, 1);
-
-       if (!muxer_upstream_msg_iter) {
-               BT_LOGE_STR("Failed to allocate one muxer's upstream message iterator wrapper.");
-               goto error;
-       }
-
-       muxer_upstream_msg_iter->msg_iter = self_msg_iter;
-       bt_self_component_port_input_message_iterator_get_ref(muxer_upstream_msg_iter->msg_iter);
-       muxer_upstream_msg_iter->msgs = g_queue_new();
-       if (!muxer_upstream_msg_iter->msgs) {
-               BT_LOGE_STR("Failed to allocate a GQueue.");
-               goto error;
-       }
-
-       g_ptr_array_add(muxer_msg_iter->active_muxer_upstream_msg_iters,
-               muxer_upstream_msg_iter);
-       BT_LOGD("Added muxer's upstream message iterator wrapper: "
-               "addr=%p, muxer-msg-iter-addr=%p, msg-iter-addr=%p",
-               muxer_upstream_msg_iter, muxer_msg_iter,
-               self_msg_iter);
-
-       goto end;
-
-error:
-       g_free(muxer_upstream_msg_iter);
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static
-bt_self_component_status add_available_input_port(
-               bt_self_component_filter *self_comp)
-{
-       struct muxer_comp *muxer_comp = bt_self_component_get_data(
-               bt_self_component_filter_as_self_component(self_comp));
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       GString *port_name = NULL;
-
-       BT_ASSERT(muxer_comp);
-       port_name = g_string_new("in");
-       if (!port_name) {
-               BT_LOGE_STR("Failed to allocate a GString.");
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto end;
-       }
-
-       g_string_append_printf(port_name, "%u", muxer_comp->next_port_num);
-       status = bt_self_component_filter_add_input_port(
-               self_comp, port_name->str, NULL, NULL);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               BT_LOGE("Cannot add input port to muxer component: "
-                       "port-name=\"%s\", comp-addr=%p, status=%s",
-                       port_name->str, self_comp,
-                       bt_self_component_status_string(status));
-               goto end;
-       }
-
-       muxer_comp->available_input_ports++;
-       muxer_comp->next_port_num++;
-       BT_LOGD("Added one input port to muxer component: "
-               "port-name=\"%s\", comp-addr=%p",
-               port_name->str, self_comp);
-
-end:
-       if (port_name) {
-               g_string_free(port_name, TRUE);
-       }
-
-       return status;
-}
-
-static
-bt_self_component_status create_output_port(
-               bt_self_component_filter *self_comp)
-{
-       return bt_self_component_filter_add_output_port(
-               self_comp, "out", NULL, NULL);
-}
-
-static
-void destroy_muxer_comp(struct muxer_comp *muxer_comp)
-{
-       if (!muxer_comp) {
-               return;
-       }
-
-       g_free(muxer_comp);
-}
-
-static
-bt_value *get_default_params(void)
-{
-       bt_value *params;
-       int ret;
-
-       params = bt_value_map_create();
-       if (!params) {
-               BT_LOGE_STR("Cannot create a map value object.");
-               goto error;
-       }
-
-       ret = bt_value_map_insert_bool_entry(params,
-               ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME, false);
-       if (ret) {
-               BT_LOGE_STR("Cannot add boolean value to map value object.");
-               goto error;
-       }
-
-       goto end;
-
-error:
-       BT_VALUE_PUT_REF_AND_RESET(params);
-
-end:
-       return params;
-}
-
-static
-int configure_muxer_comp(struct muxer_comp *muxer_comp,
-               const bt_value *params)
-{
-       bt_value *default_params = NULL;
-       bt_value *real_params = NULL;
-       const bt_value *assume_absolute_clock_classes = NULL;
-       int ret = 0;
-       bt_bool bool_val;
-
-       default_params = get_default_params();
-       if (!default_params) {
-               BT_LOGE("Cannot get default parameters: "
-                       "muxer-comp-addr=%p", muxer_comp);
-               goto error;
-       }
-
-       ret = bt_value_map_extend(default_params, params, &real_params);
-       if (ret) {
-               BT_LOGE("Cannot extend default parameters map value: "
-                       "muxer-comp-addr=%p, def-params-addr=%p, "
-                       "params-addr=%p", muxer_comp, default_params,
-                       params);
-               goto error;
-       }
-
-       assume_absolute_clock_classes = bt_value_map_borrow_entry_value(real_params,
-                                                                       ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME);
-       if (assume_absolute_clock_classes &&
-                       !bt_value_is_bool(assume_absolute_clock_classes)) {
-               BT_LOGE("Expecting a boolean value for the `%s` parameter: "
-                       "muxer-comp-addr=%p, value-type=%s",
-                       ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME, muxer_comp,
-                       bt_common_value_type_string(
-                               bt_value_get_type(assume_absolute_clock_classes)));
-               goto error;
-       }
-
-       bool_val = bt_value_bool_get(assume_absolute_clock_classes);
-       muxer_comp->assume_absolute_clock_classes = (bool) bool_val;
-       BT_LOGD("Configured muxer component: muxer-comp-addr=%p, "
-               "assume-absolute-clock-classes=%d",
-               muxer_comp, muxer_comp->assume_absolute_clock_classes);
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       bt_value_put_ref(default_params);
-       bt_value_put_ref(real_params);
-       return ret;
-}
-
-BT_HIDDEN
-bt_self_component_status muxer_init(
-               bt_self_component_filter *self_comp,
-               const bt_value *params, void *init_data)
-{
-       int ret;
-       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
-       struct muxer_comp *muxer_comp = g_new0(struct muxer_comp, 1);
-
-       BT_LOGD("Initializing muxer component: "
-               "comp-addr=%p, params-addr=%p", self_comp, params);
-
-       if (!muxer_comp) {
-               BT_LOGE_STR("Failed to allocate one muxer component.");
-               goto error;
-       }
-
-       ret = configure_muxer_comp(muxer_comp, params);
-       if (ret) {
-               BT_LOGE("Cannot configure muxer component: "
-                       "muxer-comp-addr=%p, params-addr=%p",
-                       muxer_comp, params);
-               goto error;
-       }
-
-       muxer_comp->self_comp = self_comp;
-       bt_self_component_set_data(
-               bt_self_component_filter_as_self_component(self_comp),
-               muxer_comp);
-       status = add_available_input_port(self_comp);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               BT_LOGE("Cannot ensure that at least one muxer component's input port is available: "
-                       "muxer-comp-addr=%p, status=%s",
-                       muxer_comp,
-                       bt_self_component_status_string(status));
-               goto error;
-       }
-
-       status = create_output_port(self_comp);
-       if (status) {
-               BT_LOGE("Cannot create muxer component's output port: "
-                       "muxer-comp-addr=%p, status=%s",
-                       muxer_comp,
-                       bt_self_component_status_string(status));
-               goto error;
-       }
-
-       BT_LOGD("Initialized muxer component: "
-               "comp-addr=%p, params-addr=%p, muxer-comp-addr=%p",
-               self_comp, params, muxer_comp);
-
-       goto end;
-
-error:
-       destroy_muxer_comp(muxer_comp);
-       bt_self_component_set_data(
-               bt_self_component_filter_as_self_component(self_comp),
-               NULL);
-
-       if (status == BT_SELF_COMPONENT_STATUS_OK) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-       }
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-void muxer_finalize(bt_self_component_filter *self_comp)
-{
-       struct muxer_comp *muxer_comp = bt_self_component_get_data(
-               bt_self_component_filter_as_self_component(self_comp));
-
-       BT_LOGD("Finalizing muxer component: comp-addr=%p",
-               self_comp);
-       destroy_muxer_comp(muxer_comp);
-}
-
-static
-bt_self_component_port_input_message_iterator *
-create_msg_iter_on_input_port(bt_self_component_port_input *self_port)
-{
-       const bt_port *port = bt_self_component_port_as_port(
-               bt_self_component_port_input_as_self_component_port(
-                       self_port));
-       bt_self_component_port_input_message_iterator *msg_iter =
-               NULL;
-
-       BT_ASSERT(port);
-       BT_ASSERT(bt_port_is_connected(port));
-
-       // TODO: Advance the iterator to >= the time of the latest
-       //       returned message by the muxer message
-       //       iterator which creates it.
-       msg_iter = bt_self_component_port_input_message_iterator_create(
-               self_port);
-       if (!msg_iter) {
-               BT_LOGE("Cannot create upstream message iterator on input port: "
-                       "port-addr=%p, port-name=\"%s\"",
-                       port, bt_port_get_name(port));
-               goto end;
-       }
-
-       BT_LOGD("Created upstream message iterator on input port: "
-               "port-addr=%p, port-name=\"%s\", msg-iter-addr=%p",
-               port, bt_port_get_name(port), msg_iter);
-
-end:
-       return msg_iter;
-}
-
-static
-bt_self_message_iterator_status muxer_upstream_msg_iter_next(
-               struct muxer_upstream_msg_iter *muxer_upstream_msg_iter,
-               bool *is_ended)
-{
-       bt_self_message_iterator_status status;
-       bt_message_iterator_status input_port_iter_status;
-       bt_message_array_const msgs;
-       uint64_t i;
-       uint64_t count;
-
-       BT_LOGV("Calling upstream message iterator's \"next\" method: "
-               "muxer-upstream-msg-iter-wrap-addr=%p, msg-iter-addr=%p",
-               muxer_upstream_msg_iter,
-               muxer_upstream_msg_iter->msg_iter);
-       input_port_iter_status = bt_self_component_port_input_message_iterator_next(
-               muxer_upstream_msg_iter->msg_iter, &msgs, &count);
-       BT_LOGV("Upstream message iterator's \"next\" method returned: "
-               "status=%s", bt_message_iterator_status_string(input_port_iter_status));
-
-       switch (input_port_iter_status) {
-       case BT_MESSAGE_ITERATOR_STATUS_OK:
-               /*
-                * Message iterator's current message is
-                * valid: it must be considered for muxing operations.
-                */
-               BT_LOGV_STR("Validated upstream message iterator wrapper.");
-               BT_ASSERT(count > 0);
-
-               /* Move messages to our queue */
-               for (i = 0; i < count; i++) {
-                       /*
-                        * Push to tail in order; other side
-                        * (muxer_msg_iter_do_next_one()) consumes
-                        * from the head first.
-                        */
-                       g_queue_push_tail(muxer_upstream_msg_iter->msgs,
-                               (void *) msgs[i]);
-               }
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
-               /*
-                * Message iterator's current message is not
-                * valid anymore. Return
-                * BT_MESSAGE_ITERATOR_STATUS_AGAIN immediately.
-                */
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN;
-               break;
-       case BT_MESSAGE_ITERATOR_STATUS_END:    /* Fall-through. */
-               /*
-                * Message iterator reached the end: release it. It
-                * won't be considered again to find the youngest
-                * message.
-                */
-               *is_ended = true;
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-               break;
-       default:
-               /* Error or unsupported status code */
-               BT_LOGE("Error or unsupported status code: "
-                       "status-code=%d", input_port_iter_status);
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               break;
-       }
-
-       return status;
-}
-
-static
-int get_msg_ts_ns(struct muxer_comp *muxer_comp,
-               struct muxer_msg_iter *muxer_msg_iter,
-               const bt_message *msg, int64_t last_returned_ts_ns,
-               int64_t *ts_ns)
-{
-       const bt_clock_snapshot *clock_snapshot = NULL;
-       int ret = 0;
-       bt_message_stream_activity_clock_snapshot_state sa_cs_state;
-       const bt_stream_class *stream_class = NULL;
-       bt_message_type msg_type;
-
-       BT_ASSERT(msg);
-       BT_ASSERT(ts_ns);
-       BT_LOGV("Getting message's timestamp: "
-               "muxer-msg-iter-addr=%p, msg-addr=%p, "
-               "last-returned-ts=%" PRId64,
-               muxer_msg_iter, msg, last_returned_ts_ns);
-
-       if (unlikely(muxer_msg_iter->clock_class_expectation ==
-                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NONE)) {
-               *ts_ns = last_returned_ts_ns;
-               goto end;
-       }
-
-       msg_type = bt_message_get_type(msg);
-
-       if (unlikely(msg_type == BT_MESSAGE_TYPE_PACKET_BEGINNING)) {
-               stream_class = bt_stream_borrow_class_const(
-                       bt_packet_borrow_stream_const(
-                               bt_message_packet_beginning_borrow_packet_const(
-                                       msg)));
-       } else if (unlikely(msg_type == BT_MESSAGE_TYPE_PACKET_END)) {
-               stream_class = bt_stream_borrow_class_const(
-                       bt_packet_borrow_stream_const(
-                               bt_message_packet_end_borrow_packet_const(
-                                       msg)));
-       } else if (unlikely(msg_type == BT_MESSAGE_TYPE_DISCARDED_EVENTS)) {
-               stream_class = bt_stream_borrow_class_const(
-                       bt_message_discarded_events_borrow_stream_const(msg));
-       } else if (unlikely(msg_type == BT_MESSAGE_TYPE_DISCARDED_PACKETS)) {
-               stream_class = bt_stream_borrow_class_const(
-                       bt_message_discarded_packets_borrow_stream_const(msg));
-       }
-
-       switch (msg_type) {
-       case BT_MESSAGE_TYPE_EVENT:
-               BT_ASSERT(bt_message_event_borrow_stream_class_default_clock_class_const(
-                               msg));
-               clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-               if (bt_stream_class_packets_have_beginning_default_clock_snapshot(
-                               stream_class)) {
-                       clock_snapshot = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
-                               msg);
-               } else {
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_PACKET_END:
-               if (bt_stream_class_packets_have_end_default_clock_snapshot(
-                               stream_class)) {
-                       clock_snapshot = bt_message_packet_end_borrow_default_clock_snapshot_const(
-                               msg);
-               } else {
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-               if (bt_stream_class_discarded_events_have_default_clock_snapshots(
-                               stream_class)) {
-                       clock_snapshot = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-                               msg);
-               } else {
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-               if (bt_stream_class_discarded_packets_have_default_clock_snapshots(
-                               stream_class)) {
-                       clock_snapshot = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-                               msg);
-               } else {
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-               BT_ASSERT(bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
-                               msg));
-               sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
-                       msg, &clock_snapshot);
-               if (sa_cs_state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-               BT_ASSERT(bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
-                               msg));
-               sa_cs_state = bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
-                       msg, &clock_snapshot);
-               if (sa_cs_state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-               clock_snapshot = bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
-                       msg);
-               break;
-       default:
-               /* All the other messages have a higher priority */
-               BT_LOGV_STR("Message has no timestamp: using the last returned timestamp.");
-               *ts_ns = last_returned_ts_ns;
-               goto end;
-       }
-
-       ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot, ts_ns);
-       if (ret) {
-               BT_LOGE("Cannot get nanoseconds from Epoch of clock snapshot: "
-                       "clock-snapshot-addr=%p", clock_snapshot);
-               goto error;
-       }
-
-       goto end;
-
-no_clock_snapshot:
-       BT_LOGV_STR("Message's default clock snapshot is missing: "
-               "using the last returned timestamp.");
-       *ts_ns = last_returned_ts_ns;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       if (ret == 0) {
-               BT_LOGV("Found message's timestamp: "
-                       "muxer-msg-iter-addr=%p, msg-addr=%p, "
-                       "last-returned-ts=%" PRId64 ", ts=%" PRId64,
-                       muxer_msg_iter, msg, last_returned_ts_ns,
-                       *ts_ns);
-       }
-
-       return ret;
-}
-
-static inline
-int validate_clock_class(struct muxer_msg_iter *muxer_msg_iter,
-               struct muxer_comp *muxer_comp,
-               const bt_clock_class *clock_class)
-{
-       int ret = 0;
-       const unsigned char *cc_uuid;
-       const char *cc_name;
-
-       BT_ASSERT(clock_class);
-       cc_uuid = bt_clock_class_get_uuid(clock_class);
-       cc_name = bt_clock_class_get_name(clock_class);
-
-       if (muxer_msg_iter->clock_class_expectation ==
-                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ANY) {
-               /*
-                * This is the first clock class that this muxer
-                * message iterator encounters. Its properties
-                * determine what to expect for the whole lifetime of
-                * the iterator without a true
-                * `assume-absolute-clock-classes` parameter.
-                */
-               if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
-                       /* Expect absolute clock classes */
-                       muxer_msg_iter->clock_class_expectation =
-                               MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE;
-               } else {
-                       if (cc_uuid) {
-                               /*
-                                * Expect non-absolute clock classes
-                                * with a specific UUID.
-                                */
-                               muxer_msg_iter->clock_class_expectation =
-                                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID;
-                               memcpy(muxer_msg_iter->expected_clock_class_uuid,
-                                       cc_uuid, BABELTRACE_UUID_LEN);
-                       } else {
-                               /*
-                                * Expect non-absolute clock classes
-                                * with no UUID.
-                                */
-                               muxer_msg_iter->clock_class_expectation =
-                                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID;
-                       }
-               }
-       }
-
-       if (!muxer_comp->assume_absolute_clock_classes) {
-               switch (muxer_msg_iter->clock_class_expectation) {
-               case MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE:
-                       if (!bt_clock_class_origin_is_unix_epoch(clock_class)) {
-                               BT_LOGE("Expecting an absolute clock class, "
-                                       "but got a non-absolute one: "
-                                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                                       clock_class, cc_name);
-                               goto error;
-                       }
-                       break;
-               case MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID:
-                       if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
-                               BT_LOGE("Expecting a non-absolute clock class with no UUID, "
-                                       "but got an absolute one: "
-                                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                                       clock_class, cc_name);
-                               goto error;
-                       }
-
-                       if (cc_uuid) {
-                               BT_LOGE("Expecting a non-absolute clock class with no UUID, "
-                                       "but got one with a UUID: "
-                                       "clock-class-addr=%p, clock-class-name=\"%s\", "
-                                       "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-                                       clock_class, cc_name,
-                                       (unsigned int) cc_uuid[0],
-                                       (unsigned int) cc_uuid[1],
-                                       (unsigned int) cc_uuid[2],
-                                       (unsigned int) cc_uuid[3],
-                                       (unsigned int) cc_uuid[4],
-                                       (unsigned int) cc_uuid[5],
-                                       (unsigned int) cc_uuid[6],
-                                       (unsigned int) cc_uuid[7],
-                                       (unsigned int) cc_uuid[8],
-                                       (unsigned int) cc_uuid[9],
-                                       (unsigned int) cc_uuid[10],
-                                       (unsigned int) cc_uuid[11],
-                                       (unsigned int) cc_uuid[12],
-                                       (unsigned int) cc_uuid[13],
-                                       (unsigned int) cc_uuid[14],
-                                       (unsigned int) cc_uuid[15]);
-                               goto error;
-                       }
-                       break;
-               case MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID:
-                       if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
-                               BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
-                                       "but got an absolute one: "
-                                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                                       clock_class, cc_name);
-                               goto error;
-                       }
-
-                       if (!cc_uuid) {
-                               BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
-                                       "but got one with no UUID: "
-                                       "clock-class-addr=%p, clock-class-name=\"%s\"",
-                                       clock_class, cc_name);
-                               goto error;
-                       }
-
-                       if (memcmp(muxer_msg_iter->expected_clock_class_uuid,
-                                       cc_uuid, BABELTRACE_UUID_LEN) != 0) {
-                               BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
-                                       "but got one with different UUID: "
-                                       "clock-class-addr=%p, clock-class-name=\"%s\", "
-                                       "expected-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", "
-                                       "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
-                                       clock_class, cc_name,
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[0],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[1],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[2],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[3],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[4],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[5],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[6],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[7],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[8],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[9],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[10],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[11],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[12],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[13],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[14],
-                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[15],
-                                       (unsigned int) cc_uuid[0],
-                                       (unsigned int) cc_uuid[1],
-                                       (unsigned int) cc_uuid[2],
-                                       (unsigned int) cc_uuid[3],
-                                       (unsigned int) cc_uuid[4],
-                                       (unsigned int) cc_uuid[5],
-                                       (unsigned int) cc_uuid[6],
-                                       (unsigned int) cc_uuid[7],
-                                       (unsigned int) cc_uuid[8],
-                                       (unsigned int) cc_uuid[9],
-                                       (unsigned int) cc_uuid[10],
-                                       (unsigned int) cc_uuid[11],
-                                       (unsigned int) cc_uuid[12],
-                                       (unsigned int) cc_uuid[13],
-                                       (unsigned int) cc_uuid[14],
-                                       (unsigned int) cc_uuid[15]);
-                               goto error;
-                       }
-                       break;
-               case MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NONE:
-                       BT_LOGE("Expecting no clock class, but got one: "
-                               "clock-class-addr=%p, clock-class-name=\"%s\"",
-                               clock_class, cc_name);
-                       goto error;
-               default:
-                       /* Unexpected */
-                       BT_LOGF("Unexpected clock class expectation: "
-                               "expectation-code=%d",
-                               muxer_msg_iter->clock_class_expectation);
-                       abort();
-               }
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static inline
-int validate_new_stream_clock_class(struct muxer_msg_iter *muxer_msg_iter,
-               struct muxer_comp *muxer_comp, const bt_stream *stream)
-{
-       int ret = 0;
-       const bt_stream_class *stream_class =
-               bt_stream_borrow_class_const(stream);
-       const bt_clock_class *clock_class =
-               bt_stream_class_borrow_default_clock_class_const(stream_class);
-
-       if (!clock_class) {
-               if (muxer_msg_iter->clock_class_expectation ==
-                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ANY) {
-                       /* Expect no clock class */
-                       muxer_msg_iter->clock_class_expectation =
-                               MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NONE;
-               } else {
-                       BT_LOGE("Expecting stream class with a default clock class: "
-                               "stream-class-addr=%p, stream-class-name=\"%s\", "
-                               "stream-class-id=%" PRIu64,
-                               stream_class, bt_stream_class_get_name(stream_class),
-                               bt_stream_class_get_id(stream_class));
-                       ret = -1;
-               }
-
-               goto end;
-       }
-
-       ret = validate_clock_class(muxer_msg_iter, muxer_comp, clock_class);
-
-end:
-       return ret;
-}
-
-/*
- * This function finds the youngest available message amongst the
- * non-ended upstream message iterators and returns the upstream
- * message iterator which has it, or
- * BT_MESSAGE_ITERATOR_STATUS_END if there's no available
- * message.
- *
- * This function does NOT:
- *
- * * Update any upstream message iterator.
- * * Check the upstream message iterators to retry.
- *
- * On sucess, this function sets *muxer_upstream_msg_iter to the
- * upstream message iterator of which the current message is
- * the youngest, and sets *ts_ns to its time.
- */
-static
-bt_self_message_iterator_status
-muxer_msg_iter_youngest_upstream_msg_iter(
-               struct muxer_comp *muxer_comp,
-               struct muxer_msg_iter *muxer_msg_iter,
-               struct muxer_upstream_msg_iter **muxer_upstream_msg_iter,
-               int64_t *ts_ns)
-{
-       size_t i;
-       int ret;
-       int64_t youngest_ts_ns = INT64_MAX;
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_ASSERT(muxer_comp);
-       BT_ASSERT(muxer_msg_iter);
-       BT_ASSERT(muxer_upstream_msg_iter);
-       *muxer_upstream_msg_iter = NULL;
-
-       for (i = 0; i < muxer_msg_iter->active_muxer_upstream_msg_iters->len;
-                       i++) {
-               const bt_message *msg;
-               struct muxer_upstream_msg_iter *cur_muxer_upstream_msg_iter =
-                       g_ptr_array_index(
-                               muxer_msg_iter->active_muxer_upstream_msg_iters,
-                               i);
-               int64_t msg_ts_ns;
-
-               if (!cur_muxer_upstream_msg_iter->msg_iter) {
-                       /* This upstream message iterator is ended */
-                       BT_LOGV("Skipping ended upstream message iterator: "
-                               "muxer-upstream-msg-iter-wrap-addr=%p",
-                               cur_muxer_upstream_msg_iter);
-                       continue;
-               }
-
-               BT_ASSERT(cur_muxer_upstream_msg_iter->msgs->length > 0);
-               msg = g_queue_peek_head(cur_muxer_upstream_msg_iter->msgs);
-               BT_ASSERT(msg);
-
-               if (unlikely(bt_message_get_type(msg) ==
-                               BT_MESSAGE_TYPE_STREAM_BEGINNING)) {
-                       ret = validate_new_stream_clock_class(
-                               muxer_msg_iter, muxer_comp,
-                               bt_message_stream_beginning_borrow_stream_const(
-                                       msg));
-                       if (ret) {
-                               /*
-                                * validate_new_stream_clock_class() logs
-                                * errors.
-                                */
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-               } else if (unlikely(bt_message_get_type(msg) ==
-                               BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY)) {
-                       const bt_clock_snapshot *cs;
-
-                       cs = bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
-                               msg);
-                       ret = validate_clock_class(muxer_msg_iter, muxer_comp,
-                               bt_clock_snapshot_borrow_clock_class_const(cs));
-                       if (ret) {
-                               /* validate_clock_class() logs errors */
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-               }
-
-               ret = get_msg_ts_ns(muxer_comp, muxer_msg_iter, msg,
-                       muxer_msg_iter->last_returned_ts_ns, &msg_ts_ns);
-               if (ret) {
-                       /* get_msg_ts_ns() logs errors */
-                       *muxer_upstream_msg_iter = NULL;
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                       goto end;
-               }
-
-               if (msg_ts_ns <= youngest_ts_ns) {
-                       *muxer_upstream_msg_iter =
-                               cur_muxer_upstream_msg_iter;
-                       youngest_ts_ns = msg_ts_ns;
-                       *ts_ns = youngest_ts_ns;
-               }
-       }
-
-       if (!*muxer_upstream_msg_iter) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-               *ts_ns = INT64_MIN;
-       }
-
-end:
-       return status;
-}
-
-static
-bt_self_message_iterator_status validate_muxer_upstream_msg_iter(
-       struct muxer_upstream_msg_iter *muxer_upstream_msg_iter,
-       bool *is_ended)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_LOGV("Validating muxer's upstream message iterator wrapper: "
-               "muxer-upstream-msg-iter-wrap-addr=%p",
-               muxer_upstream_msg_iter);
-
-       if (muxer_upstream_msg_iter->msgs->length > 0 ||
-                       !muxer_upstream_msg_iter->msg_iter) {
-               BT_LOGV("Already valid or not considered: "
-                       "queue-len=%u, upstream-msg-iter-addr=%p",
-                       muxer_upstream_msg_iter->msgs->length,
-                       muxer_upstream_msg_iter->msg_iter);
-               goto end;
-       }
-
-       /* muxer_upstream_msg_iter_next() logs details/errors */
-       status = muxer_upstream_msg_iter_next(muxer_upstream_msg_iter,
-               is_ended);
-
-end:
-       return status;
-}
-
-static
-bt_self_message_iterator_status validate_muxer_upstream_msg_iters(
-               struct muxer_msg_iter *muxer_msg_iter)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       size_t i;
-
-       BT_LOGV("Validating muxer's upstream message iterator wrappers: "
-               "muxer-msg-iter-addr=%p", muxer_msg_iter);
-
-       for (i = 0; i < muxer_msg_iter->active_muxer_upstream_msg_iters->len;
-                       i++) {
-               bool is_ended = false;
-               struct muxer_upstream_msg_iter *muxer_upstream_msg_iter =
-                       g_ptr_array_index(
-                               muxer_msg_iter->active_muxer_upstream_msg_iters,
-                               i);
-
-               status = validate_muxer_upstream_msg_iter(
-                       muxer_upstream_msg_iter, &is_ended);
-               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                       if (status < 0) {
-                               BT_LOGE("Cannot validate muxer's upstream message iterator wrapper: "
-                                       "muxer-msg-iter-addr=%p, "
-                                       "muxer-upstream-msg-iter-wrap-addr=%p",
-                                       muxer_msg_iter,
-                                       muxer_upstream_msg_iter);
-                       } else {
-                               BT_LOGV("Cannot validate muxer's upstream message iterator wrapper: "
-                                       "muxer-msg-iter-addr=%p, "
-                                       "muxer-upstream-msg-iter-wrap-addr=%p",
-                                       muxer_msg_iter,
-                                       muxer_upstream_msg_iter);
-                       }
-
-                       goto end;
-               }
-
-               /*
-                * Move this muxer upstream message iterator to the
-                * array of ended iterators if it's ended.
-                */
-               if (unlikely(is_ended)) {
-                       BT_LOGV("Muxer's upstream message iterator wrapper: ended or canceled: "
-                               "muxer-msg-iter-addr=%p, "
-                               "muxer-upstream-msg-iter-wrap-addr=%p",
-                               muxer_msg_iter, muxer_upstream_msg_iter);
-                       g_ptr_array_add(
-                               muxer_msg_iter->ended_muxer_upstream_msg_iters,
-                               muxer_upstream_msg_iter);
-                       muxer_msg_iter->active_muxer_upstream_msg_iters->pdata[i] = NULL;
-
-                       /*
-                        * Use g_ptr_array_remove_fast() because the
-                        * order of those elements is not important.
-                        */
-                       g_ptr_array_remove_index_fast(
-                               muxer_msg_iter->active_muxer_upstream_msg_iters,
-                               i);
-                       i--;
-               }
-       }
-
-end:
-       return status;
-}
-
-static inline
-bt_self_message_iterator_status muxer_msg_iter_do_next_one(
-               struct muxer_comp *muxer_comp,
-               struct muxer_msg_iter *muxer_msg_iter,
-               const bt_message **msg)
-{
-       bt_self_message_iterator_status status;
-       struct muxer_upstream_msg_iter *muxer_upstream_msg_iter = NULL;
-       int64_t next_return_ts;
-
-       status = validate_muxer_upstream_msg_iters(muxer_msg_iter);
-       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-               /* validate_muxer_upstream_msg_iters() logs details */
-               goto end;
-       }
-
-       /*
-        * At this point we know that all the existing upstream
-        * message iterators are valid. We can find the one,
-        * amongst those, of which the current message is the
-        * youngest.
-        */
-       status = muxer_msg_iter_youngest_upstream_msg_iter(muxer_comp,
-                       muxer_msg_iter, &muxer_upstream_msg_iter,
-                       &next_return_ts);
-       if (status < 0 || status == BT_SELF_MESSAGE_ITERATOR_STATUS_END) {
-               if (status < 0) {
-                       BT_LOGE("Cannot find the youngest upstream message iterator wrapper: "
-                               "status=%s",
-                               bt_common_self_message_iterator_status_string(status));
-               } else {
-                       BT_LOGV("Cannot find the youngest upstream message iterator wrapper: "
-                               "status=%s",
-                               bt_common_self_message_iterator_status_string(status));
-               }
-
-               goto end;
-       }
-
-       if (next_return_ts < muxer_msg_iter->last_returned_ts_ns) {
-               BT_LOGE("Youngest upstream message iterator wrapper's timestamp is less than muxer's message iterator's last returned timestamp: "
-                       "muxer-msg-iter-addr=%p, ts=%" PRId64 ", "
-                       "last-returned-ts=%" PRId64,
-                       muxer_msg_iter, next_return_ts,
-                       muxer_msg_iter->last_returned_ts_ns);
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       BT_LOGV("Found youngest upstream message iterator wrapper: "
-               "muxer-msg-iter-addr=%p, "
-               "muxer-upstream-msg-iter-wrap-addr=%p, "
-               "ts=%" PRId64,
-               muxer_msg_iter, muxer_upstream_msg_iter, next_return_ts);
-       BT_ASSERT(status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK);
-       BT_ASSERT(muxer_upstream_msg_iter);
-
-       /*
-        * Consume from the queue's head: other side
-        * (muxer_upstream_msg_iter_next()) writes to the tail.
-        */
-       *msg = g_queue_pop_head(muxer_upstream_msg_iter->msgs);
-       BT_ASSERT(*msg);
-       muxer_msg_iter->last_returned_ts_ns = next_return_ts;
-
-end:
-       return status;
-}
-
-static
-bt_self_message_iterator_status muxer_msg_iter_do_next(
-               struct muxer_comp *muxer_comp,
-               struct muxer_msg_iter *muxer_msg_iter,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       uint64_t i = 0;
-
-       while (i < capacity && status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-               status = muxer_msg_iter_do_next_one(muxer_comp,
-                       muxer_msg_iter, &msgs[i]);
-               if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                       i++;
-               }
-       }
-
-       if (i > 0) {
-               /*
-                * Even if muxer_msg_iter_do_next_one() returned
-                * something else than
-                * BT_MESSAGE_ITERATOR_STATUS_OK, we accumulated
-                * message objects in the output message
-                * array, so we need to return
-                * BT_MESSAGE_ITERATOR_STATUS_OK so that they are
-                * transfered to downstream. This other status occurs
-                * again the next time muxer_msg_iter_do_next() is
-                * called, possibly without any accumulated
-                * message, in which case we'll return it.
-                */
-               *count = i;
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       }
-
-       return status;
-}
-
-static
-void destroy_muxer_msg_iter(struct muxer_msg_iter *muxer_msg_iter)
-{
-       if (!muxer_msg_iter) {
-               return;
-       }
-
-       BT_LOGD("Destroying muxer component's message iterator: "
-               "muxer-msg-iter-addr=%p", muxer_msg_iter);
-
-       if (muxer_msg_iter->active_muxer_upstream_msg_iters) {
-               BT_LOGD_STR("Destroying muxer's active upstream message iterator wrappers.");
-               g_ptr_array_free(
-                       muxer_msg_iter->active_muxer_upstream_msg_iters, TRUE);
-       }
-
-       if (muxer_msg_iter->ended_muxer_upstream_msg_iters) {
-               BT_LOGD_STR("Destroying muxer's ended upstream message iterator wrappers.");
-               g_ptr_array_free(
-                       muxer_msg_iter->ended_muxer_upstream_msg_iters, TRUE);
-       }
-
-       g_free(muxer_msg_iter);
-}
-
-static
-int muxer_msg_iter_init_upstream_iterators(struct muxer_comp *muxer_comp,
-               struct muxer_msg_iter *muxer_msg_iter)
-{
-       int64_t count;
-       int64_t i;
-       int ret = 0;
-
-       count = bt_component_filter_get_input_port_count(
-               bt_self_component_filter_as_component_filter(
-                       muxer_comp->self_comp));
-       if (count < 0) {
-               BT_LOGD("No input port to initialize for muxer component's message iterator: "
-                       "muxer-comp-addr=%p, muxer-msg-iter-addr=%p",
-                       muxer_comp, muxer_msg_iter);
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               bt_self_component_port_input_message_iterator *upstream_msg_iter;
-               bt_self_component_port_input *self_port =
-                       bt_self_component_filter_borrow_input_port_by_index(
-                               muxer_comp->self_comp, i);
-               const bt_port *port;
-
-               BT_ASSERT(self_port);
-               port = bt_self_component_port_as_port(
-                       bt_self_component_port_input_as_self_component_port(
-                               self_port));
-               BT_ASSERT(port);
-
-               if (!bt_port_is_connected(port)) {
-                       /* Skip non-connected port */
-                       continue;
-               }
-
-               upstream_msg_iter = create_msg_iter_on_input_port(self_port);
-               if (!upstream_msg_iter) {
-                       /* create_msg_iter_on_input_port() logs errors */
-                       BT_ASSERT(!upstream_msg_iter);
-                       ret = -1;
-                       goto end;
-               }
-
-               ret = muxer_msg_iter_add_upstream_msg_iter(muxer_msg_iter,
-                       upstream_msg_iter);
-               bt_self_component_port_input_message_iterator_put_ref(
-                       upstream_msg_iter);
-               if (ret) {
-                       /* muxer_msg_iter_add_upstream_msg_iter() logs errors */
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status muxer_msg_iter_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_filter *self_comp,
-               bt_self_component_port_output *port)
-{
-       struct muxer_comp *muxer_comp = NULL;
-       struct muxer_msg_iter *muxer_msg_iter = NULL;
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       int ret;
-
-       muxer_comp = bt_self_component_get_data(
-               bt_self_component_filter_as_self_component(self_comp));
-       BT_ASSERT(muxer_comp);
-       BT_LOGD("Initializing muxer component's message iterator: "
-               "comp-addr=%p, muxer-comp-addr=%p, msg-iter-addr=%p",
-               self_comp, muxer_comp, self_msg_iter);
-
-       if (muxer_comp->initializing_muxer_msg_iter) {
-               /*
-                * Weird, unhandled situation detected: downstream
-                * creates a muxer message iterator while creating
-                * another muxer message iterator (same component).
-                */
-               BT_LOGE("Recursive initialization of muxer component's message iterator: "
-                       "comp-addr=%p, muxer-comp-addr=%p, msg-iter-addr=%p",
-                       self_comp, muxer_comp, self_msg_iter);
-               goto error;
-       }
-
-       muxer_comp->initializing_muxer_msg_iter = true;
-       muxer_msg_iter = g_new0(struct muxer_msg_iter, 1);
-       if (!muxer_msg_iter) {
-               BT_LOGE_STR("Failed to allocate one muxer component's message iterator.");
-               goto error;
-       }
-
-       muxer_msg_iter->last_returned_ts_ns = INT64_MIN;
-       muxer_msg_iter->active_muxer_upstream_msg_iters =
-               g_ptr_array_new_with_free_func(
-                       (GDestroyNotify) destroy_muxer_upstream_msg_iter);
-       if (!muxer_msg_iter->active_muxer_upstream_msg_iters) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       muxer_msg_iter->ended_muxer_upstream_msg_iters =
-               g_ptr_array_new_with_free_func(
-                       (GDestroyNotify) destroy_muxer_upstream_msg_iter);
-       if (!muxer_msg_iter->ended_muxer_upstream_msg_iters) {
-               BT_LOGE_STR("Failed to allocate a GPtrArray.");
-               goto error;
-       }
-
-       ret = muxer_msg_iter_init_upstream_iterators(muxer_comp,
-               muxer_msg_iter);
-       if (ret) {
-               BT_LOGE("Cannot initialize connected input ports for muxer component's message iterator: "
-                       "comp-addr=%p, muxer-comp-addr=%p, "
-                       "muxer-msg-iter-addr=%p, msg-iter-addr=%p, ret=%d",
-                       self_comp, muxer_comp, muxer_msg_iter,
-                       self_msg_iter, ret);
-               goto error;
-       }
-
-       bt_self_message_iterator_set_data(self_msg_iter, muxer_msg_iter);
-       BT_LOGD("Initialized muxer component's message iterator: "
-               "comp-addr=%p, muxer-comp-addr=%p, muxer-msg-iter-addr=%p, "
-               "msg-iter-addr=%p",
-               self_comp, muxer_comp, muxer_msg_iter, self_msg_iter);
-       goto end;
-
-error:
-       destroy_muxer_msg_iter(muxer_msg_iter);
-       bt_self_message_iterator_set_data(self_msg_iter, NULL);
-       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-
-end:
-       muxer_comp->initializing_muxer_msg_iter = false;
-       return status;
-}
-
-BT_HIDDEN
-void muxer_msg_iter_finalize(bt_self_message_iterator *self_msg_iter)
-{
-       struct muxer_msg_iter *muxer_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_iter);
-       bt_self_component *self_comp = NULL;
-       struct muxer_comp *muxer_comp = NULL;
-
-       self_comp = bt_self_message_iterator_borrow_component(
-               self_msg_iter);
-       BT_ASSERT(self_comp);
-       muxer_comp = bt_self_component_get_data(self_comp);
-       BT_LOGD("Finalizing muxer component's message iterator: "
-               "comp-addr=%p, muxer-comp-addr=%p, muxer-msg-iter-addr=%p, "
-               "msg-iter-addr=%p",
-               self_comp, muxer_comp, muxer_msg_iter, self_msg_iter);
-
-       if (muxer_msg_iter) {
-               destroy_muxer_msg_iter(muxer_msg_iter);
-       }
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status muxer_msg_iter_next(
-               bt_self_message_iterator *self_msg_iter,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       bt_self_message_iterator_status status;
-       struct muxer_msg_iter *muxer_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_iter);
-       bt_self_component *self_comp = NULL;
-       struct muxer_comp *muxer_comp = NULL;
-
-       BT_ASSERT(muxer_msg_iter);
-       self_comp = bt_self_message_iterator_borrow_component(
-               self_msg_iter);
-       BT_ASSERT(self_comp);
-       muxer_comp = bt_self_component_get_data(self_comp);
-       BT_ASSERT(muxer_comp);
-       BT_LOGV("Muxer component's message iterator's \"next\" method called: "
-               "comp-addr=%p, muxer-comp-addr=%p, muxer-msg-iter-addr=%p, "
-               "msg-iter-addr=%p",
-               self_comp, muxer_comp, muxer_msg_iter, self_msg_iter);
-
-       status = muxer_msg_iter_do_next(muxer_comp, muxer_msg_iter,
-               msgs, capacity, count);
-       if (status < 0) {
-               BT_LOGE("Cannot get next message: "
-                       "comp-addr=%p, muxer-comp-addr=%p, muxer-msg-iter-addr=%p, "
-                       "msg-iter-addr=%p, status=%s",
-                       self_comp, muxer_comp, muxer_msg_iter, self_msg_iter,
-                       bt_common_self_message_iterator_status_string(status));
-       } else {
-               BT_LOGV("Returning from muxer component's message iterator's \"next\" method: "
-                       "status=%s",
-                       bt_common_self_message_iterator_status_string(status));
-       }
-
-       return status;
-}
-
-BT_HIDDEN
-bt_self_component_status muxer_input_port_connected(
-               bt_self_component_filter *self_comp,
-               bt_self_component_port_input *self_port,
-               const bt_port_output *other_port)
-{
-       bt_self_component_status status;
-
-       status = add_available_input_port(self_comp);
-       if (status) {
-               /*
-                * Only way to report an error later since this
-                * method does not return anything.
-                */
-               BT_LOGE("Cannot add one muxer component's input port: "
-                       "status=%s",
-                       bt_self_component_status_string(status));
-               goto end;
-       }
-
-end:
-       return status;
-}
-
-static inline
-bt_bool muxer_upstream_msg_iters_can_all_seek_beginning(
-               GPtrArray *muxer_upstream_msg_iters)
-{
-       uint64_t i;
-       bt_bool ret = BT_TRUE;
-
-       for (i = 0; i < muxer_upstream_msg_iters->len; i++) {
-               struct muxer_upstream_msg_iter *upstream_msg_iter =
-                       muxer_upstream_msg_iters->pdata[i];
-
-               if (!bt_self_component_port_input_message_iterator_can_seek_beginning(
-                               upstream_msg_iter->msg_iter)) {
-                       ret = BT_FALSE;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_bool muxer_msg_iter_can_seek_beginning(
-               bt_self_message_iterator *self_msg_iter)
-{
-       struct muxer_msg_iter *muxer_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_iter);
-       bt_bool ret = BT_TRUE;
-
-       if (!muxer_upstream_msg_iters_can_all_seek_beginning(
-                       muxer_msg_iter->active_muxer_upstream_msg_iters)) {
-               ret = BT_FALSE;
-               goto end;
-       }
-
-       if (!muxer_upstream_msg_iters_can_all_seek_beginning(
-                       muxer_msg_iter->ended_muxer_upstream_msg_iters)) {
-               ret = BT_FALSE;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status muxer_msg_iter_seek_beginning(
-               bt_self_message_iterator *self_msg_iter)
-{
-       struct muxer_msg_iter *muxer_msg_iter =
-               bt_self_message_iterator_get_data(self_msg_iter);
-       bt_message_iterator_status status = BT_MESSAGE_ITERATOR_STATUS_OK;
-       uint64_t i;
-
-       /* Seek all ended upstream iterators first */
-       for (i = 0; i < muxer_msg_iter->ended_muxer_upstream_msg_iters->len;
-                       i++) {
-               struct muxer_upstream_msg_iter *upstream_msg_iter =
-                       muxer_msg_iter->ended_muxer_upstream_msg_iters->pdata[i];
-
-               status = bt_self_component_port_input_message_iterator_seek_beginning(
-                       upstream_msg_iter->msg_iter);
-               if (status != BT_MESSAGE_ITERATOR_STATUS_OK) {
-                       goto end;
-               }
-
-               empty_message_queue(upstream_msg_iter);
-       }
-
-       /* Seek all previously active upstream iterators */
-       for (i = 0; i < muxer_msg_iter->active_muxer_upstream_msg_iters->len;
-                       i++) {
-               struct muxer_upstream_msg_iter *upstream_msg_iter =
-                       muxer_msg_iter->active_muxer_upstream_msg_iters->pdata[i];
-
-               status = bt_self_component_port_input_message_iterator_seek_beginning(
-                       upstream_msg_iter->msg_iter);
-               if (status != BT_MESSAGE_ITERATOR_STATUS_OK) {
-                       goto end;
-               }
-
-               empty_message_queue(upstream_msg_iter);
-       }
-
-       /* Make them all active */
-       for (i = 0; i < muxer_msg_iter->ended_muxer_upstream_msg_iters->len;
-                       i++) {
-               struct muxer_upstream_msg_iter *upstream_msg_iter =
-                       muxer_msg_iter->ended_muxer_upstream_msg_iters->pdata[i];
-
-               g_ptr_array_add(muxer_msg_iter->active_muxer_upstream_msg_iters,
-                       upstream_msg_iter);
-               muxer_msg_iter->ended_muxer_upstream_msg_iters->pdata[i] = NULL;
-       }
-
-       g_ptr_array_remove_range(muxer_msg_iter->ended_muxer_upstream_msg_iters,
-               0, muxer_msg_iter->ended_muxer_upstream_msg_iters->len);
-       muxer_msg_iter->last_returned_ts_ns = INT64_MIN;
-       muxer_msg_iter->clock_class_expectation =
-               MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ANY;
-
-end:
-       return (bt_self_message_iterator_status) status;
-}
diff --git a/plugins/utils/muxer/muxer.h b/plugins/utils/muxer/muxer.h
deleted file mode 100644 (file)
index 23ec8c2..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef BABELTRACE_PLUGINS_UTILS_MUXER_H
-#define BABELTRACE_PLUGINS_UTILS_MUXER_H
-
-/*
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdint.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/babeltrace-internal.h>
-
-BT_HIDDEN
-bt_self_component_status muxer_init(
-               bt_self_component_filter *self_comp,
-               const bt_value *params, void *init_data);
-
-BT_HIDDEN
-void muxer_finalize(bt_self_component_filter *self_comp);
-
-BT_HIDDEN
-bt_self_message_iterator_status muxer_msg_iter_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_filter *self_comp,
-               bt_self_component_port_output *self_port);
-
-BT_HIDDEN
-void muxer_msg_iter_finalize(
-               bt_self_message_iterator *self_msg_iter);
-
-BT_HIDDEN
-bt_self_message_iterator_status muxer_msg_iter_next(
-               bt_self_message_iterator *self_msg_iter,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count);
-
-BT_HIDDEN
-bt_self_component_status muxer_input_port_connected(
-               bt_self_component_filter *comp,
-               bt_self_component_port_input *self_port,
-               const bt_port_output *other_port);
-
-BT_HIDDEN
-bt_bool muxer_msg_iter_can_seek_beginning(
-               bt_self_message_iterator *message_iterator);
-
-BT_HIDDEN
-bt_self_message_iterator_status muxer_msg_iter_seek_beginning(
-               bt_self_message_iterator *message_iterator);
-
-#endif /* BABELTRACE_PLUGINS_UTILS_MUXER_H */
diff --git a/plugins/utils/plugin.c b/plugins/utils/plugin.c
deleted file mode 100644 (file)
index d6b5b24..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <babeltrace2/babeltrace.h>
-#include "dummy/dummy.h"
-#include "counter/counter.h"
-#include "muxer/muxer.h"
-#include "trimmer/trimmer.h"
-
-#ifndef BT_BUILT_IN_PLUGINS
-BT_PLUGIN_MODULE();
-#endif
-
-BT_PLUGIN(utils);
-BT_PLUGIN_DESCRIPTION("Graph utilities");
-BT_PLUGIN_AUTHOR("Julien Desfossez, Jérémie Galarneau, Philippe Proulx");
-BT_PLUGIN_LICENSE("MIT");
-
-/* sink.utils.dummy */
-BT_PLUGIN_SINK_COMPONENT_CLASS(dummy, dummy_consume);
-BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(dummy, dummy_init);
-BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(dummy, dummy_finalize);
-BT_PLUGIN_SINK_COMPONENT_CLASS_GRAPH_IS_CONFIGURED_METHOD(dummy,
-       dummy_graph_is_configured);
-BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(dummy,
-       "Consume messages and discard them.");
-
-/* sink.utils.counter */
-BT_PLUGIN_SINK_COMPONENT_CLASS(counter, counter_consume);
-BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(counter, counter_init);
-BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(counter, counter_finalize);
-BT_PLUGIN_SINK_COMPONENT_CLASS_GRAPH_IS_CONFIGURED_METHOD(counter,
-       counter_graph_is_configured);
-BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(counter,
-       "Count messages and print the results.");
-
-/* flt.utils.trimmer */
-BT_PLUGIN_FILTER_COMPONENT_CLASS(trimmer, trimmer_msg_iter_next);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(trimmer,
-       "Keep messages that occur within a specific time range.");
-BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD(trimmer, trimmer_init);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(trimmer, trimmer_finalize);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD(trimmer,
-       trimmer_msg_iter_init);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD(trimmer,
-       trimmer_msg_iter_finalize);
-
-/* flt.utils.muxer */
-BT_PLUGIN_FILTER_COMPONENT_CLASS(muxer, muxer_msg_iter_next);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(muxer,
-       "Sort messages from multiple input ports to a single output port by time.");
-BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD(muxer, muxer_init);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(muxer, muxer_finalize);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_INPUT_PORT_CONNECTED_METHOD(muxer,
-       muxer_input_port_connected);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD(muxer,
-       muxer_msg_iter_init);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD(muxer,
-       muxer_msg_iter_finalize);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD(muxer,
-       muxer_msg_iter_seek_beginning);
-BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CAN_SEEK_BEGINNING_METHOD(muxer,
-       muxer_msg_iter_can_seek_beginning);
diff --git a/plugins/utils/trimmer/Makefile.am b/plugins/utils/trimmer/Makefile.am
deleted file mode 100644 (file)
index 050db0c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-AM_CPPFLAGS += -I$(top_srcdir)/plugins \
-           -I$(top_srcdir)/plugins/libctfcopytrace
-
-noinst_LTLIBRARIES = libbabeltrace2-plugin-trimmer.la
-libbabeltrace2_plugin_trimmer_la_SOURCES = \
-       trimmer.c \
-       trimmer.h \
-       logging.c \
-       logging.h
diff --git a/plugins/utils/trimmer/logging.c b/plugins/utils/trimmer/logging.c
deleted file mode 100644 (file)
index f8b9be1..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_trimmer_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_INIT_LOG_LEVEL(bt_plugin_utils_trimmer_log_level,
-       "BABELTRACE_FLT_UTILS_TRIMMER_LOG_LEVEL");
diff --git a/plugins/utils/trimmer/logging.h b/plugins/utils/trimmer/logging.h
deleted file mode 100644 (file)
index 3bcd7ea..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef PLUGINS_UTILS_TRIMMER_LOGGING_H
-#define PLUGINS_UTILS_TRIMMER_LOGGING_H
-
-/*
- * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_trimmer_log_level
-#include <babeltrace2/logging-internal.h>
-
-BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_utils_trimmer_log_level);
-
-#endif /* PLUGINS_UTILS_TRIMMER_LOGGING_H */
diff --git a/plugins/utils/trimmer/trimmer.c b/plugins/utils/trimmer/trimmer.c
deleted file mode 100644 (file)
index 1227dc5..0000000
+++ /dev/null
@@ -1,2049 +0,0 @@
-/*
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-UTILS-TRIMMER-FLT"
-#include "logging.h"
-
-#include <babeltrace2/compat/utc-internal.h>
-#include <babeltrace2/compat/time-internal.h>
-#include <babeltrace2/babeltrace.h>
-#include <babeltrace2/common-internal.h>
-#include <plugins-common.h>
-#include <babeltrace2/assert-internal.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <glib.h>
-
-#include "trimmer.h"
-
-#define NS_PER_S       INT64_C(1000000000)
-
-static const char * const in_port_name = "in";
-
-struct trimmer_time {
-       unsigned int hour, minute, second, ns;
-};
-
-struct trimmer_bound {
-       /*
-        * Nanoseconds from origin, valid if `is_set` is set and
-        * `is_infinite` is false.
-        */
-       int64_t ns_from_origin;
-
-       /* True if this bound's full time (`ns_from_origin`) is set */
-       bool is_set;
-
-       /*
-        * True if this bound represents the infinity (negative or
-        * positive depending on which bound it is). If this is true,
-        * then we don't care about `ns_from_origin` above.
-        */
-       bool is_infinite;
-
-       /*
-        * This bound's time without the date; this time is used to set
-        * `ns_from_origin` once we know the date.
-        */
-       struct trimmer_time time;
-};
-
-struct trimmer_comp {
-       struct trimmer_bound begin, end;
-       bool is_gmt;
-};
-
-enum trimmer_iterator_state {
-       /*
-        * Find the first message's date and set the bounds's times
-        * accordingly.
-        */
-       TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN,
-
-       /*
-        * Initially seek to the trimming range's beginning time.
-        */
-       TRIMMER_ITERATOR_STATE_SEEK_INITIALLY,
-
-       /*
-        * Fill the output message queue for as long as received input
-        * messages are within the trimming time range.
-        */
-       TRIMMER_ITERATOR_STATE_TRIM,
-
-       /* Flush the remaining messages in the output message queue */
-       TRIMMER_ITERATOR_STATE_ENDING,
-
-       /* Trimming operation and message iterator is ended */
-       TRIMMER_ITERATOR_STATE_ENDED,
-};
-
-struct trimmer_iterator {
-       /* Weak */
-       struct trimmer_comp *trimmer_comp;
-
-       /* Weak */
-       bt_self_message_iterator *self_msg_iter;
-
-       enum trimmer_iterator_state state;
-
-       /* Owned by this */
-       bt_self_component_port_input_message_iterator *upstream_iter;
-       struct trimmer_bound begin, end;
-
-       /*
-        * Queue of `const bt_message *` (owned by the queue).
-        *
-        * This is where the trimming operation pushes the messages to
-        * output by this message iterator.
-        */
-       GQueue *output_messages;
-
-       /*
-        * Hash table of `bt_stream *` (weak) to
-        * `struct trimmer_iterator_stream_state *` (owned by the HT).
-        */
-       GHashTable *stream_states;
-};
-
-struct trimmer_iterator_stream_state {
-       /*
-        * True if both stream beginning and initial stream activity
-        * beginning messages were pushed for this stream.
-        */
-       bool inited;
-
-       /*
-        * True if the last pushed message for this stream was a stream
-        * activity end message.
-        */
-       bool last_msg_is_stream_activity_end;
-
-       /*
-        * Time to use for a generated stream end activity message when
-        * ending the stream.
-        */
-       int64_t stream_act_end_ns_from_origin;
-
-       /* Weak */
-       const bt_stream *stream;
-
-       /* Owned by this (`NULL` initially and between packets) */
-       const bt_packet *cur_packet;
-
-       /* Owned by this */
-       const bt_message *stream_beginning_msg;
-};
-
-static
-void destroy_trimmer_comp(struct trimmer_comp *trimmer_comp)
-{
-       BT_ASSERT(trimmer_comp);
-       g_free(trimmer_comp);
-}
-
-static
-struct trimmer_comp *create_trimmer_comp(void)
-{
-       return g_new0(struct trimmer_comp, 1);
-}
-
-BT_HIDDEN
-void trimmer_finalize(bt_self_component_filter *self_comp)
-{
-       struct trimmer_comp *trimmer_comp =
-               bt_self_component_get_data(
-                       bt_self_component_filter_as_self_component(self_comp));
-
-       if (trimmer_comp) {
-               destroy_trimmer_comp(trimmer_comp);
-       }
-}
-
-/*
- * Sets the time (in ns from origin) of a trimmer bound from date and
- * time components.
- *
- * Returns a negative value if anything goes wrong.
- */
-static
-int set_bound_ns_from_origin(struct trimmer_bound *bound,
-               unsigned int year, unsigned int month, unsigned int day,
-               unsigned int hour, unsigned int minute, unsigned int second,
-               unsigned int ns, bool is_gmt)
-{
-       int ret = 0;
-       time_t result;
-       struct tm tm = {
-               .tm_sec = second,
-               .tm_min = minute,
-               .tm_hour = hour,
-               .tm_mday = day,
-               .tm_mon = month - 1,
-               .tm_year = year - 1900,
-               .tm_isdst = -1,
-       };
-
-       if (is_gmt) {
-               result = bt_timegm(&tm);
-       } else {
-               result = mktime(&tm);
-       }
-
-       if (result < 0) {
-               ret = -1;
-               goto end;
-       }
-
-       BT_ASSERT(bound);
-       bound->ns_from_origin = (int64_t) result;
-       bound->ns_from_origin *= NS_PER_S;
-       bound->ns_from_origin += ns;
-       bound->is_set = true;
-
-end:
-       return ret;
-}
-
-/*
- * Parses a timestamp, figuring out its format.
- *
- * Returns a negative value if anything goes wrong.
- *
- * Expected formats:
- *
- *     YYYY-MM-DD hh:mm[:ss[.ns]]
- *     [hh:mm:]ss[.ns]
- *     [-]s[.ns]
- *
- * TODO: Check overflows.
- */
-static
-int set_bound_from_str(const char *str, struct trimmer_bound *bound,
-               bool is_gmt)
-{
-       int ret = 0;
-       int s_ret;
-       unsigned int year, month, day, hour, minute, second, ns;
-       char dummy;
-
-       /* Try `YYYY-MM-DD hh:mm:ss.ns` format */
-       s_ret = sscanf(str, "%u-%u-%u %u:%u:%u.%u%c", &year, &month, &day,
-               &hour, &minute, &second, &ns, &dummy);
-       if (s_ret == 7) {
-               ret = set_bound_ns_from_origin(bound, year, month, day,
-                       hour, minute, second, ns, is_gmt);
-               goto end;
-       }
-
-       /* Try `YYYY-MM-DD hh:mm:ss` format */
-       s_ret = sscanf(str, "%u-%u-%u %u:%u:%u%c", &year, &month, &day,
-               &hour, &minute, &second, &dummy);
-       if (s_ret == 6) {
-               ret = set_bound_ns_from_origin(bound, year, month, day,
-                       hour, minute, second, 0, is_gmt);
-               goto end;
-       }
-
-       /* Try `YYYY-MM-DD hh:mm` format */
-       s_ret = sscanf(str, "%u-%u-%u %u:%u%c", &year, &month, &day,
-               &hour, &minute, &dummy);
-       if (s_ret == 5) {
-               ret = set_bound_ns_from_origin(bound, year, month, day,
-                       hour, minute, 0, 0, is_gmt);
-               goto end;
-       }
-
-       /* Try `YYYY-MM-DD` format */
-       s_ret = sscanf(str, "%u-%u-%u%c", &year, &month, &day, &dummy);
-       if (s_ret == 3) {
-               ret = set_bound_ns_from_origin(bound, year, month, day,
-                       0, 0, 0, 0, is_gmt);
-               goto end;
-       }
-
-       /* Try `hh:mm:ss.ns` format */
-       s_ret = sscanf(str, "%u:%u:%u.%u%c", &hour, &minute, &second, &ns,
-               &dummy);
-       if (s_ret == 4) {
-               bound->time.hour = hour;
-               bound->time.minute = minute;
-               bound->time.second = second;
-               bound->time.ns = ns;
-               goto end;
-       }
-
-       /* Try `hh:mm:ss` format */
-       s_ret = sscanf(str, "%u:%u:%u%c", &hour, &minute, &second, &dummy);
-       if (s_ret == 3) {
-               bound->time.hour = hour;
-               bound->time.minute = minute;
-               bound->time.second = second;
-               bound->time.ns = 0;
-               goto end;
-       }
-
-       /* Try `-s.ns` format */
-       s_ret = sscanf(str, "-%u.%u%c", &second, &ns, &dummy);
-       if (s_ret == 2) {
-               bound->ns_from_origin = -((int64_t) second) * NS_PER_S;
-               bound->ns_from_origin -= (int64_t) ns;
-               bound->is_set = true;
-               goto end;
-       }
-
-       /* Try `s.ns` format */
-       s_ret = sscanf(str, "%u.%u%c", &second, &ns, &dummy);
-       if (s_ret == 2) {
-               bound->ns_from_origin = ((int64_t) second) * NS_PER_S;
-               bound->ns_from_origin += (int64_t) ns;
-               bound->is_set = true;
-               goto end;
-       }
-
-       /* Try `-s` format */
-       s_ret = sscanf(str, "-%u%c", &second, &dummy);
-       if (s_ret == 1) {
-               bound->ns_from_origin = -((int64_t) second) * NS_PER_S;
-               bound->is_set = true;
-               goto end;
-       }
-
-       /* Try `s` format */
-       s_ret = sscanf(str, "%u%c", &second, &dummy);
-       if (s_ret == 1) {
-               bound->ns_from_origin = (int64_t) second * NS_PER_S;
-               bound->is_set = true;
-               goto end;
-       }
-
-       BT_LOGE("Invalid date/time format: param=\"%s\"", str);
-       ret = -1;
-
-end:
-       return ret;
-}
-
-/*
- * Sets a trimmer bound's properties from a parameter string/integer
- * value.
- *
- * Returns a negative value if anything goes wrong.
- */
-static
-int set_bound_from_param(const char *param_name, const bt_value *param,
-               struct trimmer_bound *bound, bool is_gmt)
-{
-       int ret;
-       const char *arg;
-       char tmp_arg[64];
-
-       if (bt_value_is_signed_integer(param)) {
-               int64_t value = bt_value_signed_integer_get(param);
-
-               /*
-                * Just convert it to a temporary string to handle
-                * everything the same way.
-                */
-               sprintf(tmp_arg, "%" PRId64, value);
-               arg = tmp_arg;
-       } else if (bt_value_is_string(param)) {
-               arg = bt_value_string_get(param);
-       } else {
-               BT_LOGE("`%s` parameter must be an integer or a string value.",
-                       param_name);
-               ret = -1;
-               goto end;
-       }
-
-       ret = set_bound_from_str(arg, bound, is_gmt);
-
-end:
-       return ret;
-}
-
-static
-int validate_trimmer_bounds(struct trimmer_bound *begin,
-               struct trimmer_bound *end)
-{
-       int ret = 0;
-
-       BT_ASSERT(begin->is_set);
-       BT_ASSERT(end->is_set);
-
-       if (!begin->is_infinite && !end->is_infinite &&
-                       begin->ns_from_origin > end->ns_from_origin) {
-               BT_LOGE("Trimming time range's beginning time is greater than end time: "
-                       "begin-ns-from-origin=%" PRId64 ", "
-                       "end-ns-from-origin=%" PRId64,
-                       begin->ns_from_origin,
-                       end->ns_from_origin);
-               ret = -1;
-               goto end;
-       }
-
-       if (!begin->is_infinite && begin->ns_from_origin == INT64_MIN) {
-               BT_LOGE("Invalid trimming time range's beginning time: "
-                       "ns-from-origin=%" PRId64,
-                       begin->ns_from_origin);
-               ret = -1;
-               goto end;
-       }
-
-       if (!end->is_infinite && end->ns_from_origin == INT64_MIN) {
-               BT_LOGE("Invalid trimming time range's end time: "
-                       "ns-from-origin=%" PRId64,
-                       end->ns_from_origin);
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static
-int init_trimmer_comp_from_params(struct trimmer_comp *trimmer_comp,
-               const bt_value *params)
-{
-       const bt_value *value;
-       int ret = 0;
-
-       BT_ASSERT(params);
-        value = bt_value_map_borrow_entry_value_const(params, "gmt");
-       if (value) {
-               trimmer_comp->is_gmt = (bool) bt_value_bool_get(value);
-       }
-
-        value = bt_value_map_borrow_entry_value_const(params, "begin");
-       if (value) {
-               if (set_bound_from_param("begin", value,
-                               &trimmer_comp->begin, trimmer_comp->is_gmt)) {
-                       /* set_bound_from_param() logs errors */
-                       ret = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-       } else {
-               trimmer_comp->begin.is_infinite = true;
-               trimmer_comp->begin.is_set = true;
-       }
-
-        value = bt_value_map_borrow_entry_value_const(params, "end");
-       if (value) {
-               if (set_bound_from_param("end", value,
-                               &trimmer_comp->end, trimmer_comp->is_gmt)) {
-                       /* set_bound_from_param() logs errors */
-                       ret = BT_SELF_COMPONENT_STATUS_ERROR;
-                       goto end;
-               }
-       } else {
-               trimmer_comp->end.is_infinite = true;
-               trimmer_comp->end.is_set = true;
-       }
-
-end:
-       if (trimmer_comp->begin.is_set && trimmer_comp->end.is_set) {
-               /* validate_trimmer_bounds() logs errors */
-               ret = validate_trimmer_bounds(&trimmer_comp->begin,
-                       &trimmer_comp->end);
-       }
-
-       return ret;
-}
-
-bt_self_component_status trimmer_init(bt_self_component_filter *self_comp,
-               const bt_value *params, void *init_data)
-{
-       int ret;
-       bt_self_component_status status;
-       struct trimmer_comp *trimmer_comp = create_trimmer_comp();
-
-       if (!trimmer_comp) {
-               status = BT_SELF_COMPONENT_STATUS_NOMEM;
-               goto error;
-       }
-
-       status = bt_self_component_filter_add_input_port(
-               self_comp, in_port_name, NULL, NULL);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-
-       status = bt_self_component_filter_add_output_port(
-               self_comp, "out", NULL, NULL);
-       if (status != BT_SELF_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-
-       ret = init_trimmer_comp_from_params(trimmer_comp, params);
-       if (ret) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-               goto error;
-       }
-
-       bt_self_component_set_data(
-               bt_self_component_filter_as_self_component(self_comp),
-               trimmer_comp);
-       goto end;
-
-error:
-       if (status == BT_SELF_COMPONENT_STATUS_OK) {
-               status = BT_SELF_COMPONENT_STATUS_ERROR;
-       }
-
-       if (trimmer_comp) {
-               destroy_trimmer_comp(trimmer_comp);
-       }
-
-end:
-       return status;
-}
-
-static
-void destroy_trimmer_iterator(struct trimmer_iterator *trimmer_it)
-{
-       BT_ASSERT(trimmer_it);
-       bt_self_component_port_input_message_iterator_put_ref(
-               trimmer_it->upstream_iter);
-
-       if (trimmer_it->output_messages) {
-               g_queue_free(trimmer_it->output_messages);
-       }
-
-       if (trimmer_it->stream_states) {
-               g_hash_table_destroy(trimmer_it->stream_states);
-       }
-
-       g_free(trimmer_it);
-}
-
-static
-void destroy_trimmer_iterator_stream_state(
-               struct trimmer_iterator_stream_state *sstate)
-{
-       BT_ASSERT(sstate);
-       BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
-       BT_MESSAGE_PUT_REF_AND_RESET(sstate->stream_beginning_msg);
-       g_free(sstate);
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status trimmer_msg_iter_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_filter *self_comp,
-               bt_self_component_port_output *port)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       struct trimmer_iterator *trimmer_it;
-
-       trimmer_it = g_new0(struct trimmer_iterator, 1);
-       if (!trimmer_it) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto end;
-       }
-
-       trimmer_it->trimmer_comp = bt_self_component_get_data(
-               bt_self_component_filter_as_self_component(self_comp));
-       BT_ASSERT(trimmer_it->trimmer_comp);
-
-       if (trimmer_it->trimmer_comp->begin.is_set &&
-                       trimmer_it->trimmer_comp->end.is_set) {
-               /*
-                * Both trimming time range's bounds are set, so skip
-                * the
-                * `TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN`
-                * phase.
-                */
-               trimmer_it->state = TRIMMER_ITERATOR_STATE_SEEK_INITIALLY;
-       }
-
-       trimmer_it->begin = trimmer_it->trimmer_comp->begin;
-       trimmer_it->end = trimmer_it->trimmer_comp->end;
-       trimmer_it->upstream_iter =
-               bt_self_component_port_input_message_iterator_create(
-                       bt_self_component_filter_borrow_input_port_by_name(
-                               self_comp, in_port_name));
-       if (!trimmer_it->upstream_iter) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       trimmer_it->output_messages = g_queue_new();
-       if (!trimmer_it->output_messages) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto end;
-       }
-
-       trimmer_it->stream_states = g_hash_table_new_full(g_direct_hash,
-               g_direct_equal, NULL,
-               (GDestroyNotify) destroy_trimmer_iterator_stream_state);
-       if (!trimmer_it->stream_states) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto end;
-       }
-
-       trimmer_it->self_msg_iter = self_msg_iter;
-       bt_self_message_iterator_set_data(self_msg_iter, trimmer_it);
-
-end:
-       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK && trimmer_it) {
-               destroy_trimmer_iterator(trimmer_it);
-       }
-
-       return status;
-}
-
-static inline
-int get_msg_ns_from_origin(const bt_message *msg, int64_t *ns_from_origin,
-               bool *skip)
-{
-       const bt_clock_class *clock_class = NULL;
-       const bt_clock_snapshot *clock_snapshot = NULL;
-       bt_message_stream_activity_clock_snapshot_state sa_cs_state;
-       int ret = 0;
-
-       BT_ASSERT(msg);
-       BT_ASSERT(ns_from_origin);
-       BT_ASSERT(skip);
-
-       switch (bt_message_get_type(msg)) {
-       case BT_MESSAGE_TYPE_EVENT:
-               clock_class =
-                       bt_message_event_borrow_stream_class_default_clock_class_const(
-                               msg);
-               if (unlikely(!clock_class)) {
-                       goto error;
-               }
-
-               clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-               clock_class =
-                       bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
-                               msg);
-               if (unlikely(!clock_class)) {
-                       goto error;
-               }
-
-               clock_snapshot = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_PACKET_END:
-               clock_class =
-                       bt_message_packet_end_borrow_stream_class_default_clock_class_const(
-                               msg);
-               if (unlikely(!clock_class)) {
-                       goto error;
-               }
-
-               clock_snapshot = bt_message_packet_end_borrow_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-               clock_class =
-                       bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
-                               msg);
-               if (unlikely(!clock_class)) {
-                       goto error;
-               }
-
-               clock_snapshot = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-               clock_class =
-                       bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
-                               msg);
-               if (unlikely(!clock_class)) {
-                       goto error;
-               }
-
-               clock_snapshot = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-                       msg);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-               clock_class =
-                       bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
-                               msg);
-               if (unlikely(!clock_class)) {
-                       goto error;
-               }
-
-               sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
-                       msg, &clock_snapshot);
-               if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN ||
-                               sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE) {
-                       /* Lowest possible time to always include them */
-                       *ns_from_origin = INT64_MIN;
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-               clock_class =
-                       bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
-                               msg);
-               if (unlikely(!clock_class)) {
-                       goto error;
-               }
-
-               sa_cs_state = bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
-                       msg, &clock_snapshot);
-               if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN) {
-                       /* Lowest time to always include it */
-                       *ns_from_origin = INT64_MIN;
-                       goto no_clock_snapshot;
-               } else if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE) {
-                       /* Greatest time to always exclude it */
-                       *ns_from_origin = INT64_MAX;
-                       goto no_clock_snapshot;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
-               clock_snapshot =
-                       bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
-                               msg);
-               break;
-       default:
-               goto no_clock_snapshot;
-       }
-
-       ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot,
-               ns_from_origin);
-       if (unlikely(ret)) {
-               goto error;
-       }
-
-       goto end;
-
-no_clock_snapshot:
-       *skip = true;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static inline
-void put_messages(bt_message_array_const msgs, uint64_t count)
-{
-       uint64_t i;
-
-       for (i = 0; i < count; i++) {
-               BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
-       }
-}
-
-static inline
-int set_trimmer_iterator_bound(struct trimmer_bound *bound,
-               int64_t ns_from_origin, bool is_gmt)
-{
-       struct tm tm;
-       time_t time_seconds = (time_t) (ns_from_origin / NS_PER_S);
-       int ret = 0;
-
-       BT_ASSERT(!bound->is_set);
-       errno = 0;
-
-       /* We only need to extract the date from this time */
-       if (is_gmt) {
-               bt_gmtime_r(&time_seconds, &tm);
-       } else {
-               bt_localtime_r(&time_seconds, &tm);
-       }
-
-       if (errno) {
-               BT_LOGE_ERRNO("Cannot convert timestamp to date and time",
-                       "ts=%" PRId64, (int64_t) time_seconds);
-               ret = -1;
-               goto end;
-       }
-
-       ret = set_bound_ns_from_origin(bound, tm.tm_year + 1900, tm.tm_mon + 1,
-               tm.tm_mday, bound->time.hour, bound->time.minute,
-               bound->time.second, bound->time.ns, is_gmt);
-
-end:
-       return ret;
-}
-
-static
-bt_self_message_iterator_status state_set_trimmer_iterator_bounds(
-               struct trimmer_iterator *trimmer_it)
-{
-       bt_message_iterator_status upstream_iter_status =
-               BT_MESSAGE_ITERATOR_STATUS_OK;
-       struct trimmer_comp *trimmer_comp = trimmer_it->trimmer_comp;
-       bt_message_array_const msgs;
-       uint64_t count = 0;
-       int64_t ns_from_origin = INT64_MIN;
-       uint64_t i;
-       int ret;
-
-       BT_ASSERT(!trimmer_it->begin.is_set ||
-               !trimmer_it->end.is_set);
-
-       while (true) {
-               upstream_iter_status =
-                       bt_self_component_port_input_message_iterator_next(
-                               trimmer_it->upstream_iter, &msgs, &count);
-               if (upstream_iter_status != BT_MESSAGE_ITERATOR_STATUS_OK) {
-                       goto end;
-               }
-
-               for (i = 0; i < count; i++) {
-                       const bt_message *msg = msgs[i];
-                       bool skip = false;
-                       int ret;
-
-                       ret = get_msg_ns_from_origin(msg, &ns_from_origin,
-                               &skip);
-                       if (ret) {
-                               goto error;
-                       }
-
-                       if (skip) {
-                               continue;
-                       }
-
-                       BT_ASSERT(ns_from_origin != INT64_MIN &&
-                               ns_from_origin != INT64_MAX);
-                       put_messages(msgs, count);
-                       goto found;
-               }
-
-               put_messages(msgs, count);
-       }
-
-found:
-       if (!trimmer_it->begin.is_set) {
-               BT_ASSERT(!trimmer_it->begin.is_infinite);
-               ret = set_trimmer_iterator_bound(&trimmer_it->begin,
-                       ns_from_origin, trimmer_comp->is_gmt);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       if (!trimmer_it->end.is_set) {
-               BT_ASSERT(!trimmer_it->end.is_infinite);
-               ret = set_trimmer_iterator_bound(&trimmer_it->end,
-                       ns_from_origin, trimmer_comp->is_gmt);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       ret = validate_trimmer_bounds(&trimmer_it->begin,
-               &trimmer_it->end);
-       if (ret) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       put_messages(msgs, count);
-       upstream_iter_status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
-
-end:
-       return (int) upstream_iter_status;
-}
-
-static
-bt_self_message_iterator_status state_seek_initially(
-               struct trimmer_iterator *trimmer_it)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_ASSERT(trimmer_it->begin.is_set);
-
-       if (trimmer_it->begin.is_infinite) {
-               if (!bt_self_component_port_input_message_iterator_can_seek_beginning(
-                               trimmer_it->upstream_iter)) {
-                       BT_LOGE_STR("Cannot make upstream message iterator initially seek its beginning.");
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                       goto end;
-               }
-
-               status = (int) bt_self_component_port_input_message_iterator_seek_beginning(
-                       trimmer_it->upstream_iter);
-       } else {
-               if (!bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
-                               trimmer_it->upstream_iter,
-                               trimmer_it->begin.ns_from_origin)) {
-                       BT_LOGE("Cannot make upstream message iterator initially seek: "
-                               "seek-ns-from-origin=%" PRId64,
-                               trimmer_it->begin.ns_from_origin);
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                       goto end;
-               }
-
-               status = (int) bt_self_component_port_input_message_iterator_seek_ns_from_origin(
-                       trimmer_it->upstream_iter, trimmer_it->begin.ns_from_origin);
-       }
-
-       if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-               trimmer_it->state = TRIMMER_ITERATOR_STATE_TRIM;
-       }
-
-end:
-       return status;
-}
-
-static inline
-void push_message(struct trimmer_iterator *trimmer_it, const bt_message *msg)
-{
-       g_queue_push_head(trimmer_it->output_messages, (void *) msg);
-}
-
-static inline
-const bt_message *pop_message(struct trimmer_iterator *trimmer_it)
-{
-       return g_queue_pop_tail(trimmer_it->output_messages);
-}
-
-static inline
-int clock_raw_value_from_ns_from_origin(const bt_clock_class *clock_class,
-               int64_t ns_from_origin, uint64_t *raw_value)
-{
-
-       int64_t cc_offset_s;
-       uint64_t cc_offset_cycles;
-       uint64_t cc_freq;
-
-       bt_clock_class_get_offset(clock_class, &cc_offset_s, &cc_offset_cycles);
-       cc_freq = bt_clock_class_get_frequency(clock_class);
-       return bt_common_clock_value_from_ns_from_origin(cc_offset_s,
-               cc_offset_cycles, cc_freq, ns_from_origin, raw_value);
-}
-
-static inline
-bt_self_message_iterator_status end_stream(struct trimmer_iterator *trimmer_it,
-               struct trimmer_iterator_stream_state *sstate)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       uint64_t raw_value;
-       const bt_clock_class *clock_class;
-       int ret;
-       bt_message *msg = NULL;
-
-       BT_ASSERT(!trimmer_it->end.is_infinite);
-
-       if (!sstate->stream) {
-               goto end;
-       }
-
-       if (sstate->cur_packet) {
-               /*
-                * The last message could not have been a stream
-                * activity end message if we have a current packet.
-                */
-               BT_ASSERT(!sstate->last_msg_is_stream_activity_end);
-
-               /*
-                * Create and push a packet end message, making its time
-                * the trimming range's end time.
-                */
-               clock_class = bt_stream_class_borrow_default_clock_class_const(
-                       bt_stream_borrow_class_const(sstate->stream));
-               BT_ASSERT(clock_class);
-               ret = clock_raw_value_from_ns_from_origin(clock_class,
-                       trimmer_it->end.ns_from_origin, &raw_value);
-               if (ret) {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                       goto end;
-               }
-
-               msg = bt_message_packet_end_create_with_default_clock_snapshot(
-                       trimmer_it->self_msg_iter, sstate->cur_packet,
-                       raw_value);
-               if (!msg) {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-                       goto end;
-               }
-
-               push_message(trimmer_it, msg);
-               msg = NULL;
-               BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
-
-               /*
-                * Because we generated a packet end message, set the
-                * stream activity end message's time to use to the
-                * trimming range's end time (this packet end message's
-                * time).
-                */
-               sstate->stream_act_end_ns_from_origin =
-                       trimmer_it->end.ns_from_origin;
-       }
-
-       if (!sstate->last_msg_is_stream_activity_end) {
-               /* Create and push a stream activity end message */
-               msg = bt_message_stream_activity_end_create(
-                       trimmer_it->self_msg_iter, sstate->stream);
-               if (!msg) {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-                       goto end;
-               }
-
-               clock_class = bt_stream_class_borrow_default_clock_class_const(
-                       bt_stream_borrow_class_const(sstate->stream));
-               BT_ASSERT(clock_class);
-
-               if (sstate->stream_act_end_ns_from_origin == INT64_MIN) {
-                       /*
-                        * We received at least what is necessary to
-                        * have a stream state (stream beginning and
-                        * stream activity beginning messages), but
-                        * nothing else: use the trimmer range's end
-                        * time.
-                        */
-                       sstate->stream_act_end_ns_from_origin =
-                               trimmer_it->end.ns_from_origin;
-               }
-
-               ret = clock_raw_value_from_ns_from_origin(clock_class,
-                       sstate->stream_act_end_ns_from_origin, &raw_value);
-               if (ret) {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                       goto end;
-               }
-
-               bt_message_stream_activity_end_set_default_clock_snapshot(
-                       msg, raw_value);
-               push_message(trimmer_it, msg);
-               msg = NULL;
-       }
-
-       /* Create and push a stream end message */
-       msg = bt_message_stream_end_create(trimmer_it->self_msg_iter,
-               sstate->stream);
-       if (!msg) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto end;
-       }
-
-       push_message(trimmer_it, msg);
-       msg = NULL;
-
-       /*
-        * Just to make sure that we don't use this stream state again
-        * in the future without an obvious error.
-        */
-       sstate->stream = NULL;
-
-end:
-       bt_message_put_ref(msg);
-       return status;
-}
-
-static inline
-bt_self_message_iterator_status end_iterator_streams(
-               struct trimmer_iterator *trimmer_it)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       GHashTableIter iter;
-       gpointer key, sstate;
-
-       if (trimmer_it->end.is_infinite) {
-               /*
-                * An infinite trimming range's end time guarantees that
-                * we received (and pushed) all the appropriate end
-                * messages.
-                */
-               goto remove_all;
-       }
-
-       /*
-        * End each stream and then remove them from the hash table of
-        * stream states to release unneeded references.
-        */
-       g_hash_table_iter_init(&iter, trimmer_it->stream_states);
-
-       while (g_hash_table_iter_next(&iter, &key, &sstate)) {
-               status = end_stream(trimmer_it, sstate);
-               if (status) {
-                       goto end;
-               }
-       }
-
-remove_all:
-       g_hash_table_remove_all(trimmer_it->stream_states);
-
-end:
-       return status;
-}
-
-static inline
-bt_self_message_iterator_status create_stream_beginning_activity_message(
-               struct trimmer_iterator *trimmer_it,
-               const bt_stream *stream,
-               const bt_clock_class *clock_class, bt_message **msg)
-{
-       bt_message *local_msg;
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_ASSERT(msg);
-       BT_ASSERT(!trimmer_it->begin.is_infinite);
-
-       local_msg = bt_message_stream_activity_beginning_create(
-               trimmer_it->self_msg_iter, stream);
-       if (!local_msg) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto end;
-       }
-
-       if (clock_class) {
-               int ret;
-               uint64_t raw_value;
-
-               ret = clock_raw_value_from_ns_from_origin(clock_class,
-                       trimmer_it->begin.ns_from_origin, &raw_value);
-               if (ret) {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                       bt_message_put_ref(local_msg);
-                       goto end;
-               }
-
-               bt_message_stream_activity_beginning_set_default_clock_snapshot(
-                       local_msg, raw_value);
-       }
-
-       BT_MESSAGE_MOVE_REF(*msg, local_msg);
-
-end:
-       return status;
-}
-
-/*
- * Makes sure to initialize a stream state, pushing the appropriate
- * initial messages.
- *
- * `stream_act_beginning_msg` is an initial stream activity beginning
- * message to potentially use, depending on its clock snapshot state.
- * This function consumes `stream_act_beginning_msg` unconditionally.
- */
-static inline
-bt_self_message_iterator_status ensure_stream_state_is_inited(
-               struct trimmer_iterator *trimmer_it,
-               struct trimmer_iterator_stream_state *sstate,
-               const bt_message *stream_act_beginning_msg)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       bt_message *new_msg = NULL;
-       const bt_clock_class *clock_class =
-               bt_stream_class_borrow_default_clock_class_const(
-                       bt_stream_borrow_class_const(sstate->stream));
-
-       BT_ASSERT(!sstate->inited);
-
-       if (!sstate->stream_beginning_msg) {
-               /* No initial stream beginning message: create one */
-               sstate->stream_beginning_msg =
-                       bt_message_stream_beginning_create(
-                               trimmer_it->self_msg_iter, sstate->stream);
-               if (!sstate->stream_beginning_msg) {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-                       goto end;
-               }
-       }
-
-       /* Push initial stream beginning message */
-       BT_ASSERT(sstate->stream_beginning_msg);
-       push_message(trimmer_it, sstate->stream_beginning_msg);
-       sstate->stream_beginning_msg = NULL;
-
-       if (stream_act_beginning_msg) {
-               /*
-                * Initial stream activity beginning message exists: if
-                * its time is -inf, then create and push a new one
-                * having the trimming range's beginning time. Otherwise
-                * push it as is (known and unknown).
-                */
-               const bt_clock_snapshot *cs;
-               bt_message_stream_activity_clock_snapshot_state sa_cs_state;
-
-               sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
-                       stream_act_beginning_msg, &cs);
-               if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE &&
-                               !trimmer_it->begin.is_infinite) {
-                       /*
-                        * -inf time: use trimming range's beginning
-                        * time (which is not -inf).
-                        */
-                       status = create_stream_beginning_activity_message(
-                               trimmer_it, sstate->stream, clock_class,
-                               &new_msg);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       push_message(trimmer_it, new_msg);
-                       new_msg = NULL;
-               } else {
-                       /* Known/unknown: push as is */
-                       push_message(trimmer_it, stream_act_beginning_msg);
-                       stream_act_beginning_msg = NULL;
-               }
-       } else {
-               BT_ASSERT(!trimmer_it->begin.is_infinite);
-
-               /*
-                * No stream beginning activity message: create and push
-                * a new message.
-                */
-               status = create_stream_beginning_activity_message(
-                       trimmer_it, sstate->stream, clock_class, &new_msg);
-               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                       goto end;
-               }
-
-               push_message(trimmer_it, new_msg);
-               new_msg = NULL;
-       }
-
-       sstate->inited = true;
-
-end:
-       bt_message_put_ref(new_msg);
-       bt_message_put_ref(stream_act_beginning_msg);
-       return status;
-}
-
-static inline
-bt_self_message_iterator_status ensure_cur_packet_exists(
-       struct trimmer_iterator *trimmer_it,
-       struct trimmer_iterator_stream_state *sstate,
-       const bt_packet *packet)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       int ret;
-       const bt_clock_class *clock_class =
-               bt_stream_class_borrow_default_clock_class_const(
-                       bt_stream_borrow_class_const(sstate->stream));
-       bt_message *msg = NULL;
-       uint64_t raw_value;
-
-       BT_ASSERT(!trimmer_it->begin.is_infinite);
-       BT_ASSERT(!sstate->cur_packet);
-
-       /*
-        * Create and push an initial packet beginning message,
-        * making its time the trimming range's beginning time.
-        */
-       ret = clock_raw_value_from_ns_from_origin(clock_class,
-               trimmer_it->begin.ns_from_origin, &raw_value);
-       if (ret) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
-               trimmer_it->self_msg_iter, packet, raw_value);
-       if (!msg) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-               goto end;
-       }
-
-       push_message(trimmer_it, msg);
-       msg = NULL;
-
-       /* Set packet as this stream's current packet */
-       sstate->cur_packet = packet;
-       bt_packet_get_ref(sstate->cur_packet);
-
-end:
-       bt_message_put_ref(msg);
-       return status;
-}
-
-/*
- * Handles a message which is associated to a given stream state. This
- * _could_ make the iterator's output message queue grow; this could
- * also consume the message without pushing anything to this queue, only
- * modifying the stream state.
- *
- * This function consumes the `msg` reference, _whatever the outcome_.
- *
- * `ns_from_origin` is the message's time, as given by
- * get_msg_ns_from_origin().
- *
- * This function sets `reached_end` if handling this message made the
- * iterator reach the end of the trimming range. Note that the output
- * message queue could contain messages even if this function sets
- * `reached_end`.
- */
-static inline
-bt_self_message_iterator_status handle_message_with_stream_state(
-               struct trimmer_iterator *trimmer_it, const bt_message *msg,
-               struct trimmer_iterator_stream_state *sstate,
-               int64_t ns_from_origin, bool *reached_end)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       bt_message_type msg_type = bt_message_get_type(msg);
-       int ret;
-
-       switch (msg_type) {
-       case BT_MESSAGE_TYPE_EVENT:
-               if (unlikely(!trimmer_it->end.is_infinite &&
-                               ns_from_origin > trimmer_it->end.ns_from_origin)) {
-                       status = end_iterator_streams(trimmer_it);
-                       *reached_end = true;
-                       break;
-               }
-
-               if (unlikely(!sstate->inited)) {
-                       status = ensure_stream_state_is_inited(trimmer_it,
-                               sstate, NULL);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-               }
-
-               if (unlikely(!sstate->cur_packet)) {
-                       const bt_event *event =
-                               bt_message_event_borrow_event_const(msg);
-                       const bt_packet *packet = bt_event_borrow_packet_const(
-                               event);
-
-                       status = ensure_cur_packet_exists(trimmer_it, sstate,
-                               packet);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(sstate->cur_packet);
-               push_message(trimmer_it, msg);
-               msg = NULL;
-               break;
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-               if (unlikely(!trimmer_it->end.is_infinite &&
-                               ns_from_origin > trimmer_it->end.ns_from_origin)) {
-                       status = end_iterator_streams(trimmer_it);
-                       *reached_end = true;
-                       break;
-               }
-
-               if (unlikely(!sstate->inited)) {
-                       status = ensure_stream_state_is_inited(trimmer_it,
-                               sstate, NULL);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(!sstate->cur_packet);
-               sstate->cur_packet =
-                       bt_message_packet_beginning_borrow_packet_const(msg);
-               bt_packet_get_ref(sstate->cur_packet);
-               push_message(trimmer_it, msg);
-               msg = NULL;
-               break;
-       case BT_MESSAGE_TYPE_PACKET_END:
-               sstate->stream_act_end_ns_from_origin = ns_from_origin;
-
-               if (unlikely(!trimmer_it->end.is_infinite &&
-                               ns_from_origin > trimmer_it->end.ns_from_origin)) {
-                       status = end_iterator_streams(trimmer_it);
-                       *reached_end = true;
-                       break;
-               }
-
-               if (unlikely(!sstate->inited)) {
-                       status = ensure_stream_state_is_inited(trimmer_it,
-                               sstate, NULL);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-               }
-
-               if (unlikely(!sstate->cur_packet)) {
-                       const bt_packet *packet =
-                               bt_message_packet_end_borrow_packet_const(msg);
-
-                       status = ensure_cur_packet_exists(trimmer_it, sstate,
-                               packet);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-               }
-
-               BT_ASSERT(sstate->cur_packet);
-               BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
-               push_message(trimmer_it, msg);
-               msg = NULL;
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-       {
-               /*
-                * `ns_from_origin` is the message's time range's
-                * beginning time here.
-                */
-               int64_t end_ns_from_origin;
-               const bt_clock_snapshot *end_cs;
-
-               if (bt_message_get_type(msg) ==
-                               BT_MESSAGE_TYPE_DISCARDED_EVENTS) {
-                       /*
-                        * Safe to ignore the return value because we
-                        * know there's a default clock and it's always
-                        * known.
-                        */
-                       end_cs = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
-                               msg);
-               } else {
-                       /*
-                        * Safe to ignore the return value because we
-                        * know there's a default clock and it's always
-                        * known.
-                        */
-                       end_cs = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
-                               msg);
-               }
-
-               if (bt_clock_snapshot_get_ns_from_origin(end_cs,
-                               &end_ns_from_origin)) {
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                       goto end;
-               }
-
-               sstate->stream_act_end_ns_from_origin = end_ns_from_origin;
-
-               if (!trimmer_it->end.is_infinite &&
-                               ns_from_origin > trimmer_it->end.ns_from_origin) {
-                       status = end_iterator_streams(trimmer_it);
-                       *reached_end = true;
-                       break;
-               }
-
-               if (!trimmer_it->end.is_infinite &&
-                               end_ns_from_origin > trimmer_it->end.ns_from_origin) {
-                       /*
-                        * This message's end time is outside the
-                        * trimming time range: replace it with a new
-                        * message having an end time equal to the
-                        * trimming time range's end and without a
-                        * count.
-                        */
-                       const bt_clock_class *clock_class =
-                               bt_clock_snapshot_borrow_clock_class_const(
-                                       end_cs);
-                       const bt_clock_snapshot *begin_cs;
-                       bt_message *new_msg;
-                       uint64_t end_raw_value;
-
-                       ret = clock_raw_value_from_ns_from_origin(clock_class,
-                               trimmer_it->end.ns_from_origin, &end_raw_value);
-                       if (ret) {
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       if (msg_type == BT_MESSAGE_TYPE_DISCARDED_EVENTS) {
-                               begin_cs = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
-                                       msg);
-                               new_msg = bt_message_discarded_events_create_with_default_clock_snapshots(
-                                       trimmer_it->self_msg_iter,
-                                       sstate->stream,
-                                       bt_clock_snapshot_get_value(begin_cs),
-                                       end_raw_value);
-                       } else {
-                               begin_cs = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
-                                       msg);
-                               new_msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
-                                       trimmer_it->self_msg_iter,
-                                       sstate->stream,
-                                       bt_clock_snapshot_get_value(begin_cs),
-                                       end_raw_value);
-                       }
-
-                       if (!new_msg) {
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-                               goto end;
-                       }
-
-                       /* Replace the original message */
-                       BT_MESSAGE_MOVE_REF(msg, new_msg);
-               }
-
-               if (unlikely(!sstate->inited)) {
-                       status = ensure_stream_state_is_inited(trimmer_it,
-                               sstate, NULL);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-               }
-
-               push_message(trimmer_it, msg);
-               msg = NULL;
-               break;
-       }
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-               if (!trimmer_it->end.is_infinite &&
-                               ns_from_origin > trimmer_it->end.ns_from_origin) {
-                       /*
-                        * This only happens when the message's time is
-                        * known and is greater than the trimming
-                        * range's end time. Unknown and -inf times are
-                        * always less than
-                        * `trimmer_it->end.ns_from_origin`.
-                        */
-                       status = end_iterator_streams(trimmer_it);
-                       *reached_end = true;
-                       break;
-               }
-
-               if (!sstate->inited) {
-                       status = ensure_stream_state_is_inited(trimmer_it,
-                               sstate, msg);
-                       msg = NULL;
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-               } else {
-                       push_message(trimmer_it, msg);
-                       msg = NULL;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-               if (trimmer_it->end.is_infinite) {
-                       push_message(trimmer_it, msg);
-                       msg = NULL;
-                       break;
-               }
-
-               if (ns_from_origin == INT64_MIN) {
-                       /* Unknown: push as is if stream state is inited */
-                       if (sstate->inited) {
-                               push_message(trimmer_it, msg);
-                               msg = NULL;
-                               sstate->last_msg_is_stream_activity_end = true;
-                       }
-               } else if (ns_from_origin == INT64_MAX) {
-                       /* Infinite: use trimming range's end time */
-                       sstate->stream_act_end_ns_from_origin =
-                               trimmer_it->end.ns_from_origin;
-               } else {
-                       /* Known: check if outside of trimming range */
-                       if (ns_from_origin > trimmer_it->end.ns_from_origin) {
-                               sstate->stream_act_end_ns_from_origin =
-                                       trimmer_it->end.ns_from_origin;
-                               status = end_iterator_streams(trimmer_it);
-                               *reached_end = true;
-                               break;
-                       }
-
-                       if (!sstate->inited) {
-                               /*
-                                * First message for this stream is a
-                                * stream activity end: we can't deduce
-                                * anything about the stream activity
-                                * beginning's time, and using this
-                                * message's time would make a useless
-                                * pair of stream activity beginning/end
-                                * with the same time. Just skip this
-                                * message and wait for something
-                                * useful.
-                                */
-                               break;
-                       }
-
-                       push_message(trimmer_it, msg);
-                       msg = NULL;
-                       sstate->last_msg_is_stream_activity_end = true;
-                       sstate->stream_act_end_ns_from_origin = ns_from_origin;
-               }
-
-               break;
-       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
-               /*
-                * We don't know what follows at this point, so just
-                * keep this message until we know what to do with it
-                * (it will be used in ensure_stream_state_is_inited()).
-                */
-               BT_ASSERT(!sstate->inited);
-               BT_MESSAGE_MOVE_REF(sstate->stream_beginning_msg, msg);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_END:
-               if (sstate->inited) {
-                       /*
-                        * This is the end of an inited stream: end this
-                        * stream if its stream activity end message
-                        * time is not the trimming range's end time
-                        * (which means the final stream activity end
-                        * message had an infinite time). end_stream()
-                        * will generate its own stream end message.
-                        */
-                       if (trimmer_it->end.is_infinite) {
-                               push_message(trimmer_it, msg);
-                               msg = NULL;
-                               g_hash_table_remove(trimmer_it->stream_states,
-                                       sstate->stream);
-                       } else if (sstate->stream_act_end_ns_from_origin <
-                                       trimmer_it->end.ns_from_origin) {
-                               status = end_stream(trimmer_it, sstate);
-                               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                                       goto end;
-                               }
-
-                               /* We won't need this stream state again */
-                               g_hash_table_remove(trimmer_it->stream_states,
-                                       sstate->stream);
-                       }
-               } else {
-                       /* We dont't need this stream state anymore */
-                       g_hash_table_remove(trimmer_it->stream_states, sstate->stream);
-               }
-
-               break;
-       default:
-               break;
-       }
-
-end:
-       /* We release the message's reference whatever the outcome */
-       bt_message_put_ref(msg);
-       return BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-}
-
-/*
- * Handles an input message. This _could_ make the iterator's output
- * message queue grow; this could also consume the message without
- * pushing anything to this queue, only modifying the stream state.
- *
- * This function consumes the `msg` reference, _whatever the outcome_.
- *
- * This function sets `reached_end` if handling this message made the
- * iterator reach the end of the trimming range. Note that the output
- * message queue could contain messages even if this function sets
- * `reached_end`.
- */
-static inline
-bt_self_message_iterator_status handle_message(
-               struct trimmer_iterator *trimmer_it, const bt_message *msg,
-               bool *reached_end)
-{
-       bt_self_message_iterator_status status;
-       const bt_stream *stream = NULL;
-       int64_t ns_from_origin = INT64_MIN;
-       bool skip;
-       int ret;
-       struct trimmer_iterator_stream_state *sstate = NULL;
-
-       /* Find message's associated stream */
-       switch (bt_message_get_type(msg)) {
-       case BT_MESSAGE_TYPE_EVENT:
-               stream = bt_event_borrow_stream_const(
-                       bt_message_event_borrow_event_const(msg));
-               break;
-       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
-               stream = bt_packet_borrow_stream_const(
-                       bt_message_packet_beginning_borrow_packet_const(msg));
-               break;
-       case BT_MESSAGE_TYPE_PACKET_END:
-               stream = bt_packet_borrow_stream_const(
-                       bt_message_packet_end_borrow_packet_const(msg));
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
-               stream = bt_message_discarded_events_borrow_stream_const(msg);
-               break;
-       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
-               stream = bt_message_discarded_packets_borrow_stream_const(msg);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
-               stream = bt_message_stream_activity_beginning_borrow_stream_const(msg);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
-               stream = bt_message_stream_activity_end_borrow_stream_const(msg);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
-               stream = bt_message_stream_beginning_borrow_stream_const(msg);
-               break;
-       case BT_MESSAGE_TYPE_STREAM_END:
-               stream = bt_message_stream_end_borrow_stream_const(msg);
-               break;
-       default:
-               break;
-       }
-
-       if (likely(stream)) {
-               /* Find stream state */
-               sstate = g_hash_table_lookup(trimmer_it->stream_states,
-                       stream);
-               if (unlikely(!sstate)) {
-                       /* No stream state yet: create one now */
-                       const bt_stream_class *sc;
-
-                       /*
-                        * Validate right now that the stream's class
-                        * has a registered default clock class so that
-                        * an existing stream state guarantees existing
-                        * default clock snapshots for its associated
-                        * messages.
-                        *
-                        * Also check that clock snapshots are always
-                        * known.
-                        */
-                       sc = bt_stream_borrow_class_const(stream);
-                       if (!bt_stream_class_borrow_default_clock_class_const(sc)) {
-                               BT_LOGE("Unsupported stream: stream class does "
-                                       "not have a default clock class: "
-                                       "stream-addr=%p, "
-                                       "stream-id=%" PRIu64 ", "
-                                       "stream-name=\"%s\"",
-                                       stream, bt_stream_get_id(stream),
-                                       bt_stream_get_name(stream));
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       /*
-                        * Temporary: make sure packet beginning, packet
-                        * end, discarded events, and discarded packets
-                        * messages have default clock snapshots until
-                        * the support for not having them is
-                        * implemented.
-                        */
-                       if (!bt_stream_class_packets_have_beginning_default_clock_snapshot(
-                                       sc)) {
-                               BT_LOGE("Unsupported stream: packets have "
-                                       "no beginning clock snapshot: "
-                                       "stream-addr=%p, "
-                                       "stream-id=%" PRIu64 ", "
-                                       "stream-name=\"%s\"",
-                                       stream, bt_stream_get_id(stream),
-                                       bt_stream_get_name(stream));
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       if (!bt_stream_class_packets_have_end_default_clock_snapshot(
-                                       sc)) {
-                               BT_LOGE("Unsupported stream: packets have "
-                                       "no end clock snapshot: "
-                                       "stream-addr=%p, "
-                                       "stream-id=%" PRIu64 ", "
-                                       "stream-name=\"%s\"",
-                                       stream, bt_stream_get_id(stream),
-                                       bt_stream_get_name(stream));
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       if (bt_stream_class_supports_discarded_events(sc) &&
-                                       !bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
-                               BT_LOGE("Unsupported stream: discarded events "
-                                       "have no clock snapshots: "
-                                       "stream-addr=%p, "
-                                       "stream-id=%" PRIu64 ", "
-                                       "stream-name=\"%s\"",
-                                       stream, bt_stream_get_id(stream),
-                                       bt_stream_get_name(stream));
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       if (bt_stream_class_supports_discarded_packets(sc) &&
-                                       !bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
-                               BT_LOGE("Unsupported stream: discarded packets "
-                                       "have no clock snapshots: "
-                                       "stream-addr=%p, "
-                                       "stream-id=%" PRIu64 ", "
-                                       "stream-name=\"%s\"",
-                                       stream, bt_stream_get_id(stream),
-                                       bt_stream_get_name(stream));
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-                               goto end;
-                       }
-
-                       sstate = g_new0(struct trimmer_iterator_stream_state,
-                               1);
-                       if (!sstate) {
-                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
-                               goto end;
-                       }
-
-                       sstate->stream = stream;
-                       sstate->stream_act_end_ns_from_origin = INT64_MIN;
-                       g_hash_table_insert(trimmer_it->stream_states,
-                               (void *) stream, sstate);
-               }
-       }
-
-       /* Retrieve the message's time */
-       ret = get_msg_ns_from_origin(msg, &ns_from_origin, &skip);
-       if (unlikely(ret)) {
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
-               goto end;
-       }
-
-       if (likely(sstate)) {
-               /* Message associated to a stream */
-               status = handle_message_with_stream_state(trimmer_it, msg,
-                       sstate, ns_from_origin, reached_end);
-
-               /*
-                * handle_message_with_stream_state() unconditionally
-                * consumes `msg`.
-                */
-               msg = NULL;
-       } else {
-               /*
-                * Message not associated to a stream (message iterator
-                * inactivity).
-                */
-               if (unlikely(ns_from_origin > trimmer_it->end.ns_from_origin)) {
-                       BT_MESSAGE_PUT_REF_AND_RESET(msg);
-                       status = end_iterator_streams(trimmer_it);
-                       *reached_end = true;
-               } else {
-                       push_message(trimmer_it, msg);
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-                       msg = NULL;
-               }
-       }
-
-end:
-       /* We release the message's reference whatever the outcome */
-       bt_message_put_ref(msg);
-       return status;
-}
-
-static inline
-void fill_message_array_from_output_messages(
-               struct trimmer_iterator *trimmer_it,
-               bt_message_array_const msgs, uint64_t capacity, uint64_t *count)
-{
-       *count = 0;
-
-       /*
-        * Move auto-seek messages to the output array (which is this
-        * iterator's base message array).
-        */
-       while (capacity > 0 && !g_queue_is_empty(trimmer_it->output_messages)) {
-               msgs[*count] = pop_message(trimmer_it);
-               capacity--;
-               (*count)++;
-       }
-
-       BT_ASSERT(*count > 0);
-}
-
-static inline
-bt_self_message_iterator_status state_ending(
-               struct trimmer_iterator *trimmer_it,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       if (g_queue_is_empty(trimmer_it->output_messages)) {
-               trimmer_it->state = TRIMMER_ITERATOR_STATE_ENDED;
-               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-               goto end;
-       }
-
-       fill_message_array_from_output_messages(trimmer_it, msgs,
-               capacity, count);
-
-end:
-       return status;
-}
-
-static inline
-bt_self_message_iterator_status state_trim(struct trimmer_iterator *trimmer_it,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-       bt_message_array_const my_msgs;
-       uint64_t my_count;
-       uint64_t i;
-       bool reached_end = false;
-
-       while (g_queue_is_empty(trimmer_it->output_messages)) {
-               status = (int) bt_self_component_port_input_message_iterator_next(
-                       trimmer_it->upstream_iter, &my_msgs, &my_count);
-               if (unlikely(status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK)) {
-                       if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_END) {
-                               status = end_iterator_streams(trimmer_it);
-                               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                                       goto end;
-                               }
-
-                               trimmer_it->state =
-                                       TRIMMER_ITERATOR_STATE_ENDING;
-                               status = state_ending(trimmer_it, msgs,
-                                       capacity, count);
-                       }
-
-                       goto end;
-               }
-
-               BT_ASSERT(my_count > 0);
-
-               for (i = 0; i < my_count; i++) {
-                       status = handle_message(trimmer_it, my_msgs[i],
-                               &reached_end);
-
-                       /*
-                        * handle_message() unconditionally consumes the
-                        * message reference.
-                        */
-                       my_msgs[i] = NULL;
-
-                       if (unlikely(status !=
-                                       BT_SELF_MESSAGE_ITERATOR_STATUS_OK)) {
-                               put_messages(my_msgs, my_count);
-                               goto end;
-                       }
-
-                       if (unlikely(reached_end)) {
-                               /*
-                                * This message's time was passed the
-                                * trimming time range's end time: we
-                                * are done. Their might still be
-                                * messages in the output message queue,
-                                * so move to the "ending" state and
-                                * apply it immediately since
-                                * state_trim() is called within the
-                                * "next" method.
-                                */
-                               put_messages(my_msgs, my_count);
-                               trimmer_it->state =
-                                       TRIMMER_ITERATOR_STATE_ENDING;
-                               status = state_ending(trimmer_it, msgs,
-                                       capacity, count);
-                               goto end;
-                       }
-               }
-       }
-
-       /*
-        * There's at least one message in the output message queue:
-        * move the messages to the output message array.
-        */
-       BT_ASSERT(!g_queue_is_empty(trimmer_it->output_messages));
-       fill_message_array_from_output_messages(trimmer_it, msgs,
-               capacity, count);
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-bt_self_message_iterator_status trimmer_msg_iter_next(
-               bt_self_message_iterator *self_msg_iter,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count)
-{
-       struct trimmer_iterator *trimmer_it =
-               bt_self_message_iterator_get_data(self_msg_iter);
-       bt_self_message_iterator_status status =
-               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
-
-       BT_ASSERT(trimmer_it);
-
-       if (likely(trimmer_it->state == TRIMMER_ITERATOR_STATE_TRIM)) {
-               status = state_trim(trimmer_it, msgs, capacity, count);
-               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                       goto end;
-               }
-       } else {
-               switch (trimmer_it->state) {
-               case TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN:
-                       status = state_set_trimmer_iterator_bounds(trimmer_it);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       status = state_seek_initially(trimmer_it);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       status = state_trim(trimmer_it, msgs, capacity, count);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       break;
-               case TRIMMER_ITERATOR_STATE_SEEK_INITIALLY:
-                       status = state_seek_initially(trimmer_it);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       status = state_trim(trimmer_it, msgs, capacity, count);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       break;
-               case TRIMMER_ITERATOR_STATE_ENDING:
-                       status = state_ending(trimmer_it, msgs, capacity,
-                               count);
-                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
-                               goto end;
-                       }
-
-                       break;
-               case TRIMMER_ITERATOR_STATE_ENDED:
-                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
-                       break;
-               default:
-                       abort();
-               }
-       }
-
-end:
-       return status;
-}
-
-BT_HIDDEN
-void trimmer_msg_iter_finalize(bt_self_message_iterator *self_msg_iter)
-{
-       struct trimmer_iterator *trimmer_it =
-               bt_self_message_iterator_get_data(self_msg_iter);
-
-       BT_ASSERT(trimmer_it);
-       destroy_trimmer_iterator(trimmer_it);
-}
diff --git a/plugins/utils/trimmer/trimmer.h b/plugins/utils/trimmer/trimmer.h
deleted file mode 100644 (file)
index e792c3e..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef BABELTRACE_PLUGINS_UTILS_TRIMMER_H
-#define BABELTRACE_PLUGINS_UTILS_TRIMMER_H
-
-/*
- * BabelTrace - Trace Trimmer Plug-in
- *
- * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <stdbool.h>
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/babeltrace.h>
-
-BT_HIDDEN
-void trimmer_finalize(bt_self_component_filter *self_comp);
-
-BT_HIDDEN
-bt_self_component_status trimmer_init(bt_self_component_filter *self_comp,
-               const bt_value *params, void *init_data);
-
-BT_HIDDEN
-bt_self_message_iterator_status trimmer_msg_iter_init(
-               bt_self_message_iterator *self_msg_iter,
-               bt_self_component_filter *self_comp,
-               bt_self_component_port_output *port);
-
-BT_HIDDEN
-bt_self_message_iterator_status trimmer_msg_iter_next(
-               bt_self_message_iterator *self_msg_iter,
-               bt_message_array_const msgs, uint64_t capacity,
-               uint64_t *count);
-
-BT_HIDDEN
-void trimmer_msg_iter_finalize(bt_self_message_iterator *self_msg_iter);
-
-#endif /* BABELTRACE_PLUGINS_UTILS_TRIMMER_H */
diff --git a/python-plugin-provider/Makefile.am b/python-plugin-provider/Makefile.am
deleted file mode 100644 (file)
index 2a269f0..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-if ENABLE_PYTHON_PLUGINS
-AM_CPPFLAGS += $(PYTHON_INCLUDE)
-
-lib_LTLIBRARIES = libbabeltrace2-python-plugin-provider.la
-
-libbabeltrace2_python_plugin_provider_la_SOURCES = \
-       python-plugin-provider.c
-libbabeltrace2_python_plugin_provider_la_LDFLAGS = \
-       $(LT_NO_UNDEFINED) \
-       -version-info $(BABELTRACE_LIBRARY_VERSION) \
-       $(PYTHON_LIBS)
-
-libbabeltrace2_python_plugin_provider_la_LIBADD =
-
-# Link the Python plugin provider library with libbabeltrace2
-# when it's not built-in the babeltrace2 executable.
-if !ENABLE_BUILT_IN_PLUGINS
-libbabeltrace2_python_plugin_provider_la_LIBADD += \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
-       $(top_builddir)/lib/libbabeltrace2.la
-endif
-endif # ENABLE_PYTHON_PLUGINS
diff --git a/python-plugin-provider/python-plugin-provider.c b/python-plugin-provider/python-plugin-provider.c
deleted file mode 100644 (file)
index 8e5ee08..0000000
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * python-plugin-provider.c
- *
- * Babeltrace Python plugin provider
- *
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#define BT_LOG_TAG "PLUGIN-PY"
-
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/compiler-internal.h>
-#include <babeltrace2/plugin/plugin-const.h>
-#include <babeltrace2/plugin/plugin-internal.h>
-#include <babeltrace2/graph/component-class.h>
-#include <babeltrace2/graph/component-class-internal.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <Python.h>
-#include <glib.h>
-#include <gmodule.h>
-
-#define PYTHON_PLUGIN_FILE_PREFIX      "bt_plugin_"
-#define PYTHON_PLUGIN_FILE_PREFIX_LEN  (sizeof(PYTHON_PLUGIN_FILE_PREFIX) - 1)
-#define PYTHON_PLUGIN_FILE_EXT         ".py"
-#define PYTHON_PLUGIN_FILE_EXT_LEN     (sizeof(PYTHON_PLUGIN_FILE_EXT) - 1)
-
-enum python_state {
-       /* init_python() not called yet */
-       PYTHON_STATE_NOT_INITED,
-
-       /* init_python() called once with success */
-       PYTHON_STATE_FULLY_INITIALIZED,
-
-       /* init_python() called once without success */
-       PYTHON_STATE_CANNOT_INITIALIZE,
-} python_state = PYTHON_STATE_NOT_INITED;
-
-static PyObject *py_try_load_plugin_module_func = NULL;
-static bool python_was_initialized_by_us;
-
-static
-void print_python_traceback_warn(void)
-{
-       if (BT_LOG_ON_WARN && Py_IsInitialized() && PyErr_Occurred()) {
-               BT_LOGW_STR("Exception occured: traceback: ");
-               PyErr_Print();
-       }
-}
-
-static
-void pyerr_clear(void)
-{
-       if (Py_IsInitialized()) {
-               PyErr_Clear();
-       }
-}
-
-static
-void init_python(void)
-{
-       PyObject *py_bt2_py_plugin_mod = NULL;
-       const char *dis_python_env;
-#ifndef __MINGW32__
-       sighandler_t old_sigint = signal(SIGINT, SIG_DFL);
-#endif
-
-       if (python_state != PYTHON_STATE_NOT_INITED) {
-               goto end;
-       }
-
-       /*
-        * User can disable Python plugin support with the
-        * BABELTRACE_DISABLE_PYTHON_PLUGINS environment variable set to
-        * 1.
-        */
-       dis_python_env = getenv("BABELTRACE_DISABLE_PYTHON_PLUGINS");
-       if (dis_python_env && strcmp(dis_python_env, "1") == 0) {
-               BT_LOGI_STR("Python plugin support is disabled because `BABELTRACE_DISABLE_PYTHON_PLUGINS=1`.");
-               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
-               goto end;
-       }
-
-       if (!Py_IsInitialized()) {
-               BT_LOGI_STR("Python interpreter is not initialized: initializing Python interpreter.");
-               Py_InitializeEx(0);
-               python_was_initialized_by_us = true;
-               BT_LOGI("Initialized Python interpreter: version=\"%s\"",
-                       Py_GetVersion());
-       } else {
-               BT_LOGI("Python interpreter is already initialized: version=\"%s\"",
-                       Py_GetVersion());
-       }
-
-       py_bt2_py_plugin_mod = PyImport_ImportModule("bt2.py_plugin");
-       if (!py_bt2_py_plugin_mod) {
-               BT_LOGI_STR("Cannot import bt2.py_plugin Python module: Python plugin support is disabled.");
-               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
-               goto end;
-       }
-
-       py_try_load_plugin_module_func =
-               PyObject_GetAttrString(py_bt2_py_plugin_mod, "_try_load_plugin_module");
-       if (!py_try_load_plugin_module_func) {
-               BT_LOGI_STR("Cannot get _try_load_plugin_module attribute from bt2.py_plugin Python module: Python plugin support is disabled.");
-               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
-               goto end;
-       }
-
-       python_state = PYTHON_STATE_FULLY_INITIALIZED;
-
-end:
-#ifndef __MINGW32__
-       if (old_sigint != SIG_ERR) {
-               (void) signal(SIGINT, old_sigint);
-       }
-#endif
-
-       print_python_traceback_warn();
-       pyerr_clear();
-       Py_XDECREF(py_bt2_py_plugin_mod);
-       return;
-}
-
-__attribute__((destructor)) static
-void fini_python(void) {
-       if (Py_IsInitialized() && python_was_initialized_by_us) {
-               if (py_try_load_plugin_module_func) {
-                       Py_DECREF(py_try_load_plugin_module_func);
-                       py_try_load_plugin_module_func = NULL;
-               }
-
-               Py_Finalize();
-               BT_LOGI_STR("Finalized Python interpreter.");
-       }
-
-       python_state = PYTHON_STATE_NOT_INITED;
-}
-
-static
-bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info)
-{
-       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;
-
-       BT_ASSERT(plugin_info);
-       BT_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);
-
-                       BT_ASSERT(py_major);
-                       BT_ASSERT(py_minor);
-                       BT_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);
-
-                       BT_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++) {
-                       bt_component_class *comp_class;
-                       PyObject *py_comp_class_addr;
-
-                       py_comp_class_addr =
-                               PyList_GetItem(py_comp_class_addrs, i);
-                       BT_ASSERT(py_comp_class_addr);
-                       if (PyLong_Check(py_comp_class_addr)) {
-                               comp_class = PyLong_AsVoidPtr(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;
-                       }
-               }
-       }
-
-       goto end;
-
-error:
-       print_python_traceback_warn();
-       pyerr_clear();
-       BT_OBJECT_PUT_REF_AND_RESET(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;
-}
-
-G_MODULE_EXPORT
-bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path)
-{
-       bt_plugin_set *plugin_set = NULL;
-       bt_plugin *plugin = NULL;
-       PyObject *py_plugin_info = NULL;
-       gchar *basename = NULL;
-       size_t path_len;
-
-       BT_ASSERT(path);
-
-       if (python_state == PYTHON_STATE_CANNOT_INITIALIZE) {
-               /*
-                * We do not even care about the rest of the function
-                * here because we already know Python cannot be fully
-                * initialized.
-                */
-               goto error;
-       }
-
-       BT_LOGD("Creating all Python plugins from file: path=\"%s\"", path);
-       path_len = strlen(path);
-
-       /* File name ends with `.py` */
-       if (strncmp(path + path_len - PYTHON_PLUGIN_FILE_EXT_LEN,
-                       PYTHON_PLUGIN_FILE_EXT,
-                       PYTHON_PLUGIN_FILE_EXT_LEN) != 0) {
-               BT_LOGD("Skipping non-Python file: path=\"%s\"", path);
-               goto error;
-       }
-
-       /* File name starts with `bt_plugin_` */
-       basename = g_path_get_basename(path);
-       if (!basename) {
-               BT_LOGW("Cannot get path's basename: path=\"%s\"", path);
-               goto error;
-       }
-
-       if (strncmp(basename, PYTHON_PLUGIN_FILE_PREFIX,
-                       PYTHON_PLUGIN_FILE_PREFIX_LEN) != 0) {
-               BT_LOGD("Skipping Python file not starting with `%s`: "
-                       "path=\"%s\"", PYTHON_PLUGIN_FILE_PREFIX, path);
-               goto error;
-       }
-
-       /*
-        * Initialize Python now.
-        *
-        * This is not done in the library contructor because the
-        * interpreter is somewhat slow to initialize. If you don't
-        * have any potential Python plugins, you don't need to endure
-        * this waiting time everytime you load the library.
-        */
-       init_python();
-       if (python_state != PYTHON_STATE_FULLY_INITIALIZED) {
-               /*
-                * For some reason we cannot initialize Python,
-                * import the required modules, and get the required
-                * attributes from them.
-                */
-               BT_LOGI("Failed to initialize Python interpreter.");
-               goto error;
-       }
-
-       /*
-        * Call bt2.py_plugin._try_load_plugin_module() with this path
-        * to get plugin info if the plugin is loadable and complete.
-        * This function returns None when there's an error, but just in
-        * case we also manually clear the last Python error state.
-        */
-       BT_LOGD_STR("Getting Python plugin info object from Python module.");
-       py_plugin_info = PyObject_CallFunction(py_try_load_plugin_module_func,
-               "(s)", path);
-       if (!py_plugin_info || py_plugin_info == Py_None) {
-               BT_LOGW("Cannot load Python plugin: path=\"%s\"", path);
-               print_python_traceback_warn();
-               PyErr_Clear();
-               goto error;
-       }
-
-       /*
-        * Get bt_plugin from plugin info object.
-        */
-       plugin = bt_plugin_from_python_plugin_info(py_plugin_info);
-       if (!plugin) {
-               BT_LOGW("Cannot create plugin object from Python plugin info object: "
-                       "path=\"%s\", py-plugin-info-addr=%p",
-                       path, py_plugin_info);
-               goto error;
-       }
-
-       bt_plugin_set_path(plugin, path);
-       plugin_set = bt_plugin_set_create();
-       if (!plugin_set) {
-               BT_LOGE_STR("Cannot create empty plugin set.");
-               goto error;
-       }
-
-       bt_plugin_set_add_plugin(plugin_set, plugin);
-       BT_LOGD("Created all Python plugins from file: path=\"%s\", "
-               "plugin-addr=%p, plugin-name=\"%s\"",
-               path, plugin, bt_plugin_get_name(plugin));
-       goto end;
-
-error:
-       BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
-
-end:
-       bt_plugin_put_ref(plugin);
-       Py_XDECREF(py_plugin_info);
-       g_free(basename);
-       return plugin_set;
-}
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..28b7bd4
--- /dev/null
@@ -0,0 +1,15 @@
+SUBDIRS = \
+       common \
+       ctfser \
+       fd-cache \
+       compat \
+       logging \
+       ctf-writer \
+       lib \
+       python-plugin-provider \
+       plugins \
+       cli \
+       bindings
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = babeltrace2.pc babeltrace2-ctf-writer.pc
diff --git a/src/babeltrace2-ctf-writer.pc.in b/src/babeltrace2-ctf-writer.pc.in
new file mode 100644 (file)
index 0000000..504d859
--- /dev/null
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Babeltrace CTF parser
+Description: libbabeltrace2-ctf provides the specific bits necessary to write a Common Trace Format (CTF) trace.
+Version: @PACKAGE_VERSION@
+Requires:
+Requires.private: uuid popt
+Libs: -L${libdir} -lbabeltrace2-ctf-writer
+Cflags: -I${includedir}
+
diff --git a/src/babeltrace2.pc.in b/src/babeltrace2.pc.in
new file mode 100644 (file)
index 0000000..646aeb4
--- /dev/null
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Babeltrace
+Description: libbabeltrace2 provides a reader for trace files, reading mainly the
+Common Trace Format (CTF).
+Version: @PACKAGE_VERSION@
+Requires:
+Requires.private: uuid popt
+Libs: -L${libdir} -lbabeltrace2
+Cflags: -I${includedir}
+
diff --git a/src/bindings/Makefile.am b/src/bindings/Makefile.am
new file mode 100644 (file)
index 0000000..773e43a
--- /dev/null
@@ -0,0 +1,3 @@
+if ENABLE_PYTHON_BINDINGS
+SUBDIRS = python
+endif
diff --git a/src/bindings/python/Makefile.am b/src/bindings/python/Makefile.am
new file mode 100644 (file)
index 0000000..f3cec07
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = bt2
diff --git a/src/bindings/python/bt2/.gitignore b/src/bindings/python/bt2/.gitignore
new file mode 100644 (file)
index 0000000..b893bce
--- /dev/null
@@ -0,0 +1,7 @@
+bt2/__init__.py
+bt2/native_bt.py
+bt2/native_bt_wrap.c
+build
+build-python-bindings.stamp
+installed_files.txt
+setup.py
diff --git a/src/bindings/python/bt2/Makefile.am b/src/bindings/python/bt2/Makefile.am
new file mode 100644 (file)
index 0000000..70da669
--- /dev/null
@@ -0,0 +1,117 @@
+# Since the shared object used by the python bindings is not built with
+# libtool, we need to add the directory containing libbabeltrace2 to the
+# linker path.
+AM_LDFLAGS=-L$(top_builddir)/src/lib/.libs
+
+INSTALLED_FILES=$(builddir)/installed_files.txt
+
+STATIC_BINDINGS_DEPS =                                 \
+       bt2/logging.c                                   \
+       bt2/logging.h                                   \
+       bt2/native_bt_clock_class.i                     \
+       bt2/native_bt_clock_snapshot.i                  \
+       bt2/native_bt_component_class.i                 \
+       bt2/native_bt_component.i                       \
+       bt2/native_bt_connection.i                      \
+       bt2/native_bt_event_class.i                     \
+       bt2/native_bt_event.i                           \
+       bt2/native_bt_field_class.i                     \
+       bt2/native_bt_field_path.i                      \
+       bt2/native_bt_field.i                           \
+       bt2/native_bt_graph.i                           \
+       bt2/native_bt.i                                 \
+       bt2/native_bt_logging.i                         \
+       bt2/native_bt_message.i                         \
+       bt2/native_bt_notifier.i                        \
+       bt2/native_bt_packet.i                          \
+       bt2/native_bt_plugin.i                          \
+       bt2/native_bt_port.i                            \
+       bt2/native_bt_query_exec.i                      \
+       bt2/native_bt_stream_class.i                    \
+       bt2/native_bt_stream.i                          \
+       bt2/native_bt_trace_class.i                     \
+       bt2/native_bt_trace.i                           \
+       bt2/native_bt_value.i                           \
+       bt2/native_bt_version.i                         \
+       bt2/clock_class.py                              \
+       bt2/clock_snapshot.py                           \
+       bt2/component.py                                \
+       bt2/connection.py                               \
+       bt2/event_class.py                              \
+       bt2/event.py                                    \
+       bt2/field.py                                    \
+       bt2/field_class.py                              \
+       bt2/field_path.py                               \
+       bt2/graph.py                                    \
+       bt2/logging.py                                  \
+       bt2/message_iterator.py                         \
+       bt2/message.py                                  \
+       bt2/object.py                                   \
+       bt2/packet.py                                   \
+       bt2/plugin.py                                   \
+       bt2/port.py                                     \
+       bt2/py_plugin.py                                \
+       bt2/query_executor.py                           \
+       bt2/stream_class.py                             \
+       bt2/stream.py                                   \
+       bt2/trace.py                                    \
+       bt2/trace_class.py                              \
+       bt2/trace_collection_message_iterator.py        \
+       bt2/utils.py                                    \
+       bt2/value.py
+
+GENERATED_BINDINGS_DEPS =      \
+       bt2/__init__.py         \
+       setup.py
+
+BUILD_FLAGS=CC="$(CC)" \
+               CFLAGS="$(GLIB_CFLAGS) $(AM_CFLAGS) $(CFLAGS)" \
+               CPPFLAGS="$(AM_CPPFLAGS) $(CPPFLAGS)" \
+               LDFLAGS="$(AM_LDFLAGS) $(LDFLAGS) $(GLIB_LIBS) $(LIBS)"
+
+all-local: build-python-bindings.stamp
+
+copy-static-deps.stamp: $(addprefix $(srcdir)/, $(STATIC_BINDINGS_DEPS))
+       @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
+               for file in $(STATIC_BINDINGS_DEPS); do \
+                       cp -f $(srcdir)/$$file $(builddir)/$$file; \
+               done; \
+       fi
+       touch $@
+
+build-python-bindings.stamp: copy-static-deps.stamp $(GENERATED_BINDINGS_DEPS)
+       $(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build_ext --force --swig "$(SWIG)"
+       $(BUILD_FLAGS) $(PYTHON) $(builddir)/setup.py build --force
+       touch $@
+
+install-exec-local: build-python-bindings.stamp
+       @opts="--prefix=$(prefix) --record $(INSTALLED_FILES) --verbose --no-compile $(DISTSETUPOPTS)"; \
+       if [ "$(DESTDIR)" != "" ]; then \
+               opts="$$opts --root=$(DESTDIR)"; \
+       fi; \
+       $(PYTHON) $(builddir)/setup.py install $$opts;
+
+clean-local:
+       rm -rf $(builddir)/build
+       @if [ x"$(srcdir)" != x"$(builddir)" ]; then \
+               for file in $(STATIC_BINDINGS_DEPS); do \
+                       rm -f $(builddir)/$$file; \
+               done; \
+       fi
+
+# Distutils' setup.py does not include an uninstall target, we thus need to do
+# it manually. We save the path of the files that were installed during the install target
+# and delete them during the uninstallation.
+uninstall-local:
+       if [ "$(DESTDIR)" != "" ]; then \
+               $(SED) -i "s|^|$(DESTDIR)/|g" $(INSTALLED_FILES); \
+       fi
+       cat $(INSTALLED_FILES) | xargs rm -rf || true
+       $(GREP) "__init__.py" $(INSTALLED_FILES) | xargs dirname | xargs rm -rf || true
+       rm -f $(INSTALLED_FILES)
+
+# distribute: extra Python modules and SWIG interface files
+EXTRA_DIST = $(STATIC_BINDINGS_DEPS)
+
+# clean: generated C and Python files (by SWIG)
+CLEANFILES = bt2/native_bt.py bt2/native_bt_wrap.c build-python-bindings.stamp copy-static-deps.stamp
diff --git a/src/bindings/python/bt2/bt2/__init__.py.in b/src/bindings/python/bt2/bt2/__init__.py.in
new file mode 100644 (file)
index 0000000..f80cf65
--- /dev/null
@@ -0,0 +1,133 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+__version__ = '@PACKAGE_VERSION@'
+
+
+from bt2.clock_class import *
+from bt2.clock_snapshot import *
+from bt2.component import *
+from bt2.component import _FilterComponent
+from bt2.component import _GenericFilterComponentClass
+from bt2.component import _GenericSinkComponentClass
+from bt2.component import _GenericSourceComponentClass
+from bt2.component import _SinkComponent
+from bt2.component import _SourceComponent
+from bt2.component import _UserFilterComponent
+from bt2.component import _UserSinkComponent
+from bt2.component import _UserSourceComponent
+from bt2.connection import *
+from bt2.connection import _Connection
+from bt2.event import _Event
+from bt2.event_class import *
+from bt2.field_class import *
+from bt2.field_path import *
+from bt2.field import *
+from bt2.graph import *
+from bt2.logging import *
+from bt2.message import *
+from bt2.message import _DiscardedEventsMessage
+from bt2.message import _DiscardedPacketsMessage
+from bt2.message_iterator import *
+from bt2.message_iterator import _UserMessageIterator
+from bt2.packet import _Packet
+from bt2.plugin import *
+from bt2.port import *
+from bt2.py_plugin import *
+from bt2.query_executor import *
+from bt2.stream import _Stream
+from bt2.stream_class import *
+from bt2.trace import *
+from bt2.trace_class import *
+from bt2.trace_collection_message_iterator import *
+from bt2.value import *
+from bt2.value import _Value
+from bt2.value import _IntegerValue
+
+
+class Error(Exception):
+    pass
+
+
+class CreationError(Error):
+    '''Raised when object creation fails due to memory issues.'''
+
+
+class InvalidQueryObject(Error):
+    pass
+
+
+class InvalidQueryParams(Error):
+    pass
+
+
+class TryAgain(Exception):
+    pass
+
+
+class Stop(StopIteration):
+    pass
+
+
+class PortConnectionRefused(Exception):
+    pass
+
+
+class IncompleteUserClass(Error):
+    pass
+
+
+class GraphCanceled(Exception):
+    pass
+
+
+class QueryExecutorCanceled(Exception):
+    pass
+
+
+class NonexistentClockSnapshot(Error):
+    pass
+
+
+class _ListenerHandle:
+    def __init__(self, listener_id, obj):
+        self._listener_id = listener_id
+        self._obj = obj
+
+
+def _init_and_register_exit():
+    import bt2.native_bt as _native_bt
+    import atexit
+
+    atexit.register(_native_bt.py3_cc_exit_handler)
+    version = (_native_bt.version_get_major(), _native_bt.version_get_minor(),
+               _native_bt.version_get_patch(), _native_bt.version_get_extra())
+    _native_bt.py3_cc_init_from_bt2()
+
+
+_init_and_register_exit()
+
+
+try:
+    del native_bt
+except:
+    pass
diff --git a/src/bindings/python/bt2/bt2/clock_class.py b/src/bindings/python/bt2/bt2/clock_class.py
new file mode 100644 (file)
index 0000000..59a93cd
--- /dev/null
@@ -0,0 +1,144 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2
+import uuid as uuidp
+
+
+class ClockClassOffset:
+    def __init__(self, seconds=0, cycles=0):
+        utils._check_int64(seconds)
+        utils._check_int64(cycles)
+        self._seconds = seconds
+        self._cycles = cycles
+
+    @property
+    def seconds(self):
+        return self._seconds
+
+    @property
+    def cycles(self):
+        return self._cycles
+
+    def __eq__(self, other):
+        if not isinstance(other, self.__class__):
+            # not comparing apples to apples
+            return False
+
+        return (self.seconds, self.cycles) == (other.seconds, other.cycles)
+
+
+class _ClockClass(object._SharedObject):
+    _get_ref = staticmethod(native_bt.clock_class_get_ref)
+    _put_ref = staticmethod(native_bt.clock_class_put_ref)
+
+    @property
+    def name(self):
+        return native_bt.clock_class_get_name(self._ptr)
+
+    def _name(self, name):
+        utils._check_str(name)
+        ret = native_bt.clock_class_set_name(self._ptr, name)
+        utils._handle_ret(ret, "cannot set clock class object's name")
+
+    _name = property(fset=_name)
+
+    @property
+    def description(self):
+        return native_bt.clock_class_get_description(self._ptr)
+
+    def _description(self, description):
+        utils._check_str(description)
+        ret = native_bt.clock_class_set_description(self._ptr, description)
+        utils._handle_ret(ret, "cannot set clock class object's description")
+
+    _description = property(fset=_description)
+
+    @property
+    def frequency(self):
+        return native_bt.clock_class_get_frequency(self._ptr)
+
+    def _frequency(self, frequency):
+        utils._check_uint64(frequency)
+        native_bt.clock_class_set_frequency(self._ptr, frequency)
+
+    _frequency = property(fset=_frequency)
+
+    @property
+    def precision(self):
+        precision = native_bt.clock_class_get_precision(self._ptr)
+        return precision
+
+    def _precision(self, precision):
+        utils._check_uint64(precision)
+        native_bt.clock_class_set_precision(self._ptr, precision)
+
+    _precision = property(fset=_precision)
+
+    @property
+    def offset(self):
+        offset_s, offset_cycles = native_bt.clock_class_get_offset(self._ptr)
+        return ClockClassOffset(offset_s, offset_cycles)
+
+    def _offset(self, offset):
+        utils._check_type(offset, ClockClassOffset)
+        native_bt.clock_class_set_offset(self._ptr, offset.seconds, offset.cycles)
+
+    _offset = property(fset=_offset)
+
+    @property
+    def origin_is_unix_epoch(self):
+        return native_bt.clock_class_origin_is_unix_epoch(self._ptr)
+
+    def _origin_is_unix_epoch(self, origin_is_unix_epoch):
+        utils._check_bool(origin_is_unix_epoch)
+        native_bt.clock_class_set_origin_is_unix_epoch(self._ptr, int(origin_is_unix_epoch))
+
+    _origin_is_unix_epoch = property(fset=_origin_is_unix_epoch)
+
+    @property
+    def uuid(self):
+        uuid_bytes = native_bt.clock_class_get_uuid(self._ptr)
+
+        if uuid_bytes is None:
+            return
+
+        return uuidp.UUID(bytes=uuid_bytes)
+
+    def _uuid(self, uuid):
+        utils._check_type(uuid, uuidp.UUID)
+        native_bt.clock_class_set_uuid(self._ptr, uuid.bytes)
+
+    _uuid = property(fset=_uuid)
+
+    def cycles_to_ns_from_origin(self, cycles):
+        utils._check_uint64(cycles)
+        ret, ns = native_bt.clock_class_cycles_to_ns_from_origin(self._ptr, cycles)
+
+        error_msg = "cannot convert clock value to nanoseconds from origin for given clock class"
+
+        if ret == native_bt.CLOCK_CLASS_STATUS_OVERFLOW:
+            raise OverflowError(error_msg)
+
+        utils._handle_ret(ret, error_msg)
+        return ns
diff --git a/src/bindings/python/bt2/bt2/clock_snapshot.py b/src/bindings/python/bt2/bt2/clock_snapshot.py
new file mode 100644 (file)
index 0000000..4bf37d6
--- /dev/null
@@ -0,0 +1,70 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import numbers
+import bt2
+import functools
+
+
+class _BaseClockSnapshot(object._UniqueObject):
+    @property
+    def clock_class(self):
+        cc_ptr = native_bt.clock_snapshot_borrow_clock_class_const(self._ptr)
+        assert cc_ptr is not None
+        return bt2.clock_class._ClockClass._create_from_ptr_and_get_ref(cc_ptr)
+
+
+@functools.total_ordering
+class _ClockSnapshot(_BaseClockSnapshot):
+    @property
+    def value(self):
+        return native_bt.clock_snapshot_get_value(self._ptr)
+
+    @property
+    def ns_from_origin(self):
+        ret, ns = native_bt.clock_snapshot_get_ns_from_origin(self._ptr)
+
+        if ret == native_bt.CLOCK_SNAPSHOT_STATUS_OVERFLOW:
+            raise OverflowError("cannot get clock snapshot's nanoseconds from origin")
+
+        return ns
+
+    def __eq__(self, other):
+        if not isinstance(other, numbers.Integral):
+            return NotImplemented
+
+        return self.value == int(other)
+
+    def __lt__(self, other):
+        if not isinstance(other, numbers.Integral):
+            return NotImplemented
+
+        return self.value < int(other)
+
+
+class _UnknownClockSnapshot(_BaseClockSnapshot):
+    pass
+
+
+class _InfiniteClockSnapshot(_BaseClockSnapshot):
+    pass
diff --git a/src/bindings/python/bt2/bt2/component.py b/src/bindings/python/bt2/bt2/component.py
new file mode 100644 (file)
index 0000000..3480f65
--- /dev/null
@@ -0,0 +1,785 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.message_iterator
+import collections.abc
+import bt2.value
+import traceback
+import bt2.port
+import sys
+import bt2
+import os
+
+
+_env_var = os.environ.get('BABELTRACE_PYTHON_BT2_NO_TRACEBACK')
+_NO_PRINT_TRACEBACK = _env_var == '1'
+
+
+# This class wraps a component class pointer. This component class could
+# have been created by Python code, but since we only have the pointer,
+# we can only wrap it in a generic way and lose the original Python
+# class.
+#
+# Subclasses must implement some methods that this base class uses:
+#
+#   - _as_component_class_ptr: static method, convert the passed component class
+#     pointer to a 'bt_component_class *'.
+
+class _GenericComponentClass(object._SharedObject):
+    @property
+    def name(self):
+        ptr = self._as_component_class_ptr(self._ptr)
+        name = native_bt.component_class_get_name(ptr)
+        assert name is not None
+        return name
+
+    @property
+    def description(self):
+        ptr = self._as_component_class_ptr(self._ptr)
+        return native_bt.component_class_get_description(ptr)
+
+    @property
+    def help(self):
+        ptr = self._as_component_class_ptr(self._ptr)
+        return native_bt.component_class_get_help(ptr)
+
+    def _component_class_ptr(self):
+        return self._as_component_class_ptr(self._ptr)
+
+    def __eq__(self, other):
+        if not isinstance(other, _GenericComponentClass):
+            try:
+                if not issubclass(other, _UserComponent):
+                    return False
+            except TypeError:
+                return False
+
+        return self.addr == other.addr
+
+
+class _GenericSourceComponentClass(_GenericComponentClass):
+    _get_ref = staticmethod(native_bt.component_class_source_get_ref)
+    _put_ref = staticmethod(native_bt.component_class_source_put_ref)
+    _as_component_class_ptr = staticmethod(native_bt.component_class_source_as_component_class)
+
+
+class _GenericFilterComponentClass(_GenericComponentClass):
+    _get_ref = staticmethod(native_bt.component_class_filter_get_ref)
+    _put_ref = staticmethod(native_bt.component_class_filter_put_ref)
+    _as_component_class_ptr = staticmethod(native_bt.component_class_filter_as_component_class)
+
+
+class _GenericSinkComponentClass(_GenericComponentClass):
+    _get_ref = staticmethod(native_bt.component_class_sink_get_ref)
+    _put_ref = staticmethod(native_bt.component_class_sink_put_ref)
+    _as_component_class_ptr = staticmethod(native_bt.component_class_sink_as_component_class)
+
+
+def _handle_component_status(status, gen_error_msg):
+    if status == native_bt.SELF_COMPONENT_STATUS_END:
+        raise bt2.Stop
+    elif status == native_bt.SELF_COMPONENT_STATUS_AGAIN:
+        raise bt2.TryAgain
+    elif status == native_bt.SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION:
+        raise bt2.PortConnectionRefused
+    elif status < 0:
+        raise bt2.Error(gen_error_msg)
+
+
+class _PortIterator(collections.abc.Iterator):
+    def __init__(self, comp_ports):
+        self._comp_ports = comp_ports
+        self._at = 0
+
+    def __next__(self):
+        if self._at == len(self._comp_ports):
+            raise StopIteration
+
+        comp_ports = self._comp_ports
+        comp_ptr = comp_ports._component_ptr
+
+        port_ptr = comp_ports._borrow_port_ptr_at_index(comp_ptr, self._at)
+        assert port_ptr is not None
+
+        name = native_bt.port_get_name(comp_ports._port_pycls._as_port_ptr(port_ptr))
+        assert name is not None
+
+        self._at += 1
+        return name
+
+
+class _ComponentPorts(collections.abc.Mapping):
+
+    # component_ptr is a bt_component_source *, bt_component_filter * or
+    # bt_component_sink *.  Its type must match the type expected by the
+    # functions passed as arguments.
+
+    def __init__(self, component_ptr,
+                 borrow_port_ptr_by_name,
+                 borrow_port_ptr_at_index,
+                 get_port_count,
+                 port_pycls):
+        self._component_ptr = component_ptr
+        self._borrow_port_ptr_by_name = borrow_port_ptr_by_name
+        self._borrow_port_ptr_at_index = borrow_port_ptr_at_index
+        self._get_port_count = get_port_count
+        self._port_pycls = port_pycls
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        port_ptr = self._borrow_port_ptr_by_name(self._component_ptr, key)
+
+        if port_ptr is None:
+            raise KeyError(key)
+
+        return self._port_pycls._create_from_ptr_and_get_ref(port_ptr)
+
+    def __len__(self):
+        count = self._get_port_count(self._component_ptr)
+        assert count >= 0
+        return count
+
+    def __iter__(self):
+        return _PortIterator(self)
+
+
+# This class holds the methods which are common to both generic
+# component objects and Python user component objects.
+#
+# Subclasses must provide these methods or property:
+#
+#   - _borrow_component_class_ptr: static method, must return a pointer to the
+#     specialized component class (e.g. 'bt_component_class_sink *') of the
+#     passed specialized component pointer (e.g. 'bt_component_sink *').
+#   - _comp_cls_type: property, one of the native_bt.COMPONENT_CLASS_TYPE_*
+#     constants.
+#   - _as_component_ptr: static method, must return the passed specialized
+#     component pointer (e.g. 'bt_component_sink *') as a 'bt_component *'.
+
+class _Component:
+    @property
+    def name(self):
+        ptr = self._as_component_ptr(self._ptr)
+        name = native_bt.component_get_name(ptr)
+        assert name is not None
+        return name
+
+    @property
+    def cls(self):
+        cc_ptr = self._borrow_component_class_ptr(self._ptr)
+        assert cc_ptr is not None
+        return _create_component_class_from_ptr_and_get_ref(cc_ptr, self._comp_cls_type)
+
+    def __eq__(self, other):
+        if not hasattr(other, 'addr'):
+            return False
+
+        return self.addr == other.addr
+
+
+class _SourceComponent(_Component):
+    _borrow_component_class_ptr = staticmethod(native_bt.component_source_borrow_class_const)
+    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE
+    _as_component_class_ptr = staticmethod(native_bt.component_class_source_as_component_class)
+    _as_component_ptr = staticmethod(native_bt.component_source_as_component_const)
+
+
+class _FilterComponent(_Component):
+    _borrow_component_class_ptr = staticmethod(native_bt.component_filter_borrow_class_const)
+    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_FILTER
+    _as_component_class_ptr = staticmethod(native_bt.component_class_filter_as_component_class)
+    _as_component_ptr = staticmethod(native_bt.component_filter_as_component_const)
+
+
+class _SinkComponent(_Component):
+    _borrow_component_class_ptr = staticmethod(native_bt.component_sink_borrow_class_const)
+    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_SINK
+    _as_component_class_ptr = staticmethod(native_bt.component_class_sink_as_component_class)
+    _as_component_ptr = staticmethod(native_bt.component_sink_as_component_const)
+
+
+# This is analogous to _GenericSourceComponentClass, but for source
+# component objects.
+class _GenericSourceComponent(object._SharedObject, _SourceComponent):
+    _get_ref = staticmethod(native_bt.component_source_get_ref)
+    _put_ref = staticmethod(native_bt.component_source_put_ref)
+
+    @property
+    def output_ports(self):
+        return _ComponentPorts(self._ptr,
+                               native_bt.component_source_borrow_output_port_by_name_const,
+                               native_bt.component_source_borrow_output_port_by_index_const,
+                               native_bt.component_source_get_output_port_count,
+                               bt2.port._OutputPort)
+
+
+# This is analogous to _GenericFilterComponentClass, but for filter
+# component objects.
+class _GenericFilterComponent(object._SharedObject, _FilterComponent):
+    _get_ref = staticmethod(native_bt.component_filter_get_ref)
+    _put_ref = staticmethod(native_bt.component_filter_put_ref)
+
+    @property
+    def output_ports(self):
+        return _ComponentPorts(self._ptr,
+                               native_bt.component_filter_borrow_output_port_by_name_const,
+                               native_bt.component_filter_borrow_output_port_by_index_const,
+                               native_bt.component_filter_get_output_port_count,
+                               bt2.port._OutputPort)
+
+    @property
+    def input_ports(self):
+        return _ComponentPorts(self._ptr,
+                               native_bt.component_filter_borrow_input_port_by_name_const,
+                               native_bt.component_filter_borrow_input_port_by_index_const,
+                               native_bt.component_filter_get_input_port_count,
+                               bt2.port._InputPort)
+
+
+# This is analogous to _GenericSinkComponentClass, but for sink
+# component objects.
+class _GenericSinkComponent(object._SharedObject, _SinkComponent):
+    _get_ref = staticmethod(native_bt.component_sink_get_ref)
+    _put_ref = staticmethod(native_bt.component_sink_put_ref)
+
+    @property
+    def input_ports(self):
+        return _ComponentPorts(self._ptr,
+                               native_bt.component_sink_borrow_input_port_by_name_const,
+                               native_bt.component_sink_borrow_input_port_by_index_const,
+                               native_bt.component_sink_get_input_port_count,
+                               bt2.port._InputPort)
+
+
+_COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS = {
+    native_bt.COMPONENT_CLASS_TYPE_SOURCE: _GenericSourceComponent,
+    native_bt.COMPONENT_CLASS_TYPE_FILTER: _GenericFilterComponent,
+    native_bt.COMPONENT_CLASS_TYPE_SINK: _GenericSinkComponent,
+}
+
+
+_COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS = {
+    native_bt.COMPONENT_CLASS_TYPE_SOURCE: _GenericSourceComponentClass,
+    native_bt.COMPONENT_CLASS_TYPE_FILTER: _GenericFilterComponentClass,
+    native_bt.COMPONENT_CLASS_TYPE_SINK: _GenericSinkComponentClass,
+}
+
+
+# Create a component Python object of type _GenericSourceComponent,
+# _GenericFilterComponent or _GenericSinkComponent, depending on
+# comp_cls_type.
+#
+#    Steals the reference to ptr from the caller.
+
+def _create_component_from_ptr(ptr, comp_cls_type):
+    return _COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS[comp_cls_type]._create_from_ptr(ptr)
+
+
+# Same as the above, but acquire a new reference instead of stealing the
+# reference from the caller.
+
+def _create_component_from_ptr_and_get_ref(ptr, comp_cls_type):
+    return _COMP_CLS_TYPE_TO_GENERIC_COMP_PYCLS[comp_cls_type]._create_from_ptr_and_get_ref(ptr)
+
+
+# Create a component class Python object of type
+# _GenericSourceComponentClass, _GenericFilterComponentClass or
+# _GenericSinkComponentClass, depending on comp_cls_type.
+#
+# Acquires a new reference to ptr.
+
+def _create_component_class_from_ptr_and_get_ref(ptr, comp_cls_type):
+    return _COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS[comp_cls_type]._create_from_ptr_and_get_ref(ptr)
+
+
+def _trim_docstring(docstring):
+    lines = docstring.expandtabs().splitlines()
+    indent = sys.maxsize
+
+    for line in lines[1:]:
+        stripped = line.lstrip()
+
+        if stripped:
+            indent = min(indent, len(line) - len(stripped))
+
+    trimmed = [lines[0].strip()]
+
+    if indent < sys.maxsize:
+        for line in lines[1:]:
+            trimmed.append(line[indent:].rstrip())
+
+    while trimmed and not trimmed[-1]:
+        trimmed.pop()
+
+    while trimmed and not trimmed[0]:
+        trimmed.pop(0)
+
+    return '\n'.join(trimmed)
+
+
+# Metaclass for component classes defined by Python code.
+#
+# The Python user can create a standard Python class which inherits one
+# of the three base classes (_UserSourceComponent, _UserFilterComponent,
+# or _UserSinkComponent). Those base classes set this class
+# (_UserComponentType) as their metaclass.
+#
+# Once the body of a user-defined component class is executed, this
+# metaclass is used to create and initialize the class. The metaclass
+# creates a native BT component class of the corresponding type and
+# associates it with this user-defined class. The metaclass also defines
+# class methods like the `name` and `description` properties to match
+# the _GenericComponentClass interface.
+#
+# The component class name which is used is either:
+#
+# * The `name` parameter of the class:
+#
+#       class MySink(bt2.SinkComponent, name='my-custom-sink'):
+#           ...
+#
+# * If the `name` class parameter is not used: the name of the class
+#   itself (`MySink` in the example above).
+#
+# The component class description which is used is the user-defined
+# class's docstring:
+#
+#     class MySink(bt2.SinkComponent):
+#         'Description goes here'
+#         ...
+#
+# A user-defined Python component class can have an __init__() method
+# which must at least accept the `params` and `name` arguments:
+#
+#     def __init__(self, params, name, something_else):
+#         ...
+#
+# The user-defined component class can also have a _finalize() method
+# (do NOT use __del__()) to be notified when the component object is
+# finalized.
+#
+# User-defined source and filter component classes must use the
+# `message_iterator_class` class parameter to specify the
+# message iterator class to use for this component class:
+#
+#     class MyMessageIterator(bt2._UserMessageIterator):
+#         ...
+#
+#     class MySource(bt2._UserSourceComponent,
+#                    message_iterator_class=MyMessageIterator):
+#         ...
+#
+# This message iterator class must inherit
+# bt2._UserMessageIterator, and it must define the _get() and
+# _next() methods. The message iterator class can also define an
+# __init__() method: this method has access to the original Python
+# component object which was used to create it as the `component`
+# property. The message iterator class can also define a
+# _finalize() method (again, do NOT use __del__()): this is called when
+# the message iterator is (really) destroyed.
+#
+# When the user-defined class is destroyed, this metaclass's __del__()
+# method is called: the native BT component class pointer is put (not
+# needed anymore, at least not by any Python code since all references
+# are dropped for __del__() to be called).
+class _UserComponentType(type):
+    # __new__() is used to catch custom class parameters
+    def __new__(meta_cls, class_name, bases, attrs, **kwargs):
+        return super().__new__(meta_cls, class_name, bases, attrs)
+
+    def __init__(cls, class_name, bases, namespace, **kwargs):
+        super().__init__(class_name, bases, namespace)
+
+        # skip our own bases; they are never directly instantiated by the user
+        own_bases = (
+            '_UserComponent',
+            '_UserFilterSinkComponent',
+            '_UserSourceComponent',
+            '_UserFilterComponent',
+            '_UserSinkComponent',
+        )
+
+        if class_name in own_bases:
+            return
+
+        comp_cls_name = kwargs.get('name', class_name)
+        utils._check_str(comp_cls_name)
+        comp_cls_descr = None
+        comp_cls_help = None
+
+        if hasattr(cls, '__doc__') and cls.__doc__ is not None:
+            utils._check_str(cls.__doc__)
+            docstring = _trim_docstring(cls.__doc__)
+            lines = docstring.splitlines()
+
+            if len(lines) >= 1:
+                comp_cls_descr = lines[0]
+
+            if len(lines) >= 3:
+                comp_cls_help = '\n'.join(lines[2:])
+
+        iter_cls = kwargs.get('message_iterator_class')
+
+        if _UserSourceComponent in bases:
+            _UserComponentType._set_iterator_class(cls, iter_cls)
+            cc_ptr = native_bt.py3_component_class_source_create(cls,
+                                                                 comp_cls_name,
+                                                                 comp_cls_descr,
+                                                                 comp_cls_help)
+        elif _UserFilterComponent in bases:
+            _UserComponentType._set_iterator_class(cls, iter_cls)
+            cc_ptr = native_bt.py3_component_class_filter_create(cls,
+                                                                 comp_cls_name,
+                                                                 comp_cls_descr,
+                                                                 comp_cls_help)
+        elif _UserSinkComponent in bases:
+            if not hasattr(cls, '_consume'):
+                raise bt2.IncompleteUserClass("cannot create component class '{}': missing a _consume() method".format(class_name))
+
+            cc_ptr = native_bt.py3_component_class_sink_create(cls,
+                                                               comp_cls_name,
+                                                               comp_cls_descr,
+                                                               comp_cls_help)
+        else:
+            raise bt2.IncompleteUserClass("cannot find a known component class base in the bases of '{}'".format(class_name))
+
+        if cc_ptr is None:
+            raise bt2.CreationError("cannot create component class '{}'".format(class_name))
+
+        cls._cc_ptr = cc_ptr
+
+    def _init_from_native(cls, comp_ptr, params_ptr):
+        # create instance, not user-initialized yet
+        self = cls.__new__(cls)
+
+        # pointer to native self component object (weak/borrowed)
+        self._ptr = comp_ptr
+
+        # call user's __init__() method
+        if params_ptr is not None:
+            params = bt2.value._create_from_ptr_and_get_ref(params_ptr)
+        else:
+            params = None
+
+        self.__init__(params)
+        return self
+
+    def __call__(cls, *args, **kwargs):
+        raise bt2.Error('cannot directly instantiate a user component from a Python module')
+
+    @staticmethod
+    def _set_iterator_class(cls, iter_cls):
+        if iter_cls is None:
+            raise bt2.IncompleteUserClass("cannot create component class '{}': missing message iterator class".format(cls.__name__))
+
+        if not issubclass(iter_cls, bt2.message_iterator._UserMessageIterator):
+            raise bt2.IncompleteUserClass("cannot create component class '{}': message iterator class does not inherit bt2._UserMessageIterator".format(cls.__name__))
+
+        if not hasattr(iter_cls, '__next__'):
+            raise bt2.IncompleteUserClass("cannot create component class '{}': message iterator class is missing a __next__() method".format(cls.__name__))
+
+        cls._iter_cls = iter_cls
+
+    @property
+    def name(cls):
+        ptr = cls._as_component_class_ptr(cls._cc_ptr)
+        return native_bt.component_class_get_name(ptr)
+
+    @property
+    def description(cls):
+        ptr = cls._as_component_class_ptr(cls._cc_ptr)
+        return native_bt.component_class_get_description(ptr)
+
+    @property
+    def help(cls):
+        ptr = cls._as_component_class_ptr(cls._cc_ptr)
+        return native_bt.component_class_get_help(ptr)
+
+    @property
+    def addr(cls):
+        return int(cls._cc_ptr)
+
+    def _query_from_native(cls, query_exec_ptr, obj, params_ptr):
+        # this can raise, in which case the native call to
+        # bt_component_class_query() returns NULL
+        if params_ptr is not None:
+            params = bt2.value._create_from_ptr_and_get_ref(params_ptr)
+        else:
+            params = None
+
+        query_exec = bt2.QueryExecutor._create_from_ptr_and_get_ref(
+            query_exec_ptr)
+
+        # this can raise, but the native side checks the exception
+        results = cls._query(query_exec, obj, params)
+
+        # this can raise, but the native side checks the exception
+        results = bt2.create_value(results)
+
+        if results is None:
+            results_addr = int(native_bt.value_null)
+        else:
+            # return new reference
+            results_addr = int(results._release())
+
+        return results_addr
+
+    def _query(cls, query_executor, obj, params):
+        raise NotImplementedError
+
+    def _component_class_ptr(self):
+        return self._as_component_class_ptr(self._cc_ptr)
+
+    def __del__(cls):
+        if hasattr(cls, '_cc_ptr'):
+            cc_ptr = cls._as_component_class_ptr(cls._cc_ptr)
+            native_bt.component_class_put_ref(cc_ptr)
+
+# Subclasses must provide these methods or property:
+#
+#   - _as_not_self_specific_component_ptr: static method, must return the passed
+#     specialized self component pointer (e.g. 'bt_self_component_sink *') as a
+#     specialized non-self pointer (e.g. 'bt_component_sink *').
+#   - _borrow_component_class_ptr: static method, must return a pointer to the
+#     specialized component class (e.g. 'bt_component_class_sink *') of the
+#     passed specialized component pointer (e.g. 'bt_component_sink *').
+#   - _comp_cls_type: property, one of the native_bt.COMPONENT_CLASS_TYPE_*
+#     constants.
+
+class _UserComponent(metaclass=_UserComponentType):
+    @property
+    def name(self):
+        ptr = self._as_not_self_specific_component_ptr(self._ptr)
+        ptr = self._as_component_ptr(ptr)
+        name = native_bt.component_get_name(ptr)
+        assert name is not None
+        return name
+
+    @property
+    def cls(self):
+        comp_ptr = self._as_not_self_specific_component_ptr(self._ptr)
+        cc_ptr = self._borrow_component_class_ptr(comp_ptr)
+        return _create_component_class_from_ptr_and_get_ref(cc_ptr, self._comp_cls_type)
+
+    @property
+    def addr(self):
+        return int(self._ptr)
+
+    def __init__(self, params=None):
+        pass
+
+    def _finalize(self):
+        pass
+
+    def _accept_port_connection(self, port, other_port):
+        return True
+
+    def _accept_port_connection_from_native(self, self_port_ptr, self_port_type, other_port_ptr):
+        port = bt2.port._create_self_from_ptr_and_get_ref(
+            self_port_ptr, self_port_type)
+
+        if self_port_type == native_bt.PORT_TYPE_OUTPUT:
+            other_port_type = native_bt.PORT_TYPE_INPUT
+        else:
+            other_port_type = native_bt.PORT_TYPE_OUTPUT
+
+        other_port = bt2.port._create_from_ptr_and_get_ref(
+            other_port_ptr, other_port_type)
+        res = self._accept_port_connection(port, other_port_ptr)
+
+        if type(res) is not bool:
+            raise TypeError("'{}' is not a 'bool' object")
+
+        return res
+
+    def _port_connected(self, port, other_port):
+        pass
+
+    def _port_connected_from_native(self, self_port_ptr, self_port_type, other_port_ptr):
+        port = bt2.port._create_self_from_ptr_and_get_ref(
+            self_port_ptr, self_port_type)
+
+        if self_port_type == native_bt.PORT_TYPE_OUTPUT:
+            other_port_type = native_bt.PORT_TYPE_INPUT
+        else:
+            other_port_type = native_bt.PORT_TYPE_OUTPUT
+
+        other_port = bt2.port._create_from_ptr_and_get_ref(
+            other_port_ptr, other_port_type)
+        self._port_connected(port, other_port)
+
+    def _graph_is_configured_from_native(self):
+        self._graph_is_configured()
+
+    def _create_trace_class(self, env=None, uuid=None,
+                            assigns_automatic_stream_class_id=True):
+        ptr = self._as_self_component_ptr(self._ptr)
+        tc_ptr = native_bt.trace_class_create(ptr)
+
+        if tc_ptr is None:
+            raise bt2.CreationError('could not create trace class')
+
+        tc = bt2._TraceClass._create_from_ptr(tc_ptr)
+
+        if env is not None:
+            for key, value in env.items():
+                tc.env[key] = value
+
+        if uuid is not None:
+            tc._uuid = uuid
+
+        tc._assigns_automatic_stream_class_id = assigns_automatic_stream_class_id
+
+        return tc
+
+    def _create_clock_class(self, frequency=None, name=None, description=None,
+                            precision=None, offset=None, origin_is_unix_epoch=True,
+                            uuid=None):
+        ptr = self._as_self_component_ptr(self._ptr)
+        cc_ptr = native_bt.clock_class_create(ptr)
+
+        if cc_ptr is None:
+            raise bt2.CreationError('could not create clock class')
+
+        cc = bt2.clock_class._ClockClass._create_from_ptr(cc_ptr)
+
+        if frequency is not None:
+            cc._frequency = frequency
+
+        if name is not None:
+            cc._name = name
+
+        if description is not None:
+            cc._description = description
+
+        if precision is not None:
+            cc._precision = precision
+
+        if offset is not None:
+            cc._offset = offset
+
+        cc._origin_is_unix_epoch = origin_is_unix_epoch
+
+        if uuid is not None:
+            cc._uuid = uuid
+
+        return cc
+
+
+class _UserSourceComponent(_UserComponent, _SourceComponent):
+    _as_not_self_specific_component_ptr = staticmethod(native_bt.self_component_source_as_component_source)
+    _as_self_component_ptr = staticmethod(native_bt.self_component_source_as_self_component)
+
+    @property
+    def _output_ports(self):
+        def get_output_port_count(self_ptr):
+            ptr = self._as_not_self_specific_component_ptr(self_ptr)
+            return native_bt.component_source_get_output_port_count(ptr)
+
+        return _ComponentPorts(self._ptr,
+                               native_bt.self_component_source_borrow_output_port_by_name,
+                               native_bt.self_component_source_borrow_output_port_by_index,
+                               get_output_port_count,
+                               bt2.port._UserComponentOutputPort)
+
+    def _add_output_port(self, name, user_data=None):
+        utils._check_str(name)
+        fn = native_bt.self_component_source_add_output_port
+        comp_status, self_port_ptr = fn(self._ptr, name, user_data)
+        _handle_component_status(comp_status,
+                                 'cannot add output port to source component object')
+        assert self_port_ptr is not None
+        return bt2.port._UserComponentOutputPort._create_from_ptr(self_port_ptr)
+
+
+class _UserFilterComponent(_UserComponent, _FilterComponent):
+    _as_not_self_specific_component_ptr = staticmethod(native_bt.self_component_filter_as_component_filter)
+    _as_self_component_ptr = staticmethod(native_bt.self_component_filter_as_self_component)
+
+    @property
+    def _output_ports(self):
+        def get_output_port_count(self_ptr):
+            ptr = self._as_not_self_specific_component_ptr(self_ptr)
+            return native_bt.component_filter_get_output_port_count(ptr)
+
+        return _ComponentPorts(self._ptr,
+                               native_bt.self_component_filter_borrow_output_port_by_name,
+                               native_bt.self_component_filter_borrow_output_port_by_index,
+                               get_output_port_count,
+                               bt2.port._UserComponentOutputPort)
+
+    @property
+    def _input_ports(self):
+        def get_input_port_count(self_ptr):
+            ptr = self._as_not_self_specific_component_ptr(self_ptr)
+            return native_bt.component_filter_get_input_port_count(ptr)
+
+        return _ComponentPorts(self._ptr,
+                               native_bt.self_component_filter_borrow_input_port_by_name,
+                               native_bt.self_component_filter_borrow_input_port_by_index,
+                               get_input_port_count,
+                               bt2.port._UserComponentInputPort)
+
+    def _add_output_port(self, name, user_data=None):
+        utils._check_str(name)
+        fn = native_bt.self_component_filter_add_output_port
+        comp_status, self_port_ptr = fn(self._ptr, name, user_data)
+        _handle_component_status(comp_status,
+                                 'cannot add output port to filter component object')
+        assert self_port_ptr
+        return bt2.port._UserComponentOutputPort._create_from_ptr(self_port_ptr)
+
+    def _add_input_port(self, name, user_data=None):
+        utils._check_str(name)
+        fn = native_bt.self_component_filter_add_input_port
+        comp_status, self_port_ptr = fn(self._ptr, name, user_data)
+        _handle_component_status(comp_status,
+                                 'cannot add input port to filter component object')
+        assert self_port_ptr
+        return bt2.port._UserComponentInputPort._create_from_ptr(self_port_ptr)
+
+
+class _UserSinkComponent(_UserComponent, _SinkComponent):
+    _as_not_self_specific_component_ptr = staticmethod(native_bt.self_component_sink_as_component_sink)
+    _as_self_component_ptr = staticmethod(native_bt.self_component_sink_as_self_component)
+
+    @property
+    def _input_ports(self):
+        def get_input_port_count(self_ptr):
+            ptr = self._as_not_self_specific_component_ptr(self_ptr)
+            return native_bt.component_sink_get_input_port_count(ptr)
+
+        return _ComponentPorts(self._ptr,
+                               native_bt.self_component_sink_borrow_input_port_by_name,
+                               native_bt.self_component_sink_borrow_input_port_by_index,
+                               get_input_port_count,
+                               bt2.port._UserComponentInputPort)
+
+    def _add_input_port(self, name, user_data=None):
+        utils._check_str(name)
+        fn = native_bt.self_component_sink_add_input_port
+        comp_status, self_port_ptr = fn(self._ptr, name, user_data)
+        _handle_component_status(comp_status,
+                                 'cannot add input port to sink component object')
+        assert self_port_ptr
+        return bt2.port._UserComponentInputPort._create_from_ptr(self_port_ptr)
diff --git a/src/bindings/python/bt2/bt2/connection.py b/src/bindings/python/bt2/bt2/connection.py
new file mode 100644 (file)
index 0000000..4c52a77
--- /dev/null
@@ -0,0 +1,43 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, utils
+import bt2.message_iterator
+import bt2.port
+import bt2
+
+
+class _Connection(bt2.object._SharedObject):
+    _get_ref = staticmethod(native_bt.connection_get_ref)
+    _put_ref = staticmethod(native_bt.connection_put_ref)
+
+    @property
+    def downstream_port(self):
+        port_ptr = native_bt.connection_borrow_downstream_port_const(self._ptr)
+        utils._handle_ptr(port_ptr, "cannot get connection object's downstream port object")
+        return bt2.port._create_from_ptr_and_get_ref(port_ptr, native_bt.PORT_TYPE_INPUT)
+
+    @property
+    def upstream_port(self):
+        port_ptr = native_bt.connection_borrow_upstream_port_const(self._ptr)
+        utils._handle_ptr(port_ptr, "cannot get connection object's upstream port object")
+        return bt2.port._create_from_ptr_and_get_ref(port_ptr, native_bt.PORT_TYPE_OUTPUT)
diff --git a/src/bindings/python/bt2/bt2/event.py b/src/bindings/python/bt2/bt2/event.py
new file mode 100644 (file)
index 0000000..4ff398b
--- /dev/null
@@ -0,0 +1,115 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.clock_class
+import bt2.event_class
+import bt2.packet
+import bt2.stream
+import bt2.field
+import bt2.clock_snapshot
+import bt2
+
+
+class _Event(object._UniqueObject):
+    @property
+    def cls(self):
+        event_class_ptr = native_bt.event_borrow_class(self._ptr)
+        assert event_class_ptr is not None
+        return bt2.event_class._EventClass._create_from_ptr_and_get_ref(event_class_ptr)
+
+    @property
+    def name(self):
+        return self.cls.name
+
+    @property
+    def id(self):
+        return self.cls.id
+
+    @property
+    def packet(self):
+        packet_ptr = native_bt.event_borrow_packet(self._ptr)
+        assert packet_ptr is not None
+        return bt2.packet._Packet._create_from_ptr_and_get_ref(packet_ptr)
+
+    @property
+    def stream(self):
+        stream_ptr = native_bt.event_borrow_stream(self._ptr)
+        assert stream_ptr is not None
+        return bt2._Stream._create_from_ptr_and_get_ref(stream_ptr)
+
+    @property
+    def common_context_field(self):
+        field_ptr = native_bt.event_borrow_common_context_field(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.field._create_field_from_ptr(field_ptr, self._owner_ptr,
+                                                self._owner_get_ref,
+                                                self._owner_put_ref)
+
+    @property
+    def specific_context_field(self):
+        field_ptr = native_bt.event_borrow_specific_context_field(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.field._create_field_from_ptr(field_ptr, self._owner_ptr,
+                                                self._owner_get_ref,
+                                                self._owner_put_ref)
+
+    @property
+    def payload_field(self):
+        field_ptr = native_bt.event_borrow_payload_field(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.field._create_field_from_ptr(field_ptr, self._owner_ptr,
+                                                self._owner_get_ref,
+                                                self._owner_put_ref)
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        payload_field = self.payload_field
+
+        if payload_field is not None and key in payload_field:
+            return payload_field[key]
+
+        specific_context_field = self.specific_context_field
+
+        if specific_context_field is not None and key in specific_context_field:
+            return specific_context_field[key]
+
+        common_context_field = self.common_context_field
+
+        if common_context_field is not None and key in common_context_field:
+            return common_context_field[key]
+
+        packet_context_field = self.packet.context_field
+
+        if packet_context_field is not None and key in packet_context_field:
+            return packet_context_field[key]
+
+        raise KeyError(key)
diff --git a/src/bindings/python/bt2/bt2/event_class.py b/src/bindings/python/bt2/bt2/event_class.py
new file mode 100644 (file)
index 0000000..d3141b8
--- /dev/null
@@ -0,0 +1,171 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.field_class
+import bt2.value
+import bt2.event
+import bt2
+
+
+class EventClassLogLevel:
+    EMERGENCY = native_bt.EVENT_CLASS_LOG_LEVEL_EMERGENCY
+    ALERT = native_bt.EVENT_CLASS_LOG_LEVEL_ALERT
+    CRITICAL = native_bt.EVENT_CLASS_LOG_LEVEL_CRITICAL
+    ERROR = native_bt.EVENT_CLASS_LOG_LEVEL_ERROR
+    WARNING = native_bt.EVENT_CLASS_LOG_LEVEL_WARNING
+    NOTICE = native_bt.EVENT_CLASS_LOG_LEVEL_NOTICE
+    INFO = native_bt.EVENT_CLASS_LOG_LEVEL_INFO
+    DEBUG_SYSTEM = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM
+    DEBUG_PROGRAM = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM
+    DEBUG_PROCESS = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS
+    DEBUG_MODULE = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE
+    DEBUG_UNIT = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT
+    DEBUG_FUNCTION = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION
+    DEBUG_LINE = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_LINE
+    DEBUG = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG
+
+
+class _EventClass(object._SharedObject):
+    _get_ref = staticmethod(native_bt.event_class_get_ref)
+    _put_ref = staticmethod(native_bt.event_class_put_ref)
+
+    @property
+    def stream_class(self):
+        sc_ptr = native_bt.event_class_borrow_stream_class(self._ptr)
+
+        if sc_ptr is not None:
+            return bt2.stream_class._StreamClass._create_from_ptr_and_get_ref(sc_ptr)
+
+    @property
+    def name(self):
+        return native_bt.event_class_get_name(self._ptr)
+
+    def _name(self, name):
+        utils._check_str(name)
+        return native_bt.event_class_set_name(self._ptr, name)
+
+    _name = property(fset=_name)
+
+    @property
+    def id(self):
+        id = native_bt.event_class_get_id(self._ptr)
+        return id if id >= 0 else None
+
+    @property
+    def log_level(self):
+        is_available, log_level = native_bt.event_class_get_log_level(self._ptr)
+
+        if is_available != native_bt.PROPERTY_AVAILABILITY_AVAILABLE:
+            return None
+
+        return _EVENT_CLASS_LOG_LEVEL_TO_OBJ[log_level]
+
+    def _log_level(self, log_level):
+        log_levels = (
+            EventClassLogLevel.EMERGENCY,
+            EventClassLogLevel.ALERT,
+            EventClassLogLevel.CRITICAL,
+            EventClassLogLevel.ERROR,
+            EventClassLogLevel.WARNING,
+            EventClassLogLevel.NOTICE,
+            EventClassLogLevel.INFO,
+            EventClassLogLevel.DEBUG_SYSTEM,
+            EventClassLogLevel.DEBUG_PROGRAM,
+            EventClassLogLevel.DEBUG_PROCESS,
+            EventClassLogLevel.DEBUG_MODULE,
+            EventClassLogLevel.DEBUG_UNIT,
+            EventClassLogLevel.DEBUG_FUNCTION,
+            EventClassLogLevel.DEBUG_LINE,
+            EventClassLogLevel.DEBUG,
+        )
+
+        if log_level not in log_levels:
+            raise ValueError("'{}' is not a valid log level".format(log_level))
+
+        native_bt.event_class_set_log_level(self._ptr, log_level)
+
+    _log_level = property(fset=_log_level)
+
+    @property
+    def emf_uri(self):
+        return native_bt.event_class_get_emf_uri(self._ptr)
+
+    def _emf_uri(self, emf_uri):
+        utils._check_str(emf_uri)
+        ret = native_bt.event_class_set_emf_uri(self._ptr, emf_uri)
+        utils._handle_ret(ret, "cannot set event class object's EMF URI")
+
+    _emf_uri = property(fset=_emf_uri)
+
+    @property
+    def specific_context_field_class(self):
+        fc_ptr = native_bt.event_class_borrow_specific_context_field_class_const(self._ptr)
+
+        if fc_ptr is None:
+            return
+
+        return bt2.field_class._create_field_class_from_ptr_and_get_ref(fc_ptr)
+
+    def _specific_context_field_class(self, context_field_class):
+        if context_field_class is not None:
+            utils._check_type(context_field_class, bt2.field_class._StructureFieldClass)
+            ret = native_bt.event_class_set_specific_context_field_class(self._ptr, context_field_class._ptr)
+            utils._handle_ret(ret, "cannot set event class object's context field class")
+
+    _specific_context_field_class = property(fset=_specific_context_field_class)
+
+    @property
+    def payload_field_class(self):
+        fc_ptr = native_bt.event_class_borrow_payload_field_class_const(self._ptr)
+
+        if fc_ptr is None:
+            return
+
+        return bt2.field_class._create_field_class_from_ptr_and_get_ref(fc_ptr)
+
+    def _payload_field_class(self, payload_field_class):
+        if payload_field_class is not None:
+            utils._check_type(payload_field_class, bt2.field_class._StructureFieldClass)
+            ret = native_bt.event_class_set_payload_field_class(self._ptr, payload_field_class._ptr)
+            utils._handle_ret(ret, "cannot set event class object's payload field class")
+
+    _payload_field_class = property(fset=_payload_field_class)
+
+
+_EVENT_CLASS_LOG_LEVEL_TO_OBJ = {
+    native_bt.EVENT_CLASS_LOG_LEVEL_EMERGENCY: EventClassLogLevel.EMERGENCY,
+    native_bt.EVENT_CLASS_LOG_LEVEL_ALERT: EventClassLogLevel.ALERT,
+    native_bt.EVENT_CLASS_LOG_LEVEL_CRITICAL: EventClassLogLevel.CRITICAL,
+    native_bt.EVENT_CLASS_LOG_LEVEL_ERROR: EventClassLogLevel.ERROR,
+    native_bt.EVENT_CLASS_LOG_LEVEL_WARNING: EventClassLogLevel.WARNING,
+    native_bt.EVENT_CLASS_LOG_LEVEL_NOTICE: EventClassLogLevel.NOTICE,
+    native_bt.EVENT_CLASS_LOG_LEVEL_INFO: EventClassLogLevel.INFO,
+    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM: EventClassLogLevel.DEBUG_SYSTEM,
+    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM: EventClassLogLevel.DEBUG_PROGRAM,
+    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS: EventClassLogLevel.DEBUG_PROCESS,
+    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE: EventClassLogLevel.DEBUG_MODULE,
+    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT: EventClassLogLevel.DEBUG_UNIT,
+    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION: EventClassLogLevel.DEBUG_FUNCTION,
+    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG_LINE: EventClassLogLevel.DEBUG_LINE,
+    native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG: EventClassLogLevel.DEBUG,
+}
diff --git a/src/bindings/python/bt2/bt2/field.py b/src/bindings/python/bt2/bt2/field.py
new file mode 100644 (file)
index 0000000..62dac5f
--- /dev/null
@@ -0,0 +1,648 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.field_class
+import collections.abc
+import functools
+import numbers
+import math
+import bt2
+
+
+def _create_field_from_ptr(ptr, owner_ptr, owner_get_ref, owner_put_ref):
+    field_class_ptr = native_bt.field_borrow_class_const(ptr)
+    utils._handle_ptr(field_class_ptr, "cannot get field object's class")
+    typeid = native_bt.field_class_get_type(field_class_ptr)
+    field = _TYPE_ID_TO_OBJ[typeid]._create_from_ptr_and_get_ref(
+        ptr, owner_ptr, owner_get_ref, owner_put_ref)
+    return field
+
+
+# Get the "effective" field of `field`.  If `field` is a variant, return the
+# currently selected field.  If `field` is of any other type, return `field`
+# directly.
+
+def _get_leaf_field(field):
+    if not isinstance(field, _VariantField):
+        return field
+
+    return _get_leaf_field(field.selected_option)
+
+
+class _Field(object._UniqueObject):
+    def __eq__(self, other):
+        other = _get_leaf_field(other)
+        return self._spec_eq(other)
+
+    @property
+    def field_class(self):
+        field_class_ptr = native_bt.field_borrow_class_const(self._ptr)
+        assert field_class_ptr is not None
+        return bt2.field_class._create_field_class_from_ptr_and_get_ref(field_class_ptr)
+
+    def _repr(self):
+        raise NotImplementedError
+
+    def __repr__(self):
+        return self._repr()
+
+
+@functools.total_ordering
+class _NumericField(_Field):
+    @staticmethod
+    def _extract_value(other):
+        if other is True or other is False:
+            return other
+
+        if isinstance(other, numbers.Integral):
+            return int(other)
+
+        if isinstance(other, numbers.Real):
+            return float(other)
+
+        if isinstance(other, numbers.Complex):
+            return complex(other)
+
+        raise TypeError("'{}' object is not a number object".format(other.__class__.__name__))
+
+    def __int__(self):
+        return int(self._value)
+
+    def __float__(self):
+        return float(self._value)
+
+    def _repr(self):
+        return repr(self._value)
+
+    def __lt__(self, other):
+        if not isinstance(other, numbers.Number):
+            raise TypeError('unorderable types: {}() < {}()'.format(self.__class__.__name__,
+                                                                    other.__class__.__name__))
+
+        return self._value < float(other)
+
+    def __le__(self, other):
+        if not isinstance(other, numbers.Number):
+            raise TypeError('unorderable types: {}() <= {}()'.format(self.__class__.__name__,
+                                                                     other.__class__.__name__))
+
+        return self._value <= float(other)
+
+    def _spec_eq(self, other):
+        if not isinstance(other, numbers.Number):
+            return NotImplemented
+
+        return self._value == complex(other)
+
+    def __rmod__(self, other):
+        return self._extract_value(other) % self._value
+
+    def __mod__(self, other):
+        return self._value % self._extract_value(other)
+
+    def __rfloordiv__(self, other):
+        return self._extract_value(other) // self._value
+
+    def __floordiv__(self, other):
+        return self._value // self._extract_value(other)
+
+    def __round__(self, ndigits=None):
+        if ndigits is None:
+            return round(self._value)
+        else:
+            return round(self._value, ndigits)
+
+    def __ceil__(self):
+        return math.ceil(self._value)
+
+    def __floor__(self):
+        return math.floor(self._value)
+
+    def __trunc__(self):
+        return int(self._value)
+
+    def __abs__(self):
+        return abs(self._value)
+
+    def __add__(self, other):
+        return self._value + self._extract_value(other)
+
+    def __radd__(self, other):
+        return self.__add__(other)
+
+    def __neg__(self):
+        return -self._value
+
+    def __pos__(self):
+        return +self._value
+
+    def __mul__(self, other):
+        return self._value * self._extract_value(other)
+
+    def __rmul__(self, other):
+        return self.__mul__(other)
+
+    def __truediv__(self, other):
+        return self._value / self._extract_value(other)
+
+    def __rtruediv__(self, other):
+        return self._extract_value(other) / self._value
+
+    def __pow__(self, exponent):
+        return self._value ** self._extract_value(exponent)
+
+    def __rpow__(self, base):
+        return self._extract_value(base) ** self._value
+
+    def __iadd__(self, other):
+        self.value = self + other
+        return self
+
+    def __isub__(self, other):
+        self.value = self - other
+        return self
+
+    def __imul__(self, other):
+        self.value = self * other
+        return self
+
+    def __itruediv__(self, other):
+        self.value = self / other
+        return self
+
+    def __ifloordiv__(self, other):
+        self.value = self // other
+        return self
+
+    def __imod__(self, other):
+        self.value = self % other
+        return self
+
+    def __ipow__(self, other):
+        self.value = self ** other
+        return self
+
+
+class _IntegralField(_NumericField, numbers.Integral):
+    def __lshift__(self, other):
+        return self._value << self._extract_value(other)
+
+    def __rlshift__(self, other):
+        return self._extract_value(other) << self._value
+
+    def __rshift__(self, other):
+        return self._value >> self._extract_value(other)
+
+    def __rrshift__(self, other):
+        return self._extract_value(other) >> self._value
+
+    def __and__(self, other):
+        return self._value & self._extract_value(other)
+
+    def __rand__(self, other):
+        return self._extract_value(other) & self._value
+
+    def __xor__(self, other):
+        return self._value ^ self._extract_value(other)
+
+    def __rxor__(self, other):
+        return self._extract_value(other) ^ self._value
+
+    def __or__(self, other):
+        return self._value | self._extract_value(other)
+
+    def __ror__(self, other):
+        return self._extract_value(other) | self._value
+
+    def __invert__(self):
+        return ~self._value
+
+    def __ilshift__(self, other):
+        self.value = self << other
+        return self
+
+    def __irshift__(self, other):
+        self.value = self >> other
+        return self
+
+    def __iand__(self, other):
+        self.value = self & other
+        return self
+
+    def __ixor__(self, other):
+        self.value = self ^ other
+        return self
+
+    def __ior__(self, other):
+        self.value = self | other
+        return self
+
+
+class _IntegerField(_IntegralField, _Field):
+    pass
+
+
+class _UnsignedIntegerField(_IntegerField, _Field):
+    _NAME = 'Unsigned integer'
+
+    def _value_to_int(self, value):
+        if not isinstance(value, numbers.Real):
+            raise TypeError('expecting a real number object')
+
+        value = int(value)
+        utils._check_uint64(value)
+
+        return value
+
+    @property
+    def _value(self):
+        return native_bt.field_unsigned_integer_get_value(self._ptr)
+
+    def _set_value(self, value):
+        value = self._value_to_int(value)
+        native_bt.field_unsigned_integer_set_value(self._ptr, value)
+
+    value = property(fset=_set_value)
+
+
+class _SignedIntegerField(_IntegerField, _Field):
+    _NAME = 'Signed integer'
+
+    def _value_to_int(self, value):
+        if not isinstance(value, numbers.Real):
+            raise TypeError('expecting a real number object')
+
+        value = int(value)
+        utils._check_int64(value)
+
+        return value
+
+    @property
+    def _value(self):
+        return native_bt.field_signed_integer_get_value(self._ptr)
+
+    def _set_value(self, value):
+        value = self._value_to_int(value)
+        native_bt.field_signed_integer_set_value(self._ptr, value)
+
+    value = property(fset=_set_value)
+
+
+class _RealField(_NumericField, numbers.Real):
+    _NAME = 'Real'
+
+    def _value_to_float(self, value):
+        if not isinstance(value, numbers.Real):
+            raise TypeError("expecting a real number object")
+
+        return float(value)
+
+    @property
+    def _value(self):
+        return native_bt.field_real_get_value(self._ptr)
+
+    def _set_value(self, value):
+        value = self._value_to_float(value)
+        native_bt.field_real_set_value(self._ptr, value)
+
+    value = property(fset=_set_value)
+
+
+class _EnumerationField(_IntegerField):
+    def _repr(self):
+        return '{} ({})'.format(self._value, ', '.join(self.labels))
+
+    @property
+    def labels(self):
+        ret, labels = self._get_mapping_labels(self._ptr)
+        utils._handle_ret(ret, "cannot get label for enumeration field")
+
+        assert labels is not None
+        return labels
+
+
+class _UnsignedEnumerationField(_EnumerationField, _UnsignedIntegerField):
+    _NAME = 'Unsigned Enumeration'
+    _get_mapping_labels = staticmethod(native_bt.field_unsigned_enumeration_get_mapping_labels)
+
+
+class _SignedEnumerationField(_EnumerationField, _SignedIntegerField):
+    _NAME = 'Signed Enumeration'
+    _get_mapping_labels = staticmethod(native_bt.field_signed_enumeration_get_mapping_labels)
+
+
+@functools.total_ordering
+class _StringField(_Field):
+    _NAME = 'String'
+
+    def _value_to_str(self, value):
+        if isinstance(value, self.__class__):
+            value = value._value
+
+        if not isinstance(value, str):
+            raise TypeError("expecting a 'str' object")
+
+        return value
+
+    @property
+    def _value(self):
+        return native_bt.field_string_get_value(self._ptr)
+
+    def _set_value(self, value):
+        value = self._value_to_str(value)
+        native_bt.field_string_set_value(self._ptr, value)
+
+    value = property(fset=_set_value)
+
+    def _spec_eq(self, other):
+        try:
+            other = self._value_to_str(other)
+        except Exception:
+            return False
+
+        return self._value == other
+
+    def __le__(self, other):
+        return self._value <= self._value_to_str(other)
+
+    def __lt__(self, other):
+        return self._value < self._value_to_str(other)
+
+    def __bool__(self):
+        return bool(self._value)
+
+    def _repr(self):
+        return repr(self._value)
+
+    def __str__(self):
+        return str(self._value)
+
+    def __getitem__(self, index):
+        return self._value[index]
+
+    def __len__(self):
+        return native_bt.field_string_get_length(self._ptr)
+
+    def __iadd__(self, value):
+        value = self._value_to_str(value)
+        ret = native_bt.field_string_append(self._ptr, value)
+        utils._handle_ret(ret, "cannot append to string field object's value")
+        return self
+
+
+class _ContainerField(_Field):
+    def __bool__(self):
+        return len(self) != 0
+
+    def __len__(self):
+        count = self._count()
+        assert count >= 0
+        return count
+
+    def __delitem__(self, index):
+        raise NotImplementedError
+
+
+class _StructureField(_ContainerField, collections.abc.MutableMapping):
+    _NAME = 'Structure'
+
+    def _count(self):
+        return len(self.field_class)
+
+    def __setitem__(self, key, value):
+        # raises if key is somehow invalid
+        field = self[key]
+
+        # the field's property does the appropriate conversion or raises
+        # the appropriate exception
+        field.value = value
+
+    def __iter__(self):
+        # same name iterator
+        return iter(self.field_class)
+
+    def _spec_eq(self, other):
+        try:
+            if len(self) != len(other):
+                return False
+
+            for self_key, self_value in self.items():
+                if self_key not in other:
+                    return False
+
+                other_value = other[self_key]
+
+                if self_value != other_value:
+                    return False
+
+            return True
+        except Exception:
+            return False
+
+    def _set_value(self, values):
+        try:
+            for key, value in values.items():
+                self[key].value = value
+        except Exception:
+            raise
+
+    value = property(fset=_set_value)
+
+    def _repr(self):
+        items = ['{}: {}'.format(repr(k), repr(v)) for k, v in self.items()]
+        return '{{{}}}'.format(', '.join(items))
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        field_ptr = native_bt.field_structure_borrow_member_field_by_name(self._ptr, key)
+
+        if field_ptr is None:
+            raise KeyError(key)
+
+        return _create_field_from_ptr(field_ptr, self._owner_ptr,
+                                      self._owner_get_ref,
+                                      self._owner_put_ref)
+
+    def member_at_index(self, index):
+        utils._check_uint64(index)
+
+        if index >= len(self):
+            raise IndexError
+
+        field_ptr = native_bt.field_structure_borrow_member_field_by_index(self._ptr, index)
+        assert field_ptr is not None
+        return _create_field_from_ptr(field_ptr, self._owner_ptr,
+                                      self._owner_get_ref,
+                                      self._owner_put_ref)
+
+
+class _VariantField(_ContainerField, _Field):
+    _NAME = 'Variant'
+
+    @property
+    def selected_option_index(self):
+        return native_bt.field_variant_get_selected_option_field_index(self._ptr)
+
+    @selected_option_index.setter
+    def selected_option_index(self, index):
+        native_bt.field_variant_select_option_field(self._ptr, index)
+
+    @property
+    def selected_option(self):
+        field_ptr = native_bt.field_variant_borrow_selected_option_field(self._ptr)
+        utils._handle_ptr(field_ptr, "cannot get variant field's selected option")
+
+        return _create_field_from_ptr(field_ptr, self._owner_ptr,
+                                      self._owner_get_ref,
+                                      self._owner_put_ref)
+
+    def _spec_eq(self, other):
+        new_self = _get_leaf_field(self)
+        return new_self == other
+
+    def __bool__(self):
+        raise NotImplementedError
+
+    def __str__(self):
+        return str(self.selected_option)
+
+    def _repr(self):
+        return repr(self.selected_option)
+
+    def _set_value(self, value):
+        self.selected_option.value = value
+
+    value = property(fset=_set_value)
+
+
+class _ArrayField(_ContainerField, _Field):
+
+    def _get_length(self):
+        return native_bt.field_array_get_length(self._ptr)
+
+    length = property(fget=_get_length)
+
+    def __getitem__(self, index):
+        if not isinstance(index, numbers.Integral):
+            raise TypeError("'{}' is not an integral number object: invalid index".format(index.__class__.__name__))
+
+        index = int(index)
+
+        if index < 0 or index >= len(self):
+            raise IndexError('{} field object index is out of range'.format(self._NAME))
+
+        field_ptr = native_bt.field_array_borrow_element_field_by_index(self._ptr, index)
+        assert(field_ptr)
+        return _create_field_from_ptr(field_ptr, self._owner_ptr,
+                                      self._owner_get_ref,
+                                      self._owner_put_ref)
+
+    def __setitem__(self, index, value):
+        # we can only set numbers and strings
+        if not isinstance(value, (numbers.Number, _StringField, str)):
+            raise TypeError('expecting number or string object')
+
+        # raises if index is somehow invalid
+        field = self[index]
+
+        if not isinstance(field, (_NumericField, _StringField)):
+            raise TypeError('can only set the value of a number or string field')
+
+        # the field's property does the appropriate conversion or raises
+        # the appropriate exception
+        field.value = value
+
+    def insert(self, index, value):
+        raise NotImplementedError
+
+    def _spec_eq(self, other):
+        try:
+            if len(self) != len(other):
+                return False
+
+            for self_field, other_field in zip(self, other):
+                if self_field != other_field:
+                    return False
+
+            return True
+        except Exception:
+            return False
+
+    def _repr(self):
+        return '[{}]'.format(', '.join([repr(v) for v in self]))
+
+
+class _StaticArrayField(_ArrayField, _Field):
+    _NAME = 'Static array'
+
+    def _count(self):
+        return native_bt.field_array_get_length(self._ptr)
+
+    def _set_value(self, values):
+        if len(self) != len(values):
+            raise ValueError(
+                'expected length of value and array field to match')
+
+        for index, value in enumerate(values):
+            if value is not None:
+                self[index].value = value
+
+    value = property(fset=_set_value)
+
+
+class _DynamicArrayField(_ArrayField, _Field):
+    _NAME = 'Dynamic array'
+
+    def _count(self):
+        return self.length
+
+    def _set_length(self, length):
+        utils._check_uint64(length)
+        ret = native_bt.field_dynamic_array_set_length(self._ptr, length)
+        utils._handle_ret(ret, "cannot set dynamic array length")
+
+    length = property(fget=_ArrayField._get_length, fset=_set_length)
+
+    def _set_value(self, values):
+        if len(values) != self.length:
+            self.length = len(values)
+
+        for index, value in enumerate(values):
+            if value is not None:
+                self[index].value = value
+
+    value = property(fset=_set_value)
+
+
+_TYPE_ID_TO_OBJ = {
+    native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerField,
+    native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerField,
+    native_bt.FIELD_CLASS_TYPE_REAL: _RealField,
+    native_bt.FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: _UnsignedEnumerationField,
+    native_bt.FIELD_CLASS_TYPE_SIGNED_ENUMERATION: _SignedEnumerationField,
+    native_bt.FIELD_CLASS_TYPE_STRING: _StringField,
+    native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureField,
+    native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayField,
+    native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY: _DynamicArrayField,
+    native_bt.FIELD_CLASS_TYPE_VARIANT: _VariantField,
+}
diff --git a/src/bindings/python/bt2/bt2/field_class.py b/src/bindings/python/bt2/bt2/field_class.py
new file mode 100644 (file)
index 0000000..27a37d9
--- /dev/null
@@ -0,0 +1,397 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import collections.abc
+import bt2.field
+import bt2.field_path
+import bt2
+
+
+def _create_field_class_from_ptr_and_get_ref(ptr):
+    typeid = native_bt.field_class_get_type(ptr)
+    return _FIELD_CLASS_TYPE_TO_OBJ[typeid]._create_from_ptr_and_get_ref(ptr)
+
+
+class IntegerDisplayBase:
+    BINARY = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY
+    OCTAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL
+    DECIMAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL
+    HEXADECIMAL = native_bt.FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL
+
+
+class _FieldClass(object._SharedObject):
+    _get_ref = staticmethod(native_bt.field_class_get_ref)
+    _put_ref = staticmethod(native_bt.field_class_put_ref)
+
+    def _check_create_status(self, ptr):
+        if ptr is None:
+            raise bt2.CreationError('cannot create {} field class object'.format(self._NAME.lower()))
+
+
+class _IntegerFieldClass(_FieldClass):
+    @property
+    def field_value_range(self):
+        size = native_bt.field_class_integer_get_field_value_range(self._ptr)
+        assert(size >= 1)
+        return size
+
+    def _field_value_range(self, size):
+        if size < 1 or size > 64:
+            raise ValueError("Value is outside valid range [1, 64] ({})".format(size))
+        native_bt.field_class_integer_set_field_value_range(self._ptr, size)
+
+    _field_value_range = property(fset=_field_value_range)
+
+    @property
+    def preferred_display_base(self):
+        base = native_bt.field_class_integer_get_preferred_display_base(
+            self._ptr)
+        assert(base >= 0)
+        return base
+
+    def _preferred_display_base(self, base):
+        utils._check_uint64(base)
+
+        if base not in (IntegerDisplayBase.BINARY,
+                        IntegerDisplayBase.OCTAL,
+                        IntegerDisplayBase.DECIMAL,
+                        IntegerDisplayBase.HEXADECIMAL):
+            raise ValueError("Display base is not a valid IntegerDisplayBase value")
+
+        native_bt.field_class_integer_set_preferred_display_base(
+            self._ptr, base)
+
+    _preferred_display_base = property(fset=_preferred_display_base)
+
+
+class _UnsignedIntegerFieldClass(_IntegerFieldClass):
+    _NAME = 'Unsigned integer'
+
+
+class _SignedIntegerFieldClass(_IntegerFieldClass):
+    _NAME = 'Signed integer'
+
+
+class _RealFieldClass(_FieldClass):
+    _NAME = 'Real'
+
+    @property
+    def is_single_precision(self):
+        return native_bt.field_class_real_is_single_precision(self._ptr)
+
+    def _is_single_precision(self, is_single_precision):
+        utils._check_bool(is_single_precision)
+        native_bt.field_class_real_set_is_single_precision(
+            self._ptr, is_single_precision)
+
+    _is_single_precision = property(fset=_is_single_precision)
+
+
+class _EnumerationFieldClassMappingRange:
+    def __init__(self, lower, upper):
+        self._lower = lower
+        self._upper = upper
+
+    @property
+    def lower(self):
+        return self._lower
+
+    @property
+    def upper(self):
+        return self._upper
+
+    def __eq__(self, other):
+        return self.lower == other.lower and self.upper == other.upper
+
+
+class _EnumerationFieldClassMapping(collections.abc.Set):
+    def __init__(self, mapping_ptr):
+        self._mapping_ptr = mapping_ptr
+
+    @property
+    def label(self):
+        mapping_ptr = self._as_enumeration_field_class_mapping_ptr(self._mapping_ptr)
+        label = native_bt.field_class_enumeration_mapping_get_label(mapping_ptr)
+        assert label is not None
+        return label
+
+    def __len__(self):
+        mapping_ptr = self._as_enumeration_field_class_mapping_ptr(self._mapping_ptr)
+        return native_bt.field_class_enumeration_mapping_get_range_count(mapping_ptr)
+
+    def __contains__(self, other_range):
+        for curr_range in self:
+            if curr_range == other_range:
+                return True
+        return False
+
+    def __iter__(self):
+        for idx in range(len(self)):
+            lower, upper = self._get_range_by_index(self._mapping_ptr, idx)
+            yield _EnumerationFieldClassMappingRange(lower, upper)
+
+
+class _UnsignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping):
+    _as_enumeration_field_class_mapping_ptr = staticmethod(native_bt.field_class_unsigned_enumeration_mapping_as_mapping_const)
+    _get_range_by_index = staticmethod(native_bt.field_class_unsigned_enumeration_mapping_get_range_by_index)
+
+
+class _SignedEnumerationFieldClassMapping(_EnumerationFieldClassMapping):
+    _as_enumeration_field_class_mapping_ptr = staticmethod(native_bt.field_class_signed_enumeration_mapping_as_mapping_const)
+    _get_range_by_index = staticmethod(native_bt.field_class_signed_enumeration_mapping_get_range_by_index)
+
+
+class _EnumerationFieldClass(_IntegerFieldClass, collections.abc.Mapping):
+    def __len__(self):
+        count = native_bt.field_class_enumeration_get_mapping_count(self._ptr)
+        assert(count >= 0)
+        return count
+
+    def map_range(self, label, lower, upper=None):
+        utils._check_str(label)
+
+        if upper is None:
+            upper = lower
+
+        ret = self._map_range(self._ptr, label, lower, upper)
+        utils._handle_ret(ret, "cannot add mapping to enumeration field class object")
+
+    def labels_by_value(self, value):
+        ret, labels = self._get_mapping_labels_by_value(self._ptr, value)
+        utils._handle_ret(ret, "cannot get mapping labels")
+        return labels
+
+    def __iter__(self):
+        for idx in range(len(self)):
+            mapping = self._get_mapping_by_index(self._ptr, idx)
+            yield mapping.label
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        for idx in range(len(self)):
+            mapping = self._get_mapping_by_index(self._ptr, idx)
+            if mapping.label == key:
+                return mapping
+
+        raise KeyError(key)
+
+    def __iadd__(self, mappings):
+        for mapping in mappings.values():
+            for range in mapping:
+                self.map_range(mapping.label, range.lower, range.upper)
+
+        return self
+
+
+class _UnsignedEnumerationFieldClass(_EnumerationFieldClass, _UnsignedIntegerFieldClass):
+    _NAME = 'Unsigned enumeration'
+
+    @staticmethod
+    def _get_mapping_by_index(enum_ptr, index):
+        mapping_ptr = native_bt.field_class_unsigned_enumeration_borrow_mapping_by_index_const(enum_ptr, index)
+        assert mapping_ptr is not None
+        return _UnsignedEnumerationFieldClassMapping(mapping_ptr)
+
+    @staticmethod
+    def _map_range(enum_ptr, label, lower, upper):
+        utils._check_uint64(lower)
+        utils._check_uint64(upper)
+        return native_bt.field_class_unsigned_enumeration_map_range(enum_ptr, label, lower, upper)
+
+    @staticmethod
+    def _get_mapping_labels_by_value(enum_ptr, value):
+        utils._check_uint64(value)
+        return native_bt.field_class_unsigned_enumeration_get_mapping_labels_by_value(enum_ptr, value)
+
+
+class _SignedEnumerationFieldClass(_EnumerationFieldClass, _SignedIntegerFieldClass):
+    _NAME = 'Signed enumeration'
+
+    @staticmethod
+    def _get_mapping_by_index(enum_ptr, index):
+        mapping_ptr = native_bt.field_class_signed_enumeration_borrow_mapping_by_index_const(enum_ptr, index)
+        assert mapping_ptr is not None
+        return _SignedEnumerationFieldClassMapping(mapping_ptr)
+
+    @staticmethod
+    def _map_range(enum_ptr, label, lower, upper):
+        utils._check_int64(lower)
+        utils._check_int64(upper)
+        return native_bt.field_class_signed_enumeration_map_range(enum_ptr, label, lower, upper)
+
+    @staticmethod
+    def _get_mapping_labels_by_value(enum_ptr, value):
+        utils._check_int64(value)
+        return native_bt.field_class_signed_enumeration_get_mapping_labels_by_value(enum_ptr, value)
+
+
+class _StringFieldClass(_FieldClass):
+    _NAME = 'String'
+
+
+class _FieldContainer(collections.abc.Mapping):
+    def __len__(self):
+        count = self._get_element_count(self._ptr)
+        assert count >= 0
+        return count
+
+    def __getitem__(self, key):
+        if not isinstance(key, str):
+            raise TypeError("key should be a 'str' object, got {}".format(key.__class__.__name__))
+
+        ptr = self._borrow_field_class_ptr_by_name(key)
+
+        if ptr is None:
+            raise KeyError(key)
+
+        return _create_field_class_from_ptr_and_get_ref(ptr)
+
+    def _borrow_field_class_ptr_by_name(self, key):
+        element_ptr = self._borrow_element_by_name(self._ptr, key)
+        if element_ptr is None:
+            return
+
+        return self._element_borrow_field_class(element_ptr)
+
+    def __iter__(self):
+        for idx in range(len(self)):
+            element_ptr = self._borrow_element_by_index(self._ptr, idx)
+            assert element_ptr is not None
+
+            yield self._element_get_name(element_ptr)
+
+    def _append_element_common(self, name, field_class):
+        utils._check_str(name)
+        utils._check_type(field_class, _FieldClass)
+        ret = self._append_element(self._ptr, name, field_class._ptr)
+        utils._handle_ret(ret, "cannot add field to {} field class object".format(self._NAME.lower()))
+
+    def __iadd__(self, fields):
+        for name, field_class in fields.items():
+            self._append_element_common(name, field_class)
+
+        return self
+
+    def _at_index(self, index):
+        utils._check_uint64(index)
+
+        if index < 0 or index >= len(self):
+            raise IndexError
+
+        element_ptr = self._borrow_element_by_index(self._ptr, index)
+        assert element_ptr is not None
+
+        field_class_ptr = self._element_borrow_field_class(element_ptr)
+
+        return _create_field_class_from_ptr_and_get_ref(field_class_ptr)
+
+
+class _StructureFieldClass(_FieldClass, _FieldContainer):
+    _NAME = 'Structure'
+    _borrow_element_by_index = staticmethod(native_bt.field_class_structure_borrow_member_by_index_const)
+    _borrow_element_by_name = staticmethod(native_bt.field_class_structure_borrow_member_by_name_const)
+    _element_get_name = staticmethod(native_bt.field_class_structure_member_get_name)
+    _element_borrow_field_class = staticmethod(native_bt.field_class_structure_member_borrow_field_class_const)
+    _get_element_count = staticmethod(native_bt.field_class_structure_get_member_count)
+    _append_element = staticmethod(native_bt.field_class_structure_append_member)
+
+    def append_member(self, name, field_class):
+        return self._append_element_common(name, field_class)
+
+    def member_at_index(self, index):
+        return self._at_index(index)
+
+
+class _VariantFieldClass(_FieldClass, _FieldContainer):
+    _NAME = 'Variant'
+    _borrow_element_by_index = staticmethod(native_bt.field_class_variant_borrow_option_by_index_const)
+    _borrow_element_by_name = staticmethod(native_bt.field_class_variant_borrow_option_by_name_const)
+    _element_get_name = staticmethod(native_bt.field_class_variant_option_get_name)
+    _element_borrow_field_class = staticmethod(native_bt.field_class_variant_option_borrow_field_class_const)
+    _get_element_count = staticmethod(native_bt.field_class_variant_get_option_count)
+    _append_element = staticmethod(native_bt.field_class_variant_append_option)
+
+    def append_option(self, name, field_class):
+        return self._append_element_common(name, field_class)
+
+    def option_at_index(self, index):
+        return self._at_index(index)
+
+    @property
+    def selector_field_path(self):
+        ptr = native_bt.field_class_variant_borrow_selector_field_path_const(self._ptr)
+        if ptr is None:
+            return
+
+        return bt2.field_path._FieldPath._create_from_ptr_and_get_ref(ptr)
+
+    def _set_selector_field_class(self, selector_fc):
+        utils._check_type(selector_fc, bt2.field_class._EnumerationFieldClass)
+        ret = native_bt.field_class_variant_set_selector_field_class(self._ptr, selector_fc._ptr)
+        utils._handle_ret(ret, "cannot set variant selector field type")
+
+    _selector_field_class = property(fset=_set_selector_field_class)
+
+
+class _ArrayFieldClass(_FieldClass):
+    @property
+    def element_field_class(self):
+        elem_fc_ptr = native_bt.field_class_array_borrow_element_field_class_const(self._ptr)
+        return _create_field_class_from_ptr_and_get_ref(elem_fc_ptr)
+
+
+class _StaticArrayFieldClass(_ArrayFieldClass):
+    @property
+    def length(self):
+        return native_bt.field_class_static_array_get_length(self._ptr)
+
+
+class _DynamicArrayFieldClass(_ArrayFieldClass):
+    @property
+    def length_field_path(self):
+        ptr = native_bt.field_class_dynamic_array_borrow_length_field_path_const(self._ptr)
+        if ptr is None:
+            return
+
+        return bt2.field_path._FieldPath._create_from_ptr_and_get_ref(ptr)
+
+    def _set_length_field_class(self, length_fc):
+        utils._check_type(length_fc, _UnsignedIntegerFieldClass)
+        ret = native_bt.field_class_dynamic_array_set_length_field_class(self._ptr, length_fc._ptr)
+        utils._handle_ret(ret, "cannot set dynamic array length field type")
+
+    _length_field_class = property(fset=_set_length_field_class)
+
+
+_FIELD_CLASS_TYPE_TO_OBJ = {
+    native_bt.FIELD_CLASS_TYPE_UNSIGNED_INTEGER: _UnsignedIntegerFieldClass,
+    native_bt.FIELD_CLASS_TYPE_SIGNED_INTEGER: _SignedIntegerFieldClass,
+    native_bt.FIELD_CLASS_TYPE_REAL: _RealFieldClass,
+    native_bt.FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION: _UnsignedEnumerationFieldClass,
+    native_bt.FIELD_CLASS_TYPE_SIGNED_ENUMERATION: _SignedEnumerationFieldClass,
+    native_bt.FIELD_CLASS_TYPE_STRING: _StringFieldClass,
+    native_bt.FIELD_CLASS_TYPE_STRUCTURE: _StructureFieldClass,
+    native_bt.FIELD_CLASS_TYPE_STATIC_ARRAY: _StaticArrayFieldClass,
+    native_bt.FIELD_CLASS_TYPE_DYNAMIC_ARRAY: _DynamicArrayFieldClass,
+    native_bt.FIELD_CLASS_TYPE_VARIANT: _VariantFieldClass,
+}
diff --git a/src/bindings/python/bt2/bt2/field_path.py b/src/bindings/python/bt2/bt2/field_path.py
new file mode 100644 (file)
index 0000000..2191171
--- /dev/null
@@ -0,0 +1,82 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import collections
+from bt2 import native_bt, object
+
+
+class Scope:
+    PACKET_CONTEXT = native_bt.SCOPE_PACKET_CONTEXT
+    EVENT_COMMON_CONTEXT = native_bt.SCOPE_EVENT_COMMON_CONTEXT
+    EVENT_SPECIFIC_CONTEXT = native_bt.SCOPE_EVENT_SPECIFIC_CONTEXT
+    EVENT_PAYLOAD = native_bt.SCOPE_EVENT_PAYLOAD
+
+
+class _FieldPathItem:
+    pass
+
+
+class _IndexFieldPathItem(_FieldPathItem):
+    def __init__(self, index):
+        self._index = index
+
+    @property
+    def index(self):
+        return self._index
+
+
+class _CurrentArrayElementFieldPathItem(_FieldPathItem):
+    pass
+
+
+class _FieldPath(object._SharedObject, collections.abc.Iterable):
+    _get_ref = staticmethod(native_bt.field_path_get_ref)
+    _put_ref = staticmethod(native_bt.field_path_put_ref)
+
+    @property
+    def root_scope(self):
+        scope = native_bt.field_path_get_root_scope(self._ptr)
+        return _SCOPE_TO_OBJ[scope]
+
+    def __len__(self):
+        return native_bt.field_path_get_item_count(self._ptr)
+
+    def __iter__(self):
+        for idx in range(len(self)):
+            item_ptr = native_bt.field_path_borrow_item_by_index_const(self._ptr, idx)
+            assert item_ptr is not None
+            item_type = native_bt.field_path_item_get_type(item_ptr)
+            if item_type == native_bt.FIELD_PATH_ITEM_TYPE_INDEX:
+                idx = native_bt.field_path_item_index_get_index(item_ptr)
+                yield _IndexFieldPathItem(idx)
+            elif item_type == native_bt.FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
+                yield  _CurrentArrayElementFieldPathItem()
+            else:
+                assert False
+
+
+_SCOPE_TO_OBJ = {
+    native_bt.SCOPE_PACKET_CONTEXT: Scope.PACKET_CONTEXT,
+    native_bt.SCOPE_EVENT_COMMON_CONTEXT: Scope.EVENT_COMMON_CONTEXT,
+    native_bt.SCOPE_EVENT_SPECIFIC_CONTEXT: Scope.EVENT_SPECIFIC_CONTEXT,
+    native_bt.SCOPE_EVENT_PAYLOAD: Scope.EVENT_PAYLOAD
+}
diff --git a/src/bindings/python/bt2/bt2/graph.py b/src/bindings/python/bt2/bt2/graph.py
new file mode 100644 (file)
index 0000000..998d310
--- /dev/null
@@ -0,0 +1,179 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.connection
+import bt2.component
+import functools
+import bt2.port
+import bt2
+
+
+def _graph_port_added_listener_from_native(user_listener,
+                                           component_ptr, component_type,
+                                           port_ptr, port_type):
+    component = bt2.component._create_component_from_ptr_and_get_ref(component_ptr, component_type)
+    port = bt2.port._create_from_ptr_and_get_ref(port_ptr, port_type)
+    user_listener(component, port)
+
+
+def _graph_ports_connected_listener_from_native(user_listener,
+                                                upstream_component_ptr, upstream_component_type,
+                                                upstream_port_ptr,
+                                                downstream_component_ptr, downstream_component_type,
+                                                downstream_port_ptr):
+    upstream_component = bt2.component._create_component_from_ptr_and_get_ref(
+        upstream_component_ptr, upstream_component_type)
+    upstream_port = bt2.port._create_from_ptr_and_get_ref(
+        upstream_port_ptr, native_bt.PORT_TYPE_OUTPUT)
+    downstream_component = bt2.component._create_component_from_ptr_and_get_ref(
+        downstream_component_ptr, downstream_component_type)
+    downstream_port = bt2.port._create_from_ptr_and_get_ref(
+        downstream_port_ptr, native_bt.PORT_TYPE_INPUT)
+    user_listener(upstream_component, upstream_port, downstream_component, downstream_port)
+
+
+class Graph(object._SharedObject):
+    _get_ref = staticmethod(native_bt.graph_get_ref)
+    _put_ref = staticmethod(native_bt.graph_put_ref)
+
+    def __init__(self):
+        ptr = native_bt.graph_create()
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create graph object')
+
+        super().__init__(ptr)
+
+    def _handle_status(self, status, gen_error_msg):
+        if status == native_bt.GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
+            raise bt2.PortConnectionRefused
+        elif status == native_bt.GRAPH_STATUS_CANCELED:
+            raise bt2.GraphCanceled
+        elif status == native_bt.GRAPH_STATUS_END:
+            raise bt2.Stop
+        elif status == native_bt.GRAPH_STATUS_AGAIN:
+            raise bt2.TryAgain
+        elif status < 0:
+            raise bt2.Error(gen_error_msg)
+
+    def add_component(self, component_class, name, params=None):
+        if isinstance(component_class, bt2.component._GenericSourceComponentClass):
+            cc_ptr = component_class._ptr
+            add_fn = native_bt.graph_add_source_component
+            cc_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE
+        elif isinstance(component_class, bt2.component._GenericFilterComponentClass):
+            cc_ptr = component_class._ptr
+            add_fn = native_bt.graph_add_filter_component
+            cc_type = native_bt.COMPONENT_CLASS_TYPE_FILTER
+        elif isinstance(component_class, bt2.component._GenericSinkComponentClass):
+            cc_ptr = component_class._ptr
+            add_fn = native_bt.graph_add_sink_component
+            cc_type = native_bt.COMPONENT_CLASS_TYPE_SINK
+        elif issubclass(component_class, bt2.component._UserSourceComponent):
+            cc_ptr = component_class._cc_ptr
+            add_fn = native_bt.graph_add_source_component
+            cc_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE
+        elif issubclass(component_class, bt2.component._UserSinkComponent):
+            cc_ptr = component_class._cc_ptr
+            add_fn = native_bt.graph_add_sink_component
+            cc_type = native_bt.COMPONENT_CLASS_TYPE_SINK
+        elif issubclass(component_class, bt2.component._UserFilterComponent):
+            cc_ptr = component_class._cc_ptr
+            add_fn = native_bt.graph_add_filter_component
+            cc_type = native_bt.COMPONENT_CLASS_TYPE_FILTER
+        else:
+            raise TypeError("'{}' is not a component class".format(
+                component_class.__class__.__name__))
+
+        utils._check_str(name)
+        params = bt2.create_value(params)
+
+        params_ptr = params._ptr if params is not None else None
+
+        status, comp_ptr = add_fn(self._ptr, cc_ptr, name, params_ptr)
+        self._handle_status(status, 'cannot add component to graph')
+        assert comp_ptr
+        return bt2.component._create_component_from_ptr(comp_ptr, cc_type)
+
+    def connect_ports(self, upstream_port, downstream_port):
+        utils._check_type(upstream_port, bt2.port._OutputPort)
+        utils._check_type(downstream_port, bt2.port._InputPort)
+        status, conn_ptr = native_bt.graph_connect_ports(self._ptr,
+                                                         upstream_port._ptr,
+                                                         downstream_port._ptr)
+        self._handle_status(status, 'cannot connect component ports within graph')
+        assert(conn_ptr)
+        return bt2.connection._Connection._create_from_ptr(conn_ptr)
+
+    def add_port_added_listener(self, listener):
+        if not callable(listener):
+            raise TypeError("'listener' parameter is not callable")
+
+        fn = native_bt.py3_graph_add_port_added_listener
+        listener_from_native = functools.partial(_graph_port_added_listener_from_native,
+                                                 listener)
+
+        listener_ids = fn(self._ptr, listener_from_native)
+        if listener_ids is None:
+            utils._raise_bt2_error('cannot add listener to graph object')
+        return bt2._ListenerHandle(listener_ids, self)
+
+    def add_ports_connected_listener(self, listener):
+        if not callable(listener):
+            raise TypeError("'listener' parameter is not callable")
+
+        fn = native_bt.py3_graph_add_ports_connected_listener
+        listener_from_native = functools.partial(_graph_ports_connected_listener_from_native,
+                                                 listener)
+
+        listener_ids = fn(self._ptr, listener_from_native)
+        if listener_ids is None:
+            utils._raise_bt2_error('cannot add listener to graph object')
+        return bt2._ListenerHandle(listener_ids, self)
+
+    def run(self):
+        status = native_bt.graph_run(self._ptr)
+
+        if status == native_bt.GRAPH_STATUS_END:
+            return
+
+        self._handle_status(status, 'graph object stopped running because of an unexpected error')
+
+    def cancel(self):
+        status = native_bt.graph_cancel(self._ptr)
+        self._handle_status(status, 'cannot cancel graph object')
+
+    @property
+    def is_canceled(self):
+        is_canceled = native_bt.graph_is_canceled(self._ptr)
+        assert(is_canceled >= 0)
+        return is_canceled > 0
+
+    def create_output_port_message_iterator(self, output_port):
+        utils._check_type(output_port, bt2.port._OutputPort)
+        msg_iter_ptr = native_bt.port_output_message_iterator_create(self._ptr, output_port._ptr)
+
+        if msg_iter_ptr is None:
+            raise bt2.CreationError('cannot create output port message iterator')
+
+        return bt2.message_iterator._OutputPortMessageIterator(msg_iter_ptr)
diff --git a/src/bindings/python/bt2/bt2/logging.c b/src/bindings/python/bt2/bt2/logging.c
new file mode 100644 (file)
index 0000000..a973803
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_python_bindings_bt2_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_python_bindings_bt2_log_level,
+       "BABELTRACE_PYTHON_BT2_LOG_LEVEL");
diff --git a/src/bindings/python/bt2/bt2/logging.h b/src/bindings/python/bt2/bt2/logging.h
new file mode 100644 (file)
index 0000000..5f98158
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef BABELTRACE_BINDINGS_PYTHON_BT2_LOGGING_H
+#define BABELTRACE_BINDINGS_PYTHON_BT2_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_python_bindings_bt2_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_python_bindings_bt2_log_level);
+
+#endif /* BABELTRACE_BINDINGS_PYTHON_BT2_LOGGING_H */
diff --git a/src/bindings/python/bt2/bt2/logging.py b/src/bindings/python/bt2/bt2/logging.py
new file mode 100644 (file)
index 0000000..51d898c
--- /dev/null
@@ -0,0 +1,59 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2
+
+
+class LoggingLevel:
+    VERBOSE = native_bt.LOGGING_LEVEL_VERBOSE
+    DEBUG = native_bt.LOGGING_LEVEL_DEBUG
+    INFO = native_bt.LOGGING_LEVEL_INFO
+    WARN = native_bt.LOGGING_LEVEL_WARN
+    ERROR = native_bt.LOGGING_LEVEL_ERROR
+    FATAL = native_bt.LOGGING_LEVEL_FATAL
+    NONE = native_bt.LOGGING_LEVEL_NONE
+
+
+def get_minimal_logging_level():
+    return native_bt.logging_get_minimal_level()
+
+
+def get_global_logging_level():
+    return native_bt.logging_get_global_level()
+
+
+def set_global_logging_level(level):
+    levels = (
+        LoggingLevel.VERBOSE,
+        LoggingLevel.DEBUG,
+        LoggingLevel.INFO,
+        LoggingLevel.WARN,
+        LoggingLevel.ERROR,
+        LoggingLevel.FATAL,
+        LoggingLevel.NONE,
+    )
+
+    if level not in levels:
+        raise TypeError("'{}' is not a valid logging level".format(level))
+
+    return native_bt.logging_set_global_level(level)
diff --git a/src/bindings/python/bt2/bt2/message.py b/src/bindings/python/bt2/bt2/message.py
new file mode 100644 (file)
index 0000000..56b545d
--- /dev/null
@@ -0,0 +1,236 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.clock_snapshot
+import bt2.packet
+import bt2.stream
+import bt2.event
+import bt2
+
+
+def _create_from_ptr(ptr):
+    msg_type = native_bt.message_get_type(ptr)
+
+    if msg_type not in _MESSAGE_TYPE_TO_CLS:
+        raise bt2.Error('unknown message type: {}'.format(msg_type))
+
+    return _MESSAGE_TYPE_TO_CLS[msg_type]._create_from_ptr(ptr)
+
+
+class _Message(object._SharedObject):
+    _get_ref = staticmethod(native_bt.message_get_ref)
+    _put_ref = staticmethod(native_bt.message_put_ref)
+
+    @staticmethod
+    def _check_has_default_clock_class(clock_class):
+        if clock_class is None:
+            raise bt2.NonexistentClockSnapshot('cannot get default clock snapshot: stream class has no default clock class')
+
+
+class _MessageWithDefaultClockSnapshot:
+    def _get_default_clock_snapshot(self, borrow_clock_snapshot_ptr):
+        snapshot_ptr = borrow_clock_snapshot_ptr(self._ptr)
+
+        return bt2.clock_snapshot._ClockSnapshot._create_from_ptr_and_get_ref(
+            snapshot_ptr, self._ptr, self._get_ref, self._put_ref)
+
+
+class _EventMessage(_Message, _MessageWithDefaultClockSnapshot):
+    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_event_borrow_default_clock_snapshot_const)
+
+    @property
+    def default_clock_snapshot(self):
+        self._check_has_default_clock_class(self.event.packet.stream.cls.default_clock_class)
+        return self._get_default_clock_snapshot(self._borrow_default_clock_snapshot_ptr)
+
+    @property
+    def event(self):
+        event_ptr = native_bt.message_event_borrow_event(self._ptr)
+        assert event_ptr is not None
+        return bt2.event._Event._create_from_ptr_and_get_ref(
+            event_ptr, self._ptr, self._get_ref, self._put_ref)
+
+
+class _PacketMessage(_Message, _MessageWithDefaultClockSnapshot):
+    @property
+    def default_clock_snapshot(self):
+        self._check_has_default_clock_class(self.packet.stream.cls.default_clock_class)
+        return self._get_default_clock_snapshot(self._borrow_default_clock_snapshot_ptr)
+
+    @property
+    def packet(self):
+        packet_ptr = self._borrow_packet_ptr(self._ptr)
+        assert packet_ptr is not None
+        return bt2.packet._Packet._create_from_ptr_and_get_ref(packet_ptr)
+
+
+class _PacketBeginningMessage(_PacketMessage):
+    _borrow_packet_ptr = staticmethod(native_bt.message_packet_beginning_borrow_packet)
+    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_packet_beginning_borrow_default_clock_snapshot_const)
+
+
+class _PacketEndMessage(_PacketMessage):
+    _borrow_packet_ptr = staticmethod(native_bt.message_packet_end_borrow_packet)
+    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_packet_end_borrow_default_clock_snapshot_const)
+
+
+class _StreamMessage(_Message):
+    @property
+    def stream(self):
+        stream_ptr = self._borrow_stream_ptr(self._ptr)
+        assert stream_ptr
+        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
+
+
+class _StreamBeginningMessage(_StreamMessage):
+    _borrow_stream_ptr = staticmethod(native_bt.message_stream_beginning_borrow_stream)
+
+
+class _StreamEndMessage(_StreamMessage):
+    _borrow_stream_ptr = staticmethod(native_bt.message_stream_end_borrow_stream)
+
+
+class _StreamActivityMessage(_Message):
+    @property
+    def default_clock_snapshot(self):
+        self._check_has_default_clock_class(self.stream.cls.default_clock_class)
+        status, snapshot_ptr = self._borrow_default_clock_snapshot_ptr(self._ptr)
+
+        if status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
+            snapshot_type = bt2.clock_snapshot._ClockSnapshot
+        elif status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
+            snapshot_type = bt2.clock_snapshot._UnknownClockSnapshot
+        elif status == native_bt.MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
+            snapshot_type = bt2.clock_snapshot._InfiniteClockSnapshot
+        else:
+            raise bt2.Error('cannot borrow default clock snapshot from message')
+
+        assert snapshot_ptr is not None
+
+        return snapshot_type._create_from_ptr_and_get_ref(
+            snapshot_ptr, self._ptr, self._get_ref, self._put_ref)
+
+    def _default_clock_snapshot(self, value):
+        self._set_default_clock_snapshot_ptr(self._ptr, value)
+
+    _default_clock_snapshot = property(fset=_default_clock_snapshot)
+
+    @property
+    def stream(self):
+        stream_ptr = self._borrow_stream_ptr(self._ptr)
+        assert stream_ptr
+        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
+
+
+class _StreamActivityBeginningMessage(_StreamActivityMessage):
+    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_beginning_borrow_default_clock_snapshot_const)
+    _set_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_beginning_set_default_clock_snapshot)
+    _borrow_stream_ptr = staticmethod(native_bt.message_stream_activity_beginning_borrow_stream)
+
+
+class _StreamActivityEndMessage(_StreamActivityMessage):
+    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_end_borrow_default_clock_snapshot_const)
+    _set_default_clock_snapshot_ptr = staticmethod(native_bt.message_stream_activity_end_set_default_clock_snapshot)
+    _borrow_stream_ptr = staticmethod(native_bt.message_stream_activity_end_borrow_stream)
+
+
+class _MessageIteratorInactivityMessage(_Message, _MessageWithDefaultClockSnapshot):
+    _borrow_default_clock_snapshot_ptr = staticmethod(native_bt.message_message_iterator_inactivity_borrow_default_clock_snapshot_const)
+
+    @property
+    def default_clock_snapshot(self):
+        # This kind of message always has a default clock class: no
+        # need to call self._check_has_default_clock_class() here.
+        return self._get_default_clock_snapshot(self._borrow_default_clock_snapshot_ptr)
+
+
+class _DiscardedMessage(_Message, _MessageWithDefaultClockSnapshot):
+    @property
+    def stream(self):
+        stream_ptr = self._borrow_stream_ptr(self._ptr)
+        assert stream_ptr
+        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
+
+    @property
+    def count(self):
+        avail, count = self._get_count(self._ptr)
+        if avail is native_bt.PROPERTY_AVAILABILITY_AVAILABLE:
+            return count
+
+    def _set_count(self, count):
+        utils._check_uint64(count)
+        self._set_count(self._ptr, count)
+
+    _count = property(fset=_set_count)
+
+    def _check_has_default_clock_snapshots(self):
+        if not self._has_default_clock_snapshots:
+            raise bt2.NonexistentClockSnapshot('cannot get default clock snapshot: such a message has no clock snapshots for this stream class')
+
+    @property
+    def beginning_default_clock_snapshot(self):
+        self._check_has_default_clock_snapshots()
+        return self._get_default_clock_snapshot(self._borrow_beginning_clock_snapshot_ptr)
+
+    @property
+    def end_default_clock_snapshot(self):
+        self._check_has_default_clock_snapshots()
+        return self._get_default_clock_snapshot(self._borrow_end_clock_snapshot_ptr)
+
+
+class _DiscardedEventsMessage(_DiscardedMessage):
+    _borrow_stream_ptr = staticmethod(native_bt.message_discarded_events_borrow_stream_const)
+    _get_count = staticmethod(native_bt.message_discarded_events_get_count)
+    _set_count = staticmethod(native_bt.message_discarded_events_set_count)
+    _borrow_beginning_clock_snapshot_ptr = staticmethod(native_bt.message_discarded_events_borrow_beginning_default_clock_snapshot_const)
+    _borrow_end_clock_snapshot_ptr = staticmethod(native_bt.message_discarded_events_borrow_end_default_clock_snapshot_const)
+
+    @property
+    def _has_default_clock_snapshots(self):
+        return self.stream.cls.discarded_events_have_default_clock_snapshots
+
+
+class _DiscardedPacketsMessage(_DiscardedMessage):
+    _borrow_stream_ptr = staticmethod(native_bt.message_discarded_packets_borrow_stream_const)
+    _get_count = staticmethod(native_bt.message_discarded_packets_get_count)
+    _set_count = staticmethod(native_bt.message_discarded_packets_set_count)
+    _borrow_beginning_clock_snapshot_ptr = staticmethod(native_bt.message_discarded_packets_borrow_beginning_default_clock_snapshot_const)
+    _borrow_end_clock_snapshot_ptr = staticmethod(native_bt.message_discarded_packets_borrow_end_default_clock_snapshot_const)
+
+    @property
+    def _has_default_clock_snapshots(self):
+        return self.stream.cls.discarded_packets_have_default_clock_snapshots
+
+
+_MESSAGE_TYPE_TO_CLS = {
+    native_bt.MESSAGE_TYPE_EVENT: _EventMessage,
+    native_bt.MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY: _MessageIteratorInactivityMessage,
+    native_bt.MESSAGE_TYPE_STREAM_BEGINNING: _StreamBeginningMessage,
+    native_bt.MESSAGE_TYPE_STREAM_END: _StreamEndMessage,
+    native_bt.MESSAGE_TYPE_PACKET_BEGINNING: _PacketBeginningMessage,
+    native_bt.MESSAGE_TYPE_PACKET_END: _PacketEndMessage,
+    native_bt.MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING: _StreamActivityBeginningMessage,
+    native_bt.MESSAGE_TYPE_STREAM_ACTIVITY_END: _StreamActivityEndMessage,
+    native_bt.MESSAGE_TYPE_DISCARDED_EVENTS: _DiscardedEventsMessage,
+    native_bt.MESSAGE_TYPE_DISCARDED_PACKETS: _DiscardedPacketsMessage,
+}
diff --git a/src/bindings/python/bt2/bt2/message_iterator.py b/src/bindings/python/bt2/bt2/message_iterator.py
new file mode 100644 (file)
index 0000000..7f996b0
--- /dev/null
@@ -0,0 +1,337 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.message
+import collections.abc
+import bt2.component
+import bt2
+
+
+class _MessageIterator(collections.abc.Iterator):
+    def _handle_status(self, status, gen_error_msg):
+        if status == native_bt.MESSAGE_ITERATOR_STATUS_AGAIN:
+            raise bt2.TryAgain
+        elif status == native_bt.MESSAGE_ITERATOR_STATUS_END:
+            raise bt2.Stop
+        elif status < 0:
+            raise bt2.Error(gen_error_msg)
+
+    def __next__(self):
+        raise NotImplementedError
+
+
+class _GenericMessageIterator(object._SharedObject, _MessageIterator):
+    def __init__(self, ptr):
+            self._current_msgs = []
+            self._at = 0
+            super().__init__(ptr)
+
+    def __next__(self):
+        if len(self._current_msgs) == self._at:
+            status, msgs = self._get_msg_range(self._ptr)
+            self._handle_status(status,
+                                'unexpected error: cannot advance the message iterator')
+            self._current_msgs = msgs
+            self._at = 0
+
+        msg_ptr = self._current_msgs[self._at]
+        self._at += 1
+
+        return bt2.message._create_from_ptr(msg_ptr)
+
+
+# This is created when a component wants to iterate on one of its input ports.
+class _UserComponentInputPortMessageIterator(_GenericMessageIterator):
+    _get_msg_range = staticmethod(native_bt.py3_self_component_port_input_get_msg_range)
+    _get_ref = staticmethod(native_bt.self_component_port_input_message_iterator_get_ref)
+    _put_ref = staticmethod(native_bt.self_component_port_input_message_iterator_put_ref)
+
+
+# This is created when the user wants to iterate on a component's output port,
+# from outside the graph.
+class _OutputPortMessageIterator(_GenericMessageIterator):
+    _get_msg_range = staticmethod(native_bt.py3_port_output_get_msg_range)
+    _get_ref = staticmethod(native_bt.port_output_message_iterator_get_ref)
+    _put_ref = staticmethod(native_bt.port_output_message_iterator_put_ref)
+
+
+# This is extended by the user to implement component classes in Python.  It
+# is created for a given output port when an input port message iterator is
+# created on the input port on the other side of the connection.  It is also
+# created when an output port message iterator is created on this output port.
+#
+# Its purpose is to feed the messages that should go out through this output
+# port.
+class _UserMessageIterator(_MessageIterator):
+    def __new__(cls, ptr):
+        # User iterator objects are always created by the native side,
+        # that is, never instantiated directly by Python code.
+        #
+        # The native code calls this, then manually calls
+        # self.__init__() without the `ptr` argument. The user has
+        # access to self.component during this call, thanks to this
+        # self._ptr argument being set.
+        #
+        # self._ptr is NOT owned by this object here, so there's nothing
+        # to do in __del__().
+        self = super().__new__(cls)
+        self._ptr = ptr
+        return self
+
+    def _init_from_native(self, self_output_port_ptr):
+        self_output_port = bt2.port._create_self_from_ptr_and_get_ref(
+            self_output_port_ptr, native_bt.PORT_TYPE_OUTPUT)
+        self.__init__(self_output_port)
+
+    def __init__(self, output_port):
+        pass
+
+    @property
+    def _component(self):
+        return native_bt.py3_get_user_component_from_user_msg_iter(self._ptr)
+
+    @property
+    def addr(self):
+        return int(self._ptr)
+
+    def _finalize(self):
+        pass
+
+    def __next__(self):
+        raise bt2.Stop
+
+    def _next_from_native(self):
+        # this can raise anything: it's catched by the native part
+        try:
+            msg = next(self)
+        except StopIteration:
+            raise bt2.Stop
+        except:
+            raise
+
+        utils._check_type(msg, bt2.message._Message)
+
+        # Release the reference to the native part.
+        ptr = msg._release()
+        return int(ptr)
+
+    # Validate that the presence or lack of presence of a
+    # `default_clock_snapshot` value is valid in the context of `stream_class`.
+    @staticmethod
+    def _validate_default_clock_snapshot(stream_class, default_clock_snapshot):
+        stream_class_has_default_clock_class = stream_class.default_clock_class is not None
+
+        if stream_class_has_default_clock_class and default_clock_snapshot is None:
+            raise bt2.Error(
+                'stream class has a default clock class, default_clock_snapshot should not be None')
+
+        if not stream_class_has_default_clock_class and default_clock_snapshot is not None:
+            raise bt2.Error(
+                'stream class has no default clock class, default_clock_snapshot should be None')
+
+    def _create_event_message(self, event_class, packet, default_clock_snapshot=None):
+        utils._check_type(event_class, bt2.event_class._EventClass)
+        utils._check_type(packet, bt2.packet._Packet)
+        self._validate_default_clock_snapshot(packet.stream.cls, default_clock_snapshot)
+
+        if default_clock_snapshot is not None:
+            utils._check_uint64(default_clock_snapshot)
+            ptr = native_bt.message_event_create_with_default_clock_snapshot(
+                self._ptr, event_class._ptr, packet._ptr, default_clock_snapshot)
+        else:
+            ptr = native_bt.message_event_create(
+                self._ptr, event_class._ptr, packet._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create event message object')
+
+        return bt2.message._EventMessage(ptr)
+
+    def _create_message_iterator_inactivity_message(self, clock_class, clock_snapshot):
+        utils._check_type(clock_class, bt2.clock_class._ClockClass)
+        ptr = native_bt.message_message_iterator_inactivity_create(
+            self._ptr, clock_class._ptr, clock_snapshot)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create inactivity message object')
+
+        return bt2.message._MessageIteratorInactivityMessage(ptr)
+
+    def _create_stream_beginning_message(self, stream):
+        utils._check_type(stream, bt2.stream._Stream)
+
+        ptr = native_bt.message_stream_beginning_create(self._ptr, stream._ptr)
+        if ptr is None:
+            raise bt2.CreationError('cannot create stream beginning message object')
+
+        return bt2.message._StreamBeginningMessage(ptr)
+
+    def _create_stream_activity_beginning_message(self, stream, default_clock_snapshot=None):
+        utils._check_type(stream, bt2.stream._Stream)
+        self._validate_default_clock_snapshot(stream.cls, default_clock_snapshot)
+
+        ptr = native_bt.message_stream_activity_beginning_create(self._ptr, stream._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError(
+                'cannot create stream activity beginning message object')
+
+        msg = bt2.message._StreamActivityBeginningMessage(ptr)
+
+        if default_clock_snapshot is not None:
+            msg._default_clock_snapshot = default_clock_snapshot
+
+        return msg
+
+    def _create_stream_activity_end_message(self, stream, default_clock_snapshot=None):
+        utils._check_type(stream, bt2.stream._Stream)
+        self._validate_default_clock_snapshot(stream.cls, default_clock_snapshot)
+
+        ptr = native_bt.message_stream_activity_end_create(self._ptr, stream._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError(
+                'cannot create stream activity end message object')
+
+        msg = bt2.message._StreamActivityEndMessage(ptr)
+
+        if default_clock_snapshot is not None:
+            msg._default_clock_snapshot = default_clock_snapshot
+
+        return msg
+
+    def _create_stream_end_message(self, stream):
+        utils._check_type(stream, bt2.stream._Stream)
+
+        ptr = native_bt.message_stream_end_create(self._ptr, stream._ptr)
+        if ptr is None:
+            raise bt2.CreationError('cannot create stream end message object')
+
+        return bt2.message._StreamEndMessage(ptr)
+
+    def _create_packet_beginning_message(self, packet, default_clock_snapshot=None):
+        utils._check_type(packet, bt2.packet._Packet)
+
+        if packet.stream.cls.packets_have_beginning_default_clock_snapshot:
+            if default_clock_snapshot is None:
+                raise ValueError("packet beginning messages in this stream must have a default clock snapshots")
+
+            utils._check_uint64(default_clock_snapshot)
+            ptr = native_bt.message_packet_beginning_create_with_default_clock_snapshot(
+                self._ptr, packet._ptr, default_clock_snapshot)
+        else:
+            if default_clock_snapshot is not None:
+                raise ValueError("packet beginning messages in this stream must not have a default clock snapshots")
+
+            ptr = native_bt.message_packet_beginning_create(self._ptr, packet._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create packet beginning message object')
+
+        return bt2.message._PacketBeginningMessage(ptr)
+
+    def _create_packet_end_message(self, packet, default_clock_snapshot=None):
+        utils._check_type(packet, bt2.packet._Packet)
+
+        if packet.stream.cls.packets_have_end_default_clock_snapshot:
+            if default_clock_snapshot is None:
+                raise ValueError("packet end messages in this stream must have a default clock snapshots")
+
+            utils._check_uint64(default_clock_snapshot)
+            ptr = native_bt.message_packet_end_create_with_default_clock_snapshot(
+                self._ptr, packet._ptr, default_clock_snapshot)
+        else:
+            if default_clock_snapshot is not None:
+                raise ValueError("packet end messages in this stream must not have a default clock snapshots")
+
+            ptr = native_bt.message_packet_end_create(self._ptr, packet._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create packet end message object')
+
+        return bt2.message._PacketEndMessage(ptr)
+
+    def _create_discarded_events_message(self, stream, count=None,
+                                         beg_clock_snapshot=None,
+                                         end_clock_snapshot=None):
+        utils._check_type(stream, bt2.stream._Stream)
+
+        if not stream.cls.supports_discarded_events:
+            raise ValueError('stream class does not support discarded events')
+
+        if stream.cls.discarded_events_have_default_clock_snapshots:
+            if beg_clock_snapshot is None or end_clock_snapshot is None:
+                raise ValueError('discarded events have default clock snapshots for this stream class')
+
+            utils._check_uint64(beg_clock_snapshot)
+            utils._check_uint64(end_clock_snapshot)
+            ptr = native_bt.message_discarded_events_create_with_default_clock_snapshots(
+                self._ptr, stream._ptr, beg_clock_snapshot, end_clock_snapshot)
+        else:
+            if beg_clock_snapshot is not None or end_clock_snapshot is not None:
+                raise ValueError('discarded events have no default clock snapshots for this stream class')
+
+            ptr = native_bt.message_discarded_events_create(
+                self._ptr, stream._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot discarded events message object')
+
+        msg = bt2.message._DiscardedEventsMessage(ptr)
+
+        if count is not None:
+            msg._count = count
+
+        return msg
+
+    def _create_discarded_packets_message(self, stream, count=None, beg_clock_snapshot=None, end_clock_snapshot=None):
+        utils._check_type(stream, bt2.stream._Stream)
+
+        if not stream.cls.supports_discarded_packets:
+            raise ValueError('stream class does not support discarded packets')
+
+        if stream.cls.discarded_packets_have_default_clock_snapshots:
+            if beg_clock_snapshot is None or end_clock_snapshot is None:
+                raise ValueError('discarded packets have default clock snapshots for this stream class')
+
+            utils._check_uint64(beg_clock_snapshot)
+            utils._check_uint64(end_clock_snapshot)
+            ptr = native_bt.message_discarded_packets_create_with_default_clock_snapshots(
+                self._ptr, stream._ptr, beg_clock_snapshot, end_clock_snapshot)
+        else:
+            if beg_clock_snapshot is not None or end_clock_snapshot is not None:
+                raise ValueError('discarded packets have no default clock snapshots for this stream class')
+
+            ptr = native_bt.message_discarded_packets_create(
+                self._ptr, stream._ptr)
+
+        if ptr is None:
+            raise bt2.CreationError('cannot discarded packets message object')
+
+        msg = bt2.message._DiscardedPacketsMessage(ptr)
+
+        if count is not None:
+            msg._count = count
+
+        return msg
+
diff --git a/src/bindings/python/bt2/bt2/native_bt.i b/src/bindings/python/bt2/bt2/native_bt.i
new file mode 100644 (file)
index 0000000..bf20edc
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SWIGPYTHON
+# error Unsupported output language
+#endif
+
+%module native_bt
+
+%{
+#define BT_LOG_TAG "PY-NATIVE"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include <babeltrace2/property.h>
+#include "common/assert.h"
+
+typedef const uint8_t *bt_uuid;
+%}
+
+typedef int bt_bool;
+
+/* For uint*_t/int*_t */
+%include "stdint.i"
+
+/*
+ * Remove `bt_` and `BT_` prefixes from function names, global variables and
+ * enumeration items
+ */
+%rename("%(strip:[bt_])s", %$isfunction) "";
+%rename("%(strip:[bt_])s", %$isvariable) "";
+%rename("%(strip:[BT_])s", %$isenumitem) "";
+
+/*
+ * Output argument typemap for string output (always appends)
+ *
+ * We initialize the output parameter `temp_value` to an invalid but non-zero
+ * pointer value.  This is to make sure we don't rely on its initial value in
+ * the epilogue (where we call SWIG_Python_str_FromChar).  When they fail,
+ * functions on which we apply this typemap don't guarantee that the value of
+ * `temp_value` will be unchanged or valid.
+ */
+%typemap(in, numinputs=0) (const char **OUT) (char *temp_value = (void *) 1) {
+       $1 = &temp_value;
+}
+
+%typemap(argout) (const char **OUT) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result, SWIG_Python_str_FromChar(*$1));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for value output (always appends) */
+%typemap(in, numinputs=0) (bt_value **OUT) (struct bt_value *temp_value = NULL) {
+       $1 = &temp_value;
+}
+
+%typemap(argout) (bt_value **OUT) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_value, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for initialized uint64_t output parameter (always appends) */
+%typemap(in, numinputs=0) (uint64_t *OUT) (uint64_t temp) {
+       $1 = &temp;
+}
+
+%typemap(argout) uint64_t *OUT {
+       $result = SWIG_Python_AppendOutput(resultobj,
+                       SWIG_From_unsigned_SS_long_SS_long((*$1)));
+}
+
+/* Output argument typemap for initialized int64_t output parameter (always appends) */
+%typemap(in, numinputs=0) (int64_t *OUT) (int64_t temp) {
+       $1 = &temp;
+}
+
+%typemap(argout) (int64_t *OUT) {
+       $result = SWIG_Python_AppendOutput(resultobj, SWIG_From_long_SS_long((*$1)));
+}
+
+/* Output argument typemap for initialized unsigned int output parameter (always appends) */
+%typemap(in, numinputs=0) (unsigned int *OUT) (unsigned int temp) {
+       $1 = &temp;
+}
+
+%typemap(argout) (unsigned int *OUT) {
+       $result = SWIG_Python_AppendOutput(resultobj,
+                       SWIG_From_unsigned_SS_long_SS_long((uint64_t) (*$1)));
+}
+/* Output argument typemap for initialized double output parameter (always appends) */
+%typemap(in, numinputs=0) (double *OUT) (double temp) {
+       $1 = &temp;
+}
+
+%typemap(argout) (double *OUT) {
+       $result = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*$1)));
+}
+
+/* Input argument typemap for UUID bytes */
+%typemap(in) bt_uuid {
+       $1 = (unsigned char *) PyBytes_AsString($input);
+}
+
+/* Output argument typemap for UUID bytes */
+%typemap(out) bt_uuid {
+       if (!$1) {
+               Py_INCREF(Py_None);
+               $result = Py_None;
+       } else {
+               $result = PyBytes_FromStringAndSize((const char *) $1, 16);
+       }
+}
+
+/* Input argument typemap for bt_bool */
+%typemap(in) bt_bool {
+       $1 = PyObject_IsTrue($input);
+}
+
+/* Output argument typemap for bt_bool */
+%typemap(out) bt_bool {
+       if ($1 > 0) {
+               $result = Py_True;
+       } else {
+               $result = Py_False;
+       }
+       Py_INCREF($result);
+       return $result;
+}
+
+/*
+ * Input and output argument typemaps for raw Python objects (direct).
+ *
+ * Those typemaps honor the convention of Python C function calls with
+ * respect to reference counting: parameters are passed as borrowed
+ * references, and objects are returned as new references. The wrapped
+ * C function must ensure that the return value is always a new
+ * reference, and never steal parameter references.
+ */
+%typemap(in) PyObject * {
+       $1 = $input;
+}
+
+%typemap(out) PyObject * {
+       $result = $1;
+}
+
+/* From property.h */
+
+typedef enum bt_property_availability {
+       BT_PROPERTY_AVAILABILITY_AVAILABLE,
+       BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE,
+} bt_property_availability;
+
+/* Per-module interface files */
+%include "native_bt_clock_class.i"
+%include "native_bt_clock_snapshot.i"
+%include "native_bt_component.i"
+%include "native_bt_component_class.i"
+%include "native_bt_connection.i"
+%include "native_bt_event.i"
+%include "native_bt_event_class.i"
+%include "native_bt_field.i"
+%include "native_bt_field_class.i"
+%include "native_bt_field_path.i"
+%include "native_bt_graph.i"
+%include "native_bt_logging.i"
+%include "native_bt_message.i"
+%include "native_bt_notifier.i"
+%include "native_bt_packet.i"
+%include "native_bt_plugin.i"
+%include "native_bt_port.i"
+%include "native_bt_query_exec.i"
+%include "native_bt_stream.i"
+%include "native_bt_stream_class.i"
+%include "native_bt_trace.i"
+%include "native_bt_trace_class.i"
+%include "native_bt_value.i"
+%include "native_bt_version.i"
diff --git a/src/bindings/python/bt2/bt2/native_bt_clock_class.i b/src/bindings/python/bt2/bt2/native_bt_clock_class.i
new file mode 100644 (file)
index 0000000..bf8ea43
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From clock-class-const.h */
+
+typedef enum bt_clock_class_status {
+       BT_CLOCK_CLASS_STATUS_OK = 0,
+       BT_CLOCK_CLASS_STATUS_NOMEM = -12,
+       BT_CLOCK_CLASS_STATUS_OVERFLOW = -75,
+} bt_clock_class_status;
+
+extern const char *bt_clock_class_get_name(
+               const bt_clock_class *clock_class);
+
+extern const char *bt_clock_class_get_description(
+               const bt_clock_class *clock_class);
+
+extern uint64_t bt_clock_class_get_frequency(
+               const bt_clock_class *clock_class);
+
+extern uint64_t bt_clock_class_get_precision(
+               const bt_clock_class *clock_class);
+
+extern void bt_clock_class_get_offset(const bt_clock_class *clock_class,
+               int64_t *OUT, uint64_t *OUT);
+
+extern bt_bool bt_clock_class_origin_is_unix_epoch(
+               const bt_clock_class *clock_class);
+
+extern bt_uuid bt_clock_class_get_uuid(
+               const bt_clock_class *clock_class);
+
+extern bt_clock_class_status bt_clock_class_cycles_to_ns_from_origin(
+               const bt_clock_class *clock_class,
+               uint64_t cycles, int64_t *OUT);
+
+extern void bt_clock_class_get_ref(const bt_clock_class *clock_class);
+
+extern void bt_clock_class_put_ref(const bt_clock_class *clock_class);
+
+/* From clock-class.h */
+
+extern bt_clock_class *bt_clock_class_create(bt_self_component *self_comp);
+
+extern bt_clock_class_status bt_clock_class_set_name(
+               bt_clock_class *clock_class, const char *name);
+
+extern bt_clock_class_status bt_clock_class_set_description(
+               bt_clock_class *clock_class, const char *description);
+
+extern void bt_clock_class_set_frequency(bt_clock_class *clock_class,
+               uint64_t freq);
+
+extern void bt_clock_class_set_precision(bt_clock_class *clock_class,
+               uint64_t precision);
+
+extern void bt_clock_class_set_offset(bt_clock_class *clock_class,
+               int64_t seconds, uint64_t cycles);
+
+extern void bt_clock_class_set_origin_is_unix_epoch(bt_clock_class *clock_class,
+               bt_bool origin_is_unix_epoch);
+
+extern void bt_clock_class_set_uuid(bt_clock_class *clock_class,
+               bt_uuid uuid);
diff --git a/src/bindings/python/bt2/bt2/native_bt_clock_snapshot.i b/src/bindings/python/bt2/bt2/native_bt_clock_snapshot.i
new file mode 100644 (file)
index 0000000..a2ca8e8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From clock-snapshot-const.h */
+
+typedef enum bt_clock_snapshot_status {
+       BT_CLOCK_SNAPSHOT_STATUS_OK = 0,
+       BT_CLOCK_SNAPSHOT_STATUS_OVERFLOW = -75,
+} bt_clock_snapshot_status;
+
+extern const bt_clock_class *bt_clock_snapshot_borrow_clock_class_const(
+               const bt_clock_snapshot *clock_snapshot);
+
+extern uint64_t bt_clock_snapshot_get_value(
+               const bt_clock_snapshot *clock_snapshot);
+
+extern bt_clock_snapshot_status bt_clock_snapshot_get_ns_from_origin(
+               const bt_clock_snapshot *clock_snapshot,
+               int64_t *OUT);
diff --git a/src/bindings/python/bt2/bt2/native_bt_component.i b/src/bindings/python/bt2/bt2/native_bt_component.i
new file mode 100644 (file)
index 0000000..f484263
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Output argument typemap for self port output (always appends) */
+%typemap(in, numinputs=0)
+       (bt_self_component_port_input **OUT)
+       (bt_self_component_port_input *temp_self_port = NULL) {
+       $1 = &temp_self_port;
+}
+
+%typemap(argout) bt_self_component_port_input **OUT {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_self_component_port_input, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for self port output (always appends) */
+%typemap(in, numinputs=0)
+       (bt_self_component_port_output **OUT)
+       (bt_self_component_port_output *temp_self_port = NULL) {
+       $1 = &temp_self_port;
+}
+
+%typemap(argout) (bt_self_component_port_output **OUT) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_self_component_port_output, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Typemaps used for user data attached to self component ports. */
+
+/*
+ * The user data Python object is kept as the user data of the port, we pass
+ * the PyObject pointer directly to the port creation function.
+ */
+%typemap(in) void *PY_SELF_PORT_USER_DATA {
+       $1 = $input;
+}
+
+/*
+ * The port, if created successfully, now owns a reference to the Python object,
+ * we reflect that here.
+ */
+%typemap(argout) void *PY_SELF_PORT_USER_DATA {
+       if (PyLong_AsLong($result) == BT_SELF_COMPONENT_STATUS_OK) {
+               Py_INCREF($1);
+       }
+}
+
+/* From component-const.h */
+
+extern const char *bt_component_get_name(const bt_component *component);
+
+extern const bt_component_class *bt_component_borrow_class_const(
+               const bt_component *component);
+
+extern bt_component_class_type bt_component_get_class_type(
+               const bt_component *component);
+
+bt_bool bt_component_is_source(const bt_component *component);
+
+bt_bool bt_component_is_filter(const bt_component *component);
+
+bt_bool bt_component_is_sink(const bt_component *component);
+
+extern bt_bool bt_component_graph_is_canceled(
+               const bt_component *component);
+
+extern void bt_component_get_ref(const bt_component *component);
+
+extern void bt_component_put_ref(const bt_component *component);
+
+/* From component-source-const.h */
+
+const bt_component *bt_component_source_as_component_const(
+               const bt_component_source *component);
+
+extern const bt_component_class_source *
+bt_component_source_borrow_class_const(
+               const bt_component_source *component);
+
+extern uint64_t bt_component_source_get_output_port_count(
+               const bt_component_source *component);
+
+extern const bt_port_output *
+bt_component_source_borrow_output_port_by_name_const(
+               const bt_component_source *component, const char *name);
+
+extern const bt_port_output *
+bt_component_source_borrow_output_port_by_index_const(
+               const bt_component_source *component, uint64_t index);
+
+extern void bt_component_source_get_ref(
+               const bt_component_source *component_source);
+
+extern void bt_component_source_put_ref(
+               const bt_component_source *component_source);
+
+/* From component-filter-const.h */
+
+const bt_component *bt_component_filter_as_component_const(
+               const bt_component_filter *component);
+
+extern const bt_component_class_filter *
+bt_component_filter_borrow_class_const(
+               const bt_component_filter *component);
+
+extern uint64_t bt_component_filter_get_input_port_count(
+               const bt_component_filter *component);
+
+extern const bt_port_input *
+bt_component_filter_borrow_input_port_by_name_const(
+               const bt_component_filter *component, const char *name);
+
+extern const bt_port_input *
+bt_component_filter_borrow_input_port_by_index_const(
+               const bt_component_filter *component, uint64_t index);
+
+extern uint64_t bt_component_filter_get_output_port_count(
+               const bt_component_filter *component);
+
+extern const bt_port_output *
+bt_component_filter_borrow_output_port_by_name_const(
+               const bt_component_filter *component, const char *name);
+
+extern const bt_port_output *
+bt_component_filter_borrow_output_port_by_index_const(
+               const bt_component_filter *component, uint64_t index);
+
+extern void bt_component_filter_get_ref(
+               const bt_component_filter *component_filter);
+
+extern void bt_component_filter_put_ref(
+               const bt_component_filter *component_filter);
+
+/* From component-sink-const.h */
+
+const bt_component *bt_component_sink_as_component_const(
+               const bt_component_sink *component);
+
+extern const bt_component_class_sink *
+bt_component_sink_borrow_class_const(
+               const bt_component_sink *component);
+
+extern uint64_t bt_component_sink_get_input_port_count(
+               const bt_component_sink *component);
+
+extern const bt_port_input *
+bt_component_sink_borrow_input_port_by_name_const(
+               const bt_component_sink *component, const char *name);
+
+extern const bt_port_input *
+bt_component_sink_borrow_input_port_by_index_const(
+               const bt_component_sink *component, uint64_t index);
+
+extern void bt_component_sink_get_ref(
+               const bt_component_sink *component_sink);
+
+extern void bt_component_sink_put_ref(
+               const bt_component_sink *component_sink);
+
+/* From self-component.h */
+
+typedef enum bt_self_component_status {
+       BT_SELF_COMPONENT_STATUS_OK = 0,
+       BT_SELF_COMPONENT_STATUS_END = 1,
+       BT_SELF_COMPONENT_STATUS_AGAIN = 11,
+       BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION = 111,
+       BT_SELF_COMPONENT_STATUS_ERROR = -1,
+       BT_SELF_COMPONENT_STATUS_NOMEM = -12,
+} bt_self_component_status;
+
+const bt_component *bt_self_component_as_component(
+               bt_self_component *self_component);
+
+extern void *bt_self_component_get_data(
+               const bt_self_component *self_component);
+
+extern void bt_self_component_set_data(
+               bt_self_component *self_component, void *data);
+
+/* From self-component-source.h */
+
+bt_self_component *bt_self_component_source_as_self_component(
+               bt_self_component_source *self_comp_source);
+
+const bt_component_source *
+bt_self_component_source_as_component_source(
+               bt_self_component_source *self_comp_source);
+
+extern bt_self_component_port_output *
+bt_self_component_source_borrow_output_port_by_name(
+               bt_self_component_source *self_component,
+               const char *name);
+
+extern bt_self_component_port_output *
+bt_self_component_source_borrow_output_port_by_index(
+               bt_self_component_source *self_component,
+               uint64_t index);
+
+extern bt_self_component_status
+bt_self_component_source_add_output_port(
+               bt_self_component_source *self_component,
+               const char *name, void *PY_SELF_PORT_USER_DATA,
+               bt_self_component_port_output **OUT);
+
+/* From self-component-filter.h */
+
+bt_self_component *bt_self_component_filter_as_self_component(
+               bt_self_component_filter *self_comp_filter);
+
+const bt_component_filter *
+bt_self_component_filter_as_component_filter(
+               bt_self_component_filter *self_comp_filter);
+
+extern bt_self_component_port_output *
+bt_self_component_filter_borrow_output_port_by_name(
+               bt_self_component_filter *self_component,
+               const char *name);
+
+extern bt_self_component_port_output *
+bt_self_component_filter_borrow_output_port_by_index(
+               bt_self_component_filter *self_component,
+               uint64_t index);
+
+extern bt_self_component_status
+bt_self_component_filter_add_output_port(
+               bt_self_component_filter *self_component,
+               const char *name, void *PY_SELF_PORT_USER_DATA,
+               bt_self_component_port_output **OUT);
+
+extern bt_self_component_port_input *
+bt_self_component_filter_borrow_input_port_by_name(
+               bt_self_component_filter *self_component,
+               const char *name);
+
+extern bt_self_component_port_input *
+bt_self_component_filter_borrow_input_port_by_index(
+               bt_self_component_filter *self_component,
+               uint64_t index);
+
+extern bt_self_component_status
+bt_self_component_filter_add_input_port(
+               bt_self_component_filter *self_component,
+               const char *name, void *PY_SELF_PORT_USER_DATA,
+               bt_self_component_port_input **OUT);
+
+/* From self-component-sink.h */
+
+bt_self_component *bt_self_component_sink_as_self_component(
+               bt_self_component_sink *self_comp_sink);
+
+const bt_component_sink *
+bt_self_component_sink_as_component_sink(
+               bt_self_component_sink *self_comp_sink);
+
+extern bt_self_component_port_input *
+bt_self_component_sink_borrow_input_port_by_name(
+               bt_self_component_sink *self_component,
+               const char *name);
+
+extern bt_self_component_port_input *
+bt_self_component_sink_borrow_input_port_by_index(
+               bt_self_component_sink *self_component, uint64_t index);
+
+extern bt_self_component_status
+bt_self_component_sink_add_input_port(
+               bt_self_component_sink *self_component,
+               const char *name, void *PY_SELF_PORT_USER_DATA,
+               bt_self_component_port_input **OUT);
diff --git a/src/bindings/python/bt2/bt2/native_bt_component_class.i b/src/bindings/python/bt2/bt2/native_bt_component_class.i
new file mode 100644 (file)
index 0000000..1dfa011
--- /dev/null
@@ -0,0 +1,1761 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From component-class-const.h */
+
+typedef enum bt_component_class_status {
+       BT_COMPONENT_CLASS_STATUS_OK = 0,
+       BT_COMPONENT_CLASS_STATUS_NOMEM = -12,
+} bt_component_class_status;
+
+typedef enum bt_component_class_type {
+       BT_COMPONENT_CLASS_TYPE_SOURCE = 0,
+       BT_COMPONENT_CLASS_TYPE_FILTER = 1,
+       BT_COMPONENT_CLASS_TYPE_SINK = 2,
+} bt_component_class_type;
+
+extern const char *bt_component_class_get_name(
+               const bt_component_class *component_class);
+
+extern const char *bt_component_class_get_description(
+               const bt_component_class *component_class);
+
+extern const char *bt_component_class_get_help(
+               const bt_component_class *component_class);
+
+extern bt_component_class_type bt_component_class_get_type(
+               const bt_component_class *component_class);
+
+bt_bool bt_component_class_is_source(
+               const bt_component_class *component_class);
+
+bt_bool bt_component_class_is_filter(
+               const bt_component_class *component_class);
+
+bt_bool bt_component_class_is_sink(
+               const bt_component_class *component_class);
+
+extern void bt_component_class_get_ref(
+               const bt_component_class *component_class);
+
+extern void bt_component_class_put_ref(
+               const bt_component_class *component_class);
+
+/* From component-class-source-const.h */
+
+const bt_component_class *
+bt_component_class_source_as_component_class_const(
+               const bt_component_class_source *comp_cls_source);
+
+extern void bt_component_class_source_get_ref(
+               const bt_component_class_source *component_class_source);
+
+extern void bt_component_class_source_put_ref(
+               const bt_component_class_source *component_class_source);
+
+/* From component-class-source.h */
+
+typedef bt_self_component_status
+(*bt_component_class_source_init_method)(
+               bt_self_component_source *self_component,
+               const bt_value *params, void *init_method_data);
+
+typedef void (*bt_component_class_source_finalize_method)(
+               bt_self_component_source *self_component);
+
+typedef bt_self_message_iterator_status
+(*bt_component_class_source_message_iterator_init_method)(
+               bt_self_message_iterator *message_iterator,
+               bt_self_component_source *self_component,
+               bt_self_component_port_output *port);
+
+typedef void
+(*bt_component_class_source_message_iterator_finalize_method)(
+               bt_self_message_iterator *message_iterator);
+
+typedef bt_self_message_iterator_status
+(*bt_component_class_source_message_iterator_next_method)(
+               bt_self_message_iterator *message_iterator,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count);
+
+typedef bt_self_message_iterator_status
+(*bt_component_class_source_message_iterator_seek_ns_from_origin_method)(
+               bt_self_message_iterator *message_iterator,
+               int64_t ns_from_origin);
+
+typedef bt_self_message_iterator_status
+(*bt_component_class_source_message_iterator_seek_beginning_method)(
+               bt_self_message_iterator *message_iterator);
+
+typedef bt_bool
+(*bt_component_class_source_message_iterator_can_seek_ns_from_origin_method)(
+               bt_self_message_iterator *message_iterator,
+               int64_t ns_from_origin);
+
+typedef bt_bool
+(*bt_component_class_source_message_iterator_can_seek_beginning_method)(
+               bt_self_message_iterator *message_iterator);
+
+typedef bt_query_status (*bt_component_class_source_query_method)(
+               bt_self_component_class_source *comp_class,
+               const bt_query_executor *query_executor,
+               const char *object, const bt_value *params,
+               const bt_value **result);
+
+typedef bt_self_component_status
+(*bt_component_class_source_accept_output_port_connection_method)(
+               bt_self_component_source *self_component,
+               bt_self_component_port_output *self_port,
+               const bt_port_input *other_port);
+
+typedef bt_self_component_status
+(*bt_component_class_source_output_port_connected_method)(
+               bt_self_component_source *self_component,
+               bt_self_component_port_output *self_port,
+               const bt_port_input *other_port);
+
+bt_component_class *bt_component_class_source_as_component_class(
+               bt_component_class_source *comp_cls_source);
+
+extern
+bt_component_class_source *bt_component_class_source_create(
+               const char *name,
+               bt_component_class_source_message_iterator_next_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_init_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_init_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_finalize_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_finalize_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_accept_output_port_connection_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_accept_output_port_connection_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_output_port_connected_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_output_port_connected_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_query_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_query_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_message_iterator_init_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_message_iterator_init_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_message_iterator_finalize_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_message_iterator_finalize_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_message_iterator_seek_ns_from_origin_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_message_iterator_seek_ns_from_origin_method method);
+
+extern bt_component_class_status
+bt_component_class_source_set_message_iterator_seek_beginning_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_message_iterator_seek_beginning_method method);
+
+extern bt_bool
+bt_component_class_source_set_message_iterator_can_seek_ns_from_origin_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_message_iterator_can_seek_ns_from_origin_method method);
+
+extern bt_bool
+bt_component_class_source_set_message_iterator_can_seek_beginning_method(
+               bt_component_class_source *comp_class,
+               bt_component_class_source_message_iterator_can_seek_beginning_method method);
+
+/* From component-class-filter-const.h */
+
+const bt_component_class *
+bt_component_class_filter_as_component_class_const(
+               const bt_component_class_filter *comp_cls_filter);
+
+extern void bt_component_class_filter_get_ref(
+               const bt_component_class_filter *component_class_filter);
+
+extern void bt_component_class_filter_put_ref(
+               const bt_component_class_filter *component_class_filter);
+
+/* From component-class-filter.h */
+
+typedef bt_self_component_status
+(*bt_component_class_filter_init_method)(
+               bt_self_component_filter *self_component,
+               const bt_value *params, void *init_method_data);
+
+typedef void (*bt_component_class_filter_finalize_method)(
+               bt_self_component_filter *self_component);
+
+typedef bt_self_message_iterator_status
+(*bt_component_class_filter_message_iterator_init_method)(
+               bt_self_message_iterator *message_iterator,
+               bt_self_component_filter *self_component,
+               bt_self_component_port_output *port);
+
+typedef void
+(*bt_component_class_filter_message_iterator_finalize_method)(
+               bt_self_message_iterator *message_iterator);
+
+typedef bt_self_message_iterator_status
+(*bt_component_class_filter_message_iterator_next_method)(
+               bt_self_message_iterator *message_iterator,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count);
+
+typedef bt_self_message_iterator_status
+(*bt_component_class_filter_message_iterator_seek_ns_from_origin_method)(
+               bt_self_message_iterator *message_iterator,
+               int64_t ns_from_origin);
+
+typedef bt_self_message_iterator_status
+(*bt_component_class_filter_message_iterator_seek_beginning_method)(
+               bt_self_message_iterator *message_iterator);
+
+typedef bt_bool
+(*bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method)(
+               bt_self_message_iterator *message_iterator,
+               int64_t ns_from_origin);
+
+typedef bt_bool
+(*bt_component_class_filter_message_iterator_can_seek_beginning_method)(
+               bt_self_message_iterator *message_iterator);
+
+typedef bt_query_status
+(*bt_component_class_filter_query_method)(
+               bt_self_component_class_filter *comp_class,
+               const bt_query_executor *query_executor,
+               const char *object, const bt_value *params,
+               const bt_value **result);
+
+typedef bt_self_component_status
+(*bt_component_class_filter_accept_input_port_connection_method)(
+               bt_self_component_filter *self_component,
+               bt_self_component_port_input *self_port,
+               const bt_port_output *other_port);
+
+typedef bt_self_component_status
+(*bt_component_class_filter_accept_output_port_connection_method)(
+               bt_self_component_filter *self_component,
+               bt_self_component_port_output *self_port,
+               const bt_port_input *other_port);
+
+typedef bt_self_component_status
+(*bt_component_class_filter_input_port_connected_method)(
+               bt_self_component_filter *self_component,
+               bt_self_component_port_input *self_port,
+               const bt_port_output *other_port);
+
+typedef bt_self_component_status
+(*bt_component_class_filter_output_port_connected_method)(
+               bt_self_component_filter *self_component,
+               bt_self_component_port_output *self_port,
+               const bt_port_input *other_port);
+
+bt_component_class *bt_component_class_filter_as_component_class(
+               bt_component_class_filter *comp_cls_filter);
+
+extern
+bt_component_class_filter *bt_component_class_filter_create(
+               const char *name,
+               bt_component_class_filter_message_iterator_next_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_init_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_init_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_finalize_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_finalize_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_accept_input_port_connection_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_accept_input_port_connection_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_accept_output_port_connection_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_accept_output_port_connection_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_input_port_connected_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_input_port_connected_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_output_port_connected_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_output_port_connected_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_query_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_query_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_message_iterator_init_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_message_iterator_init_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_message_iterator_finalize_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_message_iterator_finalize_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_message_iterator_seek_ns_from_origin_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_message_iterator_seek_ns_from_origin_method method);
+
+extern bt_component_class_status
+bt_component_class_filter_set_message_iterator_seek_beginning_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_message_iterator_seek_beginning_method method);
+
+extern bt_bool
+bt_component_class_filter_set_message_iterator_can_seek_ns_from_origin_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method method);
+
+extern bt_bool
+bt_component_class_filter_set_message_iterator_can_seek_beginning_method(
+               bt_component_class_filter *comp_class,
+               bt_component_class_filter_message_iterator_can_seek_beginning_method method);
+
+/* From component-class-sink-const.h */
+
+const bt_component_class *
+bt_component_class_sink_as_component_class_const(
+               const bt_component_class_sink *comp_cls_sink);
+
+extern void bt_component_class_sink_get_ref(
+               const bt_component_class_sink *component_class_sink);
+
+extern void bt_component_class_sink_put_ref(
+               const bt_component_class_sink *component_class_sink);
+
+/* From component-class-sink.h */
+
+typedef bt_self_component_status (*bt_component_class_sink_init_method)(
+               bt_self_component_sink *self_component,
+               const bt_value *params, void *init_method_data);
+
+typedef void (*bt_component_class_sink_finalize_method)(
+               bt_self_component_sink *self_component);
+
+typedef bt_query_status
+(*bt_component_class_sink_query_method)(
+               bt_self_component_class_sink *comp_class,
+               const bt_query_executor *query_executor,
+               const char *object, const bt_value *params,
+               const bt_value **result);
+
+typedef bt_self_component_status
+(*bt_component_class_sink_accept_input_port_connection_method)(
+               bt_self_component_sink *self_component,
+               bt_self_component_port_input *self_port,
+               const bt_port_output *other_port);
+
+typedef bt_self_component_status
+(*bt_component_class_sink_input_port_connected_method)(
+               bt_self_component_sink *self_component,
+               bt_self_component_port_input *self_port,
+               const bt_port_output *other_port);
+
+typedef bt_self_component_status
+(*bt_component_class_sink_graph_is_configured_method)(
+               bt_self_component_sink *self_component);
+
+typedef bt_self_component_status (*bt_component_class_sink_consume_method)(
+       bt_self_component_sink *self_component);
+
+bt_component_class *bt_component_class_sink_as_component_class(
+               bt_component_class_sink *comp_cls_sink);
+
+extern
+bt_component_class_sink *bt_component_class_sink_create(
+               const char *name,
+               bt_component_class_sink_consume_method method);
+
+extern bt_component_class_status bt_component_class_sink_set_init_method(
+               bt_component_class_sink *comp_class,
+               bt_component_class_sink_init_method method);
+
+extern bt_component_class_status bt_component_class_sink_set_finalize_method(
+               bt_component_class_sink *comp_class,
+               bt_component_class_sink_finalize_method method);
+
+extern bt_component_class_status
+bt_component_class_sink_set_accept_input_port_connection_method(
+               bt_component_class_sink *comp_class,
+               bt_component_class_sink_accept_input_port_connection_method method);
+
+extern bt_component_class_status
+bt_component_class_sink_set_input_port_connected_method(
+               bt_component_class_sink *comp_class,
+               bt_component_class_sink_input_port_connected_method method);
+
+extern bt_component_class_status
+bt_component_class_sink_set_graph_is_configured_method(
+               bt_component_class_sink *comp_class,
+               bt_component_class_sink_graph_is_configured_method method);
+
+extern bt_component_class_status bt_component_class_sink_set_query_method(
+               bt_component_class_sink *comp_class,
+               bt_component_class_sink_query_method method);
+
+/* From self-component-class-source.h */
+
+const bt_component_class_source *
+bt_self_component_class_source_as_component_class_source(
+               bt_self_component_class_source *self_comp_cls_source);
+
+/* From self-component-class-filter.h */
+
+const bt_component_class_filter *
+bt_self_component_class_filter_as_component_class_filter(
+               bt_self_component_class_filter *self_comp_cls_filter);
+
+/* From self-component-class-sink.h */
+
+const bt_component_class_sink *
+bt_self_component_class_sink_as_component_class_sink(
+               bt_self_component_class_sink *self_comp_cls_sink);
+
+%{
+/*
+ * This hash table associates a BT component class object address to a
+ * user-defined Python class (PyObject *). The keys and values are NOT
+ * owned by this hash table. The Python class objects are owned by the
+ * Python module, which should not be unloaded until it is not possible
+ * to create a user Python component anyway.
+ *
+ * This hash table is written to when a user-defined Python component
+ * class is created by one of the bt_py3_component_class_*_create()
+ * functions.
+ *
+ * This function is read from when a user calls bt_component_create()
+ * with a component class pointer created by one of the functions above.
+ * In this case, the original Python class needs to be found to
+ * instantiate it and associate the created Python component object with
+ * a BT component object instance.
+ */
+
+static GHashTable *bt_cc_ptr_to_py_cls;
+
+static void register_cc_ptr_to_py_cls(struct bt_component_class *bt_cc,
+               PyObject *py_cls)
+{
+       if (!bt_cc_ptr_to_py_cls) {
+               /*
+                * Lazy-initializing this GHashTable because GLib
+                * might not be initialized yet and it needs to be
+                * before we call g_hash_table_new()
+                */
+               BT_LOGD_STR("Creating native component class to Python component class hash table.");
+               bt_cc_ptr_to_py_cls = g_hash_table_new(g_direct_hash, g_direct_equal);
+               BT_ASSERT(bt_cc_ptr_to_py_cls);
+       }
+
+       g_hash_table_insert(bt_cc_ptr_to_py_cls, (gpointer) bt_cc,
+               (gpointer) py_cls);
+}
+
+static PyObject *lookup_cc_ptr_to_py_cls(const bt_component_class *bt_cc)
+{
+       if (!bt_cc_ptr_to_py_cls) {
+               BT_LOGW("Cannot look up Python component class because hash table is NULL: "
+                       "comp-cls-addr=%p", bt_cc);
+               return NULL;
+       }
+
+       return (PyObject *) g_hash_table_lookup(bt_cc_ptr_to_py_cls,
+               (gconstpointer) bt_cc);
+}
+
+
+/*
+ * Useful Python objects.
+ */
+
+static PyObject *py_mod_bt2 = NULL;
+static PyObject *py_mod_bt2_exc_error_type = NULL;
+static PyObject *py_mod_bt2_exc_try_again_type = NULL;
+static PyObject *py_mod_bt2_exc_stop_type = NULL;
+static PyObject *py_mod_bt2_exc_port_connection_refused_type = NULL;
+static PyObject *py_mod_bt2_exc_msg_iter_canceled_type = NULL;
+static PyObject *py_mod_bt2_exc_invalid_query_object_type = NULL;
+static PyObject *py_mod_bt2_exc_invalid_query_params_type = NULL;
+
+static void bt_py3_cc_init_from_bt2(void)
+{
+       /*
+        * This is called once the bt2 package is loaded.
+        *
+        * Those modules and functions are needed while the package is
+        * used. Loading them here is safe because we know the bt2
+        * package is imported, and we know that the user cannot use the
+        * code here without importing bt2 first.
+        */
+       py_mod_bt2 = PyImport_ImportModule("bt2");
+       BT_ASSERT(py_mod_bt2);
+       py_mod_bt2_exc_error_type =
+               PyObject_GetAttrString(py_mod_bt2, "Error");
+       BT_ASSERT(py_mod_bt2_exc_error_type);
+       py_mod_bt2_exc_try_again_type =
+               PyObject_GetAttrString(py_mod_bt2, "TryAgain");
+       BT_ASSERT(py_mod_bt2_exc_try_again_type);
+       py_mod_bt2_exc_stop_type =
+               PyObject_GetAttrString(py_mod_bt2, "Stop");
+       BT_ASSERT(py_mod_bt2_exc_stop_type);
+       py_mod_bt2_exc_port_connection_refused_type =
+               PyObject_GetAttrString(py_mod_bt2, "PortConnectionRefused");
+       BT_ASSERT(py_mod_bt2_exc_port_connection_refused_type);
+       py_mod_bt2_exc_invalid_query_object_type =
+               PyObject_GetAttrString(py_mod_bt2, "InvalidQueryObject");
+       BT_ASSERT(py_mod_bt2_exc_invalid_query_object_type);
+       py_mod_bt2_exc_invalid_query_params_type =
+               PyObject_GetAttrString(py_mod_bt2, "InvalidQueryParams");
+       BT_ASSERT(py_mod_bt2_exc_invalid_query_params_type);
+}
+
+static void bt_py3_cc_exit_handler(void)
+{
+       /*
+        * This is an exit handler (set by the bt2 package).
+        *
+        * We only give back the references that we took in
+        * bt_py3_cc_init_from_bt2() here. The global variables continue
+        * to exist for the code of this file, but they are now borrowed
+        * references. If this code is executed, it means that somehow
+        * the modules are still loaded, so it should be safe to use
+        * them even without a strong reference.
+        *
+        * We cannot do this in the library's destructor because it
+        * gets executed once Python is already finalized.
+        */
+       Py_XDECREF(py_mod_bt2);
+       Py_XDECREF(py_mod_bt2_exc_error_type);
+       Py_XDECREF(py_mod_bt2_exc_try_again_type);
+       Py_XDECREF(py_mod_bt2_exc_stop_type);
+       Py_XDECREF(py_mod_bt2_exc_port_connection_refused_type);
+       Py_XDECREF(py_mod_bt2_exc_msg_iter_canceled_type);
+       Py_XDECREF(py_mod_bt2_exc_invalid_query_object_type);
+       Py_XDECREF(py_mod_bt2_exc_invalid_query_params_type);
+}
+
+
+/* Library destructor */
+
+__attribute__((destructor))
+static void bt_py3_native_comp_class_dtor(void) {
+       /* Destroy component class association hash table */
+       if (bt_cc_ptr_to_py_cls) {
+               BT_LOGD_STR("Destroying native component class to Python component class hash table.");
+               g_hash_table_destroy(bt_cc_ptr_to_py_cls);
+       }
+}
+
+
+// TODO: maybe we can wrap code in the Python methods (e.g. _query_from_native)
+// in a try catch and print the error there instead, it would be simpler.
+static
+void bt2_py_loge_exception(void)
+{
+       PyObject *type = NULL;
+       PyObject *value = NULL;
+       PyObject *traceback = NULL;
+       PyObject *traceback_module = NULL;
+       PyObject *format_exception_func = NULL;
+       PyObject *exc_str_list = NULL;
+       GString *msg_buf = NULL;
+       Py_ssize_t i;
+
+       BT_ASSERT(PyErr_Occurred() != NULL);
+
+       PyErr_Fetch(&type, &value, &traceback);
+
+       BT_ASSERT(type != NULL);
+
+       /*
+       * traceback can be NULL, when we fail to call a Python function from the
+       * native code (there is not Python stack at that point).  E.g.:
+       *
+       *   TypeError: _accept_port_connection_from_native() takes 3 positional arguments but 4 were given
+       */
+
+
+       /* Make sure `value` is what we expected - an instance of `type`. */
+       PyErr_NormalizeException(&type, &value, &traceback);
+
+       traceback_module = PyImport_ImportModule("traceback");
+       if (!traceback_module) {
+               BT_LOGE_STR("Failed to log Python exception (could not import traceback module).");
+               goto end;
+       }
+
+       format_exception_func = PyObject_GetAttrString(traceback_module,
+               traceback ? "format_exception" : "format_exception_only");
+       if (!format_exception_func) {
+               BT_LOGE_STR("Failed to log Python exception (could not find format_exception).");
+               goto end;
+       }
+
+       if (!PyCallable_Check(format_exception_func)) {
+               BT_LOGE_STR("Failed to log Python exception (format_exception is not callable).");
+               goto end;
+       }
+
+       exc_str_list = PyObject_CallFunctionObjArgs(format_exception_func, type, value, traceback, NULL);
+       if (!exc_str_list) {
+               PyErr_Print();
+               BT_LOGE_STR("Failed to log Python exception (call to format_exception failed).");
+               goto end;
+       }
+
+       msg_buf = g_string_new(NULL);
+
+       for (i = 0; i < PyList_Size(exc_str_list); i++) {
+               PyObject *exc_str = PyList_GetItem(exc_str_list, i);
+               const char *str = PyUnicode_AsUTF8(exc_str);
+               if (!str) {
+                       BT_LOGE_STR("Failed to log Python exception (failed to convert exception to string).");
+                       goto end;
+               }
+
+               g_string_append(msg_buf, str);
+       }
+
+       BT_LOGE_STR(msg_buf->str);
+
+end:
+       if (msg_buf) {
+               g_string_free(msg_buf, TRUE);
+       }
+       Py_XDECREF(exc_str_list);
+       Py_XDECREF(format_exception_func);
+       Py_XDECREF(traceback_module);
+
+       /* PyErr_Restore takes our references. */
+       PyErr_Restore(type, value, traceback);
+}
+
+static bt_self_component_status bt_py3_exc_to_self_component_status(void)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       PyObject *exc = PyErr_Occurred();
+
+       if (!exc) {
+               goto end;
+       }
+
+       if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_try_again_type)) {
+               status = BT_SELF_COMPONENT_STATUS_AGAIN;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_stop_type)) {
+               status = BT_SELF_COMPONENT_STATUS_END;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_port_connection_refused_type)) {
+               status = BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION;
+       } else {
+               bt2_py_loge_exception();
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+       }
+
+end:
+       PyErr_Clear();
+       return status;
+}
+
+/* Component class proxy methods (delegate to the attached Python object) */
+
+static bt_self_message_iterator_status
+bt_py3_exc_to_self_message_iterator_status(void)
+{
+       enum bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       PyObject *exc = PyErr_Occurred();
+
+       if (!exc) {
+               goto end;
+       }
+
+       if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_stop_type)) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+       } else if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_try_again_type)) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN;
+       } else {
+               bt2_py_loge_exception();
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+       }
+
+end:
+       PyErr_Clear();
+       return status;
+}
+
+static enum bt_query_status bt_py3_exc_to_query_status(void)
+{
+       enum bt_query_status status = BT_QUERY_STATUS_OK;
+       PyObject *exc = PyErr_Occurred();
+
+       if (!exc) {
+               goto end;
+       }
+
+       if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_invalid_query_object_type)) {
+               status = BT_QUERY_STATUS_INVALID_OBJECT;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_invalid_query_params_type)) {
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+       } else if (PyErr_GivenExceptionMatches(exc,
+                       py_mod_bt2_exc_try_again_type)) {
+               status = BT_QUERY_STATUS_AGAIN;
+       } else {
+               bt2_py_loge_exception();
+               status = BT_QUERY_STATUS_ERROR;
+       }
+
+end:
+       PyErr_Clear();
+       return status;
+}
+
+static bt_self_component_status
+bt_py3_component_class_init(
+               bt_self_component *self_component,
+               void *self_component_v,
+               swig_type_info *self_comp_cls_type_swig_type,
+               const bt_value *params,
+               void *init_method_data)
+{
+       const bt_component *component = bt_self_component_as_component(self_component);
+       const bt_component_class *component_class = bt_component_borrow_class_const(component);
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       PyObject *py_cls = NULL;
+       PyObject *py_comp = NULL;
+       PyObject *py_params_ptr = NULL;
+       PyObject *py_comp_ptr = NULL;
+
+       (void) init_method_data;
+
+       BT_ASSERT(self_component);
+       BT_ASSERT(self_component_v);
+       BT_ASSERT(self_comp_cls_type_swig_type);
+
+       /*
+        * Get the user-defined Python class which created this
+        * component's class in the first place (borrowed
+        * reference).
+        */
+       py_cls = lookup_cc_ptr_to_py_cls(component_class);
+       if (!py_cls) {
+               BT_LOGE("Cannot find Python class associated to native component class: "
+                       "comp-cls-addr=%p", component_class);
+               goto error;
+       }
+
+       /* Parameters pointer -> SWIG pointer Python object */
+       py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params),
+               SWIGTYPE_p_bt_value, 0);
+       if (!py_params_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_v),
+               self_comp_cls_type_swig_type, 0);
+       if (!py_comp_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       /*
+        * Do the equivalent of this:
+        *
+        *     py_comp = py_cls._init_from_native(py_comp_ptr, py_params_ptr)
+        *
+        * _UserComponentType._init_from_native() calls the Python
+        * component object's __init__() function.
+        */
+       py_comp = PyObject_CallMethod(py_cls,
+               "_init_from_native", "(OO)", py_comp_ptr, py_params_ptr);
+       if (!py_comp) {
+               bt2_py_loge_exception();
+               BT_LOGE("Failed to call Python class's _init_from_native() method: "
+                       "py-cls-addr=%p", py_cls);
+
+               goto error;
+       }
+
+       /*
+        * Our user Python component object is now fully created and
+        * initialized by the user. Since we just created it, this
+        * native component is its only (persistent) owner.
+        */
+       bt_self_component_set_data(self_component, py_comp);
+       py_comp = NULL;
+       goto end;
+
+error:
+       status = BT_SELF_COMPONENT_STATUS_ERROR;
+
+       /*
+        * Clear any exception: we're returning a bad status anyway. If
+        * this call originated from Python (creation from a plugin's
+        * component class, for example), then the user gets an
+        * appropriate creation error.
+        */
+       PyErr_Clear();
+
+end:
+       Py_XDECREF(py_comp);
+       Py_XDECREF(py_params_ptr);
+       Py_XDECREF(py_comp_ptr);
+       return status;
+}
+
+/*
+ * Method of bt_component_class_source to initialize a bt_self_component_source
+ * of that class.
+ */
+
+static bt_self_component_status
+bt_py3_component_class_source_init(bt_self_component_source *self_component_source,
+               const bt_value *params, void *init_method_data)
+{
+       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
+       return bt_py3_component_class_init(
+               self_component,
+               self_component_source,
+               SWIGTYPE_p_bt_self_component_source,
+               params, init_method_data);
+}
+
+static bt_self_component_status
+bt_py3_component_class_filter_init(bt_self_component_filter *self_component_filter,
+               const bt_value *params, void *init_method_data)
+{
+       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
+       return bt_py3_component_class_init(
+               self_component,
+               self_component_filter,
+               SWIGTYPE_p_bt_self_component_filter,
+               params, init_method_data);
+}
+
+static bt_self_component_status
+bt_py3_component_class_sink_init(bt_self_component_sink *self_component_sink,
+               const bt_value *params, void *init_method_data)
+{
+       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
+       return bt_py3_component_class_init(
+               self_component,
+               self_component_sink,
+               SWIGTYPE_p_bt_self_component_sink,
+               params, init_method_data);
+}
+
+static void bt_py3_component_class_finalize(bt_self_component *self_component)
+{
+       PyObject *py_comp = bt_self_component_get_data(self_component);
+       BT_ASSERT(py_comp);
+
+       /* Call user's _finalize() method */
+       PyObject *py_method_result = PyObject_CallMethod(py_comp,
+               "_finalize", NULL);
+
+       if (PyErr_Occurred()) {
+               BT_LOGW("User's _finalize() method raised an exception: ignoring.");
+       }
+
+       /*
+        * Ignore any exception raised by the _finalize() method because
+        * it won't change anything at this point: the component is
+        * being destroyed anyway.
+        */
+       PyErr_Clear();
+       Py_XDECREF(py_method_result);
+       Py_DECREF(py_comp);
+}
+
+static void
+bt_py3_component_class_source_finalize(bt_self_component_source *self_component_source)
+{
+       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
+       bt_py3_component_class_finalize(self_component);
+}
+
+static void
+bt_py3_component_class_filter_finalize(bt_self_component_filter *self_component_filter)
+{
+       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
+       bt_py3_component_class_finalize(self_component);
+}
+
+static void
+bt_py3_component_class_sink_finalize(bt_self_component_sink *self_component_sink)
+{
+       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
+       bt_py3_component_class_finalize(self_component);
+}
+
+static bt_self_component_status
+bt_py3_component_class_accept_port_connection(
+               bt_self_component *self_component,
+               bt_self_component_port *self_component_port,
+               bt_port_type self_component_port_type,
+               const bt_port *other_port)
+{
+       enum bt_self_component_status status;
+       PyObject *py_comp = NULL;
+       PyObject *py_self_port_ptr = NULL;
+       PyObject *py_other_port_ptr = NULL;
+       PyObject *py_method_result = NULL;
+
+       py_comp = bt_self_component_get_data(self_component);
+       BT_ASSERT(py_comp);
+
+       swig_type_info *self_component_port_swig_type = NULL;
+       swig_type_info *other_port_swig_type = NULL;
+       switch (self_component_port_type) {
+       case BT_PORT_TYPE_INPUT:
+               self_component_port_swig_type = SWIGTYPE_p_bt_self_component_port_input;
+               other_port_swig_type = SWIGTYPE_p_bt_port_output;
+               break;
+       case BT_PORT_TYPE_OUTPUT:
+               self_component_port_swig_type = SWIGTYPE_p_bt_self_component_port_output;
+               other_port_swig_type = SWIGTYPE_p_bt_port_input;
+               break;
+       }
+       BT_ASSERT(self_component_port_swig_type != NULL);
+       BT_ASSERT(other_port_swig_type != NULL);
+
+       py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port),
+               self_component_port_swig_type, 0);
+       if (!py_self_port_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port),
+               other_port_swig_type, 0);
+       if (!py_other_port_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_accept_port_connection_from_native", "(OiO)", py_self_port_ptr,
+               self_component_port_type, py_other_port_ptr);
+
+       status = bt_py3_exc_to_self_component_status();
+       if (!py_method_result && status == BT_SELF_COMPONENT_STATUS_OK) {
+               /* Pretty sure this should never happen, but just in case */
+               BT_LOGE("User's _accept_port_connection() method failed without raising an exception: "
+                       "status=%d", status);
+               goto error;
+       }
+
+       if (status == BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
+               /*
+                * Looks like the user method raised
+                * PortConnectionRefused: accept this like if it
+                * returned False.
+                */
+               goto end;
+       } else if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               BT_LOGE("User's _accept_port_connection() raised an unexpected exception: "
+                       "status=%d", status);
+               goto error;
+       }
+
+       BT_ASSERT(PyBool_Check(py_method_result));
+
+       if (py_method_result == Py_True) {
+               status = BT_SELF_COMPONENT_STATUS_OK;
+       } else {
+               status = BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION;
+       }
+
+       goto end;
+
+error:
+       status = BT_SELF_COMPONENT_STATUS_ERROR;
+
+       /*
+        * Clear any exception: we're returning a bad status anyway. If
+        * this call originated from Python, then the user gets an
+        * appropriate error.
+        */
+       PyErr_Clear();
+
+end:
+       Py_XDECREF(py_self_port_ptr);
+       Py_XDECREF(py_other_port_ptr);
+       Py_XDECREF(py_method_result);
+       return status;
+}
+
+static bt_self_component_status
+bt_py3_component_class_source_accept_output_port_connection(bt_self_component_source *self_component_source,
+        bt_self_component_port_output *self_component_port_output,
+        const bt_port_input *other_port_input)
+{
+       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
+       bt_self_component_port *self_component_port = bt_self_component_port_output_as_self_component_port(self_component_port_output);
+       const bt_port *other_port = bt_port_input_as_port_const(other_port_input);
+       return bt_py3_component_class_accept_port_connection(self_component, self_component_port, BT_PORT_TYPE_OUTPUT, other_port);
+}
+
+static bt_self_component_status
+bt_py3_component_class_filter_accept_input_port_connection(bt_self_component_filter *self_component_filter,
+               bt_self_component_port_input *self_component_port_input,
+               const bt_port_output *other_port_output)
+{
+       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
+       bt_self_component_port *self_component_port = bt_self_component_port_input_as_self_component_port(self_component_port_input);
+       const bt_port *other_port = bt_port_output_as_port_const(other_port_output);
+       return bt_py3_component_class_accept_port_connection(self_component, self_component_port, BT_PORT_TYPE_INPUT, other_port);
+}
+
+static bt_self_component_status
+bt_py3_component_class_filter_accept_output_port_connection(bt_self_component_filter *self_component_filter,
+               bt_self_component_port_output *self_component_port_output,
+               const bt_port_input *other_port_input)
+{
+       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
+       bt_self_component_port *self_component_port = bt_self_component_port_output_as_self_component_port(self_component_port_output);
+       const bt_port *other_port = bt_port_input_as_port_const(other_port_input);
+       return bt_py3_component_class_accept_port_connection(self_component, self_component_port, BT_PORT_TYPE_OUTPUT, other_port);
+}
+
+static bt_self_component_status
+bt_py3_component_class_sink_accept_input_port_connection(bt_self_component_sink *self_component_sink,
+               bt_self_component_port_input *self_component_port_input,
+               const bt_port_output *other_port_output)
+{
+       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
+       bt_self_component_port *self_component_port = bt_self_component_port_input_as_self_component_port(self_component_port_input);
+       const bt_port *other_port = bt_port_output_as_port_const(other_port_output);
+       return bt_py3_component_class_accept_port_connection(self_component, self_component_port, BT_PORT_TYPE_INPUT, other_port);
+}
+
+static bt_self_component_status
+bt_py3_component_class_port_connected(
+               bt_self_component *self_component,
+               void *self_component_port,
+               swig_type_info *self_component_port_swig_type,
+               bt_port_type self_component_port_type,
+               const void *other_port,
+               swig_type_info *other_port_swig_type)
+{
+       bt_self_component_status status;
+       PyObject *py_comp = NULL;
+       PyObject *py_self_port_ptr = NULL;
+       PyObject *py_other_port_ptr = NULL;
+       PyObject *py_method_result = NULL;
+
+       py_comp = bt_self_component_get_data(self_component);
+       BT_ASSERT(py_comp);
+
+       py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port),
+               self_component_port_swig_type, 0);
+       if (!py_self_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port),
+               other_port_swig_type, 0);
+       if (!py_other_port_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;       }
+
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_port_connected_from_native", "(OiO)", py_self_port_ptr,
+               self_component_port_type, py_other_port_ptr);
+
+       BT_ASSERT(!py_method_result || py_method_result == Py_None);
+
+       status = bt_py3_exc_to_self_component_status();
+
+end:
+       Py_XDECREF(py_self_port_ptr);
+       Py_XDECREF(py_other_port_ptr);
+       Py_XDECREF(py_method_result);
+
+       return status;
+}
+
+static bt_self_component_status
+bt_py3_component_class_source_output_port_connected(
+               bt_self_component_source *self_component_source,
+               bt_self_component_port_output *self_component_port_output,
+               const bt_port_input *other_port_input)
+{
+       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
+
+       return bt_py3_component_class_port_connected(
+               self_component,
+               self_component_port_output,
+               SWIGTYPE_p_bt_self_component_port_output,
+               BT_PORT_TYPE_OUTPUT,
+               other_port_input,
+               SWIGTYPE_p_bt_port_input);
+}
+
+static bt_self_component_status
+bt_py3_component_class_filter_input_port_connected(
+               bt_self_component_filter *self_component_filter,
+               bt_self_component_port_input *self_component_port_input,
+               const bt_port_output *other_port_output)
+{
+       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
+
+       return bt_py3_component_class_port_connected(
+               self_component,
+               self_component_port_input,
+               SWIGTYPE_p_bt_self_component_port_input,
+               BT_PORT_TYPE_INPUT,
+               other_port_output,
+               SWIGTYPE_p_bt_port_output);
+}
+
+static bt_self_component_status
+bt_py3_component_class_filter_output_port_connected(
+               bt_self_component_filter *self_component_filter,
+               bt_self_component_port_output *self_component_port_output,
+               const bt_port_input *other_port_input)
+{
+       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
+
+       return bt_py3_component_class_port_connected(
+               self_component,
+               self_component_port_output,
+               SWIGTYPE_p_bt_self_component_port_output,
+               BT_PORT_TYPE_OUTPUT,
+               other_port_input,
+               SWIGTYPE_p_bt_port_input);
+}
+
+static bt_self_component_status
+bt_py3_component_class_sink_input_port_connected(
+               bt_self_component_sink *self_component_sink,
+               bt_self_component_port_input *self_component_port_input,
+               const bt_port_output *other_port_output)
+{
+       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
+
+       return bt_py3_component_class_port_connected(
+               self_component,
+               self_component_port_input,
+               SWIGTYPE_p_bt_self_component_port_input,
+               BT_PORT_TYPE_INPUT,
+               other_port_output,
+               SWIGTYPE_p_bt_port_output);
+}
+
+static bt_self_component_status
+bt_py3_component_class_sink_graph_is_configured(bt_self_component_sink *self_component_sink)
+{
+       PyObject *py_comp = NULL;
+       PyObject *py_method_result = NULL;
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
+
+       py_comp = bt_self_component_get_data(self_component);
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_graph_is_configured_from_native", NULL);
+
+       BT_ASSERT(!py_method_result || py_method_result == Py_None);
+
+       status = bt_py3_exc_to_self_component_status();
+
+       Py_XDECREF(py_method_result);
+
+       return status;
+}
+
+static bt_query_status
+bt_py3_component_class_query(
+               const bt_component_class *component_class,
+               const bt_query_executor *query_executor,
+               const char *object, const bt_value *params,
+               const bt_value **result)
+{
+       PyObject *py_cls = NULL;
+       PyObject *py_params_ptr = NULL;
+       PyObject *py_query_exec_ptr = NULL;
+       PyObject *py_query_func = NULL;
+       PyObject *py_object = NULL;
+       PyObject *py_results_addr = NULL;
+       bt_query_status status = BT_QUERY_STATUS_OK;
+
+       py_cls = lookup_cc_ptr_to_py_cls(component_class);
+       if (!py_cls) {
+               BT_LOGE("Cannot find Python class associated to native component class: "
+                       "comp-cls-addr=%p", component_class);
+               goto error;
+       }
+
+       py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params),
+               SWIGTYPE_p_bt_value, 0);
+       if (!py_params_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_query_exec_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(query_executor),
+               SWIGTYPE_p_bt_query_executor, 0);
+       if (!py_query_exec_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_object = SWIG_FromCharPtr(object);
+       if (!py_object) {
+               BT_LOGE_STR("Failed to create a Python string.");
+               goto error;
+       }
+
+       py_results_addr = PyObject_CallMethod(py_cls,
+               "_query_from_native", "(OOO)", py_query_exec_ptr,
+               py_object, py_params_ptr);
+
+       if (!py_results_addr) {
+               BT_LOGE("Failed to call Python class's _query_from_native() method: "
+                       "py-cls-addr=%p", py_cls);
+               status = bt_py3_exc_to_query_status();
+               goto end;
+       }
+
+       /*
+        * The returned object, on success, is an integer object
+        * (PyLong) containing the address of a BT value object (new
+        * reference).
+        */
+       *result = PyLong_AsVoidPtr(py_results_addr);
+       BT_ASSERT(!PyErr_Occurred());
+       BT_ASSERT(*result);
+       goto end;
+
+error:
+       PyErr_Clear();
+       status = BT_QUERY_STATUS_ERROR;
+
+end:
+       Py_XDECREF(py_params_ptr);
+       Py_XDECREF(py_query_exec_ptr);
+       Py_XDECREF(py_query_func);
+       Py_XDECREF(py_object);
+       Py_XDECREF(py_results_addr);
+       return status;
+}
+
+static bt_query_status
+bt_py3_component_class_source_query(
+               bt_self_component_class_source *self_component_class_source,
+               const bt_query_executor *query_executor,
+               const char *object, const bt_value *params,
+               const bt_value **result)
+{
+       const bt_component_class_source *component_class_source = bt_self_component_class_source_as_component_class_source(self_component_class_source);
+       const bt_component_class *component_class = bt_component_class_source_as_component_class_const(component_class_source);
+       return bt_py3_component_class_query(component_class, query_executor, object, params, result);
+}
+
+static bt_query_status
+bt_py3_component_class_filter_query(
+               bt_self_component_class_filter *self_component_class_filter,
+               const bt_query_executor *query_executor,
+               const char *object, const bt_value *params,
+               const bt_value **result)
+{
+       const bt_component_class_filter *component_class_filter = bt_self_component_class_filter_as_component_class_filter(self_component_class_filter);
+       const bt_component_class *component_class = bt_component_class_filter_as_component_class_const(component_class_filter);
+       return bt_py3_component_class_query(component_class, query_executor, object, params, result);
+}
+
+static bt_query_status
+bt_py3_component_class_sink_query(
+               bt_self_component_class_sink *self_component_class_sink,
+               const bt_query_executor *query_executor,
+               const char *object, const bt_value *params,
+               const bt_value **result)
+{
+       const bt_component_class_sink *component_class_sink = bt_self_component_class_sink_as_component_class_sink(self_component_class_sink);
+       const bt_component_class *component_class = bt_component_class_sink_as_component_class_const(component_class_sink);
+       return bt_py3_component_class_query(component_class, query_executor, object, params, result);
+}
+
+static bt_self_message_iterator_status
+bt_py3_component_class_message_iterator_init(
+               bt_self_message_iterator *self_message_iterator,
+               bt_self_component *self_component,
+               bt_self_component_port_output *self_component_port_output)
+{
+       bt_self_message_iterator_status status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       PyObject *py_comp_cls = NULL;
+       PyObject *py_iter_cls = NULL;
+       PyObject *py_iter_ptr = NULL;
+       PyObject *py_component_port_output_ptr = NULL;
+       PyObject *py_init_method_result = NULL;
+       PyObject *py_iter = NULL;
+       PyObject *py_comp;
+
+       py_comp = bt_self_component_get_data(self_component);
+
+       /* Find user's Python message iterator class */
+       py_comp_cls = PyObject_GetAttrString(py_comp, "__class__");
+       if (!py_comp_cls) {
+               BT_LOGE_STR("Cannot get Python object's `__class__` attribute.");
+               goto error;
+       }
+
+       py_iter_cls = PyObject_GetAttrString(py_comp_cls, "_iter_cls");
+       if (!py_iter_cls) {
+               BT_LOGE_STR("Cannot get Python class's `_iter_cls` attribute.");
+               goto error;
+       }
+
+       py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_message_iterator),
+               SWIGTYPE_p_bt_self_message_iterator, 0);
+       if (!py_iter_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       /*
+        * Create object with borrowed native message iterator
+        * reference:
+        *
+        *     py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr)
+        */
+       py_iter = PyObject_CallMethod(py_iter_cls, "__new__",
+               "(OO)", py_iter_cls, py_iter_ptr);
+       if (!py_iter) {
+               BT_LOGE("Failed to call Python class's __new__() method: "
+                       "py-cls-addr=%p", py_iter_cls);
+               bt2_py_loge_exception();
+               goto error;
+       }
+
+       /*
+        * Initialize object:
+        *
+        *     py_iter.__init__(self_output_port)
+        *
+         * through the _init_for_native helper static method.
+        *
+        * At this point, py_iter._ptr is set, so this initialization
+        * function has access to self._component (which gives it the
+        * user Python component object from which the iterator was
+        * created).
+        */
+        py_component_port_output_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port_output),
+               SWIGTYPE_p_bt_self_component_port_output, 0);
+       if (!py_component_port_output_ptr) {
+               BT_LOGE_STR("Failed to create a SWIG pointer object.");
+               goto error;
+       }
+
+       py_init_method_result = PyObject_CallMethod(py_iter, "_init_from_native", "O", py_component_port_output_ptr);
+       if (!py_init_method_result) {
+               BT_LOGE_STR("User's __init__() method failed.");
+               bt2_py_loge_exception();
+               goto error;
+       }
+
+       /*
+        * Since the Python code can never instantiate a user-defined
+        * message iterator class, the native message iterator
+        * object does NOT belong to a user Python message iterator
+        * object (borrowed reference). However this Python object is
+        * owned by this native message iterator object.
+        *
+        * In the Python world, the lifetime of the native message
+        * iterator is managed by a _GenericMessageIterator
+        * instance:
+        *
+        *     _GenericMessageIterator instance:
+        *         owns a native bt_message_iterator object (iter)
+        *             owns a _UserMessageIterator instance (py_iter)
+        *                 self._ptr is a borrowed reference to the
+        *                 native bt_private_connection_private_message_iterator
+        *                 object (iter)
+        */
+       bt_self_message_iterator_set_data(self_message_iterator, py_iter);
+       py_iter = NULL;
+       goto end;
+
+error:
+       status = bt_py3_exc_to_self_message_iterator_status();
+       if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+               /*
+                * Looks like there wasn't any exception from the Python
+                * side, but we're still in an error state here.
+                */
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+       }
+
+       /*
+        * Clear any exception: we're returning a bad status anyway. If
+        * this call originated from Python, then the user gets an
+        * appropriate creation error.
+        */
+       PyErr_Clear();
+
+end:
+       Py_XDECREF(py_comp_cls);
+       Py_XDECREF(py_iter_cls);
+       Py_XDECREF(py_iter_ptr);
+       Py_XDECREF(py_component_port_output_ptr);
+       Py_XDECREF(py_init_method_result);
+       Py_XDECREF(py_iter);
+       return status;
+}
+
+static bt_self_message_iterator_status
+bt_py3_component_class_source_message_iterator_init(
+               bt_self_message_iterator *self_message_iterator,
+               bt_self_component_source *self_component_source,
+               bt_self_component_port_output *self_component_port_output)
+{
+       bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
+       return bt_py3_component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output);
+}
+
+static bt_self_message_iterator_status
+bt_py3_component_class_filter_message_iterator_init(
+               bt_self_message_iterator *self_message_iterator,
+               bt_self_component_filter *self_component_filter,
+               bt_self_component_port_output *self_component_port_output)
+{
+       bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
+       return bt_py3_component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output);
+}
+
+static void
+bt_py3_component_class_message_iterator_finalize(
+               bt_self_message_iterator *message_iterator)
+{
+       PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator);
+       PyObject *py_method_result = NULL;
+
+       BT_ASSERT(py_message_iter);
+
+       /* Call user's _finalize() method */
+       py_method_result = PyObject_CallMethod(py_message_iter,
+               "_finalize", NULL);
+
+       if (PyErr_Occurred()) {
+               BT_LOGW("User's _finalize() method raised an exception: ignoring.");
+       }
+
+       /*
+        * Ignore any exception raised by the _finalize() method because
+        * it won't change anything at this point: the component is
+        * being destroyed anyway.
+        */
+       PyErr_Clear();
+       Py_XDECREF(py_method_result);
+       Py_DECREF(py_message_iter);
+}
+
+/* Valid for both sources and filters. */
+
+static bt_self_message_iterator_status
+bt_py3_component_class_message_iterator_next(
+                       bt_self_message_iterator *message_iterator,
+                       bt_message_array_const msgs, uint64_t capacity,
+                       uint64_t *count)
+{
+       bt_self_message_iterator_status status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator);
+       PyObject *py_method_result = NULL;
+
+       BT_ASSERT(py_message_iter);
+       py_method_result = PyObject_CallMethod(py_message_iter,
+               "_next_from_native", NULL);
+       if (!py_method_result) {
+               status = bt_py3_exc_to_self_message_iterator_status();
+               BT_ASSERT(status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK);
+               goto end;
+       }
+
+       /*
+        * The returned object, on success, is an integer object
+        * (PyLong) containing the address of a native message
+        * object (which is now ours).
+        */
+       msgs[0] = PyLong_AsVoidPtr(py_method_result);
+       *count = 1;
+
+       /* Clear potential overflow error; should never happen */
+       BT_ASSERT(!PyErr_Occurred());
+       goto end;
+
+end:
+       Py_XDECREF(py_method_result);
+       return status;
+}
+
+static bt_self_component_status
+bt_py3_component_class_sink_consume(bt_self_component_sink *self_component_sink)
+{
+       bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
+       PyObject *py_comp = bt_self_component_get_data(self_component);
+       PyObject *py_method_result = NULL;
+       bt_self_component_status status;
+
+       BT_ASSERT(py_comp);
+       py_method_result = PyObject_CallMethod(py_comp,
+               "_consume", NULL);
+
+       status = bt_py3_exc_to_self_component_status();
+       if (!py_method_result && status == BT_SELF_COMPONENT_STATUS_OK) {
+               /* Pretty sure this should never happen, but just in case */
+               BT_LOGE("User's _consume() method failed without raising an exception: "
+                       "status=%d", status);
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+       }
+
+       Py_XDECREF(py_method_result);
+       return status;
+}
+
+static
+int bt_py3_component_class_set_help_and_desc(
+               bt_component_class *component_class,
+               const char *description, const char *help)
+{
+       int ret;
+
+       if (description) {
+               ret = bt_component_class_set_description(component_class, description);
+               if (ret) {
+                       BT_LOGE("Cannot set component class's description: "
+                               "comp-cls-addr=%p", component_class);
+                       goto end;
+               }
+       }
+
+       if (help) {
+               ret = bt_component_class_set_help(component_class, help);
+               if (ret) {
+                       BT_LOGE("Cannot set component class's help text: "
+                               "comp-cls-addr=%p", component_class);
+                       goto end;
+               }
+       }
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static
+bt_component_class_source *bt_py3_component_class_source_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help)
+{
+       bt_component_class_source *component_class_source;
+       bt_component_class *component_class;
+       int ret;
+
+       BT_ASSERT(py_cls);
+
+       component_class_source = bt_component_class_source_create(name,
+               bt_py3_component_class_message_iterator_next);
+       if (!component_class_source) {
+               BT_LOGE_STR("Cannot create source component class.");
+               goto end;
+       }
+
+       component_class = bt_component_class_source_as_component_class(component_class_source);
+
+       if (bt_py3_component_class_set_help_and_desc(component_class, description, help)) {
+               goto end;
+       }
+
+       ret = bt_component_class_source_set_init_method(component_class_source, bt_py3_component_class_source_init);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_source_set_finalize_method (component_class_source, bt_py3_component_class_source_finalize);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_source_set_accept_output_port_connection_method(component_class_source,
+               bt_py3_component_class_source_accept_output_port_connection);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_source_set_output_port_connected_method(component_class_source,
+               bt_py3_component_class_source_output_port_connected);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_source_set_query_method(component_class_source, bt_py3_component_class_source_query);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_source_set_message_iterator_init_method(
+               component_class_source, bt_py3_component_class_source_message_iterator_init);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_source_set_message_iterator_finalize_method(
+               component_class_source, bt_py3_component_class_message_iterator_finalize);
+       BT_ASSERT(ret == 0);
+
+       register_cc_ptr_to_py_cls(component_class, py_cls);
+
+end:
+       return component_class_source;
+}
+
+static
+bt_component_class_filter *bt_py3_component_class_filter_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help)
+{
+       bt_component_class *component_class;
+       bt_component_class_filter *component_class_filter;
+       int ret;
+
+       BT_ASSERT(py_cls);
+
+       component_class_filter = bt_component_class_filter_create(name,
+               bt_py3_component_class_message_iterator_next);
+       if (!component_class_filter) {
+               BT_LOGE_STR("Cannot create filter component class.");
+               goto end;
+       }
+
+       component_class = bt_component_class_filter_as_component_class(component_class_filter);
+
+       if (bt_py3_component_class_set_help_and_desc(component_class, description, help)) {
+               goto end;
+       }
+
+       ret = bt_component_class_filter_set_init_method(component_class_filter, bt_py3_component_class_filter_init);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_filter_set_finalize_method (component_class_filter, bt_py3_component_class_filter_finalize);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_filter_set_accept_input_port_connection_method(component_class_filter,
+               bt_py3_component_class_filter_accept_input_port_connection);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_filter_set_accept_output_port_connection_method(component_class_filter,
+               bt_py3_component_class_filter_accept_output_port_connection);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_filter_set_input_port_connected_method(component_class_filter,
+               bt_py3_component_class_filter_input_port_connected);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_filter_set_output_port_connected_method(component_class_filter,
+               bt_py3_component_class_filter_output_port_connected);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_filter_set_query_method(component_class_filter, bt_py3_component_class_filter_query);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_filter_set_message_iterator_init_method(
+               component_class_filter, bt_py3_component_class_filter_message_iterator_init);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_filter_set_message_iterator_finalize_method(
+               component_class_filter, bt_py3_component_class_message_iterator_finalize);
+       BT_ASSERT(ret == 0);
+
+       register_cc_ptr_to_py_cls(component_class, py_cls);
+
+end:
+       return component_class_filter;
+}
+
+static
+bt_component_class_sink *bt_py3_component_class_sink_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help)
+{
+       bt_component_class_sink *component_class_sink;
+       bt_component_class *component_class;
+       int ret;
+
+       BT_ASSERT(py_cls);
+
+       component_class_sink = bt_component_class_sink_create(name, bt_py3_component_class_sink_consume);
+
+       if (!component_class_sink) {
+               BT_LOGE_STR("Cannot create sink component class.");
+               goto end;
+       }
+
+       component_class = bt_component_class_sink_as_component_class(component_class_sink);
+
+       if (bt_py3_component_class_set_help_and_desc(component_class, description, help)) {
+               goto end;
+       }
+
+       ret = bt_component_class_sink_set_init_method(component_class_sink, bt_py3_component_class_sink_init);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_sink_set_finalize_method(component_class_sink, bt_py3_component_class_sink_finalize);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_sink_set_accept_input_port_connection_method(component_class_sink,
+               bt_py3_component_class_sink_accept_input_port_connection);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_sink_set_input_port_connected_method(component_class_sink,
+               bt_py3_component_class_sink_input_port_connected);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_sink_set_graph_is_configured_method(component_class_sink,
+               bt_py3_component_class_sink_graph_is_configured);
+       BT_ASSERT(ret == 0);
+       ret = bt_component_class_sink_set_query_method(component_class_sink, bt_py3_component_class_sink_query);
+       BT_ASSERT(ret == 0);
+
+       register_cc_ptr_to_py_cls(component_class, py_cls);
+
+end:
+       return component_class_sink;
+}
+%}
+
+struct bt_component_class_source *bt_py3_component_class_source_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help);
+struct bt_component_class_filter *bt_py3_component_class_filter_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help);
+struct bt_component_class_sink *bt_py3_component_class_sink_create(
+               PyObject *py_cls, const char *name, const char *description,
+               const char *help);
+void bt_py3_cc_init_from_bt2(void);
+void bt_py3_cc_exit_handler(void);
diff --git a/src/bindings/python/bt2/bt2/native_bt_connection.i b/src/bindings/python/bt2/bt2/native_bt_connection.i
new file mode 100644 (file)
index 0000000..dbdb04a
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From connection-const.h */
+
+extern const bt_port_input *bt_connection_borrow_downstream_port_const(
+               const bt_connection *connection);
+
+extern const bt_port_output *bt_connection_borrow_upstream_port_const(
+               const bt_connection *connection);
+
+extern void bt_connection_get_ref(const bt_connection *connection);
+
+extern void bt_connection_put_ref(const bt_connection *connection);
diff --git a/src/bindings/python/bt2/bt2/native_bt_event.i b/src/bindings/python/bt2/bt2/native_bt_event.i
new file mode 100644 (file)
index 0000000..82ddbfa
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From event-const.h */
+
+typedef enum bt_event_status {
+       BT_EVENT_STATUS_OK = 0,
+       BT_EVENT_STATUS_NOMEM = -12,
+} bt_event_status;
+
+extern const bt_event_class *bt_event_borrow_class_const(
+               const bt_event *event);
+
+extern const bt_packet *bt_event_borrow_packet_const(
+               const bt_event *event);
+
+extern const bt_stream *bt_event_borrow_stream_const(
+               const bt_event *event);
+
+extern const bt_field *bt_event_borrow_common_context_field_const(
+               const bt_event *event);
+
+extern const bt_field *bt_event_borrow_specific_context_field_const(
+               const bt_event *event);
+
+extern const bt_field *bt_event_borrow_payload_field_const(
+               const bt_event *event);
+
+/* From event.h */
+
+extern bt_event_class *bt_event_borrow_class(bt_event *event);
+
+extern bt_packet *bt_event_borrow_packet(bt_event *event);
+
+extern bt_stream *bt_event_borrow_stream(bt_event *event);
+
+extern bt_field *
+bt_event_borrow_common_context_field(bt_event *event);
+
+extern bt_field *
+bt_event_borrow_specific_context_field(bt_event *event);
+
+extern bt_field *bt_event_borrow_payload_field(bt_event *event);
diff --git a/src/bindings/python/bt2/bt2/native_bt_event_class.i b/src/bindings/python/bt2/bt2/native_bt_event_class.i
new file mode 100644 (file)
index 0000000..cac0c41
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Output argument typemap for initialized event class log level output
+ * parameter (always appends).
+ */
+%typemap(in, numinputs=0)
+       (bt_event_class_log_level *OUT)
+       (bt_event_class_log_level temp = -1) {
+       $1 = &temp;
+}
+
+%typemap(argout) bt_event_class_log_level *OUT {
+       /* SWIG_Python_AppendOutput() steals the created object */
+       $result = SWIG_Python_AppendOutput($result, SWIG_From_int(*$1));
+}
+
+/* From event-class-const.h */
+
+typedef enum bt_event_class_status {
+       BT_EVENT_CLASS_STATUS_OK = 0,
+       BT_EVENT_CLASS_STATUS_NOMEM = -12,
+} bt_event_class_status;
+
+typedef enum bt_event_class_log_level {
+       BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY,
+       BT_EVENT_CLASS_LOG_LEVEL_ALERT,
+       BT_EVENT_CLASS_LOG_LEVEL_CRITICAL,
+       BT_EVENT_CLASS_LOG_LEVEL_ERROR,
+       BT_EVENT_CLASS_LOG_LEVEL_WARNING,
+       BT_EVENT_CLASS_LOG_LEVEL_NOTICE,
+       BT_EVENT_CLASS_LOG_LEVEL_INFO,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE,
+       BT_EVENT_CLASS_LOG_LEVEL_DEBUG,
+} bt_event_class_log_level;
+
+extern const bt_stream_class *bt_event_class_borrow_stream_class_const(
+               const bt_event_class *event_class);
+
+extern const char *bt_event_class_get_name(const bt_event_class *event_class);
+
+extern uint64_t bt_event_class_get_id(const bt_event_class *event_class);
+
+extern bt_property_availability bt_event_class_get_log_level(
+               const bt_event_class *event_class,
+               bt_event_class_log_level *OUT);
+
+extern const char *bt_event_class_get_emf_uri(
+               const bt_event_class *event_class);
+
+extern const bt_field_class *
+bt_event_class_borrow_specific_context_field_class_const(
+               const bt_event_class *event_class);
+
+extern const bt_field_class *bt_event_class_borrow_payload_field_class_const(
+               const bt_event_class *event_class);
+
+extern void bt_event_class_get_ref(const bt_event_class *event_class);
+
+extern void bt_event_class_put_ref(const bt_event_class *event_class);
+
+/* From event-class.h */
+
+extern bt_event_class *bt_event_class_create(
+               bt_stream_class *stream_class);
+
+extern bt_event_class *bt_event_class_create_with_id(
+               bt_stream_class *stream_class, uint64_t id);
+
+extern bt_stream_class *bt_event_class_borrow_stream_class(
+               bt_event_class *event_class);
+
+extern bt_event_class_status bt_event_class_set_name(
+               bt_event_class *event_class, const char *name);
+
+extern void bt_event_class_set_log_level(bt_event_class *event_class,
+               bt_event_class_log_level log_level);
+
+extern bt_event_class_status bt_event_class_set_emf_uri(
+               bt_event_class *event_class, const char *emf_uri);
+
+extern bt_event_class_status
+bt_event_class_set_specific_context_field_class(bt_event_class *event_class,
+               bt_field_class *field_class);
+
+extern bt_field_class *
+bt_event_class_borrow_specific_context_field_class(bt_event_class *event_class);
+
+extern bt_event_class_status bt_event_class_set_payload_field_class(
+               bt_event_class *event_class,
+               bt_field_class *field_class);
+
+extern bt_field_class *bt_event_class_borrow_payload_field_class(
+               bt_event_class *event_class);
diff --git a/src/bindings/python/bt2/bt2/native_bt_field.i b/src/bindings/python/bt2/bt2/native_bt_field.i
new file mode 100644 (file)
index 0000000..f4511f4
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* For label type mappings. */
+%include "native_bt_field_class.i"
+
+/* From field-const.h */
+
+typedef enum bt_field_status {
+       BT_FIELD_STATUS_OK = 0,
+       BT_FIELD_STATUS_NOMEM = -12,
+} bt_field_status;
+
+extern const bt_field_class *bt_field_borrow_class_const(
+               const bt_field *field);
+
+extern bt_field_class_type bt_field_get_class_type(
+               const bt_field *field);
+
+extern int64_t bt_field_signed_integer_get_value(const bt_field *field);
+
+extern uint64_t bt_field_unsigned_integer_get_value(
+               const bt_field *field);
+
+extern double bt_field_real_get_value(const bt_field *field);
+
+extern bt_field_status bt_field_unsigned_enumeration_get_mapping_labels(
+               const bt_field *field,
+               bt_field_class_enumeration_mapping_label_array *LABELARRAY,
+               uint64_t *LABELCOUNT);
+
+extern bt_field_status bt_field_signed_enumeration_get_mapping_labels(
+               const bt_field *field,
+               bt_field_class_enumeration_mapping_label_array *LABELARRAY,
+               uint64_t *LABELCOUNT);
+
+extern const char *bt_field_string_get_value(const bt_field *field);
+
+extern uint64_t bt_field_string_get_length(const bt_field *field);
+
+extern const bt_field *
+bt_field_structure_borrow_member_field_by_index_const(
+               const bt_field *field, uint64_t index);
+
+extern const bt_field *
+bt_field_structure_borrow_member_field_by_name_const(
+               const bt_field *field, const char *name);
+
+extern uint64_t bt_field_array_get_length(const bt_field *field);
+
+extern const bt_field *
+bt_field_array_borrow_element_field_by_index_const(
+               const bt_field *field, uint64_t index);
+
+extern uint64_t bt_field_variant_get_selected_option_field_index(
+               const bt_field *field);
+
+extern const bt_field *
+bt_field_variant_borrow_selected_option_field_const(
+               const bt_field *field);
+
+/* From field.h */
+
+extern void bt_field_signed_integer_set_value(bt_field *field,
+               int64_t value);
+
+extern void bt_field_unsigned_integer_set_value(bt_field *field,
+               uint64_t value);
+
+extern void bt_field_real_set_value(bt_field *field, double value);
+
+extern bt_field_status bt_field_string_set_value(bt_field *field,
+               const char *value);
+
+extern bt_field_status bt_field_string_append(bt_field *field,
+               const char *value);
+
+extern bt_field_status bt_field_string_append_with_length(bt_field *field,
+               const char *value, uint64_t length);
+
+extern bt_field_status bt_field_string_clear(bt_field *field);
+
+extern bt_field *bt_field_structure_borrow_member_field_by_index(
+               bt_field *field, uint64_t index);
+
+extern bt_field *bt_field_structure_borrow_member_field_by_name(
+               bt_field *field, const char *name);
+
+extern bt_field *bt_field_array_borrow_element_field_by_index(
+               bt_field *field, uint64_t index);
+
+extern bt_field_status bt_field_dynamic_array_set_length(bt_field *field,
+               uint64_t length);
+
+extern bt_field_status bt_field_variant_select_option_field(
+               bt_field *field, uint64_t index);
+
+extern bt_field *bt_field_variant_borrow_selected_option_field(
+               bt_field *field);
diff --git a/src/bindings/python/bt2/bt2/native_bt_field_class.i b/src/bindings/python/bt2/bt2/native_bt_field_class.i
new file mode 100644 (file)
index 0000000..b6173c0
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+%typemap(in, numinputs=0)
+       (bt_field_class_enumeration_mapping_label_array *LABELARRAY, uint64_t *LABELCOUNT)
+       (bt_field_class_enumeration_mapping_label_array temp_array, uint64_t temp_label_count = 0) {
+       $1 = &temp_array;
+       $2 = &temp_label_count;
+}
+
+%typemap(argout)
+       (bt_field_class_enumeration_mapping_label_array *LABELARRAY, uint64_t *LABELCOUNT) {
+       if (*$1) {
+               PyObject *py_label_list = PyList_New(*$2);
+               for (int i = 0; i < *$2; i++) {
+                       PyList_SET_ITEM(py_label_list, i, PyUnicode_FromString((*$1)[i]));
+               }
+
+               $result = SWIG_Python_AppendOutput($result, py_label_list);
+       } else {
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for value output (always appends) */
+%typemap(in, numinputs=0)
+       (const bt_field_class_signed_enumeration_mapping_ranges **ENUM_RANGE_MAPPING)
+       (bt_field_class_signed_enumeration_mapping_ranges *temp_value = NULL) {
+       $1 = &temp_value;
+}
+
+%typemap(argout)
+       (const bt_field_class_signed_enumeration_mapping_ranges **ENUM_RANGE_MAPPING) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_field_class_signed_enumeration_mapping_ranges, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for value output (always appends) */
+%typemap(in, numinputs=0)
+       (const bt_field_class_unsigned_enumeration_mapping_ranges **ENUM_RANGE_MAPPING)
+       (bt_field_class_unsigned_enumeration_mapping_ranges *temp_value = NULL) {
+       $1 = &temp_value;
+}
+
+%typemap(argout)
+       (const bt_field_class_unsigned_enumeration_mapping_ranges **ENUM_RANGE_MAPPING ) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_field_class_unsigned_enumeration_mapping_ranges, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* From field-class-const.h */
+
+typedef enum bt_field_class_status {
+       BT_FIELD_CLASS_STATUS_OK = 0,
+       BT_FIELD_CLASS_STATUS_NOMEM = -12,
+} bt_field_class_status;
+
+typedef enum bt_field_class_type {
+       BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER,
+       BT_FIELD_CLASS_TYPE_SIGNED_INTEGER,
+       BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
+       BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
+       BT_FIELD_CLASS_TYPE_REAL,
+       BT_FIELD_CLASS_TYPE_STRING,
+       BT_FIELD_CLASS_TYPE_STRUCTURE,
+       BT_FIELD_CLASS_TYPE_STATIC_ARRAY,
+       BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY,
+       BT_FIELD_CLASS_TYPE_VARIANT,
+} bt_field_class_type;
+
+typedef enum bt_field_class_integer_preferred_display_base {
+       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY,
+       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL,
+       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
+} bt_field_class_integer_preferred_display_base;
+
+extern bt_field_class_type bt_field_class_get_type(
+               const bt_field_class *field_class);
+
+extern uint64_t bt_field_class_integer_get_field_value_range(
+               const bt_field_class *field_class);
+
+extern bt_field_class_integer_preferred_display_base
+bt_field_class_integer_get_preferred_display_base(
+               const bt_field_class *field_class);
+
+extern bt_bool bt_field_class_real_is_single_precision(
+               const bt_field_class *field_class);
+
+extern uint64_t bt_field_class_enumeration_get_mapping_count(
+               const bt_field_class *field_class);
+
+extern const bt_field_class_unsigned_enumeration_mapping *
+bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
+               const bt_field_class *field_class, uint64_t index);
+
+extern const bt_field_class_signed_enumeration_mapping *
+bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
+               const bt_field_class *field_class, uint64_t index);
+
+const bt_field_class_enumeration_mapping *
+bt_field_class_unsigned_enumeration_mapping_as_mapping_const(
+               const bt_field_class_unsigned_enumeration_mapping *mapping);
+
+const bt_field_class_enumeration_mapping *
+bt_field_class_signed_enumeration_mapping_as_mapping_const(
+               const bt_field_class_signed_enumeration_mapping *mapping);
+
+extern const char *bt_field_class_enumeration_mapping_get_label(
+               const bt_field_class_enumeration_mapping *mapping);
+
+extern uint64_t bt_field_class_enumeration_mapping_get_range_count(
+               const bt_field_class_enumeration_mapping *mapping);
+
+extern void
+bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
+               const bt_field_class_unsigned_enumeration_mapping *mapping,
+               uint64_t index, uint64_t *OUT, uint64_t *OUT);
+
+extern void
+bt_field_class_signed_enumeration_mapping_get_range_by_index(
+               const bt_field_class_signed_enumeration_mapping *mapping,
+               uint64_t index, int64_t *OUT, int64_t *OUT);
+
+extern bt_field_class_status
+bt_field_class_unsigned_enumeration_get_mapping_labels_by_value(
+               const bt_field_class *field_class, uint64_t value,
+               bt_field_class_enumeration_mapping_label_array *LABELARRAY,
+               uint64_t *LABELCOUNT);
+
+extern bt_field_class_status
+bt_field_class_signed_enumeration_get_mapping_labels_by_value(
+               const bt_field_class *field_class, int64_t value,
+               bt_field_class_enumeration_mapping_label_array *LABELARRAY,
+               uint64_t *LABELCOUNT);
+
+extern uint64_t bt_field_class_structure_get_member_count(
+               const bt_field_class *field_class);
+
+extern const bt_field_class_structure_member *
+bt_field_class_structure_borrow_member_by_index_const(
+               const bt_field_class *field_class, uint64_t index);
+
+extern const bt_field_class_structure_member *
+bt_field_class_structure_borrow_member_by_name_const(
+               const bt_field_class *field_class, const char *name);
+
+extern const char *bt_field_class_structure_member_get_name(
+               const bt_field_class_structure_member *member);
+
+extern const bt_field_class *
+bt_field_class_structure_member_borrow_field_class_const(
+               const bt_field_class_structure_member *member);
+
+extern const bt_field_class *
+bt_field_class_array_borrow_element_field_class_const(
+               const bt_field_class *field_class);
+
+extern uint64_t bt_field_class_static_array_get_length(
+               const bt_field_class *field_class);
+
+extern const bt_field_path *
+bt_field_class_dynamic_array_borrow_length_field_path_const(
+               const bt_field_class *field_class);
+
+extern const bt_field_path *
+bt_field_class_variant_borrow_selector_field_path_const(
+               const bt_field_class *field_class);
+
+extern uint64_t bt_field_class_variant_get_option_count(
+               const bt_field_class *field_class);
+
+extern const bt_field_class_variant_option *
+bt_field_class_variant_borrow_option_by_index_const(
+               const bt_field_class *field_class, uint64_t index);
+
+extern const bt_field_class_variant_option *
+bt_field_class_variant_borrow_option_by_name_const(
+               const bt_field_class *field_class, const char *name);
+
+extern const char *bt_field_class_variant_option_get_name(
+               const bt_field_class_variant_option *option);
+
+extern const bt_field_class *
+bt_field_class_variant_option_borrow_field_class_const(
+               const bt_field_class_variant_option *option);
+
+extern void bt_field_class_get_ref(const bt_field_class *field_class);
+
+extern void bt_field_class_put_ref(const bt_field_class *field_class);
+
+/* From field-class.h */
+
+extern bt_field_class *bt_field_class_unsigned_integer_create(
+               bt_trace_class *trace_class);
+
+extern bt_field_class *bt_field_class_signed_integer_create(
+               bt_trace_class *trace_class);
+
+extern void bt_field_class_integer_set_field_value_range(
+               bt_field_class *field_class, uint64_t size);
+
+extern void bt_field_class_integer_set_preferred_display_base(
+               bt_field_class *field_class,
+               bt_field_class_integer_preferred_display_base base);
+
+extern bt_field_class *bt_field_class_real_create(bt_trace_class *trace_class);
+
+extern void bt_field_class_real_set_is_single_precision(
+               bt_field_class *field_class,
+               bt_bool is_single_precision);
+
+extern bt_field_class *bt_field_class_unsigned_enumeration_create(
+               bt_trace_class *trace_class);
+
+extern bt_field_class *bt_field_class_signed_enumeration_create(
+               bt_trace_class *trace_class);
+
+extern bt_field_class_status bt_field_class_unsigned_enumeration_map_range(
+               bt_field_class *field_class, const char *label,
+               uint64_t range_lower, uint64_t range_upper);
+
+extern bt_field_class_status bt_field_class_signed_enumeration_map_range(
+               bt_field_class *field_class, const char *label,
+               int64_t range_lower, int64_t range_upper);
+
+extern bt_field_class *bt_field_class_string_create(
+               bt_trace_class *trace_class);
+
+extern bt_field_class *bt_field_class_structure_create(
+               bt_trace_class *trace_class);
+
+extern bt_field_class_status bt_field_class_structure_append_member(
+               bt_field_class *struct_field_class,
+               const char *name, bt_field_class *field_class);
+
+extern bt_field_class_structure_member *
+bt_field_class_structure_borrow_member_by_index(
+               bt_field_class *field_class, uint64_t index);
+
+extern bt_field_class_structure_member *
+bt_field_class_structure_borrow_member_by_name(
+               bt_field_class *field_class, const char *name);
+
+extern bt_field_class *bt_field_class_static_array_create(
+               bt_trace_class *trace_class,
+               bt_field_class *elem_field_class, uint64_t length);
+
+extern bt_field_class *bt_field_class_dynamic_array_create(
+               bt_trace_class *trace_class,
+               bt_field_class *elem_field_class);
+
+extern bt_field_class *bt_field_class_array_borrow_element_field_class(
+               bt_field_class *field_class);
+
+extern bt_field_class_status
+bt_field_class_dynamic_array_set_length_field_class(
+               bt_field_class *field_class,
+               bt_field_class *length_field_class);
+
+extern bt_field_class *bt_field_class_variant_create(
+               bt_trace_class *trace_class);
+
+extern bt_field_class_status
+bt_field_class_variant_set_selector_field_class(bt_field_class *field_class,
+               bt_field_class *selector_field_class);
+
+extern bt_field_class_status bt_field_class_variant_append_option(
+               bt_field_class *var_field_class,
+               const char *name, bt_field_class *field_class);
+
+extern bt_field_class_variant_option *
+bt_field_class_variant_borrow_option_by_index(
+               bt_field_class *field_class, uint64_t index);
+
+extern bt_field_class_variant_option *
+bt_field_class_variant_borrow_option_by_name(
+               bt_field_class *field_class, char *name);
+
+extern bt_field_class *bt_field_class_variant_option_borrow_field_class(
+               bt_field_class_variant_option *option);
diff --git a/src/bindings/python/bt2/bt2/native_bt_field_path.i b/src/bindings/python/bt2/bt2/native_bt_field_path.i
new file mode 100644 (file)
index 0000000..5369f44
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From field-path-const.h */
+
+typedef enum bt_field_path_item_type {
+       BT_FIELD_PATH_ITEM_TYPE_INDEX,
+       BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT,
+} bt_field_path_item_type;
+
+typedef enum bt_scope {
+       BT_SCOPE_PACKET_CONTEXT,
+       BT_SCOPE_EVENT_COMMON_CONTEXT,
+       BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
+       BT_SCOPE_EVENT_PAYLOAD,
+} bt_scope;
+
+extern bt_scope bt_field_path_get_root_scope(
+               const bt_field_path *field_path);
+
+extern uint64_t bt_field_path_get_item_count(
+               const bt_field_path *field_path);
+
+extern const bt_field_path_item *bt_field_path_borrow_item_by_index_const(
+               const bt_field_path *field_path, uint64_t index);
+
+extern bt_field_path_item_type bt_field_path_item_get_type(
+               const bt_field_path_item *field_path_item);
+
+extern uint64_t bt_field_path_item_index_get_index(
+               const bt_field_path_item *field_path_item);
+
+extern void bt_field_path_get_ref(const bt_field_path *field_path);
+
+extern void bt_field_path_put_ref(const bt_field_path *field_path);
diff --git a/src/bindings/python/bt2/bt2/native_bt_graph.i b/src/bindings/python/bt2/bt2/native_bt_graph.i
new file mode 100644 (file)
index 0000000..bb7a5d1
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Output argument typemap for connection output (always appends) */
+%typemap(in, numinputs=0)
+       (const bt_connection **BTOUTCONN)
+       (bt_connection *temp_conn = NULL) {
+       $1 = &temp_conn;
+}
+
+%typemap(argout)
+       (const bt_connection **BTOUTCONN) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_connection, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* Output argument typemap for component output (always appends) */
+%typemap(in, numinputs=0)
+       (const bt_component_source **OUT)
+       (bt_component_source *temp_comp = NULL) {
+       $1 = &temp_comp;
+}
+
+%typemap(in, numinputs=0)
+       (const bt_component_filter **OUT)
+       (bt_component_filter *temp_comp = NULL) {
+       $1 = &temp_comp;
+}
+
+%typemap(in, numinputs=0)
+       (const bt_component_sink **OUT)
+       (bt_component_sink *temp_comp = NULL) {
+       $1 = &temp_comp;
+}
+
+%typemap(argout) (const bt_component_source **OUT) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_component_source, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+%typemap(argout) (const bt_component_filter **OUT) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_component_filter, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+%typemap(argout) (const bt_component_sink **OUT) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_component_sink, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* From graph-const.h */
+
+typedef enum bt_graph_status {
+       BT_GRAPH_STATUS_OK = 0,
+       BT_GRAPH_STATUS_END = 1,
+       BT_GRAPH_STATUS_AGAIN = 11,
+       BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION = 111,
+       BT_GRAPH_STATUS_CANCELED = 125,
+       BT_GRAPH_STATUS_ERROR = -1,
+       BT_GRAPH_STATUS_NOMEM = -12,
+} bt_graph_status;
+
+extern bt_bool bt_graph_is_canceled(const bt_graph *graph);
+
+extern void bt_graph_get_ref(const bt_graph *graph);
+
+extern void bt_graph_put_ref(const bt_graph *graph);
+
+/* From graph.h */
+
+typedef enum bt_graph_listener_status {
+       BT_GRAPH_LISTENER_STATUS_OK = 0,
+       BT_GRAPH_LISTENER_STATUS_ERROR = -1,
+       BT_GRAPH_LISTENER_STATUS_NOMEM = -12,
+} bt_graph_listener_status;
+
+
+typedef bt_graph_listener_status
+(*bt_graph_filter_component_input_port_added_listener_func)(
+               const bt_component_filter *component,
+               const bt_port_input *port, void *data);
+
+typedef bt_graph_listener_status
+(*bt_graph_sink_component_input_port_added_listener_func)(
+               const bt_component_sink *component,
+               const bt_port_input *port, void *data);
+
+typedef bt_graph_listener_status
+(*bt_graph_source_component_output_port_added_listener_func)(
+               const bt_component_source *component,
+               const bt_port_output *port, void *data);
+
+typedef bt_graph_listener_status
+(*bt_graph_filter_component_output_port_added_listener_func)(
+               const bt_component_filter *component,
+               const bt_port_output *port, void *data);
+
+typedef bt_graph_listener_status
+(*bt_graph_source_filter_component_ports_connected_listener_func)(
+               const bt_component_source *source_component,
+               const bt_component_filter *filter_component,
+               const bt_port_output *upstream_port,
+               const bt_port_input *downstream_port, void *data);
+
+typedef bt_graph_listener_status
+(*bt_graph_source_sink_component_ports_connected_listener_func)(
+               const bt_component_source *source_component,
+               const bt_component_sink *sink_component,
+               const bt_port_output *upstream_port,
+               const bt_port_input *downstream_port, void *data);
+
+typedef bt_graph_listener_status
+(*bt_graph_filter_filter_component_ports_connected_listener_func)(
+               const bt_component_filter *filter_component_upstream,
+               const bt_component_filter *filter_component_downstream,
+               const bt_port_output *upstream_port,
+               const bt_port_input *downstream_port,
+               void *data);
+
+typedef bt_graph_listener_status
+(*bt_graph_filter_sink_component_ports_connected_listener_func)(
+               const bt_component_filter *filter_component,
+               const bt_component_sink *sink_component,
+               const bt_port_output *upstream_port,
+               const bt_port_input *downstream_port, void *data);
+
+typedef void (* bt_graph_listener_removed_func)(void *data);
+
+extern bt_graph *bt_graph_create(void);
+
+extern bt_graph_status bt_graph_add_source_component(bt_graph *graph,
+               const bt_component_class_source *component_class,
+               const char *name, const bt_value *params,
+               const bt_component_source **OUT);
+
+extern bt_graph_status bt_graph_add_source_component_with_init_method_data(
+               bt_graph *graph,
+               const bt_component_class_source *component_class,
+               const char *name, const bt_value *params,
+               void *init_method_data,
+               const bt_component_source **OUT);
+
+extern bt_graph_status bt_graph_add_filter_component(bt_graph *graph,
+               const bt_component_class_filter *component_class,
+               const char *name, const bt_value *params,
+               const bt_component_filter **OUT);
+
+extern bt_graph_status bt_graph_add_filter_component_with_init_method_data(
+               bt_graph *graph,
+               const bt_component_class_filter *component_class,
+               const char *name, const bt_value *params,
+               void *init_method_data,
+               const bt_component_filter **OUT);
+
+extern bt_graph_status bt_graph_add_sink_component(
+               bt_graph *graph, const bt_component_class_sink *component_class,
+               const char *name, const bt_value *params,
+               const bt_component_sink **OUT);
+
+extern bt_graph_status bt_graph_add_sink_component_with_init_method_data(
+               bt_graph *graph, const bt_component_class_sink *component_class,
+               const char *name, const bt_value *params,
+               void *init_method_data,
+               const bt_component_sink **OUT);
+
+extern bt_graph_status bt_graph_connect_ports(bt_graph *graph,
+               const bt_port_output *upstream,
+               const bt_port_input *downstream,
+               const bt_connection **BTOUTCONN);
+
+extern bt_graph_status bt_graph_run(bt_graph *graph);
+
+extern bt_graph_status bt_graph_consume(bt_graph *graph);
+
+extern bt_graph_status bt_graph_add_filter_component_input_port_added_listener(
+               bt_graph *graph,
+               bt_graph_filter_component_input_port_added_listener_func listener,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *listener_id);
+
+extern bt_graph_status bt_graph_add_sink_component_input_port_added_listener(
+               bt_graph *graph,
+               bt_graph_sink_component_input_port_added_listener_func listener,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *listener_id);
+
+extern bt_graph_status bt_graph_add_source_component_output_port_added_listener(
+               bt_graph *graph,
+               bt_graph_source_component_output_port_added_listener_func listener,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *listener_id);
+
+extern bt_graph_status bt_graph_add_filter_component_output_port_added_listener(
+               bt_graph *graph,
+               bt_graph_filter_component_output_port_added_listener_func listener,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *listener_id);
+
+extern bt_graph_status
+bt_graph_add_source_filter_component_ports_connected_listener(
+               bt_graph *graph,
+               bt_graph_source_filter_component_ports_connected_listener_func listener,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *listener_id);
+
+extern bt_graph_status
+bt_graph_add_filter_filter_component_ports_connected_listener(
+               bt_graph *graph,
+               bt_graph_filter_filter_component_ports_connected_listener_func listener,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *listener_id);
+
+extern bt_graph_status
+bt_graph_add_source_sink_component_ports_connected_listener(
+               bt_graph *graph,
+               bt_graph_source_sink_component_ports_connected_listener_func listener,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *listener_id);
+
+extern bt_graph_status
+bt_graph_add_filter_sink_component_ports_connected_listener(
+               bt_graph *graph,
+               bt_graph_filter_sink_component_ports_connected_listener_func listener,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *listener_id);
+
+extern bt_graph_status bt_graph_cancel(bt_graph *graph);
+
+/* Helper functions for Python */
+
+%{
+
+static void graph_listener_removed(void *py_callable)
+{
+       BT_ASSERT(py_callable);
+       Py_DECREF(py_callable);
+}
+
+static bt_graph_listener_status
+port_added_listener(
+       const void *component,
+       swig_type_info *component_swig_type,
+       bt_component_class_type component_class_type,
+       const void *port,
+       swig_type_info *port_swig_type,
+       bt_port_type port_type,
+       void *py_callable)
+{
+       PyObject *py_component_ptr = NULL;
+       PyObject *py_port_ptr = NULL;
+       PyObject *py_res = NULL;
+       bt_graph_listener_status status;
+
+       py_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component), component_swig_type, 0);
+       if (!py_component_ptr) {
+               BT_LOGF_STR("Failed to create component SWIG pointer object.");
+               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
+               goto end;
+       }
+
+       py_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(port), port_swig_type, 0);
+       if (!py_port_ptr) {
+               BT_LOGF_STR("Failed to create port SWIG pointer object.");
+               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
+               goto end;
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(OiOi)",
+               py_component_ptr, component_class_type, py_port_ptr, port_type);
+       if (!py_res) {
+               bt2_py_loge_exception();
+               PyErr_Clear();
+               status = BT_GRAPH_LISTENER_STATUS_ERROR;
+               goto end;
+       }
+       
+       BT_ASSERT(py_res == Py_None);
+       status = BT_GRAPH_LISTENER_STATUS_OK;
+
+end:
+       Py_XDECREF(py_res);
+       Py_XDECREF(py_port_ptr);
+       Py_XDECREF(py_component_ptr);
+
+       return status;
+}
+
+static bt_graph_listener_status
+source_component_output_port_added_listener(const bt_component_source *component_source,
+                                           const bt_port_output *port_output, void *py_callable)
+{
+       return port_added_listener(
+               component_source, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE,
+               port_output, SWIGTYPE_p_bt_port_output, BT_PORT_TYPE_OUTPUT, py_callable);
+}
+
+static bt_graph_listener_status
+filter_component_input_port_added_listener(const bt_component_filter *component_filter,
+                                          const bt_port_input *port_input, void *py_callable)
+{
+       return port_added_listener(
+               component_filter, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
+               port_input, SWIGTYPE_p_bt_port_input, BT_PORT_TYPE_INPUT, py_callable);
+}
+
+static bt_graph_listener_status
+filter_component_output_port_added_listener(const bt_component_filter *component_filter,
+                                           const bt_port_output *port_output, void *py_callable)
+{
+       return port_added_listener(
+               component_filter, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
+               port_output, SWIGTYPE_p_bt_port_output, BT_PORT_TYPE_OUTPUT, py_callable);
+}
+
+static bt_graph_listener_status
+sink_component_input_port_added_listener(const bt_component_sink *component_sink,
+                                        const bt_port_input *port_input, void *py_callable)
+{
+       return port_added_listener(
+               component_sink, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK,
+               port_input, SWIGTYPE_p_bt_port_input, BT_PORT_TYPE_INPUT, py_callable);
+}
+
+static PyObject *
+bt_py3_graph_add_port_added_listener(struct bt_graph *graph,
+                                    PyObject *py_callable)
+{
+       PyObject *py_listener_ids = NULL;
+       PyObject *py_listener_id = NULL;
+       int listener_id;
+       bt_graph_status status;
+
+       BT_ASSERT(graph);
+       BT_ASSERT(py_callable);
+
+       /*
+        * Behind the scene, we will be registering 4 different listeners and
+        * return all of their ids.
+        */
+       py_listener_ids = PyTuple_New(4);
+       if (!py_listener_ids) {
+               goto error;
+       }
+
+       /* source output port */
+       status = bt_graph_add_source_component_output_port_added_listener(
+               graph, source_component_output_port_added_listener,
+               graph_listener_removed, py_callable, &listener_id);
+       if (status != BT_GRAPH_STATUS_OK) {
+               goto error;
+       }
+
+       py_listener_id = PyLong_FromLong(listener_id);
+       if (!py_listener_id) {
+               goto error;
+       }
+
+       PyTuple_SET_ITEM(py_listener_ids, 0, py_listener_id);
+       py_listener_id = NULL;
+
+       /* filter input port */
+       status = bt_graph_add_filter_component_input_port_added_listener(
+               graph, filter_component_input_port_added_listener,
+               graph_listener_removed, py_callable, &listener_id);
+       if (status != BT_GRAPH_STATUS_OK) {
+               goto error;
+       }
+
+       py_listener_id = PyLong_FromLong(listener_id);
+       if (!py_listener_id) {
+               goto error;
+       }
+
+       PyTuple_SET_ITEM(py_listener_ids, 1, py_listener_id);
+       py_listener_id = NULL;
+
+       /* filter output port */
+       status = bt_graph_add_filter_component_output_port_added_listener(
+               graph, filter_component_output_port_added_listener,
+               graph_listener_removed, py_callable, &listener_id);
+       if (status != BT_GRAPH_STATUS_OK) {
+               goto error;
+       }
+
+       py_listener_id = PyLong_FromLong(listener_id);
+       if (!py_listener_id) {
+               goto error;
+       }
+
+       PyTuple_SET_ITEM(py_listener_ids, 2, py_listener_id);
+       py_listener_id = NULL;
+
+       /* sink input port */
+       status = bt_graph_add_sink_component_input_port_added_listener(
+               graph, sink_component_input_port_added_listener,
+               graph_listener_removed, py_callable, &listener_id);
+       if (status != BT_GRAPH_STATUS_OK) {
+               goto error;
+       }
+
+       py_listener_id = PyLong_FromLong(listener_id);
+       if (!py_listener_id) {
+               goto error;
+       }
+
+
+       PyTuple_SET_ITEM(py_listener_ids, 3, py_listener_id);
+       py_listener_id = NULL;
+
+       Py_INCREF(py_callable);
+       Py_INCREF(py_callable);
+       Py_INCREF(py_callable);
+       Py_INCREF(py_callable);
+
+       goto end;
+
+error:
+       Py_XDECREF(py_listener_ids);
+       py_listener_ids = Py_None;
+       Py_INCREF(py_listener_ids);
+
+end:
+
+       Py_XDECREF(py_listener_id);
+       return py_listener_ids;
+}
+
+static bt_graph_listener_status
+ports_connected_listener(
+               const void *upstream_component,
+               swig_type_info *upstream_component_swig_type,
+               bt_component_class_type upstream_component_class_type,
+               const bt_port_output *upstream_port,
+               const void *downstream_component,
+               swig_type_info *downstream_component_swig_type,
+               bt_component_class_type downstream_component_class_type,
+               const bt_port_input *downstream_port,
+               void *py_callable)
+{
+       PyObject *py_upstream_component_ptr = NULL;
+       PyObject *py_upstream_port_ptr = NULL;
+       PyObject *py_downstream_component_ptr = NULL;
+       PyObject *py_downstream_port_ptr = NULL;
+       PyObject *py_res = NULL;
+       bt_graph_listener_status status;
+
+       py_upstream_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(upstream_component),
+               upstream_component_swig_type, 0);
+       if (!py_upstream_component_ptr) {
+               BT_LOGF_STR("Failed to create upstream component SWIG pointer object.");
+               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
+               goto end;
+       }
+
+       py_upstream_port_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr(upstream_port), SWIGTYPE_p_bt_port_output, 0);
+       if (!py_upstream_port_ptr) {
+               BT_LOGF_STR("Failed to create upstream port SWIG pointer object.");
+               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
+               goto end;
+       }
+       
+       py_downstream_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(downstream_component),
+               downstream_component_swig_type, 0);
+       if (!py_downstream_component_ptr) {
+               BT_LOGF_STR("Failed to create downstream component SWIG pointer object.");
+               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
+               goto end;
+       }
+
+       py_downstream_port_ptr = SWIG_NewPointerObj(
+               SWIG_as_voidptr(downstream_port), SWIGTYPE_p_bt_port_input, 0);
+       if (!py_downstream_port_ptr) {
+               BT_LOGF_STR("Failed to create downstream port SWIG pointer object.");
+               status = BT_GRAPH_LISTENER_STATUS_NOMEM;
+               goto end;
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(OiOOiO)",
+               py_upstream_component_ptr, upstream_component_class_type,
+               py_upstream_port_ptr,
+               py_downstream_component_ptr, downstream_component_class_type,
+               py_downstream_port_ptr);
+       if (!py_res) {
+               bt2_py_loge_exception();
+               PyErr_Clear();
+               status = BT_GRAPH_LISTENER_STATUS_ERROR;
+               goto end;
+       }
+       
+       BT_ASSERT(py_res == Py_None);
+       status = BT_GRAPH_LISTENER_STATUS_OK;
+
+end:
+       Py_XDECREF(py_upstream_component_ptr);
+       Py_XDECREF(py_upstream_port_ptr);
+       Py_XDECREF(py_downstream_component_ptr);
+       Py_XDECREF(py_downstream_port_ptr);
+       Py_XDECREF(py_res);
+
+       return status;
+}
+
+static bt_graph_listener_status
+source_filter_component_ports_connected_listener(
+       const bt_component_source *source_component,
+       const bt_component_filter *filter_component,
+       const bt_port_output *upstream_port,
+       const bt_port_input *downstream_port, void *py_callable)
+{
+       return ports_connected_listener(
+               source_component, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE,
+               upstream_port,
+               filter_component, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
+               downstream_port,
+               py_callable);
+}
+
+static bt_graph_listener_status
+source_sink_component_ports_connected_listener(
+       const bt_component_source *source_component,
+       const bt_component_sink *sink_component,
+       const bt_port_output *upstream_port,
+       const bt_port_input *downstream_port, void *py_callable)
+{
+       return ports_connected_listener(
+               source_component, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE,
+               upstream_port,
+               sink_component, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK,
+               downstream_port,
+               py_callable);
+}
+
+static bt_graph_listener_status
+filter_filter_component_ports_connected_listener(
+       const bt_component_filter *filter_component_left,
+       const bt_component_filter *filter_component_right,
+       const bt_port_output *upstream_port,
+       const bt_port_input *downstream_port, void *py_callable)
+{
+       return ports_connected_listener(
+               filter_component_left, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
+               upstream_port,
+               filter_component_right, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
+               downstream_port,
+               py_callable);
+}
+
+static bt_graph_listener_status
+filter_sink_component_ports_connected_listener(
+       const bt_component_filter *filter_component,
+       const bt_component_sink *sink_component,
+       const bt_port_output *upstream_port,
+       const bt_port_input *downstream_port, void *py_callable)
+{
+       return ports_connected_listener(
+               filter_component, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER,
+               upstream_port,
+               sink_component, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK,
+               downstream_port,
+               py_callable);
+}
+
+static PyObject*
+bt_py3_graph_add_ports_connected_listener(struct bt_graph *graph,
+       PyObject *py_callable)
+{
+       PyObject *py_listener_ids = NULL;
+       PyObject *py_listener_id = NULL;
+       int listener_id;
+       bt_graph_status status;
+
+       BT_ASSERT(graph);
+       BT_ASSERT(py_callable);
+
+       /* Behind the scene, we will be registering 4 different listeners and
+        * return all of their ids. */
+       py_listener_ids = PyTuple_New(4);
+       if (!py_listener_ids) {
+               goto error;
+       }
+
+       /* source -> filter connection */
+       status = bt_graph_add_source_filter_component_ports_connected_listener(
+               graph, source_filter_component_ports_connected_listener,
+               graph_listener_removed, py_callable, &listener_id);
+       if (status != BT_GRAPH_STATUS_OK) {
+               goto error;
+       }
+
+       py_listener_id = PyLong_FromLong(listener_id);
+       if (!py_listener_id) {
+               goto error;
+       }
+
+       PyTuple_SET_ITEM(py_listener_ids, 0, py_listener_id);
+       py_listener_id = NULL;
+
+       /* source -> sink connection */
+       status = bt_graph_add_source_sink_component_ports_connected_listener(
+               graph, source_sink_component_ports_connected_listener,
+               graph_listener_removed, py_callable, &listener_id);
+       if (status != BT_GRAPH_STATUS_OK) {
+               goto error;
+       }
+
+       py_listener_id = PyLong_FromLong(listener_id);
+       if (!py_listener_id) {
+               goto error;
+       }
+
+       PyTuple_SET_ITEM(py_listener_ids, 1, py_listener_id);
+       py_listener_id = NULL;
+
+       /* filter -> filter connection */
+       status = bt_graph_add_filter_filter_component_ports_connected_listener(
+               graph, filter_filter_component_ports_connected_listener,
+               graph_listener_removed, py_callable, &listener_id);
+       if (status != BT_GRAPH_STATUS_OK) {
+               goto error;
+       }
+
+       py_listener_id = PyLong_FromLong(listener_id);
+       if (!py_listener_id) {
+               goto error;
+       }
+
+       PyTuple_SET_ITEM(py_listener_ids, 2, py_listener_id);
+       py_listener_id = NULL;
+
+       /* filter -> sink connection */
+       status = bt_graph_add_filter_sink_component_ports_connected_listener(
+               graph, filter_sink_component_ports_connected_listener,
+               graph_listener_removed, py_callable, &listener_id);
+       if (status != BT_GRAPH_STATUS_OK) {
+               goto error;
+       }
+
+       py_listener_id = PyLong_FromLong(listener_id);
+       if (!py_listener_id) {
+               goto error;
+       }
+
+       PyTuple_SET_ITEM(py_listener_ids, 3, py_listener_id);
+       py_listener_id = NULL;
+
+       Py_INCREF(py_callable);
+       Py_INCREF(py_callable);
+       Py_INCREF(py_callable);
+       Py_INCREF(py_callable);
+
+       goto end;
+
+error:
+       Py_XDECREF(py_listener_ids);
+       py_listener_ids = Py_None;
+       Py_INCREF(py_listener_ids);
+
+end:
+
+       Py_XDECREF(py_listener_id);
+       return py_listener_ids;
+}
+
+%}
+
+PyObject *bt_py3_graph_add_port_added_listener(struct bt_graph *graph,
+               PyObject *py_callable);
+PyObject *bt_py3_graph_add_ports_connected_listener(struct bt_graph *graph,
+               PyObject *py_callable);
diff --git a/src/bindings/python/bt2/bt2/native_bt_logging.i b/src/bindings/python/bt2/bt2/native_bt_logging.i
new file mode 100644 (file)
index 0000000..df364bd
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+%{
+#include <babeltrace2/logging.h>
+%}
+
+/* Log levels */
+enum bt_logging_level {
+       BT_LOGGING_LEVEL_VERBOSE = 1,
+       BT_LOGGING_LEVEL_DEBUG = 2,
+       BT_LOGGING_LEVEL_INFO = 3,
+       BT_LOGGING_LEVEL_WARN = 4,
+       BT_LOGGING_LEVEL_ERROR = 5,
+       BT_LOGGING_LEVEL_FATAL = 6,
+       BT_LOGGING_LEVEL_NONE = 0xff,
+};
+
+/* Logging functions */
+enum bt_logging_level bt_logging_get_minimal_level(void);
+enum bt_logging_level bt_logging_get_global_level(void);
+void bt_logging_set_global_level(enum bt_logging_level log_level);
diff --git a/src/bindings/python/bt2/bt2/native_bt_message.i b/src/bindings/python/bt2/bt2/native_bt_message.i
new file mode 100644 (file)
index 0000000..0c81b93
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+/* Output argument typemap for clock value output (always appends) */
+%typemap(in, numinputs=0)
+       (const bt_clock_snapshot **BTOUTCLOCKSNAPSHOT)
+       (bt_clock_snapshot *temp_clock_snapshot = NULL) {
+       $1 = &temp_clock_snapshot;
+}
+
+%typemap(argout)
+       (const bt_clock_snapshot **BTOUTCLOCKSNAPSHOT) {
+       if (*$1) {
+               /* SWIG_Python_AppendOutput() steals the created object */
+               $result = SWIG_Python_AppendOutput($result,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(*$1),
+                                       SWIGTYPE_p_bt_clock_snapshot, 0));
+       } else {
+               /* SWIG_Python_AppendOutput() steals Py_None */
+               Py_INCREF(Py_None);
+               $result = SWIG_Python_AppendOutput($result, Py_None);
+       }
+}
+
+/* From message-const.h */
+
+typedef enum bt_message_type {
+       BT_MESSAGE_TYPE_EVENT = 0,
+       BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY = 1,
+       BT_MESSAGE_TYPE_STREAM_BEGINNING = 2,
+       BT_MESSAGE_TYPE_STREAM_END = 3,
+       BT_MESSAGE_TYPE_PACKET_BEGINNING = 4,
+       BT_MESSAGE_TYPE_PACKET_END = 5,
+       BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING = 6,
+       BT_MESSAGE_TYPE_STREAM_ACTIVITY_END = 7,
+       BT_MESSAGE_TYPE_DISCARDED_EVENTS = 8,
+       BT_MESSAGE_TYPE_DISCARDED_PACKETS = 9,
+} bt_message_type;
+
+extern bt_message_type bt_message_get_type(const bt_message *message);
+
+extern void bt_message_get_ref(const bt_message *message);
+
+extern void bt_message_put_ref(const bt_message *message);
+
+/* From message-event-const.h */
+
+extern const bt_event *bt_message_event_borrow_event_const(
+               const bt_message *message);
+
+extern const bt_clock_snapshot *
+bt_message_event_borrow_default_clock_snapshot_const(
+               const bt_message *msg);
+
+extern const bt_clock_class *
+bt_message_event_borrow_stream_class_default_clock_class_const(
+               const bt_message *msg);
+
+/* From message-event.h */
+
+extern
+bt_message *bt_message_event_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_event_class *event_class,
+               const bt_packet *packet);
+
+extern
+bt_message *bt_message_event_create_with_default_clock_snapshot(
+               bt_self_message_iterator *message_iterator,
+               const bt_event_class *event_class,
+               const bt_packet *packet, uint64_t raw_clock_value);
+
+extern bt_event *bt_message_event_borrow_event(
+               bt_message *message);
+
+/* From message-message-iterator-inactivity-const.h */
+
+extern const bt_clock_snapshot *
+bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
+               const bt_message *msg);
+
+/* From message-message-iterator-inactivity.h */
+
+extern
+bt_message *bt_message_message_iterator_inactivity_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_clock_class *default_clock_class, uint64_t raw_value);
+
+/* From message-stream-beginning-const.h */
+
+extern const bt_stream *bt_message_stream_beginning_borrow_stream_const(
+               const bt_message *message);
+
+/* From message-stream-beginning.h */
+
+extern
+bt_message *bt_message_stream_beginning_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_stream *stream);
+
+extern bt_stream *bt_message_stream_beginning_borrow_stream(
+               bt_message *message);
+
+/* From message-stream-end-const.h */
+
+extern const bt_stream *bt_message_stream_end_borrow_stream_const(
+               const bt_message *message);
+
+/* From message-stream-end.h */
+
+extern
+bt_message *bt_message_stream_end_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_stream *stream);
+
+extern bt_stream *bt_message_stream_end_borrow_stream(
+               bt_message *message);
+
+/* From message-packet-beginning-const.h */
+
+extern const bt_packet *bt_message_packet_beginning_borrow_packet_const(
+               const bt_message *message);
+
+extern const bt_clock_snapshot *
+bt_message_packet_beginning_borrow_default_clock_snapshot_const(
+               const bt_message *msg);
+
+extern const bt_clock_class *
+bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
+               const bt_message *msg);
+
+/* From message-packet-beginning.h */
+
+extern
+bt_message *bt_message_packet_beginning_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_packet *packet);
+
+extern
+bt_message *bt_message_packet_beginning_create_with_default_clock_snapshot(
+               bt_self_message_iterator *message_iterator,
+               const bt_packet *packet, uint64_t raw_value);
+
+extern bt_packet *bt_message_packet_beginning_borrow_packet(
+               bt_message *message);
+
+/* From message-packet-end-const.h */
+
+extern const bt_packet *bt_message_packet_end_borrow_packet_const(
+               const bt_message *message);
+
+extern const bt_clock_snapshot *
+bt_message_packet_end_borrow_default_clock_snapshot_const(
+               const bt_message *msg);
+
+extern const bt_clock_class *
+bt_message_packet_end_borrow_stream_class_default_clock_class_const(
+               const bt_message *msg);
+
+/* From message-packet-end.h */
+
+extern
+bt_message *bt_message_packet_end_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_packet *packet);
+
+extern
+bt_message *bt_message_packet_end_create_with_default_clock_snapshot(
+               bt_self_message_iterator *message_iterator,
+               const bt_packet *packet, uint64_t raw_value);
+
+extern bt_packet *bt_message_packet_end_borrow_packet(
+               bt_message *message);
+
+/* From message-stream-activity-const.h */
+
+typedef enum bt_message_stream_activity_clock_snapshot_state {
+       BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN,
+       BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN,
+       BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE,
+} bt_message_stream_activity_clock_snapshot_state;
+
+/* From message-stream-activity-beginning-const.h */
+
+extern bt_message_stream_activity_clock_snapshot_state
+bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
+               const bt_message *msg, const bt_clock_snapshot **BTOUTCLOCKSNAPSHOT);
+
+extern const bt_clock_class *
+bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
+               const bt_message *msg);
+
+extern const bt_stream *
+bt_message_stream_activity_beginning_borrow_stream_const(
+               const bt_message *message);
+
+/* From message-stream-activity-beginning.h */
+
+extern bt_message *bt_message_stream_activity_beginning_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_stream *stream);
+
+extern bt_stream *bt_message_stream_activity_beginning_borrow_stream(
+               bt_message *message);
+
+extern void bt_message_stream_activity_beginning_set_default_clock_snapshot_state(
+               bt_message *msg,
+               bt_message_stream_activity_clock_snapshot_state state);
+
+extern void bt_message_stream_activity_beginning_set_default_clock_snapshot(
+               bt_message *msg, uint64_t raw_value);
+
+/* From message-stream-activity-end-const.h */
+
+extern bt_message_stream_activity_clock_snapshot_state
+bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
+               const bt_message *msg, const bt_clock_snapshot **BTOUTCLOCKSNAPSHOT);
+
+extern const bt_clock_class *
+bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
+               const bt_message *msg);
+
+extern const bt_stream *
+bt_message_stream_activity_end_borrow_stream_const(
+               const bt_message *message);
+
+/* From message-stream-activity-end.h */
+
+extern bt_message *bt_message_stream_activity_end_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_stream *stream);
+
+extern void bt_message_stream_activity_end_set_default_clock_snapshot_state(
+               bt_message *msg,
+               bt_message_stream_activity_clock_snapshot_state state);
+
+extern void bt_message_stream_activity_end_set_default_clock_snapshot(
+               bt_message *msg, uint64_t raw_value);
+
+extern bt_stream *bt_message_stream_activity_end_borrow_stream(
+               bt_message *message);
+
+/* From message-discarded-events-const.h */
+
+extern const bt_clock_snapshot *
+bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+               const bt_message *msg);
+
+extern const bt_clock_snapshot *
+bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
+               const bt_message *msg);
+
+extern const bt_clock_class *
+bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
+               const bt_message *msg);
+
+extern const bt_stream *
+bt_message_discarded_events_borrow_stream_const(const bt_message *message);
+
+extern bt_property_availability bt_message_discarded_events_get_count(
+               const bt_message *message, uint64_t *OUT);
+
+/* From message-discarded-events.h */
+
+extern bt_message *bt_message_discarded_events_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_stream *stream);
+
+extern bt_message *bt_message_discarded_events_create_with_default_clock_snapshots(
+               bt_self_message_iterator *message_iterator,
+               const bt_stream *stream, uint64_t beginning_raw_value,
+               uint64_t end_raw_value);
+
+extern bt_stream *bt_message_discarded_events_borrow_stream(
+               bt_message *message);
+
+extern void bt_message_discarded_events_set_count(bt_message *message,
+               uint64_t count);
+
+/* From message-discarded-packets-const.h */
+
+extern const bt_clock_snapshot *
+bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+               const bt_message *msg);
+
+extern const bt_clock_snapshot *
+bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
+               const bt_message *msg);
+
+extern const bt_clock_class *
+bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
+               const bt_message *msg);
+
+extern const bt_stream *
+bt_message_discarded_packets_borrow_stream_const(const bt_message *message);
+
+extern bt_property_availability bt_message_discarded_packets_get_count(
+               const bt_message *message, uint64_t *OUT);
+
+/* From message-discarded-packets.h */
+
+extern bt_message *bt_message_discarded_packets_create(
+               bt_self_message_iterator *message_iterator,
+               const bt_stream *stream);
+
+extern bt_message *bt_message_discarded_packets_create_with_default_clock_snapshots(
+               bt_self_message_iterator *message_iterator,
+               const bt_stream *stream, uint64_t beginning_raw_value,
+               uint64_t end_raw_value);
+
+extern bt_stream *bt_message_discarded_packets_borrow_stream(
+               bt_message *message);
+
+extern void bt_message_discarded_packets_set_count(bt_message *message,
+               uint64_t count);
diff --git a/src/bindings/python/bt2/bt2/native_bt_notifier.i b/src/bindings/python/bt2/bt2/native_bt_notifier.i
new file mode 100644 (file)
index 0000000..b5f5390
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From message-iterator-const.h */
+
+typedef enum bt_message_iterator_status {
+       BT_MESSAGE_ITERATOR_STATUS_OK = 0,
+       BT_MESSAGE_ITERATOR_STATUS_END = 1,
+       BT_MESSAGE_ITERATOR_STATUS_AGAIN = 11,
+       BT_MESSAGE_ITERATOR_STATUS_ERROR = -1,
+       BT_MESSAGE_ITERATOR_STATUS_NOMEM = -12,
+} bt_message_iterator_status;
+
+/* From self-message-iterator.h */
+
+typedef enum bt_self_message_iterator_status {
+       BT_SELF_MESSAGE_ITERATOR_STATUS_OK = BT_MESSAGE_ITERATOR_STATUS_OK,
+       BT_SELF_MESSAGE_ITERATOR_STATUS_END = BT_MESSAGE_ITERATOR_STATUS_END,
+       BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN = BT_MESSAGE_ITERATOR_STATUS_AGAIN,
+       BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR = BT_MESSAGE_ITERATOR_STATUS_ERROR,
+       BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM = BT_MESSAGE_ITERATOR_STATUS_NOMEM,
+} bt_self_message_iterator_status;
+
+extern bt_self_component *
+bt_self_message_iterator_borrow_component(
+               bt_self_message_iterator *message_iterator);
+
+extern bt_self_port_output *
+bt_self_message_iterator_borrow_port(
+               bt_self_message_iterator *message_iterator);
+
+extern void bt_self_message_iterator_set_data(
+               bt_self_message_iterator *message_iterator,
+               void *user_data);
+
+extern void *bt_self_message_iterator_get_data(
+               const bt_self_message_iterator *message_iterator);
+
+/* From self-component-port-input-message-iterator.h */
+
+bt_message_iterator *
+bt_self_component_port_input_message_iterator_as_message_iterator(
+               bt_self_component_port_input_message_iterator *iterator);
+
+extern bt_self_component_port_input_message_iterator *
+bt_self_component_port_input_message_iterator_create(
+               bt_self_component_port_input *input_port);
+
+extern bt_component *
+bt_self_component_port_input_message_iterator_borrow_component(
+               bt_self_component_port_input_message_iterator *iterator);
+
+extern bt_message_iterator_status
+bt_self_component_port_input_message_iterator_next(
+               bt_self_component_port_input_message_iterator *iterator,
+               bt_message_array_const *msgs, uint64_t *count);
+
+extern bt_bool
+bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
+               bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin);
+
+extern bt_bool bt_self_component_port_input_message_iterator_can_seek_beginning(
+               bt_self_component_port_input_message_iterator *iterator);
+
+extern bt_message_iterator_status
+bt_self_component_port_input_message_iterator_seek_ns_from_origin(
+               bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin);
+
+extern bt_message_iterator_status
+bt_self_component_port_input_message_iterator_seek_beginning(
+               bt_self_component_port_input_message_iterator *iterator);
+
+extern void bt_self_component_port_input_message_iterator_get_ref(
+               const bt_self_component_port_input_message_iterator *self_component_port_input_message_iterator);
+
+extern void bt_self_component_port_input_message_iterator_put_ref(
+               const bt_self_component_port_input_message_iterator *self_component_port_input_message_iterator);
+
+/* From port-output-message-iterator.h */
+
+bt_message_iterator *
+bt_port_output_message_iterator_as_message_iterator(
+               bt_port_output_message_iterator *iterator);
+
+extern bt_port_output_message_iterator *
+bt_port_output_message_iterator_create(
+               bt_graph *graph,
+               const bt_port_output *output_port);
+
+extern bt_message_iterator_status
+bt_port_output_message_iterator_next(
+               bt_port_output_message_iterator *iterator,
+               bt_message_array_const *msgs, uint64_t *count);
+
+extern bt_bool bt_port_output_message_iterator_can_seek_ns_from_origin(
+               bt_port_output_message_iterator *iterator,
+               int64_t ns_from_origin);
+
+extern bt_bool bt_port_output_message_iterator_can_seek_beginning(
+               bt_port_output_message_iterator *iterator);
+
+extern bt_message_iterator_status
+bt_port_output_message_iterator_seek_ns_from_origin(
+               bt_port_output_message_iterator *iterator,
+               int64_t ns_from_origin);
+
+extern bt_message_iterator_status
+bt_port_output_message_iterator_seek_beginning(
+               bt_port_output_message_iterator *iterator);
+
+extern void bt_port_output_message_iterator_get_ref(
+               const bt_port_output_message_iterator *port_output_message_iterator);
+
+extern void bt_port_output_message_iterator_put_ref(
+               const bt_port_output_message_iterator *port_output_message_iterator);
+
+/* Helper functions for Python */
+%{
+static PyObject *bt_py3_get_user_component_from_user_msg_iter(
+               bt_self_message_iterator *self_message_iterator)
+{
+       bt_self_component *self_component = bt_self_message_iterator_borrow_component(self_message_iterator);
+       PyObject *py_comp;
+
+       BT_ASSERT(self_component);
+       py_comp = bt_self_component_get_data(self_component);
+       BT_ASSERT(py_comp);
+
+       /* Return new reference */
+       Py_INCREF(py_comp);
+       return py_comp;
+}
+
+static inline
+PyObject *create_pylist_from_messages(bt_message_array_const messages,
+               uint64_t message_count)
+{
+       uint64_t i;
+       PyObject *py_msg_list = PyList_New(message_count);
+       BT_ASSERT(py_msg_list);
+       for (i = 0; i < message_count; i++) {
+               PyList_SET_ITEM(py_msg_list, i,
+                               SWIG_NewPointerObj(SWIG_as_voidptr(messages[i]),
+                                       SWIGTYPE_p_bt_message, 0));
+       }
+
+       return py_msg_list;
+}
+
+static
+PyObject *bt_py3_get_msg_range_common(bt_message_iterator_status status,
+               bt_message_array_const messages, uint64_t message_count)
+{
+       PyObject *py_status;
+       PyObject *py_return_tuple;
+       PyObject *py_msg_list = Py_None;
+       
+       py_status = SWIG_From_long_SS_long(status);
+       if (status != BT_MESSAGE_ITERATOR_STATUS_OK) {
+               goto end;
+       }
+
+       py_msg_list = create_pylist_from_messages(messages, message_count);
+
+end:
+       py_return_tuple = PyTuple_New(2);
+       BT_ASSERT(py_return_tuple);
+       PyTuple_SET_ITEM(py_return_tuple, 0, py_status);
+       PyTuple_SET_ITEM(py_return_tuple, 1, py_msg_list);
+
+       return py_return_tuple;
+}
+
+static PyObject
+*bt_py3_self_component_port_input_get_msg_range(
+               bt_self_component_port_input_message_iterator *iter)
+{
+       bt_message_array_const messages;
+       uint64_t message_count = 0;
+       bt_message_iterator_status status;
+
+       status = bt_self_component_port_input_message_iterator_next(iter, &messages,
+                               &message_count);
+       
+       return bt_py3_get_msg_range_common(status, messages, message_count);
+}
+
+static PyObject
+*bt_py3_port_output_get_msg_range(
+               bt_port_output_message_iterator *iter)
+{
+       bt_message_array_const messages;
+       uint64_t message_count = 0;
+       bt_message_iterator_status status;
+
+       status =
+               bt_port_output_message_iterator_next(iter, &messages,
+                               &message_count);
+       
+       return bt_py3_get_msg_range_common(status, messages, message_count);
+}
+%}
+
+PyObject *bt_py3_get_user_component_from_user_msg_iter(
+    bt_self_message_iterator *self_message_iterator);
+PyObject *bt_py3_self_component_port_input_get_msg_range(
+               bt_self_component_port_input_message_iterator *iter);
+PyObject *bt_py3_port_output_get_msg_range(
+               bt_port_output_message_iterator *iter);
diff --git a/src/bindings/python/bt2/bt2/native_bt_packet.i b/src/bindings/python/bt2/bt2/native_bt_packet.i
new file mode 100644 (file)
index 0000000..b4c9073
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From packet-const.h */
+
+typedef enum bt_packet_status {
+       BT_PACKET_STATUS_OK = 0,
+       BT_PACKET_STATUS_NOMEM = -12,
+} bt_packet_status;
+
+extern const bt_stream *bt_packet_borrow_stream_const(
+               const bt_packet *packet);
+
+extern
+const bt_field *bt_packet_borrow_context_field_const(
+               const bt_packet *packet);
+
+extern void bt_packet_get_ref(const bt_packet *packet);
+
+extern void bt_packet_put_ref(const bt_packet *packet);
+
+/* From packet.h */
+
+extern bt_packet *bt_packet_create(const bt_stream *stream);
+
+extern bt_stream *bt_packet_borrow_stream(bt_packet *packet);
+
+extern
+bt_field *bt_packet_borrow_context_field(bt_packet *packet);
+
+extern
+bt_packet_status bt_packet_move_context_field(bt_packet *packet,
+               bt_packet_context_field *context);
diff --git a/src/bindings/python/bt2/bt2/native_bt_plugin.i b/src/bindings/python/bt2/bt2/native_bt_plugin.i
new file mode 100644 (file)
index 0000000..435d40f
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From plugin-const.h */
+
+extern const bt_plugin *bt_plugin_find(const char *plugin_name);
+
+extern const bt_plugin_set *bt_plugin_find_all_from_file(
+               const char *path);
+
+extern const bt_plugin_set *bt_plugin_find_all_from_dir(
+               const char *path, bt_bool recurse);
+
+extern const bt_plugin_set *bt_plugin_find_all_from_static(void);
+
+extern const char *bt_plugin_get_name(const bt_plugin *plugin);
+
+extern const char *bt_plugin_get_author(const bt_plugin *plugin);
+
+extern const char *bt_plugin_get_license(const bt_plugin *plugin);
+
+extern const char *bt_plugin_get_description(const bt_plugin *plugin);
+
+extern const char *bt_plugin_get_path(const bt_plugin *plugin);
+
+extern bt_property_availability bt_plugin_get_version(
+               const bt_plugin *plugin, unsigned int *OUT,
+               unsigned int *OUT, unsigned int *OUT, const char **OUT);
+
+extern uint64_t bt_plugin_get_source_component_class_count(
+               const bt_plugin *plugin);
+
+extern uint64_t bt_plugin_get_filter_component_class_count(
+               const bt_plugin *plugin);
+
+extern uint64_t bt_plugin_get_sink_component_class_count(
+               const bt_plugin *plugin);
+
+extern const bt_component_class_source *
+bt_plugin_borrow_source_component_class_by_index_const(
+               const bt_plugin *plugin, uint64_t index);
+
+extern const bt_component_class_filter *
+bt_plugin_borrow_filter_component_class_by_index_const(
+               const bt_plugin *plugin, uint64_t index);
+
+extern const bt_component_class_sink *
+bt_plugin_borrow_sink_component_class_by_index_const(
+               const bt_plugin *plugin, uint64_t index);
+
+extern const bt_component_class_source *
+bt_plugin_borrow_source_component_class_by_name_const(
+               const bt_plugin *plugin, const char *name);
+
+extern const bt_component_class_filter *
+bt_plugin_borrow_filter_component_class_by_name_const(
+               const bt_plugin *plugin, const char *name);
+
+extern const bt_component_class_sink *
+bt_plugin_borrow_sink_component_class_by_name_const(
+               const bt_plugin *plugin, const char *name);
+
+extern void bt_plugin_get_ref(const bt_plugin *plugin);
+
+extern void bt_plugin_put_ref(const bt_plugin *plugin);
+
+/* From plugin-set-const.h */
+
+extern uint64_t bt_plugin_set_get_plugin_count(
+               const bt_plugin_set *plugin_set);
+
+extern const bt_plugin *bt_plugin_set_borrow_plugin_by_index_const(
+               const bt_plugin_set *plugin_set, uint64_t index);
+
+extern void bt_plugin_set_get_ref(const bt_plugin_set *plugin_set);
+
+extern void bt_plugin_set_put_ref(const bt_plugin_set *plugin_set);
+
+/* Helpers */
+
+bt_property_availability bt_plugin_get_version_wrapper(
+               const bt_plugin *plugin, unsigned int *OUT,
+               unsigned int *OUT, unsigned int *OUT, const char **OUT);
+
+%{
+
+/*
+ * This wrapper ensures that when the API function fails, the `*extra` output
+ * parameter is set to NULL.  This is necessary because the epilogue of the
+ * "char **OUT" typemap will use that value to make a Python str object.  We
+ * can't rely on the initial value of `*extra`, it could point to unreadable
+ * memory.
+ */
+
+bt_property_availability bt_plugin_get_version_wrapper(
+               const bt_plugin *plugin, unsigned int *major,
+               unsigned int *minor, unsigned int *patch, const char **extra)
+{
+       bt_property_availability ret;
+
+       ret = bt_plugin_get_version(plugin, major, minor, patch, extra);
+
+       if (ret == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
+               *extra = NULL;
+       }
+
+       return ret;
+}
+
+%}
diff --git a/src/bindings/python/bt2/bt2/native_bt_port.i b/src/bindings/python/bt2/bt2/native_bt_port.i
new file mode 100644 (file)
index 0000000..873c613
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * Typemap for the user data attached to (and owned by) a self component port.
+ * The pointer saved as the port's user data is directly the PyObject *.
+ *
+ * As per the CPython calling convention, we need to return a new reference to
+ * the returned object, which will be transferred to the caller.  The following
+ * typedef allows us to apply the typemap.
+ */
+%{
+typedef void *PY_SELF_PORT_USER_DATA;
+%}
+
+%typemap(out) PY_SELF_PORT_USER_DATA {
+       Py_INCREF($1);
+       $result = $1;
+}
+
+/* From port-const.h */
+
+typedef enum bt_port_type {
+       BT_PORT_TYPE_INPUT = 0,
+       BT_PORT_TYPE_OUTPUT = 1,
+} bt_port_type;
+
+extern const char *bt_port_get_name(const bt_port *port);
+
+extern bt_port_type bt_port_get_type(const bt_port *port);
+
+extern const bt_connection *bt_port_borrow_connection_const(
+               const bt_port *port);
+
+extern const bt_component *bt_port_borrow_component_const(
+               const bt_port *port);
+
+extern bt_bool bt_port_is_connected(const bt_port *port);
+
+bt_bool bt_port_is_input(const bt_port *port);
+
+bt_bool bt_port_is_output(const bt_port *port);
+
+extern void bt_port_get_ref(const bt_port *port);
+
+extern void bt_port_put_ref(const bt_port *port);
+
+/* From port-output-const.h */
+
+const bt_port *bt_port_output_as_port_const(const bt_port_output *port_output);
+
+extern void bt_port_output_get_ref(const bt_port_output *port_output);
+
+extern void bt_port_output_put_ref(const bt_port_output *port_output);
+
+/* From port-input-const.h */
+
+const bt_port *bt_port_input_as_port_const(const bt_port_input *port_input);
+
+extern void bt_port_input_get_ref(const bt_port_input *port_input);
+
+extern void bt_port_input_put_ref(const bt_port_input *port_input);
+
+/* From self-component-port.h */
+
+typedef enum bt_self_component_port_status {
+       BT_SELF_PORT_STATUS_OK = 0,
+} bt_self_component_port_status;
+
+const bt_port *bt_self_component_port_as_port(
+               bt_self_component_port *self_port);
+
+extern bt_self_component *bt_self_component_port_borrow_component(
+               bt_self_component_port *self_port);
+
+extern PY_SELF_PORT_USER_DATA bt_self_component_port_get_data(
+               const bt_self_component_port *self_port);
+
+/* From self-component-port-output.h */
+
+bt_self_component_port *
+bt_self_component_port_output_as_self_component_port(
+               bt_self_component_port_output *self_component_port);
+
+const bt_port_output *bt_self_component_port_output_as_port_output(
+               bt_self_component_port_output *self_component_port);
+
+/* From self-component-port-input.h */
+
+bt_self_component_port *
+bt_self_component_port_input_as_self_component_port(
+               bt_self_component_port_input *self_component_port);
+
+const bt_port_input *bt_self_component_port_input_as_port_input(
+               const bt_self_component_port_input *self_component_port);
diff --git a/src/bindings/python/bt2/bt2/native_bt_query_exec.i b/src/bindings/python/bt2/bt2/native_bt_query_exec.i
new file mode 100644 (file)
index 0000000..af78efa
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From query-executor-const.h */
+
+typedef enum bt_query_executor_status {
+       BT_QUERY_EXECUTOR_STATUS_OK = 0,
+       BT_QUERY_EXECUTOR_STATUS_AGAIN = 11,
+       BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED = 95,
+       BT_QUERY_EXECUTOR_STATUS_CANCELED = 125,
+       BT_QUERY_EXECUTOR_STATUS_ERROR = -1,
+       BT_QUERY_EXECUTOR_STATUS_NOMEM = -12,
+       BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT = -23,
+       BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS = -24,
+} bt_query_executor_status;
+
+extern
+bt_bool bt_query_executor_is_canceled(
+               const bt_query_executor *query_executor);
+
+extern void bt_query_executor_get_ref(
+               const bt_query_executor *query_executor);
+
+extern void bt_query_executor_put_ref(
+               const bt_query_executor *query_executor);
+
+/* From query-executor.h */
+
+extern
+bt_query_executor *bt_query_executor_create(void);
+
+extern
+bt_query_executor_status bt_query_executor_query(
+               bt_query_executor *query_executor,
+               const bt_component_class *component_class,
+               const char *object, const bt_value *params,
+               const bt_value **OUT);
+
+extern
+bt_query_executor_status bt_query_executor_cancel(
+               bt_query_executor *query_executor);
diff --git a/src/bindings/python/bt2/bt2/native_bt_stream.i b/src/bindings/python/bt2/bt2/native_bt_stream.i
new file mode 100644 (file)
index 0000000..394d987
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From stream-const.h */
+
+typedef enum bt_stream_status {
+       BT_STREAM_STATUS_OK = 0,
+       BT_STREAM_STATUS_NOMEM = -12,
+} bt_stream_status;
+
+extern const bt_stream_class *bt_stream_borrow_class_const(
+               const bt_stream *stream);
+
+extern const bt_trace *bt_stream_borrow_trace_const(
+               const bt_stream *stream);
+
+extern const char *bt_stream_get_name(const bt_stream *stream);
+
+extern uint64_t bt_stream_get_id(const bt_stream *stream);
+
+extern void bt_stream_get_ref(const bt_stream *stream);
+
+extern void bt_stream_put_ref(const bt_stream *stream);
+
+/* From stream.h */
+
+extern bt_stream *bt_stream_create(bt_stream_class *stream_class,
+               bt_trace *trace);
+
+extern bt_stream *bt_stream_create_with_id(
+               bt_stream_class *stream_class,
+               bt_trace *trace, uint64_t id);
+
+extern bt_trace *bt_stream_borrow_trace(bt_stream *stream);
+
+extern bt_stream_class *bt_stream_borrow_class(bt_stream *stream);
+
+extern bt_stream_status bt_stream_set_name(bt_stream *stream,
+               const char *name);
diff --git a/src/bindings/python/bt2/bt2/native_bt_stream_class.i b/src/bindings/python/bt2/bt2/native_bt_stream_class.i
new file mode 100644 (file)
index 0000000..e592704
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From stream-class-const.h */
+
+typedef enum bt_stream_class_status {
+       BT_STREAM_CLASS_STATUS_OK = 0,
+       BT_STREAM_CLASS_STATUS_NOMEM = -12,
+} bt_stream_class_status;
+
+extern const bt_trace_class *bt_stream_class_borrow_trace_class_const(
+               const bt_stream_class *stream_class);
+
+extern const char *bt_stream_class_get_name(
+               const bt_stream_class *stream_class);
+
+extern bt_bool bt_stream_class_assigns_automatic_event_class_id(
+               const bt_stream_class *stream_class);
+
+extern bt_bool bt_stream_class_assigns_automatic_stream_id(
+               const bt_stream_class *stream_class);
+
+extern bt_bool bt_stream_class_packets_have_beginning_default_clock_snapshot(
+               const bt_stream_class *stream_class);
+
+extern bt_bool bt_stream_class_packets_have_end_default_clock_snapshot(
+               const bt_stream_class *stream_class);
+
+extern bt_bool bt_stream_class_supports_discarded_events(
+               const bt_stream_class *stream_class);
+
+extern bt_bool bt_stream_class_supports_discarded_packets(
+               const bt_stream_class *stream_class);
+
+extern bt_bool bt_stream_class_discarded_events_have_default_clock_snapshots(
+               const bt_stream_class *stream_class);
+
+extern bt_bool bt_stream_class_discarded_packets_have_default_clock_snapshots(
+               const bt_stream_class *stream_class);
+
+extern uint64_t bt_stream_class_get_id(
+               const bt_stream_class *stream_class);
+
+extern const bt_field_class *
+bt_stream_class_borrow_packet_context_field_class_const(
+               const bt_stream_class *stream_class);
+
+extern const bt_field_class *
+bt_stream_class_borrow_event_common_context_field_class_const(
+               const bt_stream_class *stream_class);
+
+extern uint64_t bt_stream_class_get_event_class_count(
+               const bt_stream_class *stream_class);
+
+extern const bt_event_class *
+bt_stream_class_borrow_event_class_by_index_const(
+               const bt_stream_class *stream_class, uint64_t index);
+
+extern const bt_event_class *
+bt_stream_class_borrow_event_class_by_id_const(
+               const bt_stream_class *stream_class, uint64_t id);
+
+extern const bt_clock_class *
+bt_stream_class_borrow_default_clock_class_const(
+               const bt_stream_class *stream_class);
+
+extern void bt_stream_class_get_ref(const bt_stream_class *stream_class);
+
+extern void bt_stream_class_put_ref(const bt_stream_class *stream_class);
+
+/* From stream-class-const.h */
+
+extern bt_stream_class *bt_stream_class_create(
+               bt_trace_class *trace_class);
+
+extern bt_stream_class *bt_stream_class_create_with_id(
+               bt_trace_class *trace_class, uint64_t id);
+
+extern bt_trace_class *bt_stream_class_borrow_trace_class(
+               bt_stream_class *stream_class);
+
+extern bt_stream_class_status bt_stream_class_set_name(
+               bt_stream_class *stream_class, const char *name);
+
+extern void bt_stream_class_set_assigns_automatic_event_class_id(
+               bt_stream_class *stream_class, bt_bool value);
+
+extern void bt_stream_class_set_assigns_automatic_stream_id(
+               bt_stream_class *stream_class, bt_bool value);
+
+extern void bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
+               bt_stream_class *stream_class, bt_bool value);
+
+extern void bt_stream_class_set_packets_have_end_default_clock_snapshot(
+               bt_stream_class *stream_class, bt_bool value);
+
+extern void bt_stream_class_set_supports_discarded_events(
+               bt_stream_class *stream_class,
+               bt_bool supports_discarded_events,
+               bt_bool with_default_clock_snapshots);
+
+extern void bt_stream_class_set_supports_discarded_packets(
+               bt_stream_class *stream_class,
+               bt_bool supports_discarded_packets,
+               bt_bool with_default_clock_snapshots);
+
+extern bt_stream_class_status
+bt_stream_class_set_packet_context_field_class(
+               bt_stream_class *stream_class,
+               bt_field_class *field_class);
+
+extern bt_field_class *
+bt_stream_class_borrow_packet_context_field_class(
+               bt_stream_class *stream_class);
+
+extern bt_stream_class_status
+bt_stream_class_set_event_common_context_field_class(
+               bt_stream_class *stream_class,
+               bt_field_class *field_class);
+
+extern bt_field_class *
+bt_stream_class_borrow_event_common_context_field_class(
+               bt_stream_class *stream_class);
+
+extern bt_event_class *
+bt_stream_class_borrow_event_class_by_index(
+               bt_stream_class *stream_class, uint64_t index);
+
+extern bt_event_class *
+bt_stream_class_borrow_event_class_by_id(
+               bt_stream_class *stream_class, uint64_t id);
+
+extern bt_clock_class *bt_stream_class_borrow_default_clock_class(
+               bt_stream_class *stream_class);
+
+extern bt_stream_class_status bt_stream_class_set_default_clock_class(
+               bt_stream_class *stream_class,
+               bt_clock_class *clock_class);
diff --git a/src/bindings/python/bt2/bt2/native_bt_trace.i b/src/bindings/python/bt2/bt2/native_bt_trace.i
new file mode 100644 (file)
index 0000000..2d8f538
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From trace-const.h */
+
+typedef enum bt_trace_status {
+       BT_TRACE_STATUS_OK = 0,
+       BT_TRACE_STATUS_NOMEM = -12,
+} bt_trace_status;
+
+typedef void (* bt_trace_destruction_listener_func)(
+               const bt_trace *trace, void *data);
+
+extern const bt_trace_class *bt_trace_borrow_class_const(
+               const bt_trace *trace);
+
+extern const char *bt_trace_get_name(const bt_trace *trace);
+
+extern uint64_t bt_trace_get_stream_count(const bt_trace *trace);
+
+extern const bt_stream *bt_trace_borrow_stream_by_index_const(
+               const bt_trace *trace, uint64_t index);
+
+extern const bt_stream *bt_trace_borrow_stream_by_id_const(
+               const bt_trace *trace, uint64_t id);
+
+extern bt_trace_status bt_trace_add_destruction_listener(
+               const bt_trace *trace,
+               bt_trace_destruction_listener_func listener,
+               void *data, uint64_t *listener_id);
+
+extern bt_trace_status bt_trace_remove_destruction_listener(
+               const bt_trace *trace, uint64_t listener_id);
+
+extern void bt_trace_get_ref(const bt_trace *trace);
+
+extern void bt_trace_put_ref(const bt_trace *trace);
+
+/* From trace.h */
+
+extern bt_trace_class *bt_trace_borrow_class(bt_trace *trace);
+
+extern bt_trace *bt_trace_create(bt_trace_class *trace_class);
+
+extern bt_trace_status bt_trace_set_name(bt_trace *trace,
+               const char *name);
+
+extern bt_stream *bt_trace_borrow_stream_by_index(bt_trace *trace,
+               uint64_t index);
+
+extern bt_stream *bt_trace_borrow_stream_by_id(bt_trace *trace,
+               uint64_t id);
+
+%{
+static void
+trace_destroyed_listener(const bt_trace *trace, void *py_callable)
+{
+       PyObject *py_trace_ptr = NULL;
+       PyObject *py_res = NULL;
+
+       py_trace_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace),
+               SWIGTYPE_p_bt_trace, 0);
+       if (!py_trace_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_ptr);
+       if (py_res != NULL) {
+               BT_ASSERT(py_res == Py_None);
+       } else {
+               bt2_py_loge_exception();
+       }
+
+       Py_DECREF(py_trace_ptr);
+       Py_XDECREF(py_res);
+}
+
+uint64_t bt_py3_trace_add_destruction_listener(bt_trace *trace, PyObject *py_callable)
+{
+       uint64_t id = UINT64_C(-1);
+       bt_trace_status status;
+
+       BT_ASSERT(trace);
+       BT_ASSERT(py_callable);
+
+       status = bt_trace_add_destruction_listener(
+               trace, trace_destroyed_listener, py_callable, &id);
+       if (status != BT_TRACE_STATUS_OK) {
+               BT_LOGF_STR("Failed to add trace destruction listener.");
+               abort();
+       }
+
+       Py_INCREF(py_callable);
+
+       return id;
+}
+%}
+
+uint64_t bt_py3_trace_add_destruction_listener(bt_trace *trace,
+       PyObject *py_callable);
diff --git a/src/bindings/python/bt2/bt2/native_bt_trace_class.i b/src/bindings/python/bt2/bt2/native_bt_trace_class.i
new file mode 100644 (file)
index 0000000..71061ff
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From trace-class-const.h */
+
+typedef enum bt_trace_class_status {
+       BT_TRACE_CLASS_STATUS_OK = 0,
+       BT_TRACE_CLASS_STATUS_NOMEM = -12,
+} bt_trace_class_status;
+
+typedef void (* bt_trace_class_destruction_listener_func)(
+               const bt_trace_class *trace_class, void *data);
+
+extern bt_bool bt_trace_class_assigns_automatic_stream_class_id(
+               const bt_trace_class *trace_class);
+
+extern const char *bt_trace_class_get_name(
+               const bt_trace_class *trace_class);
+
+extern bt_uuid bt_trace_class_get_uuid(
+               const bt_trace_class *trace_class);
+
+extern uint64_t bt_trace_class_get_environment_entry_count(
+               const bt_trace_class *trace_class);
+
+extern void bt_trace_class_borrow_environment_entry_by_index_const(
+               const bt_trace_class *trace_class, uint64_t index,
+               const char **OUT, const bt_value **OUT);
+
+extern const bt_value *
+bt_trace_class_borrow_environment_entry_value_by_name_const(
+               const bt_trace_class *trace_class, const char *name);
+
+extern uint64_t bt_trace_class_get_stream_class_count(
+               const bt_trace_class *trace_class);
+
+extern const bt_stream_class *
+bt_trace_class_borrow_stream_class_by_index_const(
+               const bt_trace_class *trace_class, uint64_t index);
+
+extern const bt_stream_class *bt_trace_class_borrow_stream_class_by_id_const(
+               const bt_trace_class *trace_class, uint64_t id);
+
+extern bt_trace_class_status bt_trace_class_add_destruction_listener(
+        const bt_trace_class *trace_class,
+        bt_trace_class_destruction_listener_func listener,
+        void *data, uint64_t *listener_id);
+
+extern bt_trace_class_status bt_trace_class_remove_destruction_listener(
+        const bt_trace_class *trace_class, uint64_t listener_id);
+
+extern void bt_trace_class_get_ref(const bt_trace_class *trace_class);
+
+extern void bt_trace_class_put_ref(const bt_trace_class *trace_class);
+
+/* From trace-class.h */
+
+extern bt_trace_class *bt_trace_class_create(bt_self_component *self_comp);
+
+extern void bt_trace_class_set_assigns_automatic_stream_class_id(
+               bt_trace_class *trace_class, bt_bool value);
+
+extern bt_trace_class_status bt_trace_class_set_name(
+               bt_trace_class *trace_class, const char *name);
+
+extern void bt_trace_class_set_uuid(bt_trace_class *trace_class,
+               bt_uuid uuid);
+
+extern bt_trace_class_status bt_trace_class_set_environment_entry_integer(
+               bt_trace_class *trace_class,
+               const char *name, int64_t value);
+
+extern bt_trace_class_status bt_trace_class_set_environment_entry_string(
+               bt_trace_class *trace_class,
+               const char *name, const char *value);
+
+extern bt_stream_class *bt_trace_class_borrow_stream_class_by_index(
+               bt_trace_class *trace_class, uint64_t index);
+
+extern bt_stream_class *bt_trace_class_borrow_stream_class_by_id(
+               bt_trace_class *trace_class, uint64_t id);
+
+/* Helper functions for Python */
+%{
+static void
+trace_class_destroyed_listener(const bt_trace_class *trace_class, void *py_callable)
+{
+       PyObject *py_trace_class_ptr = NULL;
+       PyObject *py_res = NULL;
+
+       py_trace_class_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace_class),
+               SWIGTYPE_p_bt_trace_class, 0);
+       if (!py_trace_class_ptr) {
+               BT_LOGF_STR("Failed to create a SWIG pointer object.");
+               abort();
+       }
+
+       py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_class_ptr);
+       if (py_res != NULL) {
+               BT_ASSERT(py_res == Py_None);
+       } else {
+               bt2_py_loge_exception();
+       }
+
+       Py_DECREF(py_trace_class_ptr);
+       Py_XDECREF(py_res);
+}
+
+uint64_t bt_py3_trace_class_add_destruction_listener(bt_trace_class *trace_class,
+       PyObject *py_callable)
+{
+       uint64_t id = UINT64_C(-1);
+       bt_trace_class_status status;
+
+       BT_ASSERT(trace_class);
+       BT_ASSERT(py_callable);
+
+       status = bt_trace_class_add_destruction_listener(
+               trace_class, trace_class_destroyed_listener, py_callable, &id);
+       if (status != BT_TRACE_CLASS_STATUS_OK) {
+               BT_LOGF_STR("Failed to add trace class destruction listener.");
+               abort();
+       }
+
+       Py_INCREF(py_callable);
+
+       return id;
+}
+%}
+
+uint64_t bt_py3_trace_class_add_destruction_listener(bt_trace_class *trace_class,
+       PyObject *py_callable);
diff --git a/src/bindings/python/bt2/bt2/native_bt_value.i b/src/bindings/python/bt2/bt2/native_bt_value.i
new file mode 100644 (file)
index 0000000..1ecd21e
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* From value-const.h */
+
+typedef enum bt_value_status {
+       /// Operation canceled.
+       BT_VALUE_STATUS_CANCELED        = 125,
+
+       /// Cannot allocate memory.
+       BT_VALUE_STATUS_NOMEM           = -12,
+
+       /// Okay, no error.
+       BT_VALUE_STATUS_OK              = 0,
+} bt_value_status;
+
+typedef enum bt_value_type {
+       /// Null value object.
+       BT_VALUE_TYPE_NULL              = 0,
+
+       /// Boolean value object (holds #BT_TRUE or #BT_FALSE).
+       BT_VALUE_TYPE_BOOL              = 1,
+
+       /// Unsigned integer value object (holds an unsigned 64-bit integer raw value).
+       BT_VALUE_TYPE_UNSIGNED_INTEGER  = 2,
+
+       /// Signed integer value object (holds a signed 64-bit integer raw value).
+       BT_VALUE_TYPE_SIGNED_INTEGER    = 3,
+
+       /// Floating point number value object (holds a \c double raw value).
+       BT_VALUE_TYPE_REAL              = 4,
+
+       /// String value object.
+       BT_VALUE_TYPE_STRING            = 5,
+
+       /// Array value object.
+       BT_VALUE_TYPE_ARRAY             = 6,
+
+       /// Map value object.
+       BT_VALUE_TYPE_MAP               = 7,
+} bt_value_type;
+
+extern bt_value_type bt_value_get_type(const bt_value *object);
+
+extern bt_value_status bt_value_copy(const bt_value *object,
+               bt_value **copy);
+
+extern bt_bool bt_value_compare(const bt_value *object_a,
+               const bt_value *object_b);
+
+extern bt_bool bt_value_bool_get(const bt_value *bool_obj);
+
+extern uint64_t bt_value_unsigned_integer_get(const bt_value *integer_obj);
+
+extern int64_t bt_value_signed_integer_get(const bt_value *integer_obj);
+
+extern double bt_value_real_get(const bt_value *real_obj);
+
+extern const char *bt_value_string_get(const bt_value *string_obj);
+
+extern uint64_t bt_value_array_get_size(const bt_value *array_obj);
+
+extern const bt_value *bt_value_array_borrow_element_by_index_const(
+               const bt_value *array_obj, uint64_t index);
+
+extern uint64_t bt_value_map_get_size(const bt_value *map_obj);
+
+extern const bt_value *bt_value_map_borrow_entry_value_const(
+               const bt_value *map_obj, const char *key);
+
+typedef bt_bool (* bt_value_map_foreach_entry_const_func)(const char *key,
+               const bt_value *object, void *data);
+
+extern bt_value_status bt_value_map_foreach_entry_const(
+               const bt_value *map_obj,
+               bt_value_map_foreach_entry_const_func func, void *data);
+
+extern bt_bool bt_value_map_has_entry(const bt_value *map_obj,
+               const char *key);
+
+extern bt_value_status bt_value_map_extend(
+               const bt_value *base_map_obj,
+               const bt_value *extension_map_obj,
+               bt_value **extended_map_obj);
+
+extern void bt_value_get_ref(const bt_value *value);
+
+extern void bt_value_put_ref(const bt_value *value);
+
+/* From value.h */
+
+extern bt_value *const bt_value_null;
+
+extern bt_value *bt_value_bool_create(void);
+
+extern bt_value *bt_value_bool_create_init(bt_bool val);
+
+extern void bt_value_bool_set(bt_value *bool_obj, bt_bool val);
+
+extern bt_value *bt_value_unsigned_integer_create(void);
+
+extern bt_value *bt_value_unsigned_integer_create_init(uint64_t val);
+
+extern void bt_value_unsigned_integer_set(bt_value *integer_obj, uint64_t val);
+
+extern bt_value *bt_value_signed_integer_create(void);
+
+extern bt_value *bt_value_signed_integer_create_init(int64_t val);
+
+extern void bt_value_signed_integer_set(bt_value *integer_obj, int64_t val);
+
+extern bt_value *bt_value_real_create(void);
+
+extern bt_value *bt_value_real_create_init(double val);
+
+extern void bt_value_real_set(bt_value *real_obj, double val);
+
+extern bt_value *bt_value_string_create(void);
+
+extern bt_value *bt_value_string_create_init(const char *val);
+
+extern bt_value_status bt_value_string_set(bt_value *string_obj,
+               const char *val);
+
+extern bt_value *bt_value_array_create(void);
+
+extern bt_value *bt_value_array_borrow_element_by_index(
+               bt_value *array_obj, uint64_t index);
+
+extern bt_value_status bt_value_array_append_element(
+               bt_value *array_obj,
+               bt_value *element_obj);
+
+extern bt_value_status bt_value_array_append_bool_element(
+               bt_value *array_obj, bt_bool val);
+
+extern bt_value_status bt_value_array_append_unsigned_integer_element(
+               bt_value *array_obj, uint64_t val);
+
+extern bt_value_status bt_value_array_append_signed_integer_element(
+               bt_value *array_obj, int64_t val);
+
+extern bt_value_status bt_value_array_append_real_element(
+               bt_value *array_obj, double val);
+
+extern bt_value_status bt_value_array_append_string_element(
+               bt_value *array_obj, const char *val);
+
+extern bt_value_status bt_value_array_append_empty_array_element(
+               bt_value *array_obj);
+
+extern bt_value_status bt_value_array_append_empty_map_element(
+               bt_value *array_obj);
+
+extern bt_value_status bt_value_array_set_element_by_index(
+               bt_value *array_obj, uint64_t index,
+               bt_value *element_obj);
+
+extern bt_value *bt_value_map_create(void);
+
+extern bt_value *bt_value_map_borrow_entry_value(
+               bt_value *map_obj, const char *key);
+
+typedef bt_bool (* bt_value_map_foreach_entry_func)(const char *key,
+               bt_value *object, void *data);
+
+extern bt_value_status bt_value_map_foreach_entry(
+               bt_value *map_obj,
+               bt_value_map_foreach_entry_func func, void *data);
+
+extern bt_value_status bt_value_map_insert_entry(
+               bt_value *map_obj, const char *key,
+               bt_value *element_obj);
+
+extern bt_value_status bt_value_map_insert_bool_entry(
+               bt_value *map_obj, const char *key, bt_bool val);
+
+extern bt_value_status bt_value_map_insert_unsigned_integer_entry(
+               bt_value *map_obj, const char *key, uint64_t val);
+
+extern bt_value_status bt_value_map_insert_signed_integer_entry(
+               bt_value *map_obj, const char *key, int64_t val);
+
+extern bt_value_status bt_value_map_insert_real_entry(
+               bt_value *map_obj, const char *key, double val);
+
+extern bt_value_status bt_value_map_insert_string_entry(
+               bt_value *map_obj, const char *key,
+               const char *val);
+
+extern bt_value_status bt_value_map_insert_empty_array_entry(
+               bt_value *map_obj, const char *key);
+
+extern bt_value_status bt_value_map_insert_empty_map_entry(
+               bt_value *map_obj, const char *key);
+
+%{
+struct bt_value_map_get_keys_data {
+       struct bt_value *keys;
+};
+
+static int bt_value_map_get_keys_cb(const char *key, const struct bt_value *object, void *data)
+{
+       enum bt_value_status status;
+       struct bt_value_map_get_keys_data *priv_data = data;
+
+       status = bt_value_array_append_string_element(priv_data->keys, key);
+       if (status != BT_VALUE_STATUS_OK) {
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj)
+{
+       enum bt_value_status status;
+       struct bt_value_map_get_keys_data data;
+
+       data.keys = bt_value_array_create();
+       if (!data.keys) {
+               return NULL;
+       }
+
+       status = bt_value_map_foreach_entry_const(map_obj, bt_value_map_get_keys_cb,
+               &data);
+       if (status != BT_VALUE_STATUS_OK) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (data.keys) {
+               BT_VALUE_PUT_REF_AND_RESET(data.keys);
+       }
+
+end:
+       return data.keys;
+}
+%}
+
+struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj);
diff --git a/src/bindings/python/bt2/bt2/native_bt_version.i b/src/bindings/python/bt2/bt2/native_bt_version.i
new file mode 100644 (file)
index 0000000..3d99e7d
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Version functions */
+int bt_version_get_major(void);
+int bt_version_get_minor(void);
+int bt_version_get_patch(void);
+const char *bt_version_get_extra(void);
diff --git a/src/bindings/python/bt2/bt2/object.py b/src/bindings/python/bt2/bt2/object.py
new file mode 100644 (file)
index 0000000..218965d
--- /dev/null
@@ -0,0 +1,138 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+class _BaseObject:
+    # Ensure that the object always has _ptr set, even if it throws during
+    # construction.
+
+    def __new__(cls, *args, **kwargs):
+        obj = super().__new__(cls)
+        obj._ptr = None
+        return obj
+
+    def __init__(self, ptr):
+        self._ptr = ptr
+
+    @property
+    def addr(self):
+        return int(self._ptr)
+
+    def __repr__(self):
+        return '<{}.{} object @ {}>'.format(self.__class__.__module__,
+                                            self.__class__.__name__,
+                                            hex(self.addr))
+
+    def __copy__(self):
+        raise NotImplementedError
+
+    def __deepcopy__(self, memo):
+        raise NotImplementedError
+
+
+# A Python object that is itself not refcounted, but is wholly owned by an
+# object that is itself refcounted (a _SharedObject).  A Babeltrace unique
+# object gets destroyed once its owner gets destroyed (its refcount drops to
+# 0).
+#
+# In the Python bindings, to avoid having to deal with issues with the lifetime
+# of unique objects, we make it so acquiring a reference on a unique object
+# acquires a reference on its owner.
+
+class _UniqueObject(_BaseObject):
+
+    # Create a _UniqueObject.
+    #
+    #   - ptr: SWIG Object, pointer to the unique object.
+    #   - owner_ptr: SWIG Object, pointer to the owner of the unique
+    #     object.  A new reference is acquired.
+    #   - owner_get_ref: Callback to get a reference on the owner
+    #   - owner_put_ref: Callback to put a reference on the owner.
+
+    @classmethod
+    def _create_from_ptr_and_get_ref(cls, ptr, owner_ptr,
+                                     owner_get_ref, owner_put_ref):
+        obj = cls.__new__(cls)
+
+        obj._ptr = ptr
+        obj._owner_ptr = owner_ptr
+        obj._owner_get_ref = owner_get_ref
+        obj._owner_put_ref = owner_put_ref
+
+        obj._owner_get_ref(obj._owner_ptr)
+
+        return obj
+
+    def __del__(self):
+        self._owner_put_ref(self._owner_ptr)
+
+
+# Python object that owns a reference to a Babeltrace object.
+class _SharedObject(_BaseObject):
+
+    # Get a new reference on ptr.
+    #
+    # This must be implemented by subclasses to work correctly with a pointer
+    # of the native type they wrap.
+
+    @staticmethod
+    def _get_ref(ptr):
+        raise NotImplementedError
+
+    # Put a reference on ptr.
+    #
+    # This must be implemented by subclasses to work correctly with a pointer
+    # of the native type they wrap.
+
+    @staticmethod
+    def _put_ref(ptr):
+        raise NotImplementedError
+
+    # Create a _SharedObject from an existing reference.
+    #
+    # This assumes that the caller owns a reference to the Babeltrace object
+    # and transfers this ownership to the newly created Python object.
+
+    @classmethod
+    def _create_from_ptr(cls, ptr_owned):
+        obj = cls.__new__(cls)
+        obj._ptr = ptr_owned
+        return obj
+
+    # Like _create_from_ptr, but acquire a new reference rather than
+    # stealing the caller's reference.
+
+    @classmethod
+    def _create_from_ptr_and_get_ref(cls, ptr):
+        obj = cls._create_from_ptr(ptr)
+        cls._get_ref(obj._ptr)
+        return obj
+
+    def _release(self):
+        """Return the wrapped pointer, transfer its ownership to the
+        caller."""
+        ptr = self._ptr
+        self._ptr = None
+        return ptr
+
+    def __del__(self):
+        self._put_ref(self._ptr)
diff --git a/src/bindings/python/bt2/bt2/packet.py b/src/bindings/python/bt2/bt2/packet.py
new file mode 100644 (file)
index 0000000..93e9ac8
--- /dev/null
@@ -0,0 +1,47 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object
+import bt2.field
+import bt2
+
+
+class _Packet(object._SharedObject):
+    _get_ref = staticmethod(native_bt.packet_get_ref)
+    _put_ref = staticmethod(native_bt.packet_put_ref)
+
+    @property
+    def stream(self):
+        stream_ptr = native_bt.packet_borrow_stream(self._ptr)
+        assert stream_ptr is not None
+        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
+
+    @property
+    def context_field(self):
+        field_ptr = native_bt.packet_borrow_context_field(self._ptr)
+
+        if field_ptr is None:
+            return
+
+        return bt2.field._create_field_from_ptr(field_ptr, self._ptr,
+                                                self._get_ref,
+                                                self._put_ref)
diff --git a/src/bindings/python/bt2/bt2/plugin.py b/src/bindings/python/bt2/bt2/plugin.py
new file mode 100644 (file)
index 0000000..2d0d8b0
--- /dev/null
@@ -0,0 +1,218 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import collections.abc
+import bt2.component
+import os.path
+import bt2
+
+
+def find_plugins(path, recurse=True):
+    utils._check_str(path)
+    utils._check_bool(recurse)
+    plugin_set_ptr = None
+
+    if os.path.isfile(path):
+        plugin_set_ptr = native_bt.plugin_find_all_from_file(path)
+    elif os.path.isdir(path):
+        plugin_set_ptr = native_bt.plugin_find_all_from_dir(path, int(recurse))
+
+    if plugin_set_ptr is None:
+        return
+
+    return _PluginSet._create_from_ptr(plugin_set_ptr)
+
+
+def find_plugin(name):
+    utils._check_str(name)
+    ptr = native_bt.plugin_find(name)
+
+    if ptr is None:
+        return
+
+    return _Plugin._create_from_ptr(ptr)
+
+
+class _PluginSet(object._SharedObject, collections.abc.Sequence):
+    _put_ref = staticmethod(native_bt.plugin_set_put_ref)
+    _get_ref = staticmethod(native_bt.plugin_set_get_ref)
+
+    def __len__(self):
+        count = native_bt.plugin_set_get_plugin_count(self._ptr)
+        assert(count >= 0)
+        return count
+
+    def __getitem__(self, index):
+        utils._check_uint64(index)
+
+        if index >= len(self):
+            raise IndexError
+
+        plugin_ptr = native_bt.plugin_set_borrow_plugin_by_index_const(self._ptr, index)
+        assert plugin_ptr is not None
+        return _Plugin._create_from_ptr_and_get_ref(plugin_ptr)
+
+
+class _PluginVersion:
+    def __init__(self, major, minor, patch, extra):
+        self._major = major
+        self._minor = minor
+        self._patch = patch
+        self._extra = extra
+
+    @property
+    def major(self):
+        return self._major
+
+    @property
+    def minor(self):
+        return self._minor
+
+    @property
+    def patch(self):
+        return self._patch
+
+    @property
+    def extra(self):
+        return self._extra
+
+    def __str__(self):
+        extra = ''
+
+        if self._extra is not None:
+            extra = self._extra
+
+        return '{}.{}.{}{}'.format(self._major, self._minor, self._patch, extra)
+
+
+class _PluginComponentClassesIterator(collections.abc.Iterator):
+    def __init__(self, plugin_comp_cls):
+        self._plugin_comp_cls = plugin_comp_cls
+        self._at = 0
+
+    def __next__(self):
+        plugin_ptr = self._plugin_comp_cls._plugin._ptr
+        total = self._plugin_comp_cls._component_class_count(plugin_ptr)
+
+        if self._at == total:
+            raise StopIteration
+
+        comp_cls_ptr = self._plugin_comp_cls._borrow_component_class_by_index(plugin_ptr, self._at)
+        assert comp_cls_ptr is not None
+        self._at += 1
+
+        comp_cls_type = self._plugin_comp_cls._comp_cls_type
+        comp_cls_pycls = bt2.component._COMP_CLS_TYPE_TO_GENERIC_COMP_CLS_PYCLS[comp_cls_type]
+        comp_cls_ptr = comp_cls_pycls._as_component_class_ptr(comp_cls_ptr)
+        name = native_bt.component_class_get_name(comp_cls_ptr)
+        assert name is not None
+        return name
+
+
+class _PluginComponentClasses(collections.abc.Mapping):
+    def __init__(self, plugin):
+        self._plugin = plugin
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+        cc_ptr = self._borrow_component_class_by_name(self._plugin._ptr, key)
+
+        if cc_ptr is None:
+            raise KeyError(key)
+
+        return bt2.component._create_component_class_from_ptr_and_get_ref(cc_ptr, self._comp_cls_type)
+
+    def __len__(self):
+        return self._component_class_count(self._plugin._ptr)
+
+    def __iter__(self):
+        return _PluginComponentClassesIterator(self)
+
+
+class _PluginSourceComponentClasses(_PluginComponentClasses):
+    _component_class_count = staticmethod(native_bt.plugin_get_source_component_class_count)
+    _borrow_component_class_by_name = staticmethod(native_bt.plugin_borrow_source_component_class_by_name_const)
+    _borrow_component_class_by_index = staticmethod(native_bt.plugin_borrow_source_component_class_by_index_const)
+    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_SOURCE
+
+
+class _PluginFilterComponentClasses(_PluginComponentClasses):
+    _component_class_count = staticmethod(native_bt.plugin_get_filter_component_class_count)
+    _borrow_component_class_by_name = staticmethod(native_bt.plugin_borrow_filter_component_class_by_name_const)
+    _borrow_component_class_by_index = staticmethod(native_bt.plugin_borrow_filter_component_class_by_index_const)
+    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_FILTER
+
+
+class _PluginSinkComponentClasses(_PluginComponentClasses):
+    _component_class_count = staticmethod(native_bt.plugin_get_sink_component_class_count)
+    _borrow_component_class_by_name = staticmethod(native_bt.plugin_borrow_sink_component_class_by_name_const)
+    _borrow_component_class_by_index = staticmethod(native_bt.plugin_borrow_sink_component_class_by_index_const)
+    _comp_cls_type = native_bt.COMPONENT_CLASS_TYPE_SINK
+
+
+class _Plugin(object._SharedObject):
+    _put_ref = staticmethod(native_bt.plugin_put_ref)
+    _get_ref = staticmethod(native_bt.plugin_get_ref)
+
+    @property
+    def name(self):
+        name = native_bt.plugin_get_name(self._ptr)
+        assert(name is not None)
+        return name
+
+    @property
+    def author(self):
+        return native_bt.plugin_get_author(self._ptr)
+
+    @property
+    def license(self):
+        return native_bt.plugin_get_license(self._ptr)
+
+    @property
+    def description(self):
+        return native_bt.plugin_get_description(self._ptr)
+
+    @property
+    def path(self):
+        return native_bt.plugin_get_path(self._ptr)
+
+    @property
+    def version(self):
+        status, major, minor, patch, extra = native_bt.plugin_get_version_wrapper(self._ptr)
+
+        if status == native_bt.PROPERTY_AVAILABILITY_NOT_AVAILABLE:
+            return
+
+        return _PluginVersion(major, minor, patch, extra)
+
+    @property
+    def source_component_classes(self):
+        return _PluginSourceComponentClasses(self)
+
+    @property
+    def filter_component_classes(self):
+        return _PluginFilterComponentClasses(self)
+
+    @property
+    def sink_component_classes(self):
+        return _PluginSinkComponentClasses(self)
diff --git a/src/bindings/python/bt2/bt2/port.py b/src/bindings/python/bt2/bt2/port.py
new file mode 100644 (file)
index 0000000..f7c2366
--- /dev/null
@@ -0,0 +1,136 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object
+import bt2.component
+import bt2.connection
+import bt2.message_iterator
+import bt2.message
+import bt2
+
+
+def _create_from_ptr_and_get_ref(ptr, port_type):
+    cls = _PORT_TYPE_TO_PYCLS.get(port_type, None)
+
+    if cls is None:
+        raise bt2.Error('unknown port type: {}'.format(port_type))
+
+    return cls._create_from_ptr_and_get_ref(ptr)
+
+
+def _create_self_from_ptr_and_get_ref(ptr, port_type):
+    cls = _PORT_TYPE_TO_USER_PYCLS.get(port_type, None)
+
+    if cls is None:
+        raise bt2.Error('unknown port type: {}'.format(port_type))
+
+    return cls._create_from_ptr_and_get_ref(ptr)
+
+
+class _Port(object._SharedObject):
+    @classmethod
+    def _get_ref(cls, ptr):
+        ptr = cls._as_port_ptr(ptr)
+        return native_bt.port_get_ref(ptr)
+
+    @classmethod
+    def _put_ref(cls, ptr):
+        ptr = cls._as_port_ptr(ptr)
+        return native_bt.port_put_ref(ptr)
+
+    @property
+    def name(self):
+        ptr = self._as_port_ptr(self._ptr)
+        name = native_bt.port_get_name(ptr)
+        assert name is not None
+        return name
+
+    @property
+    def connection(self):
+        ptr = self._as_port_ptr(self._ptr)
+        conn_ptr = native_bt.port_borrow_connection_const(ptr)
+
+        if conn_ptr is None:
+            return
+
+        return bt2.connection._Connection._create_from_ptr_and_get_ref(conn_ptr)
+
+    @property
+    def is_connected(self):
+        return self.connection is not None
+
+
+class _InputPort(_Port):
+    _as_port_ptr = staticmethod(native_bt.port_input_as_port_const)
+
+
+class _OutputPort(_Port):
+    _as_port_ptr = staticmethod(native_bt.port_output_as_port_const)
+
+
+class _UserComponentPort(_Port):
+    @classmethod
+    def _as_port_ptr(cls, ptr):
+        ptr = cls._as_self_port_ptr(ptr)
+        return native_bt.self_component_port_as_port(ptr)
+
+    @property
+    def connection(self):
+        ptr = self._as_port_ptr(self._ptr)
+        conn_ptr = native_bt.port_borrow_connection_const(ptr)
+
+        if conn_ptr is None:
+            return
+
+        return bt2.connection._Connection._create_from_ptr_and_get_ref(conn_ptr)
+
+    @property
+    def user_data(self):
+        ptr = self._as_self_port_ptr(self._ptr)
+        return native_bt.self_component_port_get_data(ptr)
+
+
+class _UserComponentInputPort(_UserComponentPort, _InputPort):
+    _as_self_port_ptr = staticmethod(native_bt.self_component_port_input_as_self_component_port)
+
+    def create_message_iterator(self):
+        msg_iter_ptr = native_bt.self_component_port_input_message_iterator_create(self._ptr)
+        if msg_iter_ptr is None:
+            raise bt2.CreationError('cannot create message iterator object')
+
+        return bt2.message_iterator._UserComponentInputPortMessageIterator(msg_iter_ptr)
+
+
+class _UserComponentOutputPort(_UserComponentPort, _OutputPort):
+    _as_self_port_ptr = staticmethod(native_bt.self_component_port_output_as_self_component_port)
+
+
+_PORT_TYPE_TO_PYCLS = {
+    native_bt.PORT_TYPE_INPUT: _InputPort,
+    native_bt.PORT_TYPE_OUTPUT: _OutputPort,
+}
+
+
+_PORT_TYPE_TO_USER_PYCLS = {
+    native_bt.PORT_TYPE_INPUT: _UserComponentInputPort,
+    native_bt.PORT_TYPE_OUTPUT: _UserComponentOutputPort,
+}
diff --git a/src/bindings/python/bt2/bt2/py_plugin.py b/src/bindings/python/bt2/bt2/py_plugin.py
new file mode 100644 (file)
index 0000000..b845030
--- /dev/null
@@ -0,0 +1,135 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import utils
+import bt2.component
+
+
+def plugin_component_class(component_class):
+    if not issubclass(component_class, bt2.component._UserComponent):
+        raise TypeError('component class is not a subclass of a user component class')
+
+    component_class._bt_plugin_component_class = None
+    return component_class
+
+
+def register_plugin(module_name, name, description=None, author=None,
+                    license=None, version=None):
+    import sys
+
+    if module_name not in sys.modules:
+        raise RuntimeError("cannot find module '{}' in loaded modules".format(module_name))
+
+    utils._check_str(name)
+
+    if description is not None:
+        utils._check_str(description)
+
+    if author is not None:
+        utils._check_str(author)
+
+    if license is not None:
+        utils._check_str(license)
+
+    if version is not None:
+        if not _validate_version(version):
+            raise ValueError('wrong version: expecting a tuple: (major, minor, patch) or (major, minor, patch, extra)')
+
+    sys.modules[module_name]._bt_plugin_info = _PluginInfo(name, description,
+                                                           author, license,
+                                                           version)
+
+
+def _validate_version(version):
+    if version is None:
+        return True
+
+    if not isinstance(version, tuple):
+        return False
+
+    if len(version) < 3 or len(version) > 4:
+        return False
+
+    if not isinstance(version[0], int):
+        return False
+
+    if not isinstance(version[1], int):
+        return False
+
+    if not isinstance(version[2], int):
+        return False
+
+    if len(version) == 4:
+        if not isinstance(version[3], str):
+            return False
+
+    return True
+
+
+class _PluginInfo:
+    def __init__(self, name, description, author, license, version):
+        self.name = name
+        self.description = description
+        self.author = author
+        self.license = license
+        self.version = version
+        self.comp_class_addrs = None
+
+
+# called by the BT plugin system
+def _try_load_plugin_module(path):
+    import importlib.machinery
+    import inspect
+    import hashlib
+
+    if path is None:
+        raise TypeError('missing path')
+
+    # In order to load the module uniquely from its path, even from
+    # different files which have the same basename, we hash the path
+    # and prefix with `bt_plugin_`. This is its key in sys.modules.
+    h = hashlib.sha256()
+    h.update(path.encode())
+    module_name = 'bt_plugin_{}'.format(h.hexdigest())
+
+    # try loading the module: any raised exception is catched by the caller
+    mod = importlib.machinery.SourceFileLoader(module_name, path).load_module()
+
+    # we have the module: look for its plugin info first
+    if not hasattr(mod, '_bt_plugin_info'):
+        raise RuntimeError("missing '_bt_plugin_info' module attribute")
+
+    plugin_info = mod._bt_plugin_info
+
+    # search for user component classes
+    def is_user_comp_class(obj):
+        if not inspect.isclass(obj):
+            return False
+
+        if not hasattr(obj, '_bt_plugin_component_class'):
+            return False
+
+        return True
+
+    comp_class_entries = inspect.getmembers(mod, is_user_comp_class)
+    plugin_info.comp_class_addrs = [entry[1].addr for entry in comp_class_entries]
+    return plugin_info
diff --git a/src/bindings/python/bt2/bt2/query_executor.py b/src/bindings/python/bt2/bt2/query_executor.py
new file mode 100644 (file)
index 0000000..a87713f
--- /dev/null
@@ -0,0 +1,93 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.component
+import bt2
+
+
+class QueryExecutor(object._SharedObject):
+    _get_ref = staticmethod(native_bt.query_executor_get_ref)
+    _put_ref = staticmethod(native_bt.query_executor_put_ref)
+
+    def _handle_status(self, status, gen_error_msg):
+        if status == native_bt.QUERY_EXECUTOR_STATUS_AGAIN:
+            raise bt2.TryAgain
+        elif status == native_bt.QUERY_EXECUTOR_STATUS_CANCELED:
+            raise bt2.QueryExecutorCanceled
+        elif status == native_bt.QUERY_EXECUTOR_STATUS_INVALID_OBJECT:
+            raise bt2.InvalidQueryObject
+        elif status == native_bt.QUERY_EXECUTOR_STATUS_INVALID_PARAMS:
+            raise bt2.InvalidQueryParams
+        elif status < 0:
+            raise bt2.Error(gen_error_msg)
+
+    def __init__(self):
+        ptr = native_bt.query_executor_create()
+
+        if ptr is None:
+            raise bt2.CreationError('cannot create query executor object')
+
+        super().__init__(ptr)
+
+    def cancel(self):
+        status = native_bt.query_executor_cancel(self._ptr)
+        self._handle_status(status, 'cannot cancel query executor object')
+
+    @property
+    def is_canceled(self):
+        is_canceled = native_bt.query_executor_is_canceled(self._ptr)
+        assert(is_canceled >= 0)
+        return is_canceled > 0
+
+    def query(self, component_class, object, params=None):
+        if self.is_canceled:
+            raise bt2.QueryExecutorCanceled
+
+        if not isinstance(component_class, bt2.component._GenericComponentClass):
+            err = False
+
+            try:
+                if not issubclass(component_class, bt2.component._UserComponent):
+                    err = True
+            except TypeError:
+                err = True
+
+            if err:
+                o = component_class
+                raise TypeError("'{}' is not a component class object".format(o))
+
+        utils._check_str(object)
+
+        if params is None:
+            params_ptr = native_bt.value_null
+        else:
+            params = bt2.create_value(params)
+            params_ptr = params._ptr
+
+        cc_ptr = component_class._component_class_ptr()
+
+        status, result_ptr = native_bt.query_executor_query(self._ptr, cc_ptr,
+                                                            object, params_ptr)
+        self._handle_status(status, 'cannot query component class')
+        assert(result_ptr)
+        return bt2.value._create_from_ptr(result_ptr)
diff --git a/src/bindings/python/bt2/bt2/stream.py b/src/bindings/python/bt2/bt2/stream.py
new file mode 100644 (file)
index 0000000..5accfcd
--- /dev/null
@@ -0,0 +1,60 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2016-2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, utils
+import bt2.packet
+import bt2.event
+import bt2
+
+
+class _Stream(bt2.object._SharedObject):
+    _get_ref = staticmethod(native_bt.stream_get_ref)
+    _put_ref = staticmethod(native_bt.stream_put_ref)
+
+    @property
+    def cls(self):
+        stream_class_ptr = native_bt.stream_borrow_class(self._ptr)
+        assert stream_class_ptr is not None
+        return bt2.stream_class._StreamClass._create_from_ptr_and_get_ref(stream_class_ptr)
+
+    @property
+    def name(self):
+        return native_bt.stream_get_name(self._ptr)
+
+    def _name(self, name):
+        utils._check_str(name)
+        native_bt.stream_set_name(self._ptr, name)
+
+    _name = property(fset=_name)
+
+    @property
+    def id(self):
+        id = native_bt.stream_get_id(self._ptr)
+        return id if id >= 0 else None
+
+    def create_packet(self):
+        packet_ptr = native_bt.packet_create(self._ptr)
+
+        if packet_ptr is None:
+            raise bt2.CreationError('cannot create packet object')
+
+        return bt2.packet._Packet._create_from_ptr(packet_ptr)
diff --git a/src/bindings/python/bt2/bt2/stream_class.py b/src/bindings/python/bt2/bt2/stream_class.py
new file mode 100644 (file)
index 0000000..54b5b38
--- /dev/null
@@ -0,0 +1,253 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.field_class
+import bt2.event_class
+import collections.abc
+import bt2.stream
+import bt2
+
+
+class _StreamClass(object._SharedObject, collections.abc.Mapping):
+    _get_ref = staticmethod(native_bt.stream_class_get_ref)
+    _put_ref = staticmethod(native_bt.stream_class_put_ref)
+
+    def __getitem__(self, key):
+        utils._check_int64(key)
+        ec_ptr = native_bt.stream_class_borrow_event_class_by_id(self._ptr, key)
+
+        if ec_ptr is None:
+            raise KeyError(key)
+
+        return bt2.event_class._EventClass._create_from_ptr_and_get_ref(ec_ptr)
+
+    def __len__(self):
+        count = native_bt.stream_class_get_event_class_count(self._ptr)
+        assert count >= 0
+        return count
+
+    def __iter__(self):
+        for idx in range(len(self)):
+            ec_ptr = native_bt.stream_class_borrow_event_class_by_index_const(self._ptr, idx)
+            assert ec_ptr is not None
+
+            id = native_bt.event_class_get_id(ec_ptr)
+            assert id >= 0
+
+            yield id
+
+    def create_event_class(self, id=None, name=None, log_level=None, emf_uri=None,
+                           specific_context_field_class=None,
+                           payload_field_class=None):
+        if self.assigns_automatic_event_class_id:
+            if id is not None:
+                raise ValueError('id provided, but stream class assigns automatic event class ids')
+
+            ec_ptr = native_bt.event_class_create(self._ptr)
+        else:
+            if id is None:
+                raise ValueError('id not provided, but stream class does not assign automatic event class ids')
+
+            utils._check_uint64(id)
+            ec_ptr = native_bt.event_class_create_with_id(self._ptr, id)
+
+        event_class = bt2.event_class._EventClass._create_from_ptr(ec_ptr)
+
+        if name is not None:
+            event_class._name = name
+
+        if log_level is not None:
+            event_class._log_level = log_level
+
+        if emf_uri is not None:
+            event_class._emf_uri = emf_uri
+
+        if specific_context_field_class is not None:
+            event_class._specific_context_field_class = specific_context_field_class
+
+        if payload_field_class is not None:
+            event_class._payload_field_class = payload_field_class
+
+        return event_class
+
+    @property
+    def trace_class(self):
+        tc_ptr = native_bt.stream_class_borrow_trace_class_const(self._ptr)
+
+        if tc_ptr is not None:
+            return bt2._TraceClass._create_from_ptr_and_get_ref(tc_ptr)
+
+    @property
+    def name(self):
+        return native_bt.stream_class_get_name(self._ptr)
+
+    def _name(self, name):
+        utils._check_str(name)
+        ret = native_bt.stream_class_set_name(self._ptr, name)
+        utils._handle_ret(ret, "cannot set stream class object's name")
+
+    _name = property(fset=_name)
+
+    @property
+    def assigns_automatic_event_class_id(self):
+        return native_bt.stream_class_assigns_automatic_event_class_id(self._ptr)
+
+    def _assigns_automatic_event_class_id(self, auto_id):
+        utils._check_bool(auto_id)
+        return native_bt.stream_class_set_assigns_automatic_event_class_id(self._ptr, auto_id)
+
+    _assigns_automatic_event_class_id = property(fset=_assigns_automatic_event_class_id)
+
+    @property
+    def assigns_automatic_stream_id(self):
+        return native_bt.stream_class_assigns_automatic_stream_id(self._ptr)
+
+    def _assigns_automatic_stream_id(self, auto_id):
+        utils._check_bool(auto_id)
+        return native_bt.stream_class_set_assigns_automatic_stream_id(self._ptr, auto_id)
+
+    _assigns_automatic_stream_id = property(fset=_assigns_automatic_stream_id)
+
+    @property
+    def packets_have_beginning_default_clock_snapshot(self):
+        return native_bt.stream_class_packets_have_beginning_default_clock_snapshot(self._ptr)
+
+    def _packets_have_beginning_default_clock_snapshot(self, value):
+        utils._check_bool(value)
+        native_bt.stream_class_set_packets_have_beginning_default_clock_snapshot(self._ptr, value)
+
+    _packets_have_beginning_default_clock_snapshot = property(fset=_packets_have_beginning_default_clock_snapshot)
+
+    @property
+    def packets_have_end_default_clock_snapshot(self):
+        return native_bt.stream_class_packets_have_end_default_clock_snapshot(self._ptr)
+
+    def _packets_have_end_default_clock_snapshot(self, value):
+        utils._check_bool(value)
+        native_bt.stream_class_set_packets_have_end_default_clock_snapshot(self._ptr, value)
+
+    _packets_have_end_default_clock_snapshot = property(fset=_packets_have_end_default_clock_snapshot)
+
+    @property
+    def supports_discarded_events(self):
+        return native_bt.stream_class_supports_discarded_events(self._ptr)
+
+    def _set_supports_discarded_events(self, supports, with_cs=False):
+        utils._check_bool(supports)
+        utils._check_bool(with_cs)
+
+        if not supports and with_cs:
+            raise ValueError('cannot not support discarded events, but have default clock snapshots')
+
+        native_bt.stream_class_set_supports_discarded_events(self._ptr, supports, with_cs)
+
+    @property
+    def discarded_events_have_default_clock_snapshots(self):
+        return native_bt.stream_class_discarded_events_have_default_clock_snapshots(self._ptr)
+
+    @property
+    def supports_discarded_packets(self):
+        return native_bt.stream_class_supports_discarded_packets(self._ptr)
+
+    def _set_supports_discarded_packets(self, supports, with_cs):
+        utils._check_bool(supports)
+        utils._check_bool(with_cs)
+
+        if not supports and with_cs:
+            raise ValueError('cannot not support discarded packets, but have default clock snapshots')
+
+        native_bt.stream_class_set_supports_discarded_packets(self._ptr, supports, with_cs)
+
+    @property
+    def discarded_packets_have_default_clock_snapshots(self):
+        return native_bt.stream_class_discarded_packets_have_default_clock_snapshots(self._ptr)
+
+    @property
+    def id(self):
+        id = native_bt.stream_class_get_id(self._ptr)
+
+        if id < 0:
+            return
+
+        return id
+
+    @id.setter
+    def id(self, id):
+        utils._check_int64(id)
+        ret = native_bt.stream_class_set_id(self._ptr, id)
+        utils._handle_ret(ret, "cannot set stream class object's ID")
+
+    @property
+    def packet_context_field_class(self):
+        fc_ptr = native_bt.stream_class_borrow_packet_context_field_class_const(self._ptr)
+
+        if fc_ptr is None:
+            return
+
+        return bt2.field_class._create_field_class_from_ptr_and_get_ref(fc_ptr)
+
+    def _packet_context_field_class(self, packet_context_field_class):
+        if packet_context_field_class is not None:
+            utils._check_type(packet_context_field_class,
+                              bt2.field_class._StructureFieldClass)
+            ret = native_bt.stream_class_set_packet_context_field_class(self._ptr,
+                                                                        packet_context_field_class._ptr)
+            utils._handle_ret(ret, "cannot set stream class' packet context field class")
+
+    _packet_context_field_class = property(fset=_packet_context_field_class)
+
+    @property
+    def event_common_context_field_class(self):
+        fc_ptr = native_bt.stream_class_borrow_event_common_context_field_class_const(self._ptr)
+
+        if fc_ptr is None:
+            return
+
+        return bt2.field_class._create_field_class_from_ptr_and_get_ref(fc_ptr)
+
+    def _event_common_context_field_class(self, event_common_context_field_class):
+        if event_common_context_field_class is not None:
+            utils._check_type(event_common_context_field_class,
+                              bt2.field_class._StructureFieldClass)
+
+            set_context_fn = native_bt.stream_class_set_event_common_context_field_class
+            ret = set_context_fn(self._ptr, event_common_context_field_class._ptr)
+
+            utils._handle_ret(ret, "cannot set stream class' event context field type")
+
+    _event_common_context_field_class = property(fset=_event_common_context_field_class)
+
+    @property
+    def default_clock_class(self):
+        cc_ptr = native_bt.stream_class_borrow_default_clock_class(self._ptr)
+        if cc_ptr is None:
+            return
+
+        return bt2.clock_class._ClockClass._create_from_ptr_and_get_ref(cc_ptr)
+
+    def _default_clock_class(self, clock_class):
+        utils._check_type(clock_class, bt2.clock_class._ClockClass)
+        native_bt.stream_class_set_default_clock_class(
+            self._ptr, clock_class._ptr)
+
+    _default_clock_class = property(fset=_default_clock_class)
diff --git a/src/bindings/python/bt2/bt2/trace.py b/src/bindings/python/bt2/bt2/trace.py
new file mode 100644 (file)
index 0000000..5830ec3
--- /dev/null
@@ -0,0 +1,122 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import bt2.field_class
+import collections.abc
+import bt2.value
+import bt2.stream
+import bt2.trace_class
+import bt2
+import functools
+
+
+def _trace_destruction_listener_from_native(user_listener, trace_ptr):
+    trace = bt2.trace._Trace._create_from_ptr_and_get_ref(trace_ptr)
+    user_listener(trace)
+
+
+class _Trace(object._SharedObject, collections.abc.Mapping):
+    _get_ref = staticmethod(native_bt.trace_get_ref)
+    _put_ref = staticmethod(native_bt.trace_put_ref)
+
+    def __len__(self):
+        count = native_bt.trace_get_stream_count(self._ptr)
+        assert count >= 0
+        return count
+
+    def __getitem__(self, id):
+        utils._check_uint64(id)
+
+        stream_ptr = native_bt.trace_borrow_stream_by_id_const(self._ptr, id)
+
+        if stream_ptr is None:
+            raise KeyError(id)
+
+        return bt2.stream._Stream._create_from_ptr_and_get_ref(stream_ptr)
+
+    def __iter__(self):
+        for idx in range(len(self)):
+            stream_ptr = native_bt.trace_borrow_stream_by_index_const(self._ptr, idx)
+            assert stream_ptr is not None
+
+            id = native_bt.stream_get_id(stream_ptr)
+            assert id >= 0
+
+            yield id
+
+    @property
+    def cls(self):
+        trace_class_ptr = native_bt.trace_borrow_class(self._ptr)
+        assert trace_class_ptr is not None
+        return bt2.trace_class._TraceClass._create_from_ptr_and_get_ref(trace_class_ptr)
+
+    @property
+    def name(self):
+        return native_bt.trace_get_name(self._ptr)
+
+    def _name(self, name):
+        utils._check_str(name)
+        ret = native_bt.trace_set_name(self._ptr, name)
+        utils._handle_ret(ret, "cannot set trace class object's name")
+
+    _name = property(fset=_name)
+
+    def create_stream(self, stream_class, id=None, name=None):
+        utils._check_type(stream_class, bt2.stream_class._StreamClass)
+
+        if stream_class.assigns_automatic_stream_id:
+            if id is not None:
+                raise ValueError("id provided, but stream class assigns automatic stream ids")
+
+            stream_ptr = native_bt.stream_create(stream_class._ptr, self._ptr)
+        else:
+            if id is None:
+                raise ValueError("id not provided, but stream class does not assign automatic stream ids")
+
+            utils._check_uint64(id)
+            stream_ptr = native_bt.stream_create_with_id(stream_class._ptr, self._ptr, id)
+
+        if stream_ptr is None:
+            raise bt2.CreationError('cannot create stream object')
+
+        stream = bt2.stream._Stream._create_from_ptr(stream_ptr)
+
+        if name is not None:
+            stream._name = name
+
+        return stream
+
+    def add_destruction_listener(self, listener):
+        '''Add a listener to be called when the trace is destroyed.'''
+        if not callable(listener):
+            raise TypeError("'listener' parameter is not callable")
+
+        fn = native_bt.py3_trace_add_destruction_listener
+        listener_from_native = functools.partial(_trace_destruction_listener_from_native,
+                                                 listener)
+
+        listener_id = fn(self._ptr, listener_from_native)
+        if listener_id is None:
+            utils._raise_bt2_error('cannot add destruction listener to trace object')
+
+        return bt2._ListenerHandle(listener_id, self)
diff --git a/src/bindings/python/bt2/bt2/trace_class.py b/src/bindings/python/bt2/bt2/trace_class.py
new file mode 100644 (file)
index 0000000..5713db8
--- /dev/null
@@ -0,0 +1,335 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+# Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
+# Copyright (c) 2019 Simon Marchi <simon.marchi@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+__all__ = ['_TraceClass']
+
+import bt2
+from bt2 import native_bt, utils, object
+import bt2.stream_class
+import uuid as uuidp
+import collections.abc
+import functools
+
+
+class _TraceClassEnv(collections.abc.MutableMapping):
+    def __init__(self, trace_class):
+        self._trace_class = trace_class
+
+    def __getitem__(self, key):
+        utils._check_str(key)
+
+        borrow_entry_fn = native_bt.trace_class_borrow_environment_entry_value_by_name_const
+        value_ptr = borrow_entry_fn(self._trace_class._ptr, key)
+
+        if value_ptr is None:
+            raise KeyError(key)
+
+        return bt2.value._create_from_ptr_and_get_ref(value_ptr)
+
+    def __setitem__(self, key, value):
+        if isinstance(value, str):
+            set_env_entry_fn = native_bt.trace_class_set_environment_entry_string
+        elif isinstance(value, int):
+            set_env_entry_fn = native_bt.trace_class_set_environment_entry_integer
+        else:
+            raise TypeError('expected str or int, got {}'.format(type(value)))
+
+        ret = set_env_entry_fn(self._trace_class._ptr, key, value)
+
+        utils._handle_ret(ret, "cannot set trace class object's environment entry")
+
+    def __delitem__(self, key):
+        raise NotImplementedError
+
+    def __len__(self):
+        count = native_bt.trace_class_get_environment_entry_count(self._trace_class._ptr)
+        assert count >= 0
+        return count
+
+    def __iter__(self):
+        trace_class_ptr = self._trace_class_env._trace_class._ptr
+
+        for idx in range(len(self)):
+            borrow_entry_fn = native_bt.trace_class_borrow_environment_entry_by_index_const
+            entry_name, _ = borrow_entry_fn(trace_class_ptr, idx)
+            assert entry_name is not None
+            yield entry_name
+
+
+class _StreamClassIterator(collections.abc.Iterator):
+    def __init__(self, trace_class):
+        self._trace_class = trace_class
+        self._at = 0
+
+    def __next__(self):
+        if self._at == len(self._trace_class):
+            raise StopIteration
+
+        borrow_stream_class_fn = native_bt.trace_class_borrow_stream_class_by_index_const
+        sc_ptr = borrow_stream_class_fn(self._trace_class._ptr, self._at)
+        assert sc_ptr
+        id = native_bt.stream_class_get_id(sc_ptr)
+        assert id >= 0
+        self._at += 1
+        return id
+
+
+def _trace_class_destruction_listener_from_native(user_listener, trace_class_ptr):
+    trace_class = bt2.trace_class._TraceClass._create_from_ptr_and_get_ref(trace_class_ptr)
+    user_listener(trace_class)
+
+
+class _TraceClass(object._SharedObject, collections.abc.Mapping):
+    _get_ref = staticmethod(native_bt.trace_class_get_ref)
+    _put_ref = staticmethod(native_bt.trace_class_put_ref)
+
+    @property
+    def uuid(self):
+        uuid_bytes = native_bt.trace_class_get_uuid(self._ptr)
+        if uuid_bytes is None:
+            return
+
+        return uuidp.UUID(bytes=uuid_bytes)
+
+    def _uuid(self, uuid):
+        utils._check_type(uuid, uuidp.UUID)
+        native_bt.trace_class_set_uuid(self._ptr, uuid.bytes)
+
+    _uuid = property(fset=_uuid)
+
+    # Instantiate a trace of this class.
+
+    def __call__(self, name=None):
+        trace_ptr = native_bt.trace_create(self._ptr)
+
+        if trace_ptr is None:
+            raise bt2.CreationError('cannot create trace class object')
+
+        trace = bt2.trace._Trace._create_from_ptr(trace_ptr)
+
+        if name is not None:
+            trace._name = name
+
+        return trace
+
+    # Number of stream classes in this trace class.
+
+    def __len__(self):
+        count = native_bt.trace_class_get_stream_class_count(self._ptr)
+        assert count >= 0
+        return count
+
+    # Get a stream class by stream id.
+
+    def __getitem__(self, key):
+        utils._check_uint64(key)
+
+        sc_ptr = native_bt.trace_class_borrow_stream_class_by_id_const(self._ptr, key)
+        if sc_ptr is None:
+            raise KeyError(key)
+
+        return bt2.stream_class._StreamClass._create_from_ptr_and_get_ref(sc_ptr)
+
+    def __iter__(self):
+        for idx in range(len(self)):
+            sc_ptr = native_bt.trace_class_borrow_stream_class_by_index_const(self._ptr, idx)
+            assert sc_ptr is not None
+
+            id = native_bt.stream_class_get_id(sc_ptr)
+            assert id >= 0
+
+            yield id
+
+    @property
+    def env(self):
+        return _TraceClassEnv(self)
+
+    def create_stream_class(self, id=None,
+                            name=None,
+                            packet_context_field_class=None,
+                            event_common_context_field_class=None,
+                            default_clock_class=None,
+                            assigns_automatic_event_class_id=True,
+                            assigns_automatic_stream_id=True,
+                            packets_have_beginning_default_clock_snapshot=False,
+                            packets_have_end_default_clock_snapshot=False,
+                            supports_discarded_events=False,
+                            discarded_events_have_default_clock_snapshots=False,
+                            supports_discarded_packets=False,
+                            discarded_packets_have_default_clock_snapshots=False):
+
+        if self.assigns_automatic_stream_class_id:
+            if id is not None:
+                raise ValueError('id provided, but trace class assigns automatic stream class ids')
+
+            sc_ptr = native_bt.stream_class_create(self._ptr)
+        else:
+            if id is None:
+                raise ValueError('id not provided, but trace class does not assign automatic stream class ids')
+
+            utils._check_uint64(id)
+            sc_ptr = native_bt.stream_class_create_with_id(self._ptr, id)
+
+        sc = bt2.stream_class._StreamClass._create_from_ptr(sc_ptr)
+
+        if name is not None:
+            sc._name = name
+
+        if packet_context_field_class is not None:
+            sc._packet_context_field_class = packet_context_field_class
+
+        if event_common_context_field_class is not None:
+            sc._event_common_context_field_class = event_common_context_field_class
+
+        if default_clock_class is not None:
+            sc._default_clock_class = default_clock_class
+
+        sc._assigns_automatic_event_class_id = assigns_automatic_event_class_id
+        sc._assigns_automatic_stream_id = assigns_automatic_stream_id
+        sc._packets_have_beginning_default_clock_snapshot = packets_have_beginning_default_clock_snapshot
+        sc._packets_have_end_default_clock_snapshot = packets_have_end_default_clock_snapshot
+        sc._set_supports_discarded_events(supports_discarded_events,
+                                          discarded_events_have_default_clock_snapshots)
+        sc._set_supports_discarded_packets(supports_discarded_packets,
+                                           discarded_packets_have_default_clock_snapshots)
+        return sc
+
+    @property
+    def assigns_automatic_stream_class_id(self):
+        return native_bt.trace_class_assigns_automatic_stream_class_id(self._ptr)
+
+    def _assigns_automatic_stream_class_id(self, auto_id):
+        utils._check_bool(auto_id)
+        return native_bt.trace_class_set_assigns_automatic_stream_class_id(self._ptr, auto_id)
+
+    _assigns_automatic_stream_class_id = property(fset=_assigns_automatic_stream_class_id)
+
+    # Field class creation methods.
+
+    def _check_create_status(self, ptr, type_name):
+        if ptr is None:
+            raise bt2.CreationError(
+                'cannot create {} field class'.format(type_name))
+
+    def _create_integer_field_class(self, create_func, py_cls, type_name, field_value_range, preferred_display_base):
+        field_class_ptr = create_func(self._ptr)
+        self._check_create_status(field_class_ptr, type_name)
+
+        field_class = py_cls._create_from_ptr(field_class_ptr)
+
+        if field_value_range is not None:
+            field_class._field_value_range = field_value_range
+
+        if preferred_display_base is not None:
+            field_class._preferred_display_base = preferred_display_base
+
+        return field_class
+
+    def create_signed_integer_field_class(self, field_value_range=None, preferred_display_base=None):
+        return self._create_integer_field_class(native_bt.field_class_signed_integer_create,
+                                                bt2.field_class._SignedIntegerFieldClass,
+                                                'signed integer', field_value_range, preferred_display_base)
+
+    def create_unsigned_integer_field_class(self, field_value_range=None, preferred_display_base=None):
+        return self._create_integer_field_class(native_bt.field_class_unsigned_integer_create,
+                                                bt2.field_class._UnsignedIntegerFieldClass,
+                                                'unsigned integer', field_value_range, preferred_display_base)
+
+    def create_signed_enumeration_field_class(self, field_value_range=None, preferred_display_base=None):
+        return self._create_integer_field_class(native_bt.field_class_signed_enumeration_create,
+                                                bt2.field_class._SignedEnumerationFieldClass,
+                                                'signed enumeration', field_value_range, preferred_display_base)
+
+    def create_unsigned_enumeration_field_class(self, field_value_range=None, preferred_display_base=None):
+        return self._create_integer_field_class(native_bt.field_class_unsigned_enumeration_create,
+                                                bt2.field_class._UnsignedEnumerationFieldClass,
+                                                'unsigned enumeration', field_value_range, preferred_display_base)
+
+    def create_real_field_class(self, is_single_precision=False):
+        field_class_ptr = native_bt.field_class_real_create(self._ptr)
+        self._check_create_status(field_class_ptr, 'real')
+
+        field_class = bt2.field_class._RealFieldClass._create_from_ptr(field_class_ptr)
+
+        field_class._is_single_precision = is_single_precision
+
+        return field_class
+
+    def create_structure_field_class(self):
+        field_class_ptr = native_bt.field_class_structure_create(self._ptr)
+        self._check_create_status(field_class_ptr, 'structure')
+
+        return bt2.field_class._StructureFieldClass._create_from_ptr(field_class_ptr)
+
+    def create_string_field_class(self):
+        field_class_ptr = native_bt.field_class_string_create(self._ptr)
+        self._check_create_status(field_class_ptr, 'string')
+
+        return bt2.field_class._StringFieldClass._create_from_ptr(field_class_ptr)
+
+    def create_static_array_field_class(self, elem_fc, length):
+        utils._check_type(elem_fc, bt2.field_class._FieldClass)
+        utils._check_uint64(length)
+        ptr = native_bt.field_class_static_array_create(self._ptr, elem_fc._ptr, length)
+        self._check_create_status(ptr, 'static array')
+
+        return bt2.field_class._StaticArrayFieldClass._create_from_ptr_and_get_ref(ptr)
+
+    def create_dynamic_array_field_class(self, elem_fc, length_fc=None):
+        utils._check_type(elem_fc, bt2.field_class._FieldClass)
+        ptr = native_bt.field_class_dynamic_array_create(self._ptr, elem_fc._ptr)
+        self._check_create_status(ptr, 'dynamic array')
+        obj = bt2.field_class._DynamicArrayFieldClass._create_from_ptr(ptr)
+
+        if length_fc is not None:
+            obj._length_field_class = length_fc
+
+        return obj
+
+    def create_variant_field_class(self, selector_fc=None):
+        ptr = native_bt.field_class_variant_create(self._ptr)
+        self._check_create_status(ptr, 'variant')
+        obj = bt2.field_class._VariantFieldClass._create_from_ptr(ptr)
+
+        if selector_fc is not None:
+            obj._selector_field_class = selector_fc
+
+        return obj
+
+    # Add a listener to be called when the trace class is destroyed.
+
+    def add_destruction_listener(self, listener):
+
+        if not callable(listener):
+            raise TypeError("'listener' parameter is not callable")
+
+        fn = native_bt.py3_trace_class_add_destruction_listener
+        listener_from_native = functools.partial(_trace_class_destruction_listener_from_native,
+                                                 listener)
+
+        listener_id = fn(self._ptr, listener_from_native)
+        if listener_id is None:
+            utils._raise_bt2_error('cannot add destruction listener to trace class object')
+
+        return bt2._ListenerHandle(listener_id, self)
diff --git a/src/bindings/python/bt2/bt2/trace_collection_message_iterator.py b/src/bindings/python/bt2/bt2/trace_collection_message_iterator.py
new file mode 100644 (file)
index 0000000..10b555f
--- /dev/null
@@ -0,0 +1,322 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import utils
+import bt2
+import itertools
+import bt2.message_iterator
+import datetime
+from collections import namedtuple
+import numbers
+
+
+# a pair of component and ComponentSpec
+_ComponentAndSpec = namedtuple('_ComponentAndSpec', ['comp', 'spec'])
+
+
+class ComponentSpec:
+    def __init__(self, plugin_name, class_name, params=None):
+        utils._check_str(plugin_name)
+        utils._check_str(class_name)
+        self._plugin_name = plugin_name
+        self._class_name = class_name
+
+        if type(params) is str:
+            self._params = bt2.create_value({'paths': [params]})
+        else:
+            self._params = bt2.create_value(params)
+
+    @property
+    def plugin_name(self):
+        return self._plugin_name
+
+    @property
+    def class_name(self):
+        return self._class_name
+
+    @property
+    def params(self):
+        return self._params
+
+
+# datetime.datetime or integral to nanoseconds
+def _get_ns(obj):
+    if obj is None:
+        return
+
+    if isinstance(obj, numbers.Real):
+        # consider that it's already in seconds
+        s = obj
+    elif isinstance(obj, datetime.datetime):
+        # s -> ns
+        s = obj.timestamp()
+    else:
+        raise TypeError('"{}" is not an integral number or a datetime.datetime object'.format(obj))
+
+    return int(s * 1e9)
+
+
+class _CompClsType:
+    SOURCE = 0
+    FILTER = 1
+
+
+class TraceCollectionMessageIterator(bt2.message_iterator._MessageIterator):
+    def __init__(self, source_component_specs, filter_component_specs=None,
+                 stream_intersection_mode=False, begin=None, end=None):
+        utils._check_bool(stream_intersection_mode)
+        self._stream_intersection_mode = stream_intersection_mode
+        self._begin_ns = _get_ns(begin)
+        self._end_ns = _get_ns(end)
+
+        if type(source_component_specs) is ComponentSpec:
+            source_component_specs = [source_component_specs]
+
+        if type(filter_component_specs) is ComponentSpec:
+            filter_component_specs = [filter_component_specs]
+        elif filter_component_specs is None:
+            filter_component_specs = []
+
+        self._src_comp_specs = source_component_specs
+        self._flt_comp_specs = filter_component_specs
+        self._next_suffix = 1
+        self._connect_ports = False
+
+        # lists of _ComponentAndSpec
+        self._src_comps_and_specs = []
+        self._flt_comps_and_specs = []
+
+        self._validate_component_specs(source_component_specs)
+        self._validate_component_specs(filter_component_specs)
+        self._build_graph()
+
+    def _validate_component_specs(self, comp_specs):
+        for comp_spec in comp_specs:
+            if type(comp_spec) is not ComponentSpec:
+                raise TypeError('"{}" object is not a ComponentSpec'.format(type(comp_spec)))
+
+    def __next__(self):
+        return next(self._msg_iter)
+
+    def _create_stream_intersection_trimmer(self, component, port):
+        # find the original parameters specified by the user to create
+        # this port's component to get the `path` parameter
+        for src_comp_and_spec in self._src_comps_and_specs:
+            if component == src_comp_and_spec.comp:
+                break
+
+        try:
+            paths = src_comp_and_spec.spec.params['paths']
+        except Exception as e:
+            raise bt2.Error('all source components must be created with a "paths" parameter in stream intersection mode') from e
+
+        params = {'paths': paths}
+
+        # query the port's component for the `trace-info` object which
+        # contains the stream intersection range for each exposed
+        # trace
+        query_exec = bt2.QueryExecutor()
+        trace_info_res = query_exec.query(src_comp_and_spec.comp.cls,
+                                          'trace-info', params)
+        begin = None
+        end = None
+
+        # find the trace info for this port's trace
+        try:
+            for trace_info in trace_info_res:
+                for stream in trace_info['streams']:
+                    if stream['port-name'] == port.name:
+                        range_ns = trace_info['intersection-range-ns']
+                        begin = range_ns['begin']
+                        end = range_ns['end']
+                        break
+        except Exception:
+            pass
+
+        if begin is None or end is None:
+            raise bt2.Error('cannot find stream intersection range for port "{}"'.format(port.name))
+
+        name = 'trimmer-{}-{}'.format(src_comp_and_spec.comp.name, port.name)
+        return self._create_trimmer(begin, end, name)
+
+    def _create_muxer(self):
+        plugin = bt2.find_plugin('utils')
+
+        if plugin is None:
+            raise bt2.Error('cannot find "utils" plugin (needed for the muxer)')
+
+        if 'muxer' not in plugin.filter_component_classes:
+            raise bt2.Error('cannot find "muxer" filter component class in "utils" plugin')
+
+        comp_cls = plugin.filter_component_classes['muxer']
+        return self._graph.add_component(comp_cls, 'muxer')
+
+    def _create_trimmer(self, begin_ns, end_ns, name):
+        plugin = bt2.find_plugin('utils')
+
+        if plugin is None:
+            raise bt2.Error('cannot find "utils" plugin (needed for the trimmer)')
+
+        if 'trimmer' not in plugin.filter_component_classes:
+            raise bt2.Error('cannot find "trimmer" filter component class in "utils" plugin')
+
+        params = {}
+
+        def ns_to_string(ns):
+            s_part = ns // 1000000000
+            ns_part = ns % 1000000000
+            return '{}.{:09d}'.format(s_part, ns_part)
+
+        if begin_ns is not None:
+            params['begin'] = ns_to_string(begin_ns)
+
+        if end_ns is not None:
+            params['end'] = ns_to_string(end_ns)
+
+        comp_cls = plugin.filter_component_classes['trimmer']
+        return self._graph.add_component(comp_cls, name, params)
+
+    def _get_unique_comp_name(self, comp_spec):
+        name = '{}-{}'.format(comp_spec.plugin_name,
+                              comp_spec.class_name)
+        comps_and_specs = itertools.chain(self._src_comps_and_specs,
+                                          self._flt_comps_and_specs)
+
+        if name in [comp_and_spec.comp.name for comp_and_spec in comps_and_specs]:
+            name += '-{}'.format(self._next_suffix)
+            self._next_suffix += 1
+
+        return name
+
+    def _create_comp(self, comp_spec, comp_cls_type):
+        plugin = bt2.find_plugin(comp_spec.plugin_name)
+
+        if plugin is None:
+            raise bt2.Error('no such plugin: {}'.format(comp_spec.plugin_name))
+
+        if comp_cls_type == _CompClsType.SOURCE:
+            comp_classes = plugin.source_component_classes
+        else:
+            comp_classes = plugin.filter_component_classes
+
+        if comp_spec.class_name not in comp_classes:
+            cc_type = 'source' if comp_cls_type == _CompClsType.SOURCE else 'filter'
+            raise bt2.Error('no such {} component class in "{}" plugin: {}'.format(cc_type,
+                                                                                   comp_spec.plugin_name,
+                                                                                   comp_spec.class_name))
+
+        comp_cls = comp_classes[comp_spec.class_name]
+        name = self._get_unique_comp_name(comp_spec)
+        comp = self._graph.add_component(comp_cls, name, comp_spec.params)
+        return comp
+
+    def _get_free_muxer_input_port(self):
+        for port in self._muxer_comp.input_ports.values():
+            if not port.is_connected:
+                return port
+
+    def _connect_src_comp_port(self, component, port):
+        # if this trace collection iterator is in stream intersection
+        # mode, we need this connection:
+        #
+        #     port -> trimmer -> muxer
+        #
+        # otherwise, simply:
+        #
+        #     port -> muxer
+        if self._stream_intersection_mode:
+            trimmer_comp = self._create_stream_intersection_trimmer(component, port)
+            self._graph.connect_ports(port, trimmer_comp.input_ports['in'])
+            port_to_muxer = trimmer_comp.output_ports['out']
+        else:
+            port_to_muxer = port
+
+        self._graph.connect_ports(port_to_muxer, self._get_free_muxer_input_port())
+
+    def _graph_port_added(self, component, port):
+        if not self._connect_ports:
+            return
+
+        if type(port) is bt2.port._InputPort:
+            return
+
+        if component not in [comp.comp for comp in self._src_comps_and_specs]:
+            # do not care about non-source components (muxer, trimmer, etc.)
+            return
+
+        self._connect_src_comp_port(component, port)
+
+    def _build_graph(self):
+        self._graph = bt2.Graph()
+        self._graph.add_port_added_listener(self._graph_port_added)
+        self._muxer_comp = self._create_muxer()
+
+        if self._begin_ns is not None or self._end_ns is not None:
+            trimmer_comp = self._create_trimmer(self._begin_ns,
+                                                self._end_ns, 'trimmer')
+            self._graph.connect_ports(self._muxer_comp.output_ports['out'],
+                                      trimmer_comp.input_ports['in'])
+            msg_iter_port = trimmer_comp.output_ports['out']
+        else:
+            msg_iter_port = self._muxer_comp.output_ports['out']
+
+        # create extra filter components (chained)
+        for comp_spec in self._flt_comp_specs:
+            comp = self._create_comp(comp_spec, _CompClsType.FILTER)
+            self._flt_comps_and_specs.append(_ComponentAndSpec(comp, comp_spec))
+
+        # connect the extra filter chain
+        for comp_and_spec in self._flt_comps_and_specs:
+            in_port = list(comp_and_spec.comp.input_ports.values())[0]
+            out_port = list(comp_and_spec.comp.output_ports.values())[0]
+            self._graph.connect_ports(msg_iter_port, in_port)
+            msg_iter_port = out_port
+
+        # Here we create the components, self._graph_port_added() is
+        # called when they add ports, but the callback returns early
+        # because self._connect_ports is False. This is because the
+        # self._graph_port_added() could not find the associated source
+        # component specification in self._src_comps_and_specs because
+        # it does not exist yet (it needs the created component to
+        # exist).
+        for comp_spec in self._src_comp_specs:
+            comp = self._create_comp(comp_spec, _CompClsType.SOURCE)
+            self._src_comps_and_specs.append(_ComponentAndSpec(comp, comp_spec))
+
+        # Now we connect the ports which exist at this point. We allow
+        # self._graph_port_added() to automatically connect _new_ ports.
+        self._connect_ports = True
+
+        for comp_and_spec in self._src_comps_and_specs:
+            # Keep a separate list because comp_and_spec.output_ports
+            # could change during the connection of one of its ports.
+            # Any new port is handled by self._graph_port_added().
+            out_ports = [port for port in comp_and_spec.comp.output_ports.values()]
+
+            for out_port in out_ports:
+                if out_port.is_connected:
+                    continue
+
+                self._connect_src_comp_port(comp_and_spec.comp, out_port)
+
+        # create this trace collection iterator's message iterator
+        self._msg_iter = self._graph.create_output_port_message_iterator(msg_iter_port)
diff --git a/src/bindings/python/bt2/bt2/utils.py b/src/bindings/python/bt2/bt2/utils.py
new file mode 100644 (file)
index 0000000..bd8ebf8
--- /dev/null
@@ -0,0 +1,109 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import bt2
+
+
+def _check_bool(o):
+    if not isinstance(o, bool):
+        raise TypeError("'{}' is not a 'bool' object".format(o.__class__.__name__))
+
+
+def _check_int(o):
+    if not isinstance(o, int):
+        raise TypeError("'{}' is not an 'int' object".format(o.__class__.__name__))
+
+
+def _check_float(o):
+    if not isinstance(o, float):
+        raise TypeError("'{}' is not a 'float' object".format(o.__class__.__name__))
+
+
+def _check_str(o):
+    if not isinstance(o, str):
+        raise TypeError("'{}' is not a 'str' object".format(o.__class__.__name__))
+
+
+def _check_type(o, expected_type):
+    if not isinstance(o, expected_type):
+        raise TypeError("'{}' is not a '{}' object".format(o.__class__.__name__,
+                                                           expected_type))
+
+
+def _is_int64(v):
+    _check_int(v)
+    return v >= -(2**63) and v <= (2**63 - 1)
+
+
+def _is_uint64(v):
+    _check_int(v)
+    return v >= 0 and v <= (2**64 - 1)
+
+
+def _check_int64(v, msg=None):
+    if not _is_int64(v):
+        if msg is None:
+            msg = 'expecting a signed 64-bit integral value'
+
+        msg += ' (got {})'.format(v)
+        raise ValueError(msg)
+
+
+def _check_uint64(v, msg=None):
+    if not _is_uint64(v):
+        if msg is None:
+            msg = 'expecting an unsigned 64-bit integral value'
+
+        msg += ' (got {})'.format(v)
+        raise ValueError(msg)
+
+
+def _is_m1ull(v):
+    return v == 18446744073709551615
+
+
+def _is_pow2(v):
+    return v != 0 and ((v & (v - 1)) == 0)
+
+
+def _check_alignment(a):
+    _check_uint64(a)
+
+    if not _is_pow2(a):
+        raise ValueError('{} is not a power of two'.format(a))
+
+
+def _raise_bt2_error(msg):
+    if msg is None:
+        raise bt2.Error
+    else:
+        raise bt2.Error(msg)
+
+
+def _handle_ret(ret, msg=None):
+    if int(ret) < 0:
+        _raise_bt2_error(msg)
+
+
+def _handle_ptr(ptr, msg=None):
+    if ptr is None:
+        _raise_bt2_error(msg)
diff --git a/src/bindings/python/bt2/bt2/value.py b/src/bindings/python/bt2/bt2/value.py
new file mode 100644 (file)
index 0000000..d8b8332
--- /dev/null
@@ -0,0 +1,712 @@
+# The MIT License (MIT)
+#
+# Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from bt2 import native_bt, object, utils
+import collections.abc
+import functools
+import numbers
+import math
+import abc
+import bt2
+
+
+def _handle_status(status, obj_name):
+    if status >= 0:
+        return
+    else:
+        raise RuntimeError('unexpected error')
+
+
+def _create_from_ptr(ptr):
+    if ptr is None or ptr == native_bt.value_null:
+        return
+
+    typeid = native_bt.value_get_type(ptr)
+    return _TYPE_TO_OBJ[typeid]._create_from_ptr(ptr)
+
+
+def _create_from_ptr_and_get_ref(ptr):
+    if ptr is None or ptr == native_bt.value_null:
+        return
+
+    typeid = native_bt.value_get_type(ptr)
+    return _TYPE_TO_OBJ[typeid]._create_from_ptr_and_get_ref(ptr)
+
+
+def create_value(value):
+    if value is None:
+        # null value object
+        return
+
+    if isinstance(value, _Value):
+        return value
+
+    if isinstance(value, bool):
+        return BoolValue(value)
+
+    if isinstance(value, int):
+        return SignedIntegerValue(value)
+
+    if isinstance(value, float):
+        return RealValue(value)
+
+    if isinstance(value, str):
+        return StringValue(value)
+
+    try:
+        return MapValue(value)
+    except:
+        pass
+
+    try:
+        return ArrayValue(value)
+    except:
+        pass
+
+    raise TypeError("cannot create value object from '{}' object".format(value.__class__.__name__))
+
+
+class _Value(object._SharedObject, metaclass=abc.ABCMeta):
+    _get_ref = staticmethod(native_bt.value_get_ref)
+    _put_ref = staticmethod(native_bt.value_put_ref)
+
+    def __eq__(self, other):
+        if other is None:
+            # self is never the null value object
+            return False
+
+        # try type-specific comparison first
+        spec_eq = self._spec_eq(other)
+
+        if spec_eq is not None:
+            return spec_eq
+
+        if not isinstance(other, _Value):
+            # not comparing apples to apples
+            return False
+
+        # fall back to native comparison function
+        return native_bt.value_compare(self._ptr, other._ptr)
+
+    def __ne__(self, other):
+        return not (self == other)
+
+    @abc.abstractmethod
+    def _spec_eq(self, other):
+        pass
+
+    def _handle_status(self, status):
+        _handle_status(status, self._NAME)
+
+    def _check_create_status(self, ptr):
+        if ptr is None:
+            raise bt2.CreationError(
+                'cannot create {} value object'.format(self._NAME.lower()))
+
+
+@functools.total_ordering
+class _NumericValue(_Value):
+    @staticmethod
+    def _extract_value(other):
+        if isinstance(other, _NumericValue):
+            return other._value
+
+        if other is True or other is False:
+            return other
+
+        if isinstance(other, numbers.Integral):
+            return int(other)
+
+        if isinstance(other, numbers.Real):
+            return float(other)
+
+        if isinstance(other, numbers.Complex):
+            return complex(other)
+
+        raise TypeError("'{}' object is not a number object".format(other.__class__.__name__))
+
+    def __int__(self):
+        return int(self._value)
+
+    def __float__(self):
+        return float(self._value)
+
+    def __repr__(self):
+        return repr(self._value)
+
+    def __lt__(self, other):
+        if not isinstance(other, numbers.Number):
+            raise TypeError('unorderable types: {}() < {}()'.format(self.__class__.__name__,
+                                                                    other.__class__.__name__))
+
+        return self._value < float(other)
+
+    def __le__(self, other):
+        if not isinstance(other, numbers.Number):
+            raise TypeError('unorderable types: {}() <= {}()'.format(self.__class__.__name__,
+                                                                     other.__class__.__name__))
+
+        return self._value <= float(other)
+
+    def _spec_eq(self, other):
+        pass
+
+    def __eq__(self, other):
+        if not isinstance(other, numbers.Number):
+            return False
+
+        return self._value == complex(other)
+
+    def __rmod__(self, other):
+        return self._extract_value(other) % self._value
+
+    def __mod__(self, other):
+        return self._value % self._extract_value(other)
+
+    def __rfloordiv__(self, other):
+        return self._extract_value(other) // self._value
+
+    def __floordiv__(self, other):
+        return self._value // self._extract_value(other)
+
+    def __round__(self, ndigits=None):
+        if ndigits is None:
+            return round(self._value)
+        else:
+            return round(self._value, ndigits)
+
+    def __ceil__(self):
+        return math.ceil(self._value)
+
+    def __floor__(self):
+        return math.floor(self._value)
+
+    def __trunc__(self):
+        return int(self._value)
+
+    def __abs__(self):
+        return abs(self._value)
+
+    def __add__(self, other):
+        return self._value + self._extract_value(other)
+
+    def __radd__(self, other):
+        return self.__add__(other)
+
+    def __neg__(self):
+        return -self._value
+
+    def __pos__(self):
+        return +self._value
+
+    def __mul__(self, other):
+        return self._value * self._extract_value(other)
+
+    def __rmul__(self, other):
+        return self.__mul__(other)
+
+    def __truediv__(self, other):
+        return self._value / self._extract_value(other)
+
+    def __rtruediv__(self, other):
+        return self._extract_value(other) / self._value
+
+    def __pow__(self, exponent):
+        return self._value ** self._extract_value(exponent)
+
+    def __rpow__(self, base):
+        return self._extract_value(base) ** self._value
+
+    def __iadd__(self, other):
+        self.value = self + other
+        return self
+
+    def __isub__(self, other):
+        self.value = self - other
+        return self
+
+    def __imul__(self, other):
+        self.value = self * other
+        return self
+
+    def __itruediv__(self, other):
+        self.value = self / other
+        return self
+
+    def __ifloordiv__(self, other):
+        self.value = self // other
+        return self
+
+    def __imod__(self, other):
+        self.value = self % other
+        return self
+
+    def __ipow__(self, other):
+        self.value = self ** other
+        return self
+
+
+class _IntegralValue(_NumericValue, numbers.Integral):
+    def __lshift__(self, other):
+        return self._value << self._extract_value(other)
+
+    def __rlshift__(self, other):
+        return self._extract_value(other) << self._value
+
+    def __rshift__(self, other):
+        return self._value >> self._extract_value(other)
+
+    def __rrshift__(self, other):
+        return self._extract_value(other) >> self._value
+
+    def __and__(self, other):
+        return self._value & self._extract_value(other)
+
+    def __rand__(self, other):
+        return self._extract_value(other) & self._value
+
+    def __xor__(self, other):
+        return self._value ^ self._extract_value(other)
+
+    def __rxor__(self, other):
+        return self._extract_value(other) ^ self._value
+
+    def __or__(self, other):
+        return self._value | self._extract_value(other)
+
+    def __ror__(self, other):
+        return self._extract_value(other) | self._value
+
+    def __invert__(self):
+        return ~self._value
+
+    def __ilshift__(self, other):
+        self.value = self << other
+        return self
+
+    def __irshift__(self, other):
+        self.value = self >> other
+        return self
+
+    def __iand__(self, other):
+        self.value = self & other
+        return self
+
+    def __ixor__(self, other):
+        self.value = self ^ other
+        return self
+
+    def __ior__(self, other):
+        self.value = self | other
+        return self
+
+
+class _RealValue(_NumericValue, numbers.Real):
+    pass
+
+
+class BoolValue(_Value):
+    _NAME = 'Boolean'
+
+    def __init__(self, value=None):
+        if value is None:
+            ptr = native_bt.value_bool_create()
+        else:
+            ptr = native_bt.value_bool_create_init(self._value_to_bool(value))
+
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+    def _spec_eq(self, other):
+        if isinstance(other, numbers.Number):
+            return self._value == bool(other)
+
+    def __bool__(self):
+        return self._value
+
+    def __repr__(self):
+        return repr(self._value)
+
+    def _value_to_bool(self, value):
+        if isinstance(value, BoolValue):
+            value = value._value
+
+        if not isinstance(value, bool):
+            raise TypeError("'{}' object is not a 'bool' or 'BoolValue' object".format(value.__class__))
+
+        return int(value)
+
+    @property
+    def _value(self):
+        value = native_bt.value_bool_get(self._ptr)
+        return value != 0
+
+    def _set_value(self, value):
+        native_bt.value_bool_set(self._ptr, self._value_to_bool(value))
+
+    value = property(fset=_set_value)
+
+
+class _IntegerValue(_IntegralValue):
+    def __init__(self, value=None):
+        if value is None:
+            ptr = self._create_default_value()
+        else:
+            ptr = self._create_value(self._value_to_int(value))
+
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+    def _value_to_int(self, value):
+        if not isinstance(value, numbers.Real):
+            raise TypeError('expecting a number object')
+
+        value = int(value)
+        self._check_int_range(value)
+        return value
+
+    @property
+    def _value(self):
+        return self._get_value(self._ptr)
+
+    def _prop_set_value(self, value):
+        self._set_value(self._ptr, self._value_to_int(value))
+
+    value = property(fset=_prop_set_value)
+
+
+class UnsignedIntegerValue(_IntegerValue):
+    _check_int_range = staticmethod(utils._check_uint64)
+    _create_default_value = staticmethod(native_bt.value_unsigned_integer_create)
+    _create_value = staticmethod(native_bt.value_unsigned_integer_create_init)
+    _set_value = staticmethod(native_bt.value_unsigned_integer_set)
+    _get_value = staticmethod(native_bt.value_unsigned_integer_get)
+
+
+class SignedIntegerValue(_IntegerValue):
+    _check_int_range = staticmethod(utils._check_int64)
+    _create_default_value = staticmethod(native_bt.value_signed_integer_create)
+    _create_value = staticmethod(native_bt.value_signed_integer_create_init)
+    _set_value = staticmethod(native_bt.value_signed_integer_set)
+    _get_value = staticmethod(native_bt.value_signed_integer_get)
+
+
+class RealValue(_RealValue):
+    _NAME = 'Real number'
+
+    def __init__(self, value=None):
+        if value is None:
+            ptr = native_bt.value_real_create()
+        else:
+            value = self._value_to_float(value)
+            ptr = native_bt.value_real_create_init(value)
+
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+    def _value_to_float(self, value):
+        if not isinstance(value, numbers.Real):
+            raise TypeError("expecting a real number object")
+
+        return float(value)
+
+    @property
+    def _value(self):
+        return native_bt.value_real_get(self._ptr)
+
+    def _set_value(self, value):
+        native_bt.value_real_set(self._ptr, self._value_to_float(value))
+
+    value = property(fset=_set_value)
+
+
+@functools.total_ordering
+class StringValue(collections.abc.Sequence, _Value):
+    _NAME = 'String'
+
+    def __init__(self, value=None):
+        if value is None:
+            ptr = native_bt.value_string_create()
+        else:
+            ptr = native_bt.value_string_create_init(self._value_to_str(value))
+
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+    def _value_to_str(self, value):
+        if isinstance(value, self.__class__):
+            value = value._value
+
+        utils._check_str(value)
+        return value
+
+    @property
+    def _value(self):
+        return native_bt.value_string_get(self._ptr)
+
+    def _set_value(self, value):
+        status = native_bt.value_string_set(self._ptr, self._value_to_str(value))
+        self._handle_status(status)
+
+    value = property(fset=_set_value)
+
+    def _spec_eq(self, other):
+        try:
+            return self._value == self._value_to_str(other)
+        except:
+            return
+
+    def __le__(self, other):
+        return self._value <= self._value_to_str(other)
+
+    def __lt__(self, other):
+        return self._value < self._value_to_str(other)
+
+    def __bool__(self):
+        return bool(self._value)
+
+    def __repr__(self):
+        return repr(self._value)
+
+    def __str__(self):
+        return self._value
+
+    def __getitem__(self, index):
+        return self._value[index]
+
+    def __len__(self):
+        return len(self._value)
+
+    def __iadd__(self, value):
+        curvalue = self._value
+        curvalue += self._value_to_str(value)
+        self.value = curvalue
+        return self
+
+
+class _Container:
+    def __bool__(self):
+        return len(self) != 0
+
+    def __delitem__(self, index):
+        raise NotImplementedError
+
+
+class ArrayValue(_Container, collections.abc.MutableSequence, _Value):
+    _NAME = 'Array'
+
+    def __init__(self, value=None):
+        ptr = native_bt.value_array_create()
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+        # Python will raise a TypeError if there's anything wrong with
+        # the iterable protocol.
+        if value is not None:
+            for elem in value:
+                self.append(elem)
+
+    def _spec_eq(self, other):
+        try:
+            if len(self) != len(other):
+                # early mismatch
+                return False
+
+            for self_elem, other_elem in zip(self, other):
+                if self_elem != other_elem:
+                    return False
+
+            return True
+        except:
+            return
+
+    def __len__(self):
+        size = native_bt.value_array_get_size(self._ptr)
+        assert(size >= 0)
+        return size
+
+    def _check_index(self, index):
+        # TODO: support slices also
+        if not isinstance(index, numbers.Integral):
+            raise TypeError("'{}' object is not an integral number object: invalid index".format(index.__class__.__name__))
+
+        index = int(index)
+
+        if index < 0 or index >= len(self):
+            raise IndexError('array value object index is out of range')
+
+    def __getitem__(self, index):
+        self._check_index(index)
+        ptr = native_bt.value_array_borrow_element_by_index(self._ptr, index)
+        assert(ptr)
+        return _create_from_ptr_and_get_ref(ptr)
+
+    def __setitem__(self, index, value):
+        self._check_index(index)
+        value = create_value(value)
+
+        if value is None:
+            ptr = native_bt.value_null
+        else:
+            ptr = value._ptr
+
+        status = native_bt.value_array_set_element_by_index(
+            self._ptr, index, ptr)
+        self._handle_status(status)
+
+    def append(self, value):
+        value = create_value(value)
+
+        if value is None:
+            ptr = native_bt.value_null
+        else:
+            ptr = value._ptr
+
+        status = native_bt.value_array_append_element(self._ptr, ptr)
+        self._handle_status(status)
+
+    def __iadd__(self, iterable):
+        # Python will raise a TypeError if there's anything wrong with
+        # the iterable protocol.
+        for elem in iterable:
+            self.append(elem)
+
+        return self
+
+    def __repr__(self):
+        return '[{}]'.format(', '.join([repr(v) for v in self]))
+
+    def insert(self, value):
+        raise NotImplementedError
+
+
+class _MapValueKeyIterator(collections.abc.Iterator):
+    def __init__(self, map_obj):
+        self._map_obj = map_obj
+        self._at = 0
+        keys_ptr = native_bt.value_map_get_keys(map_obj._ptr)
+
+        if keys_ptr is None:
+            raise RuntimeError('unexpected error: cannot get map value object keys')
+
+        self._keys = _create_from_ptr(keys_ptr)
+
+    def __next__(self):
+        if self._at == len(self._map_obj):
+            raise StopIteration
+
+        key = self._keys[self._at]
+        self._at += 1
+        return str(key)
+
+
+class MapValue(_Container, collections.abc.MutableMapping, _Value):
+    _NAME = 'Map'
+
+    def __init__(self, value=None):
+        ptr = native_bt.value_map_create()
+        self._check_create_status(ptr)
+        super().__init__(ptr)
+
+        # Python will raise a TypeError if there's anything wrong with
+        # the iterable/mapping protocol.
+        if value is not None:
+            for key, elem in value.items():
+                self[key] = elem
+
+    def __eq__(self, other):
+        return _Value.__eq__(self, other)
+
+    def __ne__(self, other):
+        return _Value.__ne__(self, other)
+
+    def _spec_eq(self, other):
+        try:
+            if len(self) != len(other):
+                # early mismatch
+                return False
+
+            for self_key in self:
+                if self_key not in other:
+                    return False
+
+                self_value = self[self_key]
+                other_value = other[self_key]
+
+                if self_value != other_value:
+                    return False
+
+            return True
+        except:
+            return
+
+    def __len__(self):
+        size = native_bt.value_map_get_size(self._ptr)
+        assert(size >= 0)
+        return size
+
+    def __contains__(self, key):
+        self._check_key_type(key)
+        return native_bt.value_map_has_entry(self._ptr, key)
+
+    def _check_key_type(self, key):
+        utils._check_str(key)
+
+    def _check_key(self, key):
+        if key not in self:
+            raise KeyError(key)
+
+    def __getitem__(self, key):
+        self._check_key(key)
+        ptr = native_bt.value_map_borrow_entry_value(self._ptr, key)
+        assert(ptr)
+        return _create_from_ptr_and_get_ref(ptr)
+
+    def __iter__(self):
+        return _MapValueKeyIterator(self)
+
+    def __setitem__(self, key, value):
+        self._check_key_type(key)
+        value = create_value(value)
+
+        if value is None:
+            ptr = native_bt.value_null
+        else:
+            ptr = value._ptr
+
+        status = native_bt.value_map_insert_entry(self._ptr, key, ptr)
+        self._handle_status(status)
+
+    def __repr__(self):
+        items = ['{}: {}'.format(repr(k), repr(v)) for k, v in self.items()]
+        return '{{{}}}'.format(', '.join(items))
+
+
+_TYPE_TO_OBJ = {
+    native_bt.VALUE_TYPE_BOOL: BoolValue,
+    native_bt.VALUE_TYPE_UNSIGNED_INTEGER: UnsignedIntegerValue,
+    native_bt.VALUE_TYPE_SIGNED_INTEGER: SignedIntegerValue,
+    native_bt.VALUE_TYPE_REAL: RealValue,
+    native_bt.VALUE_TYPE_STRING: StringValue,
+    native_bt.VALUE_TYPE_ARRAY: ArrayValue,
+    native_bt.VALUE_TYPE_MAP: MapValue,
+}
diff --git a/src/bindings/python/bt2/setup.py.in b/src/bindings/python/bt2/setup.py.in
new file mode 100644 (file)
index 0000000..bc1a735
--- /dev/null
@@ -0,0 +1,86 @@
+# The MIT License (MIT)
+#
+# Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers@efficios.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import sys
+
+from distutils.core import setup, Extension
+
+PY_PATH_WARN_MSG = """
+-------------------------------------WARNING------------------------------------
+The install directory used:\n ({})\nis not included in your PYTHONPATH.
+
+To add this directory to your Python search path permanently you can add the
+following command to your .bashrc/.zshrc:
+    export PYTHONPATH="${{PYTHONPATH}}:{}"
+--------------------------------------------------------------------------------
+"""
+
+def main():
+    babeltrace_ext = Extension('bt2._native_bt',
+                        sources=['bt2/native_bt.i', 'bt2/logging.c'],
+                        libraries=['babeltrace2', 'glib-2.0'],
+                        extra_objects=['@top_builddir@/src/logging/.libs/libbabeltrace2-logging.a',
+                            '@top_builddir@/src/common/.libs/libbabeltrace2-common.a'],)
+
+    dist = setup(name='bt2',
+            version='@PACKAGE_VERSION@',
+            description='Babeltrace 2 Python Bindings',
+            packages=['bt2'],
+            package_dir={'bt2': 'bt2'},
+            options={'build':
+                {
+                    'build_base': 'build',
+                    'build_lib': 'build/build_lib'
+                },
+                'build_ext':
+                {
+                    'build_lib': 'build/build_lib'
+                }
+            },
+            url='http://diamon.org/babeltrace',
+            ext_modules=[babeltrace_ext],
+            license='MIT',
+            classifiers=[
+                'Development Status :: 5 - Production/Stable',
+                'Intended Audience :: Developers',
+                'License :: OSI Approved :: The MIT License',
+                'Programming Language :: Python :: 3'
+                'Topic :: System :: Logging',
+                ])
+
+# After the installation, we check that the install directory is included in
+# the Python search path and we print a warning message when it's not.
+# We need to do this because Python search path differs depending on the distro
+# and some distros don't include any /usr/local/ in the search path. This is
+# also useful for out-of-tree installs and tests.
+# It's only relevant to make this check on the `install` command.
+
+    if 'install' in dist.command_obj:
+        install_dir = dist.command_obj['install'].install_libbase
+        if install_dir not in sys.path:
+            # We can't consider this an error because if affects every
+            # distro differently. We only warn the user that some
+            # extra configuration is needed to use the bindings
+            print(PY_PATH_WARN_MSG.format(install_dir, install_dir))
+
+if __name__ == "__main__":
+    main()
diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am
new file mode 100644 (file)
index 0000000..45297d5
--- /dev/null
@@ -0,0 +1,100 @@
+PLUGINS_PATH = $(abs_top_builddir)/src/plugins
+LTTNG_UTILS_PLUGIN_PATH =
+
+if ENABLE_DEBUG_INFO
+LTTNG_UTILS_PLUGIN_PATH += :$(PLUGINS_PATH)/lttng-utils
+endif
+
+if BABELTRACE_BUILD_WITH_MINGW
+IN_TREE_PLUGIN_PATH := $(shell cygpath -pm "$(PLUGINS_PATH)/ctf:$(PLUGINS_PATH)/text:$(PLUGINS_PATH)/utils$(LTTNG_UTILS_PLUGIN_PATH)")
+else
+IN_TREE_PLUGIN_PATH = $(PLUGINS_PATH)/ctf:$(PLUGINS_PATH)/text:$(PLUGINS_PATH)/utils$(LTTNG_UTILS_PLUGIN_PATH)
+endif
+
+AM_CPPFLAGS += '-DCONFIG_IN_TREE_PLUGIN_PATH="$(IN_TREE_PLUGIN_PATH)"'
+
+bin_PROGRAMS = babeltrace2.bin babeltrace2-log.bin
+noinst_PROGRAMS = babeltrace2 babeltrace2-log
+
+babeltrace2_bin_SOURCES = \
+       babeltrace2.c \
+       babeltrace2-cfg.c \
+       babeltrace2-cfg.h \
+       babeltrace2-cfg-cli-args.c \
+       babeltrace2-cfg-cli-args.h \
+       babeltrace2-cfg-cli-args-connect.c \
+       babeltrace2-cfg-cli-args-connect.h \
+       babeltrace2-cfg-cli-args-default.h \
+       babeltrace2-cfg-cli-args-default.c \
+       logging.c logging.h
+
+# -Wl,--no-as-needed is needed for recent gold linker who seems to think
+# it knows better and considers libraries with constructors having
+# side-effects as dead code.
+babeltrace2_bin_LDFLAGS = $(LD_NO_AS_NEEDED)
+
+# Add all the convenience libraries used by Babeltrace plugins and the
+# library. They will be used when embedding plugins (--enable-built-in-plugins),
+# otherwise we're looking after multiple definitions of the same symbols if
+# a plugin's archive (.a) includes the convenience library because
+# we're using --whole-archive below (needed to make sure the linker does
+# not discard the plugins since the CLI does not use their symbols
+# directly).
+babeltrace2_bin_LDADD = \
+       $(top_builddir)/src/lib/libbabeltrace2.la \
+       $(top_builddir)/src/compat/libcompat.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(POPT_LIBS)
+
+if ENABLE_BUILT_IN_PLUGINS
+# Takes a plugin name and outputs the needed LDFLAGS to embed it.
+#
+# The --whole-archive option is important here. From the GNU linker's
+# documentation:
+#
+#     For each archive mentioned on the command line after the
+#     --whole-archive option, include every object file in the archive in
+#     the link, rather than searching the archive for the required object
+#     files.
+#
+# In our case, we find the plugins thanks to special sections in the
+# binary that are filled by plugin objects. If the linker discards those
+# symbols because the CLI does not use them directly, the CLI reports
+# no plugins found (plugins are effectively not embedded).
+pluginarchive = $(LD_WHOLE_ARCHIVE)$(PLUGINS_PATH)/$(1)/.libs/babeltrace-plugin-$(1).a$(LD_NO_WHOLE_ARCHIVE)
+
+# Built-in plugins
+babeltrace2_bin_LDFLAGS += $(call pluginarchive,ctf)
+babeltrace2_bin_LDFLAGS += $(call pluginarchive,text)
+babeltrace2_bin_LDFLAGS += $(call pluginarchive,utils)
+
+if ENABLE_DEBUG_INFO
+babeltrace2_bin_LDFLAGS += $(call pluginarchive,lttng-utils)
+babeltrace2_bin_LDADD += $(ELFUTILS_LIBS)
+endif
+endif
+
+if BABELTRACE_BUILD_WITH_MINGW
+babeltrace2_bin_LDADD += -lws2_32 -lrpcrt4 -lintl -liconv -lole32 -lpthread
+endif
+
+# Only used for in-tree execution and tests
+babeltrace2_SOURCES = $(babeltrace2_bin_SOURCES)
+babeltrace2_LDFLAGS = $(babeltrace2_bin_LDFLAGS)
+babeltrace2_LDADD = $(babeltrace2_bin_LDADD)
+babeltrace2_CFLAGS = $(AM_CFLAGS) -DBT_SET_DEFAULT_IN_TREE_CONFIGURATION
+
+# babeltrace2-log rules and config below
+babeltrace2_log_bin_SOURCES = babeltrace2-log.c
+babeltrace2_log_bin_LDADD = \
+       $(top_builddir)/src/compat/libcompat.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(POPT_LIBS)
+babeltrace2_log_bin_CFLAGS = $(AM_CFLAGS) '-DBT_CLI_PATH="$(abs_top_builddir)/src/cli/babeltrace2$(EXEEXT)"'
+
+# Only used for in-tree execution and tests
+babeltrace2_log_SOURCES = $(babeltrace2_log_bin_SOURCES)
+babeltrace2_log_LDADD = $(babeltrace2_log_bin_LDADD)
+babeltrace2_log_CFLAGS = $(AM_CFLAGS) '-DBT_CLI_PATH="$(bindir)/babeltrace2$(EXEEXT)"'
diff --git a/src/cli/babeltrace2-cfg-cli-args-connect.c b/src/cli/babeltrace2-cfg-cli-args-connect.c
new file mode 100644 (file)
index 0000000..7e1657e
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <babeltrace2/babeltrace.h>
+#include "common/common.h"
+#include "babeltrace2-cfg.h"
+#include "babeltrace2-cfg-cli-args-connect.h"
+
+static bool all_named_and_printable_in_array(GPtrArray *comps)
+{
+       size_t i;
+       bool all_named_and_printable = true;
+
+       for (i = 0; i < comps->len; i++) {
+               struct bt_config_component *comp = g_ptr_array_index(comps, i);
+
+               if (comp->instance_name->len == 0) {
+                       all_named_and_printable = false;
+                       goto end;
+               }
+
+               if (!bt_common_string_is_printable(comp->instance_name->str)) {
+                       all_named_and_printable = false;
+                       goto end;
+               }
+       }
+
+end:
+       return all_named_and_printable;
+}
+
+static bool all_named_and_printable(struct bt_config *cfg)
+{
+       return all_named_and_printable_in_array(cfg->cmd_data.run.sources) &&
+               all_named_and_printable_in_array(cfg->cmd_data.run.filters) &&
+               all_named_and_printable_in_array(cfg->cmd_data.run.sinks);
+}
+
+static struct bt_config_connection *bt_config_connection_create(const char *arg)
+{
+       struct bt_config_connection *cfg_connection;
+
+       cfg_connection = g_new0(struct bt_config_connection, 1);
+       if (!cfg_connection) {
+               goto error;
+       }
+
+       cfg_connection->upstream_comp_name = g_string_new(NULL);
+       if (!cfg_connection->upstream_comp_name) {
+               goto error;
+       }
+
+       cfg_connection->downstream_comp_name = g_string_new(NULL);
+       if (!cfg_connection->downstream_comp_name) {
+               goto error;
+       }
+
+       cfg_connection->upstream_port_glob = g_string_new("*");
+       if (!cfg_connection->upstream_port_glob) {
+               goto error;
+       }
+
+       cfg_connection->downstream_port_glob = g_string_new("*");
+       if (!cfg_connection->downstream_port_glob) {
+               goto error;
+       }
+
+       cfg_connection->arg = g_string_new(arg);
+       if (!cfg_connection->arg) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       g_free(cfg_connection);
+       cfg_connection = NULL;
+
+end:
+       return cfg_connection;
+}
+
+static bool validate_port_glob(const char *port_glob)
+{
+       bool is_valid = true;
+       const char *ch = port_glob;
+
+       BT_ASSERT(port_glob);
+
+       while (*ch != '\0') {
+               switch (*ch) {
+               case '\\':
+                       switch (ch[1]) {
+                       case '\0':
+                               goto end;
+                       default:
+                               ch += 2;
+                               continue;
+                       }
+               case '?':
+               case '[':
+                       /*
+                        * This is reserved for future use, to support
+                        * full globbing patterns. Those characters must
+                        * be escaped with `\`.
+                        */
+                       is_valid = false;
+                       goto end;
+               default:
+                       ch++;
+                       break;
+               }
+       }
+
+end:
+       return is_valid;
+}
+
+static int normalize_glob_pattern(GString *glob_pattern_gs)
+{
+       int ret = 0;
+       char *glob_pattern = strdup(glob_pattern_gs->str);
+
+       if (!glob_pattern) {
+               ret = -1;
+               goto end;
+       }
+
+       bt_common_normalize_star_glob_pattern(glob_pattern);
+       g_string_assign(glob_pattern_gs, glob_pattern);
+       free(glob_pattern);
+
+end:
+       return ret;
+}
+
+static struct bt_config_connection *cfg_connection_from_arg(const char *arg)
+{
+       const char *at = arg;
+       size_t end_pos;
+       struct bt_config_connection *cfg_conn = NULL;
+       GString *gs = NULL;
+       enum {
+               UPSTREAM_NAME,
+               DOWNSTREAM_NAME,
+               UPSTREAM_PORT_GLOB,
+               DOWNSTREAM_PORT_GLOB,
+       } state = UPSTREAM_NAME;
+
+       if (!bt_common_string_is_printable(arg)) {
+               goto error;
+       }
+
+       cfg_conn = bt_config_connection_create(arg);
+       if (!cfg_conn) {
+               goto error;
+       }
+
+       while (true) {
+               switch (state) {
+               case UPSTREAM_NAME:
+                       gs = bt_common_string_until(at, ".:\\", ".:", &end_pos);
+                       if (!gs || gs->len == 0) {
+                               goto error;
+                       }
+
+                       g_string_free(cfg_conn->upstream_comp_name, TRUE);
+                       cfg_conn->upstream_comp_name = gs;
+                       gs = NULL;
+
+                       if (at[end_pos] == ':') {
+                               state = DOWNSTREAM_NAME;
+                       } else if (at[end_pos] == '.') {
+                               state = UPSTREAM_PORT_GLOB;
+                       } else {
+                               goto error;
+                       }
+
+                       at += end_pos + 1;
+                       break;
+               case DOWNSTREAM_NAME:
+                       gs = bt_common_string_until(at, ".:\\", ".:", &end_pos);
+                       if (!gs || gs->len == 0) {
+                               goto error;
+                       }
+
+                       g_string_free(cfg_conn->downstream_comp_name, TRUE);
+                       cfg_conn->downstream_comp_name = gs;
+                       gs = NULL;
+
+                       if (at[end_pos] == '.') {
+                               state = DOWNSTREAM_PORT_GLOB;
+                       } else if (at[end_pos] == '\0') {
+                               goto end;
+                       } else {
+                               goto error;
+                       }
+
+                       at += end_pos + 1;
+                       break;
+               case UPSTREAM_PORT_GLOB:
+                       gs = bt_common_string_until(at, ".:", ".:", &end_pos);
+                       if (!gs || gs->len == 0) {
+                               goto error;
+                       }
+
+                       if (!validate_port_glob(gs->str)) {
+                               goto error;
+                       }
+
+                       if (normalize_glob_pattern(gs)) {
+                               goto error;
+                       }
+
+                       g_string_free(cfg_conn->upstream_port_glob, TRUE);
+                       cfg_conn->upstream_port_glob = gs;
+                       gs = NULL;
+
+                       if (at[end_pos] == ':') {
+                               state = DOWNSTREAM_NAME;
+                       } else {
+                               goto error;
+                       }
+
+                       at += end_pos + 1;
+                       break;
+               case DOWNSTREAM_PORT_GLOB:
+                       gs = bt_common_string_until(at, ".:", ".:", &end_pos);
+                       if (!gs || gs->len == 0) {
+                               goto error;
+                       }
+
+                       if (!validate_port_glob(gs->str)) {
+                               goto error;
+                       }
+
+                       if (normalize_glob_pattern(gs)) {
+                               goto error;
+                       }
+
+                       g_string_free(cfg_conn->downstream_port_glob, TRUE);
+                       cfg_conn->downstream_port_glob = gs;
+                       gs = NULL;
+
+                       if (at[end_pos] == '\0') {
+                               goto end;
+                       } else {
+                               goto error;
+                       }
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+error:
+       bt_config_connection_destroy(cfg_conn);
+       cfg_conn = NULL;
+
+end:
+       if (gs) {
+               g_string_free(gs, TRUE);
+       }
+
+       return cfg_conn;
+}
+
+static struct bt_config_component *find_component_in_array(GPtrArray *comps,
+               const char *name)
+{
+       size_t i;
+       struct bt_config_component *found_comp = NULL;
+
+       for (i = 0; i < comps->len; i++) {
+               struct bt_config_component *comp = g_ptr_array_index(comps, i);
+
+               if (strcmp(name, comp->instance_name->str) == 0) {
+                       found_comp = comp;
+                       bt_object_get_ref(found_comp);
+                       goto end;
+               }
+       }
+
+end:
+       return found_comp;
+}
+
+static struct bt_config_component *find_component(struct bt_config *cfg,
+               const char *name)
+{
+       struct bt_config_component *comp;
+
+       comp = find_component_in_array(cfg->cmd_data.run.sources, name);
+       if (comp) {
+               goto end;
+       }
+
+       comp = find_component_in_array(cfg->cmd_data.run.filters, name);
+       if (comp) {
+               goto end;
+       }
+
+       comp = find_component_in_array(cfg->cmd_data.run.sinks, name);
+       if (comp) {
+               goto end;
+       }
+
+end:
+       return comp;
+}
+
+static int validate_all_endpoints_exist(struct bt_config *cfg, char *error_buf,
+               size_t error_buf_size)
+{
+       size_t i;
+       int ret = 0;
+
+       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
+               struct bt_config_connection *connection =
+                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
+               struct bt_config_component *comp;
+
+               comp = find_component(cfg, connection->upstream_comp_name->str);
+               bt_object_put_ref(comp);
+               if (!comp) {
+                       snprintf(error_buf, error_buf_size,
+                               "Invalid connection: cannot find upstream component `%s`:\n    %s\n",
+                               connection->upstream_comp_name->str,
+                               connection->arg->str);
+                       ret = -1;
+                       goto end;
+               }
+
+               comp = find_component(cfg, connection->downstream_comp_name->str);
+               bt_object_put_ref(comp);
+               if (!comp) {
+                       snprintf(error_buf, error_buf_size,
+                               "Invalid connection: cannot find downstream component `%s`:\n    %s\n",
+                               connection->downstream_comp_name->str,
+                               connection->arg->str);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static int validate_connection_directions(struct bt_config *cfg,
+               char *error_buf, size_t error_buf_size)
+{
+       size_t i;
+       int ret = 0;
+       struct bt_config_component *src_comp = NULL;
+       struct bt_config_component *dst_comp = NULL;
+
+       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
+               struct bt_config_connection *connection =
+                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
+
+               src_comp = find_component(cfg,
+                       connection->upstream_comp_name->str);
+               BT_ASSERT(src_comp);
+               dst_comp = find_component(cfg,
+                       connection->downstream_comp_name->str);
+               BT_ASSERT(dst_comp);
+
+               if (src_comp->type == BT_COMPONENT_CLASS_TYPE_SOURCE) {
+                       if (dst_comp->type != BT_COMPONENT_CLASS_TYPE_FILTER &&
+                                       dst_comp->type != BT_COMPONENT_CLASS_TYPE_SINK) {
+                               snprintf(error_buf, error_buf_size,
+                                       "Invalid connection: source component `%s` not connected to filter or sink component:\n    %s\n",
+                                       connection->upstream_comp_name->str,
+                                       connection->arg->str);
+                               ret = -1;
+                               goto end;
+                       }
+               } else if (src_comp->type == BT_COMPONENT_CLASS_TYPE_FILTER) {
+                       if (dst_comp->type != BT_COMPONENT_CLASS_TYPE_FILTER &&
+                                       dst_comp->type != BT_COMPONENT_CLASS_TYPE_SINK) {
+                               snprintf(error_buf, error_buf_size,
+                                       "Invalid connection: filter component `%s` not connected to filter or sink component:\n    %s\n",
+                                       connection->upstream_comp_name->str,
+                                       connection->arg->str);
+                               ret = -1;
+                               goto end;
+                       }
+               } else {
+                       snprintf(error_buf, error_buf_size,
+                               "Invalid connection: cannot connect sink component `%s` to component `%s`:\n    %s\n",
+                               connection->upstream_comp_name->str,
+                               connection->downstream_comp_name->str,
+                               connection->arg->str);
+                       ret = -1;
+                       goto end;
+               }
+
+               BT_OBJECT_PUT_REF_AND_RESET(src_comp);
+               BT_OBJECT_PUT_REF_AND_RESET(dst_comp);
+       }
+
+end:
+       bt_object_put_ref(src_comp);
+       bt_object_put_ref(dst_comp);
+       return ret;
+}
+
+static int validate_no_cycles_rec(struct bt_config *cfg, GPtrArray *path,
+               char *error_buf, size_t error_buf_size)
+{
+       int ret = 0;
+       size_t conn_i;
+       const char *src_comp_name;
+
+       BT_ASSERT(path && path->len > 0);
+       src_comp_name = g_ptr_array_index(path, path->len - 1);
+
+       for (conn_i = 0; conn_i < cfg->cmd_data.run.connections->len; conn_i++) {
+               struct bt_config_connection *conn =
+                       g_ptr_array_index(cfg->cmd_data.run.connections, conn_i);
+
+               if (strcmp(conn->upstream_comp_name->str, src_comp_name) == 0) {
+                       size_t path_i;
+
+                       for (path_i = 0; path_i < path->len; path_i++) {
+                               const char *comp_name =
+                                       g_ptr_array_index(path, path_i);
+
+                               if (strcmp(comp_name, conn->downstream_comp_name->str) == 0) {
+                                       snprintf(error_buf, error_buf_size,
+                                               "Invalid connection: connection forms a cycle:\n    %s\n",
+                                               conn->arg->str);
+                                       ret = -1;
+                                       goto end;
+                               }
+                       }
+
+                       g_ptr_array_add(path, conn->downstream_comp_name->str);
+                       ret = validate_no_cycles_rec(cfg, path, error_buf,
+                                       error_buf_size);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       g_ptr_array_remove_index(path, path->len - 1);
+               }
+       }
+
+end:
+       return ret;
+}
+
+static int validate_no_cycles(struct bt_config *cfg, char *error_buf,
+               size_t error_buf_size)
+{
+       size_t i;
+       int ret = 0;
+       GPtrArray *path;
+
+       path = g_ptr_array_new();
+       if (!path) {
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_add(path, NULL);
+
+       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
+               struct bt_config_connection *conn =
+                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
+
+               g_ptr_array_index(path, 0) = conn->upstream_comp_name->str;
+               ret = validate_no_cycles_rec(cfg, path,
+                       error_buf, error_buf_size);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       if (path) {
+               g_ptr_array_free(path, TRUE);
+       }
+
+       return ret;
+}
+
+static int validate_all_components_connected_in_array(GPtrArray *comps,
+               const bt_value *connected_components,
+               char *error_buf, size_t error_buf_size)
+{
+       int ret = 0;
+       size_t i;
+
+       for (i = 0; i < comps->len; i++) {
+               struct bt_config_component *comp = g_ptr_array_index(comps, i);
+
+               if (!bt_value_map_has_entry(connected_components,
+                               comp->instance_name->str)) {
+                       snprintf(error_buf, error_buf_size,
+                               "Component `%s` is not connected\n",
+                               comp->instance_name->str);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static int validate_all_components_connected(struct bt_config *cfg,
+               char *error_buf, size_t error_buf_size)
+{
+       size_t i;
+       int ret = 0;
+       bt_value *connected_components = bt_value_map_create();
+
+       if (!connected_components) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
+               struct bt_config_connection *connection =
+                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
+
+               ret = bt_value_map_insert_entry(connected_components,
+                       connection->upstream_comp_name->str, bt_value_null);
+               if (ret) {
+                       goto end;
+               }
+
+               ret = bt_value_map_insert_entry(connected_components,
+                       connection->downstream_comp_name->str, bt_value_null);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = validate_all_components_connected_in_array(
+               cfg->cmd_data.run.sources,
+               connected_components,
+               error_buf, error_buf_size);
+       if (ret) {
+               goto end;
+       }
+
+       ret = validate_all_components_connected_in_array(
+               cfg->cmd_data.run.filters,
+               connected_components,
+               error_buf, error_buf_size);
+       if (ret) {
+               goto end;
+       }
+
+       ret = validate_all_components_connected_in_array(
+               cfg->cmd_data.run.sinks,
+               connected_components,
+               error_buf, error_buf_size);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       bt_value_put_ref(connected_components);
+       return ret;
+}
+
+static int validate_no_duplicate_connection(struct bt_config *cfg,
+               char *error_buf, size_t error_buf_size)
+{
+       size_t i;
+       int ret = 0;
+       bt_value *flat_connection_names =
+               bt_value_map_create();
+       GString *flat_connection_name = NULL;
+
+       if (!flat_connection_names) {
+               ret = -1;
+               goto end;
+       }
+
+       flat_connection_name = g_string_new(NULL);
+       if (!flat_connection_name) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
+               struct bt_config_connection *connection =
+                       g_ptr_array_index(cfg->cmd_data.run.connections, i);
+
+               g_string_printf(flat_connection_name, "%s\x01%s\x01%s\x01%s",
+                       connection->upstream_comp_name->str,
+                       connection->upstream_port_glob->str,
+                       connection->downstream_comp_name->str,
+                       connection->downstream_port_glob->str);
+
+               if (bt_value_map_has_entry(flat_connection_names,
+                                          flat_connection_name->str)) {
+                       snprintf(error_buf, error_buf_size,
+                               "Duplicate connection:\n    %s\n",
+                               connection->arg->str);
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = bt_value_map_insert_entry(flat_connection_names,
+                       flat_connection_name->str, bt_value_null);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       bt_value_put_ref(flat_connection_names);
+
+       if (flat_connection_name) {
+               g_string_free(flat_connection_name, TRUE);
+       }
+
+       return ret;
+}
+
+static int validate_connections(struct bt_config *cfg, char *error_buf,
+               size_t error_buf_size)
+{
+       int ret;
+
+       ret = validate_all_endpoints_exist(cfg, error_buf, error_buf_size);
+       if (ret) {
+               goto end;
+       }
+
+       ret = validate_connection_directions(cfg, error_buf, error_buf_size);
+       if (ret) {
+               goto end;
+       }
+
+       ret = validate_all_components_connected(cfg, error_buf, error_buf_size);
+       if (ret) {
+               goto end;
+       }
+
+       ret = validate_no_duplicate_connection(cfg, error_buf, error_buf_size);
+       if (ret) {
+               goto end;
+       }
+
+       ret = validate_no_cycles(cfg, error_buf, error_buf_size);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+int bt_config_cli_args_create_connections(struct bt_config *cfg,
+               const bt_value *connection_args,
+               char *error_buf, size_t error_buf_size)
+{
+       int ret;
+       size_t i;
+
+       if (!all_named_and_printable(cfg)) {
+               snprintf(error_buf, error_buf_size,
+                       "One or more components are unnamed (use --name) or contain a non-printable character\n");
+               goto error;
+       }
+
+       for (i = 0; i < bt_value_array_get_size(connection_args); i++) {
+               const bt_value *arg_value =
+                       bt_value_array_borrow_element_by_index_const(
+                               connection_args, i);
+               const char *arg;
+               struct bt_config_connection *cfg_connection;
+
+               arg = bt_value_string_get(arg_value);
+               cfg_connection = cfg_connection_from_arg(arg);
+               if (!cfg_connection) {
+                       snprintf(error_buf, error_buf_size, "Cannot parse --connect option's argument:\n    %s\n",
+                               arg);
+                       goto error;
+               }
+
+               g_ptr_array_add(cfg->cmd_data.run.connections,
+                       cfg_connection);
+       }
+
+
+       ret = validate_connections(cfg, error_buf, error_buf_size);
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
diff --git a/src/cli/babeltrace2-cfg-cli-args-connect.h b/src/cli/babeltrace2-cfg-cli-args-connect.h
new file mode 100644 (file)
index 0000000..37799bb
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef CLI_BABELTRACE_CFG_CLI_ARGS_CONNECT_H
+#define CLI_BABELTRACE_CFG_CLI_ARGS_CONNECT_H
+
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <babeltrace2/value.h>
+#include <glib.h>
+#include "babeltrace2-cfg.h"
+
+int bt_config_cli_args_create_connections(struct bt_config *cfg,
+               const bt_value *connection_args,
+               char *error_buf, size_t error_buf_size);
+
+#endif /* CLI_BABELTRACE_CFG_CLI_ARGS_CONNECT_H */
diff --git a/src/cli/babeltrace2-cfg-cli-args-default.c b/src/cli/babeltrace2-cfg-cli-args-default.c
new file mode 100644 (file)
index 0000000..aef23a5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "babeltrace2-cfg.h"
+#include "babeltrace2-cfg-cli-args.h"
+#include "babeltrace2-cfg-cli-args-default.h"
+
+#ifdef ENABLE_DEBUG_INFO
+# define BT_ENABLE_DEBUG_INFO  1
+#else
+# define BT_ENABLE_DEBUG_INFO  0
+#endif
+
+#ifdef BT_SET_DEFAULT_IN_TREE_CONFIGURATION
+
+struct bt_config *bt_config_cli_args_create_with_default(int argc,
+               const char *argv[], int *retcode)
+{
+       bt_value *initial_plugin_paths;
+       struct bt_config *cfg = NULL;
+       int ret;
+
+       initial_plugin_paths = bt_value_array_create();
+       if (!initial_plugin_paths) {
+               goto error;
+       }
+
+       ret = bt_config_append_plugin_paths(initial_plugin_paths,
+               CONFIG_IN_TREE_PLUGIN_PATH);
+       if (ret) {
+               goto error;
+       }
+
+       cfg = bt_config_cli_args_create(argc, argv, retcode, true, true,
+               initial_plugin_paths);
+       goto end;
+
+error:
+       *retcode = 1;
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       bt_value_put_ref(initial_plugin_paths);
+       return cfg;
+}
+
+#else /* BT_SET_DEFAULT_IN_TREE_CONFIGURATION */
+
+struct bt_config *bt_config_cli_args_create_with_default(int argc,
+               const char *argv[], int *retcode)
+{
+       return bt_config_cli_args_create(argc, argv, retcode, false, false,
+               NULL);
+}
+
+#endif /* BT_SET_DEFAULT_IN_TREE_CONFIGURATION */
diff --git a/src/cli/babeltrace2-cfg-cli-args-default.h b/src/cli/babeltrace2-cfg-cli-args-default.h
new file mode 100644 (file)
index 0000000..839b08c
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef CLI_BABELTRACE_CFG_CLI_ARGS_DEFAULT_H
+#define CLI_BABELTRACE_CFG_CLI_ARGS_DEFAULT_H
+
+/*
+ * Babeltrace Trace Converter - Default Configuration
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "babeltrace2-cfg.h"
+
+struct bt_config *bt_config_cli_args_create_with_default(int argc,
+               const char *argv[], int *retcode);
+
+#endif /* CLI_BABELTRACE_CFG_CLI_ARGS_DEFAULT_H */
diff --git a/src/cli/babeltrace2-cfg-cli-args.c b/src/cli/babeltrace2-cfg-cli-args.c
new file mode 100644 (file)
index 0000000..e1470d7
--- /dev/null
@@ -0,0 +1,5107 @@
+/*
+ * Babeltrace trace converter - parameter parsing
+ *
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CLI-CFG-CLI-ARGS"
+#include "logging.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common/assert.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <babeltrace2/babeltrace.h>
+#include "common/common.h"
+#include <popt.h>
+#include <glib.h>
+#include <sys/types.h>
+#include "babeltrace2-cfg.h"
+#include "babeltrace2-cfg-cli-args.h"
+#include "babeltrace2-cfg-cli-args-connect.h"
+#include "common/version.h"
+
+/*
+ * Error printf() macro which prepends "Error: " the first time it's
+ * called. This gives a nicer feel than having a bunch of error prefixes
+ * (since the following lines usually describe the error and possible
+ * solutions), or the error prefix just at the end.
+ */
+#define printf_err(fmt, args...)                                       \
+       do {                                                            \
+               if (is_first_error) {                                   \
+                       fprintf(stderr, "Command line error: ");        \
+                       is_first_error = false;                         \
+               }                                                       \
+               fprintf(stderr, fmt, ##args);                           \
+       } while (0)
+
+static bool is_first_error = true;
+
+/* INI-style parsing FSM states */
+enum ini_parsing_fsm_state {
+       /* Expect a map key (identifier) */
+       INI_EXPECT_MAP_KEY,
+
+       /* Expect an equal character ('=') */
+       INI_EXPECT_EQUAL,
+
+       /* Expect a value */
+       INI_EXPECT_VALUE,
+
+       /* Expect a comma character (',') */
+       INI_EXPECT_COMMA,
+};
+
+/* INI-style parsing state variables */
+struct ini_parsing_state {
+       /* Lexical scanner (owned by this) */
+       GScanner *scanner;
+
+       /* Output map value object being filled (owned by this) */
+       bt_value *params;
+
+       /* Next expected FSM state */
+       enum ini_parsing_fsm_state expecting;
+
+       /* Last decoded map key (owned by this) */
+       char *last_map_key;
+
+       /* Complete INI-style string to parse (not owned by this) */
+       const char *arg;
+
+       /* Error buffer (not owned by this) */
+       GString *ini_error;
+};
+
+/* Offset option with "is set" boolean */
+struct offset_opt {
+       int64_t value;
+       bool is_set;
+};
+
+/* Legacy "ctf"/"lttng-live" format options */
+struct ctf_legacy_opts {
+       struct offset_opt offset_s;
+       struct offset_opt offset_ns;
+       bool stream_intersection;
+};
+
+/* Legacy "text" format options */
+struct text_legacy_opts {
+       /*
+        * output, dbg_info_dir, dbg_info_target_prefix, names,
+        * and fields are owned by this.
+        */
+       GString *output;
+       GString *dbg_info_dir;
+       GString *dbg_info_target_prefix;
+       const bt_value *names;
+       const bt_value *fields;
+
+       /* Flags */
+       bool no_delta;
+       bool clock_cycles;
+       bool clock_seconds;
+       bool clock_date;
+       bool clock_gmt;
+       bool dbg_info_full_path;
+       bool verbose;
+};
+
+/* Legacy input format format */
+enum legacy_input_format {
+       LEGACY_INPUT_FORMAT_NONE = 0,
+       LEGACY_INPUT_FORMAT_CTF,
+       LEGACY_INPUT_FORMAT_LTTNG_LIVE,
+};
+
+/* Legacy output format format */
+enum legacy_output_format {
+       LEGACY_OUTPUT_FORMAT_NONE = 0,
+       LEGACY_OUTPUT_FORMAT_TEXT,
+       LEGACY_OUTPUT_FORMAT_DUMMY,
+};
+
+/*
+ * Prints the "out of memory" error.
+ */
+static
+void print_err_oom(void)
+{
+       printf_err("Out of memory\n");
+}
+
+/*
+ * Appends an "expecting token" error to the INI-style parsing state's
+ * error buffer.
+ */
+static
+void ini_append_error_expecting(struct ini_parsing_state *state,
+               GScanner *scanner, const char *expecting)
+{
+       size_t i;
+       size_t pos;
+
+       g_string_append_printf(state->ini_error, "Expecting %s:\n", expecting);
+
+       /* Only print error if there's one line */
+       if (strchr(state->arg, '\n') != NULL || strlen(state->arg) == 0) {
+               return;
+       }
+
+       g_string_append_printf(state->ini_error, "\n    %s\n", state->arg);
+       pos = g_scanner_cur_position(scanner) + 4;
+
+       if (!g_scanner_eof(scanner)) {
+               pos--;
+       }
+
+       for (i = 0; i < pos; ++i) {
+               g_string_append_printf(state->ini_error, " ");
+       }
+
+       g_string_append_printf(state->ini_error, "^\n\n");
+}
+
+/* Parse the next token as an unsigned integer. */
+static
+bt_value *ini_parse_uint(struct ini_parsing_state *state)
+{
+       bt_value *value = NULL;
+       GTokenType token_type = g_scanner_get_next_token(state->scanner);
+
+       if (token_type != G_TOKEN_INT) {
+               ini_append_error_expecting(state, state->scanner,
+                       "integer value");
+               goto end;
+       }
+
+       value = bt_value_unsigned_integer_create_init(
+               state->scanner->value.v_int64);
+
+end:
+       return value;
+}
+
+/* Parse the next token as a number and return its negation. */
+static
+bt_value *ini_parse_neg_number(struct ini_parsing_state *state)
+{
+       bt_value *value = NULL;
+       GTokenType token_type = g_scanner_get_next_token(state->scanner);
+
+       switch (token_type) {
+       case G_TOKEN_INT:
+       {
+               /* Negative integer */
+               uint64_t int_val = state->scanner->value.v_int64;
+
+               if (int_val > (((uint64_t) INT64_MAX) + 1)) {
+                       g_string_append_printf(state->ini_error,
+                               "Integer value -%" PRIu64 " is outside the range of a 64-bit signed integer\n",
+                               int_val);
+               } else {
+                       value = bt_value_signed_integer_create_init(
+                               -((int64_t) int_val));
+               }
+
+               break;
+       }
+       case G_TOKEN_FLOAT:
+               /* Negative floating point number */
+               value = bt_value_real_create_init(-state->scanner->value.v_float);
+               break;
+       default:
+               ini_append_error_expecting(state, state->scanner, "value");
+               break;
+       }
+
+       return value;
+}
+
+static bt_value *ini_parse_value(struct ini_parsing_state *state);
+
+/*
+ * Parse the current and following tokens as an array.  Arrays are formatted as
+ * an opening `[`, a list of comma-separated values and a closing `]`.  For
+ * convenience we support an optional trailing comma, after the last value.
+ *
+ * The current token of the parser must be the opening square bracket of the
+ * array.
+ */
+static
+bt_value *ini_parse_array(struct ini_parsing_state *state)
+{
+       /* The [ character must have already been ingested. */
+       BT_ASSERT(g_scanner_cur_token(state->scanner) == G_TOKEN_CHAR);
+       BT_ASSERT(g_scanner_cur_value(state->scanner).v_char == '[');
+
+       bt_value *array_value;
+       GTokenType token_type;
+
+       array_value = bt_value_array_create ();
+       token_type = g_scanner_get_next_token(state->scanner);
+
+       /* While the current token is not a ]... */
+       while (!(token_type == G_TOKEN_CHAR && g_scanner_cur_value(state->scanner).v_char == ']')) {
+               /* Parse the item... */
+               bt_value *item_value;
+               bt_value_status status;
+
+               item_value = ini_parse_value(state);
+               if (!item_value) {
+                       goto error;
+               }
+
+               /* ... and add it to the result array. */
+               status = bt_value_array_append_element(array_value, item_value);
+               BT_VALUE_PUT_REF_AND_RESET(item_value);
+
+               if (status != BT_VALUE_STATUS_OK) {
+                       goto error;
+               }
+
+               /*
+                * Ingest the token following the value, it should be either a
+                * comma or closing square brace.
+                */
+               token_type = g_scanner_get_next_token(state->scanner);
+
+               if (token_type == G_TOKEN_CHAR && g_scanner_cur_value(state->scanner).v_char == ',') {
+                       /*
+                        * Ingest the token following the comma.  If it happens
+                        * to be a closing square bracket, we'll exit the loop
+                        * and we are done (we allow trailing commas).
+                        * Otherwise, we are ready for the next ini_parse_value call.
+                        */
+                       token_type = g_scanner_get_next_token(state->scanner);
+               } else if (token_type != G_TOKEN_CHAR || g_scanner_cur_value(state->scanner).v_char != ']') {
+                       ini_append_error_expecting(state, state->scanner, ", or ]");
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       BT_VALUE_PUT_REF_AND_RESET(array_value);
+
+end:
+       return array_value;
+}
+
+/*
+ * Parse the current token (and the following ones if needed) as a value, return
+ * it as a bt_value.
+ */
+static
+bt_value *ini_parse_value(struct ini_parsing_state *state)
+{
+       bt_value *value = NULL;
+       GTokenType token_type = state->scanner->token;
+
+       switch (token_type) {
+       case G_TOKEN_CHAR:
+               if (state->scanner->value.v_char == '-') {
+                       /* Negative number */
+                       value = ini_parse_neg_number(state);
+               } else if (state->scanner->value.v_char == '+') {
+                       /* Unsigned integer */
+                       value = ini_parse_uint(state);
+               } else if (state->scanner->value.v_char == '[') {
+                       /* Array */
+                       value = ini_parse_array(state);
+               } else {
+                       ini_append_error_expecting(state, state->scanner, "value");
+               }
+               break;
+       case G_TOKEN_INT:
+       {
+               /* Positive, signed integer */
+               uint64_t int_val = state->scanner->value.v_int64;
+
+               if (int_val > INT64_MAX) {
+                       g_string_append_printf(state->ini_error,
+                               "Integer value %" PRIu64 " is outside the range of a 64-bit signed integer\n",
+                               int_val);
+               } else {
+                       value = bt_value_signed_integer_create_init(
+                               (int64_t) int_val);
+               }
+               break;
+       }
+       case G_TOKEN_FLOAT:
+               /* Positive floating point number */
+               value = bt_value_real_create_init(state->scanner->value.v_float);
+               break;
+       case G_TOKEN_STRING:
+               /* Quoted string */
+               value = bt_value_string_create_init(state->scanner->value.v_string);
+               break;
+       case G_TOKEN_IDENTIFIER:
+       {
+               /*
+                * Using symbols would be appropriate here,
+                * but said symbols are allowed as map key,
+                * so it's easier to consider everything an
+                * identifier.
+                *
+                * If one of the known symbols is not
+                * recognized here, then fall back to creating
+                * a string value.
+                */
+               const char *id = state->scanner->value.v_identifier;
+
+               if (!strcmp(id, "null") || !strcmp(id, "NULL") ||
+                               !strcmp(id, "nul")) {
+                       value = bt_value_null;
+               } else if (!strcmp(id, "true") || !strcmp(id, "TRUE") ||
+                               !strcmp(id, "yes") ||
+                               !strcmp(id, "YES")) {
+                       value = bt_value_bool_create_init(true);
+               } else if (!strcmp(id, "false") ||
+                               !strcmp(id, "FALSE") ||
+                               !strcmp(id, "no") ||
+                               !strcmp(id, "NO")) {
+                       value = bt_value_bool_create_init(false);
+               } else {
+                       value = bt_value_string_create_init(id);
+               }
+               break;
+       }
+       default:
+               /* Unset value variable will trigger the error */
+               ini_append_error_expecting(state, state->scanner, "value");
+               break;
+       }
+
+       return value;
+}
+
+static
+int ini_handle_state(struct ini_parsing_state *state)
+{
+       int ret = 0;
+       GTokenType token_type;
+       bt_value *value = NULL;
+
+       token_type = g_scanner_get_next_token(state->scanner);
+       if (token_type == G_TOKEN_EOF) {
+               if (state->expecting != INI_EXPECT_COMMA) {
+                       switch (state->expecting) {
+                       case INI_EXPECT_EQUAL:
+                               ini_append_error_expecting(state,
+                                       state->scanner, "'='");
+                               break;
+                       case INI_EXPECT_VALUE:
+                               ini_append_error_expecting(state,
+                                       state->scanner, "value");
+                               break;
+                       case INI_EXPECT_MAP_KEY:
+                               ini_append_error_expecting(state,
+                                       state->scanner, "unquoted map key");
+                               break;
+                       default:
+                               break;
+                       }
+                       goto error;
+               }
+
+               /* We're done! */
+               ret = 1;
+               goto success;
+       }
+
+       switch (state->expecting) {
+       case INI_EXPECT_MAP_KEY:
+               if (token_type != G_TOKEN_IDENTIFIER) {
+                       ini_append_error_expecting(state, state->scanner,
+                               "unquoted map key");
+                       goto error;
+               }
+
+               free(state->last_map_key);
+               state->last_map_key =
+                       strdup(state->scanner->value.v_identifier);
+               if (!state->last_map_key) {
+                       g_string_append(state->ini_error,
+                               "Out of memory\n");
+                       goto error;
+               }
+
+               if (bt_value_map_has_entry(state->params,
+                                          state->last_map_key)) {
+                       g_string_append_printf(state->ini_error,
+                               "Duplicate parameter key: `%s`\n",
+                               state->last_map_key);
+                       goto error;
+               }
+
+               state->expecting = INI_EXPECT_EQUAL;
+               goto success;
+       case INI_EXPECT_EQUAL:
+               if (token_type != G_TOKEN_CHAR) {
+                       ini_append_error_expecting(state,
+                               state->scanner, "'='");
+                       goto error;
+               }
+
+               if (state->scanner->value.v_char != '=') {
+                       ini_append_error_expecting(state,
+                               state->scanner, "'='");
+                       goto error;
+               }
+
+               state->expecting = INI_EXPECT_VALUE;
+               goto success;
+       case INI_EXPECT_VALUE:
+       {
+               value = ini_parse_value(state);
+               if (!value) {
+                       goto error;
+               }
+
+               state->expecting = INI_EXPECT_COMMA;
+               goto success;
+       }
+       case INI_EXPECT_COMMA:
+               if (token_type != G_TOKEN_CHAR) {
+                       ini_append_error_expecting(state,
+                               state->scanner, "','");
+                       goto error;
+               }
+
+               if (state->scanner->value.v_char != ',') {
+                       ini_append_error_expecting(state,
+                               state->scanner, "','");
+                       goto error;
+               }
+
+               state->expecting = INI_EXPECT_MAP_KEY;
+               goto success;
+       default:
+               abort();
+       }
+
+error:
+       ret = -1;
+       goto end;
+
+success:
+       if (value) {
+               if (bt_value_map_insert_entry(state->params,
+                               state->last_map_key, value)) {
+                       /* Only override return value on error */
+                       ret = -1;
+               }
+       }
+
+end:
+       BT_VALUE_PUT_REF_AND_RESET(value);
+       return ret;
+}
+
+/*
+ * Converts an INI-style argument to an equivalent map value object.
+ *
+ * Return value is owned by the caller.
+ */
+static
+bt_value *bt_value_from_ini(const char *arg,
+               GString *ini_error)
+{
+       /* Lexical scanner configuration */
+       GScannerConfig scanner_config = {
+               /* Skip whitespaces */
+               .cset_skip_characters = " \t\n",
+
+               /* Identifier syntax is: [a-zA-Z_][a-zA-Z0-9_.:-]* */
+               .cset_identifier_first =
+                       G_CSET_a_2_z
+                       "_"
+                       G_CSET_A_2_Z,
+               .cset_identifier_nth =
+                       G_CSET_a_2_z
+                       "_0123456789-.:"
+                       G_CSET_A_2_Z,
+
+               /* "hello" and "Hello" two different keys */
+               .case_sensitive = TRUE,
+
+               /* No comments */
+               .cpair_comment_single = NULL,
+               .skip_comment_multi = TRUE,
+               .skip_comment_single = TRUE,
+               .scan_comment_multi = FALSE,
+
+               /*
+                * Do scan identifiers, including 1-char identifiers,
+                * but NULL is a normal identifier.
+                */
+               .scan_identifier = TRUE,
+               .scan_identifier_1char = TRUE,
+               .scan_identifier_NULL = FALSE,
+
+               /*
+                * No specific symbols: null and boolean "symbols" are
+                * scanned as plain identifiers.
+                */
+               .scan_symbols = FALSE,
+               .symbol_2_token = FALSE,
+               .scope_0_fallback = FALSE,
+
+               /*
+                * Scan "0b"-, "0"-, and "0x"-prefixed integers, but not
+                * integers prefixed with "$".
+                */
+               .scan_binary = TRUE,
+               .scan_octal = TRUE,
+               .scan_float = TRUE,
+               .scan_hex = TRUE,
+               .scan_hex_dollar = FALSE,
+
+               /* Convert scanned numbers to integer tokens */
+               .numbers_2_int = TRUE,
+
+               /* Support both integers and floating-point numbers */
+               .int_2_float = FALSE,
+
+               /* Scan integers as 64-bit signed integers */
+               .store_int64 = TRUE,
+
+               /* Only scan double-quoted strings */
+               .scan_string_sq = FALSE,
+               .scan_string_dq = TRUE,
+
+               /* Do not converter identifiers to string tokens */
+               .identifier_2_string = FALSE,
+
+               /* Scan characters as G_TOKEN_CHAR token */
+               .char_2_token = FALSE,
+       };
+       struct ini_parsing_state state = {
+               .scanner = NULL,
+               .params = NULL,
+               .expecting = INI_EXPECT_MAP_KEY,
+               .arg = arg,
+               .ini_error = ini_error,
+       };
+
+       state.params = bt_value_map_create();
+       if (!state.params) {
+               goto error;
+       }
+
+       state.scanner = g_scanner_new(&scanner_config);
+       if (!state.scanner) {
+               goto error;
+       }
+
+       /* Let the scan begin */
+       g_scanner_input_text(state.scanner, arg, strlen(arg));
+
+       while (true) {
+               int ret = ini_handle_state(&state);
+
+               if (ret < 0) {
+                       /* Error */
+                       goto error;
+               } else if (ret > 0) {
+                       /* Done */
+                       break;
+               }
+       }
+
+       goto end;
+
+error:
+       BT_VALUE_PUT_REF_AND_RESET(state.params);
+
+end:
+       if (state.scanner) {
+               g_scanner_destroy(state.scanner);
+       }
+
+       free(state.last_map_key);
+       return state.params;
+}
+
+/*
+ * Returns the parameters map value object from a command-line
+ * parameter option's argument.
+ *
+ * Return value is owned by the caller.
+ */
+static
+bt_value *bt_value_from_arg(const char *arg)
+{
+       bt_value *params = NULL;
+       GString *ini_error = NULL;
+
+       ini_error = g_string_new(NULL);
+       if (!ini_error) {
+               print_err_oom();
+               goto end;
+       }
+
+       /* Try INI-style parsing */
+       params = bt_value_from_ini(arg, ini_error);
+       if (!params) {
+               printf_err("%s", ini_error->str);
+               goto end;
+       }
+
+end:
+       if (ini_error) {
+               g_string_free(ini_error, TRUE);
+       }
+
+       return params;
+}
+
+/*
+ * Returns the plugin name, component class name, component class type,
+ * and component name from a command-line --component option's argument.
+ * arg must have the following format:
+ *
+ *     [NAME:]TYPE.PLUGIN.CLS
+ *
+ * where NAME is the optional component name, TYPE is either `source`,
+ * `filter`, or `sink`, PLUGIN is the plugin name, and CLS is the
+ * component class name.
+ *
+ * On success, both *plugin and *component are not NULL. *plugin
+ * and *comp_cls are owned by the caller. On success, *name can be NULL
+ * if no component class name was found, and *comp_cls_type is set.
+ */
+static
+void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
+               char **comp_cls, bt_component_class_type *comp_cls_type)
+{
+       const char *at = arg;
+       GString *gs_name = NULL;
+       GString *gs_comp_cls_type = NULL;
+       GString *gs_plugin = NULL;
+       GString *gs_comp_cls = NULL;
+       size_t end_pos;
+
+       BT_ASSERT(arg);
+       BT_ASSERT(plugin);
+       BT_ASSERT(comp_cls);
+       BT_ASSERT(comp_cls_type);
+
+       if (!bt_common_string_is_printable(arg)) {
+               printf_err("Argument contains a non-printable character\n");
+               goto error;
+       }
+
+       /* Parse the component name */
+       gs_name = bt_common_string_until(at, ".:\\", ":", &end_pos);
+       if (!gs_name) {
+               goto error;
+       }
+
+       if (arg[end_pos] == ':') {
+               at += end_pos + 1;
+       } else {
+               /* No name */
+               g_string_assign(gs_name, "");
+       }
+
+       /* Parse the component class type */
+       gs_comp_cls_type = bt_common_string_until(at, ".:\\", ".", &end_pos);
+       if (!gs_comp_cls_type || at[end_pos] == '\0') {
+               printf_err("Missing component class type (`source`, `filter`, or `sink`)\n");
+               goto error;
+       }
+
+       if (strcmp(gs_comp_cls_type->str, "source") == 0 ||
+                       strcmp(gs_comp_cls_type->str, "src") == 0) {
+               *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SOURCE;
+       } else if (strcmp(gs_comp_cls_type->str, "filter") == 0 ||
+                       strcmp(gs_comp_cls_type->str, "flt") == 0) {
+               *comp_cls_type = BT_COMPONENT_CLASS_TYPE_FILTER;
+       } else if (strcmp(gs_comp_cls_type->str, "sink") == 0) {
+               *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SINK;
+       } else {
+               printf_err("Unknown component class type: `%s`\n",
+                       gs_comp_cls_type->str);
+               goto error;
+       }
+
+       at += end_pos + 1;
+
+       /* Parse the plugin name */
+       gs_plugin = bt_common_string_until(at, ".:\\", ".", &end_pos);
+       if (!gs_plugin || gs_plugin->len == 0 || at[end_pos] == '\0') {
+               printf_err("Missing plugin or component class name\n");
+               goto error;
+       }
+
+       at += end_pos + 1;
+
+       /* Parse the component class name */
+       gs_comp_cls = bt_common_string_until(at, ".:\\", ".", &end_pos);
+       if (!gs_comp_cls || gs_comp_cls->len == 0) {
+               printf_err("Missing component class name\n");
+               goto error;
+       }
+
+       if (at[end_pos] != '\0') {
+               /* Found a non-escaped `.` */
+               goto error;
+       }
+
+       if (name) {
+               if (gs_name->len == 0) {
+                       *name = NULL;
+                       g_string_free(gs_name, TRUE);
+               } else {
+                       *name = gs_name->str;
+                       g_string_free(gs_name, FALSE);
+               }
+       } else {
+               g_string_free(gs_name, TRUE);
+       }
+
+       *plugin = gs_plugin->str;
+       *comp_cls = gs_comp_cls->str;
+       g_string_free(gs_plugin, FALSE);
+       g_string_free(gs_comp_cls, FALSE);
+       gs_name = NULL;
+       gs_plugin = NULL;
+       gs_comp_cls = NULL;
+       goto end;
+
+error:
+       if (name) {
+               *name = NULL;
+       }
+
+       *plugin = NULL;
+       *comp_cls = NULL;
+
+end:
+       if (gs_name) {
+               g_string_free(gs_name, TRUE);
+       }
+
+       if (gs_plugin) {
+               g_string_free(gs_plugin, TRUE);
+       }
+
+       if (gs_comp_cls) {
+               g_string_free(gs_comp_cls, TRUE);
+       }
+
+       if (gs_comp_cls_type) {
+               g_string_free(gs_comp_cls_type, TRUE);
+       }
+
+       return;
+}
+
+/*
+ * Prints the Babeltrace version.
+ */
+static
+void print_version(void)
+{
+       if (GIT_VERSION[0] == '\0') {
+               puts("Babeltrace " VERSION);
+       } else {
+               puts("Babeltrace " VERSION  " - " GIT_VERSION);
+       }
+}
+
+/*
+ * Destroys a component configuration.
+ */
+static
+void bt_config_component_destroy(bt_object *obj)
+{
+       struct bt_config_component *bt_config_component =
+               container_of(obj, struct bt_config_component, base);
+
+       if (!obj) {
+               goto end;
+       }
+
+       if (bt_config_component->plugin_name) {
+               g_string_free(bt_config_component->plugin_name, TRUE);
+       }
+
+       if (bt_config_component->comp_cls_name) {
+               g_string_free(bt_config_component->comp_cls_name, TRUE);
+       }
+
+       if (bt_config_component->instance_name) {
+               g_string_free(bt_config_component->instance_name, TRUE);
+       }
+
+       BT_VALUE_PUT_REF_AND_RESET(bt_config_component->params);
+       g_free(bt_config_component);
+
+end:
+       return;
+}
+
+/*
+ * Creates a component configuration using the given plugin name and
+ * component name. `plugin_name` and `comp_cls_name` are copied (belong
+ * to the return value).
+ *
+ * Return value is owned by the caller.
+ */
+static
+struct bt_config_component *bt_config_component_create(
+               bt_component_class_type type,
+               const char *plugin_name, const char *comp_cls_name)
+{
+       struct bt_config_component *cfg_component = NULL;
+
+       cfg_component = g_new0(struct bt_config_component, 1);
+       if (!cfg_component) {
+               print_err_oom();
+               goto error;
+       }
+
+       bt_object_init_shared(&cfg_component->base,
+               bt_config_component_destroy);
+       cfg_component->type = type;
+       cfg_component->plugin_name = g_string_new(plugin_name);
+       if (!cfg_component->plugin_name) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg_component->comp_cls_name = g_string_new(comp_cls_name);
+       if (!cfg_component->comp_cls_name) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg_component->instance_name = g_string_new(NULL);
+       if (!cfg_component->instance_name) {
+               print_err_oom();
+               goto error;
+       }
+
+       /* Start with empty parameters */
+       cfg_component->params = bt_value_map_create();
+       if (!cfg_component->params) {
+               print_err_oom();
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg_component);
+
+end:
+       return cfg_component;
+}
+
+/*
+ * Creates a component configuration from a command-line --component
+ * option's argument.
+ */
+static
+struct bt_config_component *bt_config_component_from_arg(const char *arg)
+{
+       struct bt_config_component *cfg_comp = NULL;
+       char *name = NULL;
+       char *plugin_name = NULL;
+       char *comp_cls_name = NULL;
+       bt_component_class_type type;
+
+       plugin_comp_cls_names(arg, &name, &plugin_name, &comp_cls_name, &type);
+       if (!plugin_name || !comp_cls_name) {
+               goto error;
+       }
+
+       cfg_comp = bt_config_component_create(type, plugin_name, comp_cls_name);
+       if (!cfg_comp) {
+               goto error;
+       }
+
+       if (name) {
+               g_string_assign(cfg_comp->instance_name, name);
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg_comp);
+
+end:
+       g_free(name);
+       g_free(plugin_name);
+       g_free(comp_cls_name);
+       return cfg_comp;
+}
+
+/*
+ * Destroys a configuration.
+ */
+static
+void bt_config_destroy(bt_object *obj)
+{
+       struct bt_config *cfg =
+               container_of(obj, struct bt_config, base);
+
+       if (!obj) {
+               goto end;
+       }
+
+       BT_VALUE_PUT_REF_AND_RESET(cfg->plugin_paths);
+
+       switch (cfg->command) {
+       case BT_CONFIG_COMMAND_RUN:
+               if (cfg->cmd_data.run.sources) {
+                       g_ptr_array_free(cfg->cmd_data.run.sources, TRUE);
+               }
+
+               if (cfg->cmd_data.run.filters) {
+                       g_ptr_array_free(cfg->cmd_data.run.filters, TRUE);
+               }
+
+               if (cfg->cmd_data.run.sinks) {
+                       g_ptr_array_free(cfg->cmd_data.run.sinks, TRUE);
+               }
+
+               if (cfg->cmd_data.run.connections) {
+                       g_ptr_array_free(cfg->cmd_data.run.connections,
+                               TRUE);
+               }
+               break;
+       case BT_CONFIG_COMMAND_LIST_PLUGINS:
+               break;
+       case BT_CONFIG_COMMAND_HELP:
+               BT_OBJECT_PUT_REF_AND_RESET(cfg->cmd_data.help.cfg_component);
+               break;
+       case BT_CONFIG_COMMAND_QUERY:
+               BT_OBJECT_PUT_REF_AND_RESET(cfg->cmd_data.query.cfg_component);
+
+               if (cfg->cmd_data.query.object) {
+                       g_string_free(cfg->cmd_data.query.object, TRUE);
+               }
+               break;
+       case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
+               if (cfg->cmd_data.print_ctf_metadata.path) {
+                       g_string_free(cfg->cmd_data.print_ctf_metadata.path,
+                               TRUE);
+                       g_string_free(
+                               cfg->cmd_data.print_ctf_metadata.output_path,
+                               TRUE);
+               }
+               break;
+       case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
+               if (cfg->cmd_data.print_lttng_live_sessions.url) {
+                       g_string_free(
+                               cfg->cmd_data.print_lttng_live_sessions.url,
+                               TRUE);
+                       g_string_free(
+                               cfg->cmd_data.print_lttng_live_sessions.output_path,
+                               TRUE);
+               }
+               break;
+       default:
+               abort();
+       }
+
+       g_free(cfg);
+
+end:
+       return;
+}
+
+static
+void destroy_glist_of_gstring(GList *list)
+{
+       GList *at;
+
+       if (!list) {
+               return;
+       }
+
+       for (at = list; at != NULL; at = g_list_next(at)) {
+               g_string_free(at->data, TRUE);
+       }
+
+       g_list_free(list);
+}
+
+/*
+ * Creates a simple lexical scanner for parsing comma-delimited names
+ * and fields.
+ *
+ * Return value is owned by the caller.
+ */
+static
+GScanner *create_csv_identifiers_scanner(void)
+{
+       GScanner *scanner;
+       GScannerConfig scanner_config = {
+               .cset_skip_characters = " \t\n",
+               .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_",
+               .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-",
+               .case_sensitive = TRUE,
+               .cpair_comment_single = NULL,
+               .skip_comment_multi = TRUE,
+               .skip_comment_single = TRUE,
+               .scan_comment_multi = FALSE,
+               .scan_identifier = TRUE,
+               .scan_identifier_1char = TRUE,
+               .scan_identifier_NULL = FALSE,
+               .scan_symbols = FALSE,
+               .symbol_2_token = FALSE,
+               .scope_0_fallback = FALSE,
+               .scan_binary = FALSE,
+               .scan_octal = FALSE,
+               .scan_float = FALSE,
+               .scan_hex = FALSE,
+               .scan_hex_dollar = FALSE,
+               .numbers_2_int = FALSE,
+               .int_2_float = FALSE,
+               .store_int64 = FALSE,
+               .scan_string_sq = FALSE,
+               .scan_string_dq = FALSE,
+               .identifier_2_string = FALSE,
+               .char_2_token = TRUE,
+       };
+
+       scanner = g_scanner_new(&scanner_config);
+       if (!scanner) {
+               print_err_oom();
+       }
+
+       return scanner;
+}
+
+/*
+ * Converts a comma-delimited list of known names (--names option) to
+ * an array value object containing those names as string value objects.
+ *
+ * Return value is owned by the caller.
+ */
+static
+bt_value *names_from_arg(const char *arg)
+{
+       GScanner *scanner = NULL;
+       bt_value *names = NULL;
+       bool found_all = false, found_none = false, found_item = false;
+
+       names = bt_value_array_create();
+       if (!names) {
+               print_err_oom();
+               goto error;
+       }
+
+       scanner = create_csv_identifiers_scanner();
+       if (!scanner) {
+               goto error;
+       }
+
+       g_scanner_input_text(scanner, arg, strlen(arg));
+
+       while (true) {
+               GTokenType token_type = g_scanner_get_next_token(scanner);
+
+               switch (token_type) {
+               case G_TOKEN_IDENTIFIER:
+               {
+                       const char *identifier = scanner->value.v_identifier;
+
+                       if (!strcmp(identifier, "payload") ||
+                                       !strcmp(identifier, "args") ||
+                                       !strcmp(identifier, "arg")) {
+                               found_item = true;
+                               if (bt_value_array_append_string_element(names,
+                                               "payload")) {
+                                       goto error;
+                               }
+                       } else if (!strcmp(identifier, "context") ||
+                                       !strcmp(identifier, "ctx")) {
+                               found_item = true;
+                               if (bt_value_array_append_string_element(names,
+                                               "context")) {
+                                       goto error;
+                               }
+                       } else if (!strcmp(identifier, "scope") ||
+                                       !strcmp(identifier, "header")) {
+                               found_item = true;
+                               if (bt_value_array_append_string_element(names,
+                                               identifier)) {
+                                       goto error;
+                               }
+                       } else if (!strcmp(identifier, "all")) {
+                               found_all = true;
+                               if (bt_value_array_append_string_element(names,
+                                               identifier)) {
+                                       goto error;
+                               }
+                       } else if (!strcmp(identifier, "none")) {
+                               found_none = true;
+                               if (bt_value_array_append_string_element(names,
+                                               identifier)) {
+                                       goto error;
+                               }
+                       } else {
+                               printf_err("Unknown name: `%s`\n",
+                                       identifier);
+                               goto error;
+                       }
+                       break;
+               }
+               case G_TOKEN_COMMA:
+                       continue;
+               case G_TOKEN_EOF:
+                       goto end;
+               default:
+                       goto error;
+               }
+       }
+
+end:
+       if (found_none && found_all) {
+               printf_err("Only either `all` or `none` can be specified in the list given to the --names option, but not both.\n");
+               goto error;
+       }
+       /*
+        * Legacy behavior is to clear the defaults (show none) when at
+        * least one item is specified.
+        */
+       if (found_item && !found_none && !found_all) {
+               if (bt_value_array_append_string_element(names, "none")) {
+                       goto error;
+               }
+       }
+       if (scanner) {
+               g_scanner_destroy(scanner);
+       }
+       return names;
+
+error:
+       BT_VALUE_PUT_REF_AND_RESET(names);
+       if (scanner) {
+               g_scanner_destroy(scanner);
+       }
+       return names;
+}
+
+/*
+ * Converts a comma-delimited list of known fields (--fields option) to
+ * an array value object containing those fields as string
+ * value objects.
+ *
+ * Return value is owned by the caller.
+ */
+static
+bt_value *fields_from_arg(const char *arg)
+{
+       GScanner *scanner = NULL;
+       bt_value *fields;
+
+       fields = bt_value_array_create();
+       if (!fields) {
+               print_err_oom();
+               goto error;
+       }
+
+       scanner = create_csv_identifiers_scanner();
+       if (!scanner) {
+               goto error;
+       }
+
+       g_scanner_input_text(scanner, arg, strlen(arg));
+
+       while (true) {
+               GTokenType token_type = g_scanner_get_next_token(scanner);
+
+               switch (token_type) {
+               case G_TOKEN_IDENTIFIER:
+               {
+                       const char *identifier = scanner->value.v_identifier;
+
+                       if (!strcmp(identifier, "trace") ||
+                                       !strcmp(identifier, "trace:hostname") ||
+                                       !strcmp(identifier, "trace:domain") ||
+                                       !strcmp(identifier, "trace:procname") ||
+                                       !strcmp(identifier, "trace:vpid") ||
+                                       !strcmp(identifier, "loglevel") ||
+                                       !strcmp(identifier, "emf") ||
+                                       !strcmp(identifier, "callsite") ||
+                                       !strcmp(identifier, "all")) {
+                               if (bt_value_array_append_string_element(fields,
+                                               identifier)) {
+                                       goto error;
+                               }
+                       } else {
+                               printf_err("Unknown field: `%s`\n",
+                                       identifier);
+                               goto error;
+                       }
+                       break;
+               }
+               case G_TOKEN_COMMA:
+                       continue;
+               case G_TOKEN_EOF:
+                       goto end;
+               default:
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       BT_VALUE_PUT_REF_AND_RESET(fields);
+
+end:
+       if (scanner) {
+               g_scanner_destroy(scanner);
+       }
+       return fields;
+}
+
+static
+void append_param_arg(GString *params_arg, const char *key, const char *value)
+{
+       BT_ASSERT(params_arg);
+       BT_ASSERT(key);
+       BT_ASSERT(value);
+
+       if (params_arg->len != 0) {
+               g_string_append_c(params_arg, ',');
+       }
+
+       g_string_append(params_arg, key);
+       g_string_append_c(params_arg, '=');
+       g_string_append(params_arg, value);
+}
+
+/*
+ * Inserts the equivalent "prefix-NAME=yes" strings into params_arg
+ * where the names are in names_array.
+ */
+static
+int insert_flat_params_from_array(GString *params_arg,
+               const bt_value *names_array, const char *prefix)
+{
+       int ret = 0;
+       int i;
+       GString *tmpstr = NULL, *default_value = NULL;
+       bool default_set = false, non_default_set = false;
+
+       /*
+        * names_array may be NULL if no CLI options were specified to
+        * trigger its creation.
+        */
+       if (!names_array) {
+               goto end;
+       }
+
+       tmpstr = g_string_new(NULL);
+       if (!tmpstr) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       default_value = g_string_new(NULL);
+       if (!default_value) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < bt_value_array_get_size(names_array); i++) {
+               const bt_value *str_obj =
+                       bt_value_array_borrow_element_by_index_const(names_array,
+                                                                    i);
+               const char *suffix;
+               bool is_default = false;
+
+               if (!str_obj) {
+                       printf_err("Unexpected error\n");
+                       ret = -1;
+                       goto end;
+               }
+
+               suffix = bt_value_string_get(str_obj);
+
+               g_string_assign(tmpstr, prefix);
+               g_string_append(tmpstr, "-");
+
+               /* Special-case for "all" and "none". */
+               if (!strcmp(suffix, "all")) {
+                       is_default = true;
+                       g_string_assign(default_value, "show");
+               } else if (!strcmp(suffix, "none")) {
+                       is_default = true;
+                       g_string_assign(default_value, "hide");
+               }
+               if (is_default) {
+                       default_set = true;
+                       g_string_append(tmpstr, "default");
+                       append_param_arg(params_arg, tmpstr->str,
+                               default_value->str);
+               } else {
+                       non_default_set = true;
+                       g_string_append(tmpstr, suffix);
+                       append_param_arg(params_arg, tmpstr->str, "yes");
+               }
+       }
+
+       /* Implicit field-default=hide if any non-default option is set. */
+       if (non_default_set && !default_set) {
+               g_string_assign(tmpstr, prefix);
+               g_string_append(tmpstr, "-default");
+               g_string_assign(default_value, "hide");
+               append_param_arg(params_arg, tmpstr->str, default_value->str);
+       }
+
+end:
+       if (default_value) {
+               g_string_free(default_value, TRUE);
+       }
+
+       if (tmpstr) {
+               g_string_free(tmpstr, TRUE);
+       }
+
+       return ret;
+}
+
+/* popt options */
+enum {
+       OPT_NONE = 0,
+       OPT_BASE_PARAMS,
+       OPT_BEGIN,
+       OPT_CLOCK_CYCLES,
+       OPT_CLOCK_DATE,
+       OPT_CLOCK_FORCE_CORRELATE,
+       OPT_CLOCK_GMT,
+       OPT_CLOCK_OFFSET,
+       OPT_CLOCK_OFFSET_NS,
+       OPT_CLOCK_SECONDS,
+       OPT_COLOR,
+       OPT_COMPONENT,
+       OPT_CONNECT,
+       OPT_DEBUG,
+       OPT_DEBUG_INFO,
+       OPT_DEBUG_INFO_DIR,
+       OPT_DEBUG_INFO_FULL_PATH,
+       OPT_DEBUG_INFO_TARGET_PREFIX,
+       OPT_END,
+       OPT_FIELDS,
+       OPT_HELP,
+       OPT_INPUT_FORMAT,
+       OPT_LIST,
+       OPT_NAME,
+       OPT_NAMES,
+       OPT_NO_DELTA,
+       OPT_OMIT_HOME_PLUGIN_PATH,
+       OPT_OMIT_SYSTEM_PLUGIN_PATH,
+       OPT_OUTPUT,
+       OPT_OUTPUT_FORMAT,
+       OPT_PARAMS,
+       OPT_PATH,
+       OPT_PLUGIN_PATH,
+       OPT_RESET_BASE_PARAMS,
+       OPT_RETRY_DURATION,
+       OPT_RUN_ARGS,
+       OPT_RUN_ARGS_0,
+       OPT_STREAM_INTERSECTION,
+       OPT_TIMERANGE,
+       OPT_URL,
+       OPT_VERBOSE,
+};
+
+enum bt_config_component_dest {
+       BT_CONFIG_COMPONENT_DEST_UNKNOWN = -1,
+       BT_CONFIG_COMPONENT_DEST_SOURCE,
+       BT_CONFIG_COMPONENT_DEST_FILTER,
+       BT_CONFIG_COMPONENT_DEST_SINK,
+};
+
+/*
+ * Adds a configuration component to the appropriate configuration
+ * array depending on the destination.
+ */
+static
+void add_run_cfg_comp(struct bt_config *cfg,
+               struct bt_config_component *cfg_comp,
+               enum bt_config_component_dest dest)
+{
+       bt_object_get_ref(cfg_comp);
+
+       switch (dest) {
+       case BT_CONFIG_COMPONENT_DEST_SOURCE:
+               g_ptr_array_add(cfg->cmd_data.run.sources, cfg_comp);
+               break;
+       case BT_CONFIG_COMPONENT_DEST_FILTER:
+               g_ptr_array_add(cfg->cmd_data.run.filters, cfg_comp);
+               break;
+       case BT_CONFIG_COMPONENT_DEST_SINK:
+               g_ptr_array_add(cfg->cmd_data.run.sinks, cfg_comp);
+               break;
+       default:
+               abort();
+       }
+}
+
+static
+int add_run_cfg_comp_check_name(struct bt_config *cfg,
+               struct bt_config_component *cfg_comp,
+               enum bt_config_component_dest dest,
+               bt_value *instance_names)
+{
+       int ret = 0;
+
+       if (cfg_comp->instance_name->len == 0) {
+               printf_err("Found an unnamed component\n");
+               ret = -1;
+               goto end;
+       }
+
+       if (bt_value_map_has_entry(instance_names,
+                                  cfg_comp->instance_name->str)) {
+               printf_err("Duplicate component instance name:\n    %s\n",
+                       cfg_comp->instance_name->str);
+               ret = -1;
+               goto end;
+       }
+
+       if (bt_value_map_insert_entry(instance_names,
+                       cfg_comp->instance_name->str, bt_value_null)) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       add_run_cfg_comp(cfg, cfg_comp, dest);
+
+end:
+       return ret;
+}
+
+static
+int append_env_var_plugin_paths(bt_value *plugin_paths)
+{
+       int ret = 0;
+       const char *envvar;
+
+       if (bt_common_is_setuid_setgid()) {
+               BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
+               goto end;
+       }
+
+       envvar = getenv("BABELTRACE_PLUGIN_PATH");
+       if (!envvar) {
+               goto end;
+       }
+
+       ret = bt_config_append_plugin_paths(plugin_paths, envvar);
+
+end:
+       if (ret) {
+               printf_err("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH\n");
+       }
+
+       return ret;
+}
+
+static
+int append_home_and_system_plugin_paths(bt_value *plugin_paths,
+               bool omit_system_plugin_path, bool omit_home_plugin_path)
+{
+       int ret;
+
+       if (!omit_home_plugin_path) {
+               if (bt_common_is_setuid_setgid()) {
+                       BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
+               } else {
+                       char *home_plugin_dir =
+                               bt_common_get_home_plugin_path();
+
+                       if (home_plugin_dir) {
+                               ret = bt_config_append_plugin_paths(
+                                       plugin_paths, home_plugin_dir);
+                               free(home_plugin_dir);
+
+                               if (ret) {
+                                       printf_err("Invalid home plugin path\n");
+                                       goto error;
+                               }
+                       }
+               }
+       }
+
+       if (!omit_system_plugin_path) {
+               if (bt_config_append_plugin_paths(plugin_paths,
+                               bt_common_get_system_plugin_path())) {
+                       printf_err("Invalid system plugin path\n");
+                       goto error;
+               }
+       }
+       return 0;
+error:
+       printf_err("Cannot append home and system plugin paths\n");
+       return -1;
+}
+
+static
+int append_home_and_system_plugin_paths_cfg(struct bt_config *cfg)
+{
+       return append_home_and_system_plugin_paths(cfg->plugin_paths,
+               cfg->omit_system_plugin_path, cfg->omit_home_plugin_path);
+}
+
+static
+struct bt_config *bt_config_base_create(enum bt_config_command command,
+               const bt_value *initial_plugin_paths,
+               bool needs_plugins)
+{
+       struct bt_config *cfg;
+
+       /* Create config */
+       cfg = g_new0(struct bt_config, 1);
+       if (!cfg) {
+               print_err_oom();
+               goto error;
+       }
+
+       bt_object_init_shared(&cfg->base, bt_config_destroy);
+       cfg->command = command;
+       cfg->command_needs_plugins = needs_plugins;
+
+       if (initial_plugin_paths) {
+               bt_value *initial_plugin_paths_copy;
+
+               (void) bt_value_copy(initial_plugin_paths,
+                       &initial_plugin_paths_copy);
+               cfg->plugin_paths = initial_plugin_paths_copy;
+       } else {
+               cfg->plugin_paths = bt_value_array_create();
+               if (!cfg->plugin_paths) {
+                       print_err_oom();
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       return cfg;
+}
+
+static
+struct bt_config *bt_config_run_create(
+               const bt_value *initial_plugin_paths)
+{
+       struct bt_config *cfg;
+
+       /* Create config */
+       cfg = bt_config_base_create(BT_CONFIG_COMMAND_RUN,
+               initial_plugin_paths, true);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->cmd_data.run.sources = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_put_ref);
+       if (!cfg->cmd_data.run.sources) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg->cmd_data.run.filters = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_put_ref);
+       if (!cfg->cmd_data.run.filters) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg->cmd_data.run.sinks = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_put_ref);
+       if (!cfg->cmd_data.run.sinks) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg->cmd_data.run.connections = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_config_connection_destroy);
+       if (!cfg->cmd_data.run.connections) {
+               print_err_oom();
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       return cfg;
+}
+
+static
+struct bt_config *bt_config_list_plugins_create(
+               const bt_value *initial_plugin_paths)
+{
+       struct bt_config *cfg;
+
+       /* Create config */
+       cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS,
+               initial_plugin_paths, true);
+       if (!cfg) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       return cfg;
+}
+
+static
+struct bt_config *bt_config_help_create(
+               const bt_value *initial_plugin_paths)
+{
+       struct bt_config *cfg;
+
+       /* Create config */
+       cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP,
+               initial_plugin_paths, true);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->cmd_data.help.cfg_component =
+               bt_config_component_create(-1, NULL, NULL);
+       if (!cfg->cmd_data.help.cfg_component) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       return cfg;
+}
+
+static
+struct bt_config *bt_config_query_create(
+               const bt_value *initial_plugin_paths)
+{
+       struct bt_config *cfg;
+
+       /* Create config */
+       cfg = bt_config_base_create(BT_CONFIG_COMMAND_QUERY,
+               initial_plugin_paths, true);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->cmd_data.query.object = g_string_new(NULL);
+       if (!cfg->cmd_data.query.object) {
+               print_err_oom();
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       return cfg;
+}
+
+static
+struct bt_config *bt_config_print_ctf_metadata_create(
+               const bt_value *initial_plugin_paths)
+{
+       struct bt_config *cfg;
+
+       /* Create config */
+       cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_CTF_METADATA,
+               initial_plugin_paths, true);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->cmd_data.print_ctf_metadata.path = g_string_new(NULL);
+       if (!cfg->cmd_data.print_ctf_metadata.path) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg->cmd_data.print_ctf_metadata.output_path = g_string_new(NULL);
+       if (!cfg->cmd_data.print_ctf_metadata.output_path) {
+               print_err_oom();
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       return cfg;
+}
+
+static
+struct bt_config *bt_config_print_lttng_live_sessions_create(
+               const bt_value *initial_plugin_paths)
+{
+       struct bt_config *cfg;
+
+       /* Create config */
+       cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS,
+               initial_plugin_paths, true);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->cmd_data.print_lttng_live_sessions.url = g_string_new(NULL);
+       if (!cfg->cmd_data.print_lttng_live_sessions.url) {
+               print_err_oom();
+               goto error;
+       }
+
+       cfg->cmd_data.print_lttng_live_sessions.output_path =
+               g_string_new(NULL);
+       if (!cfg->cmd_data.print_lttng_live_sessions.output_path) {
+               print_err_oom();
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       return cfg;
+}
+
+static
+int bt_config_append_plugin_paths_check_setuid_setgid(
+               bt_value *plugin_paths, const char *arg)
+{
+       int ret = 0;
+
+       if (bt_common_is_setuid_setgid()) {
+               BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
+               goto end;
+       }
+
+       if (bt_config_append_plugin_paths(plugin_paths, arg)) {
+               printf_err("Invalid --plugin-path option's argument:\n    %s\n",
+                       arg);
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Prints the expected format for a --params option.
+ */
+static
+void print_expected_params_format(FILE *fp)
+{
+       fprintf(fp, "Expected format of PARAMS\n");
+       fprintf(fp, "-------------------------\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    PARAM=VALUE[,PARAM=VALUE]...\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
+       fprintf(fp, "where PARAM is the parameter name (C identifier plus the [:.-] characters),\n");
+       fprintf(fp, "and VALUE can be one of:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
+       fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
+       fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
+       fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
+       fprintf(fp, "  (`0x` prefix) unsigned (with `+` prefix) or signed 64-bit integer.\n");
+       fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
+       fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
+       fprintf(fp, "  the null and boolean value symbols above.\n");
+       fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
+       fprintf(fp, "* Array, formatted as an opening `[`, a list of comma-separated values\n");
+       fprintf(fp, "  (as described by the current list) and a closing `]`.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "You can put whitespaces allowed around individual `=` and `,` symbols.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Example:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    many=null, fresh=yes, condition=false, squirrel=-782329,\n");
+       fprintf(fp, "    play=+23, observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
+       fprintf(fp, "    escape.chars-are:allowed=\"this is a \\\" double quote\",\n");
+       fprintf(fp, "    things=[1, \"2\", 3]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run\n");
+       fprintf(fp, "babeltrace2 from a shell.\n");
+}
+
+
+/*
+ * Prints the help command usage.
+ */
+static
+void print_help_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
+       fprintf(fp, "       babeltrace2 [GENERAL OPTIONS] help [OPTIONS] TYPE.PLUGIN.CLS\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
+       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
+       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
+       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
+       fprintf(fp, "                                    dynamic plugins can be loaded\n");
+       fprintf(fp, "  -h, --help                        Show this help and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Use `babeltrace2 list-plugins` to show the list of available plugins.\n");
+}
+
+static
+struct poptOption help_long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
+       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
+       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
+       { NULL, 0, '\0', NULL, 0, NULL, NULL },
+};
+
+/*
+ * Creates a Babeltrace config object from the arguments of a help
+ * command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+static
+struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
+               int *retcode, bool force_omit_system_plugin_path,
+               bool force_omit_home_plugin_path,
+               const bt_value *initial_plugin_paths)
+{
+       poptContext pc = NULL;
+       char *arg = NULL;
+       int opt;
+       int ret;
+       struct bt_config *cfg = NULL;
+       const char *leftover;
+       char *plugin_name = NULL, *comp_cls_name = NULL;
+
+       *retcode = 0;
+       cfg = bt_config_help_create(initial_plugin_paths);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->omit_system_plugin_path = force_omit_system_plugin_path;
+       cfg->omit_home_plugin_path = force_omit_home_plugin_path;
+       ret = append_env_var_plugin_paths(cfg->plugin_paths);
+       if (ret) {
+               goto error;
+       }
+
+       /* Parse options */
+       pc = poptGetContext(NULL, argc, (const char **) argv,
+               help_long_options, 0);
+       if (!pc) {
+               printf_err("Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) > 0) {
+               arg = poptGetOptArg(pc);
+
+               switch (opt) {
+               case OPT_PLUGIN_PATH:
+                       if (bt_config_append_plugin_paths_check_setuid_setgid(
+                                       cfg->plugin_paths, arg)) {
+                               goto error;
+                       }
+                       break;
+               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+                       cfg->omit_system_plugin_path = true;
+                       break;
+               case OPT_OMIT_HOME_PLUGIN_PATH:
+                       cfg->omit_home_plugin_path = true;
+                       break;
+               case OPT_HELP:
+                       print_help_usage(stdout);
+                       *retcode = -1;
+                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                       goto end;
+               default:
+                       printf_err("Unknown command-line option specified (option code %d)\n",
+                               opt);
+                       goto error;
+               }
+
+               free(arg);
+               arg = NULL;
+       }
+
+       /* Check for option parsing error */
+       if (opt < -1) {
+               printf_err("While parsing command-line options, at option %s: %s\n",
+                       poptBadOption(pc, 0), poptStrerror(opt));
+               goto error;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               plugin_comp_cls_names(leftover, NULL,
+                       &plugin_name, &comp_cls_name,
+                       &cfg->cmd_data.help.cfg_component->type);
+               if (plugin_name && comp_cls_name) {
+                       /* Component class help */
+                       g_string_assign(
+                               cfg->cmd_data.help.cfg_component->plugin_name,
+                               plugin_name);
+                       g_string_assign(
+                               cfg->cmd_data.help.cfg_component->comp_cls_name,
+                               comp_cls_name);
+               } else {
+                       /* Fall back to plugin help */
+                       g_string_assign(
+                               cfg->cmd_data.help.cfg_component->plugin_name,
+                               leftover);
+               }
+       } else {
+               print_help_usage(stdout);
+               *retcode = -1;
+               BT_OBJECT_PUT_REF_AND_RESET(cfg);
+               goto end;
+       }
+
+       if (append_home_and_system_plugin_paths_cfg(cfg)) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       *retcode = 1;
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       g_free(plugin_name);
+       g_free(comp_cls_name);
+
+       if (pc) {
+               poptFreeContext(pc);
+       }
+
+       free(arg);
+       return cfg;
+}
+
+/*
+ * Prints the help command usage.
+ */
+static
+void print_query_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace2 [GEN OPTS] query [OPTS] TYPE.PLUGIN.CLS OBJECT\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
+       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
+       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
+       fprintf(fp, "  -p, --params=PARAMS               Set the query parameters to PARAMS\n");
+       fprintf(fp, "                                    (see the expected format of PARAMS below)\n");
+       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
+       fprintf(fp, "                                    dynamic plugins can be loaded\n");
+       fprintf(fp, "  -h, --help                        Show this help and quit\n");
+       fprintf(fp, "\n\n");
+       print_expected_params_format(fp);
+}
+
+static
+struct poptOption query_long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
+       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
+       { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
+       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
+       { NULL, 0, '\0', NULL, 0, NULL, NULL },
+};
+
+/*
+ * Creates a Babeltrace config object from the arguments of a query
+ * command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+static
+struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
+               int *retcode, bool force_omit_system_plugin_path,
+               bool force_omit_home_plugin_path,
+               const bt_value *initial_plugin_paths)
+{
+       poptContext pc = NULL;
+       char *arg = NULL;
+       int opt;
+       int ret;
+       struct bt_config *cfg = NULL;
+       const char *leftover;
+       bt_value *params;
+
+       params = bt_value_null;
+       bt_value_get_ref(bt_value_null);
+
+       *retcode = 0;
+       cfg = bt_config_query_create(initial_plugin_paths);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->omit_system_plugin_path = force_omit_system_plugin_path;
+       cfg->omit_home_plugin_path = force_omit_home_plugin_path;
+       ret = append_env_var_plugin_paths(cfg->plugin_paths);
+       if (ret) {
+               goto error;
+       }
+
+       /* Parse options */
+       pc = poptGetContext(NULL, argc, (const char **) argv,
+               query_long_options, 0);
+       if (!pc) {
+               printf_err("Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) > 0) {
+               arg = poptGetOptArg(pc);
+
+               switch (opt) {
+               case OPT_PLUGIN_PATH:
+                       if (bt_config_append_plugin_paths_check_setuid_setgid(
+                                       cfg->plugin_paths, arg)) {
+                               goto error;
+                       }
+                       break;
+               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+                       cfg->omit_system_plugin_path = true;
+                       break;
+               case OPT_OMIT_HOME_PLUGIN_PATH:
+                       cfg->omit_home_plugin_path = true;
+                       break;
+               case OPT_PARAMS:
+               {
+                       bt_value_put_ref(params);
+                       params = bt_value_from_arg(arg);
+                       if (!params) {
+                               printf_err("Invalid format for --params option's argument:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+                       break;
+               }
+               case OPT_HELP:
+                       print_query_usage(stdout);
+                       *retcode = -1;
+                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                       goto end;
+               default:
+                       printf_err("Unknown command-line option specified (option code %d)\n",
+                               opt);
+                       goto error;
+               }
+
+               free(arg);
+               arg = NULL;
+       }
+
+       /* Check for option parsing error */
+       if (opt < -1) {
+               printf_err("While parsing command-line options, at option %s: %s\n",
+                       poptBadOption(pc, 0), poptStrerror(opt));
+               goto error;
+       }
+
+       /*
+        * We need exactly two leftover arguments which are the
+        * mandatory component class specification and query object.
+        */
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               cfg->cmd_data.query.cfg_component =
+                       bt_config_component_from_arg(leftover);
+               if (!cfg->cmd_data.query.cfg_component) {
+                       printf_err("Invalid format for component class specification:\n    %s\n",
+                               leftover);
+                       goto error;
+               }
+
+               BT_ASSERT(params);
+               BT_OBJECT_MOVE_REF(cfg->cmd_data.query.cfg_component->params,
+                       params);
+       } else {
+               print_query_usage(stdout);
+               *retcode = -1;
+               BT_OBJECT_PUT_REF_AND_RESET(cfg);
+               goto end;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               if (strlen(leftover) == 0) {
+                       printf_err("Invalid empty object\n");
+                       goto error;
+               }
+
+               g_string_assign(cfg->cmd_data.query.object, leftover);
+       } else {
+               print_query_usage(stdout);
+               *retcode = -1;
+               BT_OBJECT_PUT_REF_AND_RESET(cfg);
+               goto end;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               printf_err("Unexpected argument: %s\n", leftover);
+               goto error;
+       }
+
+       if (append_home_and_system_plugin_paths_cfg(cfg)) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       *retcode = 1;
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       if (pc) {
+               poptFreeContext(pc);
+       }
+
+       bt_value_put_ref(params);
+       free(arg);
+       return cfg;
+}
+
+/*
+ * Prints the list-plugins command usage.
+ */
+static
+void print_list_plugins_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
+       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
+       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
+       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
+       fprintf(fp, "                                    dynamic plugins can be loaded\n");
+       fprintf(fp, "  -h, --help                        Show this help and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Use `babeltrace2 help` to get help for a specific plugin or component class.\n");
+}
+
+static
+struct poptOption list_plugins_long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
+       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
+       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
+       { NULL, 0, '\0', NULL, 0, NULL, NULL },
+};
+
+/*
+ * Creates a Babeltrace config object from the arguments of a
+ * list-plugins command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+static
+struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
+               int *retcode, bool force_omit_system_plugin_path,
+               bool force_omit_home_plugin_path,
+               const bt_value *initial_plugin_paths)
+{
+       poptContext pc = NULL;
+       char *arg = NULL;
+       int opt;
+       int ret;
+       struct bt_config *cfg = NULL;
+       const char *leftover;
+
+       *retcode = 0;
+       cfg = bt_config_list_plugins_create(initial_plugin_paths);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->omit_system_plugin_path = force_omit_system_plugin_path;
+       cfg->omit_home_plugin_path = force_omit_home_plugin_path;
+       ret = append_env_var_plugin_paths(cfg->plugin_paths);
+       if (ret) {
+               goto error;
+       }
+
+       /* Parse options */
+       pc = poptGetContext(NULL, argc, (const char **) argv,
+               list_plugins_long_options, 0);
+       if (!pc) {
+               printf_err("Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) > 0) {
+               arg = poptGetOptArg(pc);
+
+               switch (opt) {
+               case OPT_PLUGIN_PATH:
+                       if (bt_config_append_plugin_paths_check_setuid_setgid(
+                                       cfg->plugin_paths, arg)) {
+                               goto error;
+                       }
+                       break;
+               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+                       cfg->omit_system_plugin_path = true;
+                       break;
+               case OPT_OMIT_HOME_PLUGIN_PATH:
+                       cfg->omit_home_plugin_path = true;
+                       break;
+               case OPT_HELP:
+                       print_list_plugins_usage(stdout);
+                       *retcode = -1;
+                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                       goto end;
+               default:
+                       printf_err("Unknown command-line option specified (option code %d)\n",
+                               opt);
+                       goto error;
+               }
+
+               free(arg);
+               arg = NULL;
+       }
+
+       /* Check for option parsing error */
+       if (opt < -1) {
+               printf_err("While parsing command-line options, at option %s: %s\n",
+                       poptBadOption(pc, 0), poptStrerror(opt));
+               goto error;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               printf_err("Unexpected argument: %s\n", leftover);
+               goto error;
+       }
+
+       if (append_home_and_system_plugin_paths_cfg(cfg)) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       *retcode = 1;
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       if (pc) {
+               poptFreeContext(pc);
+       }
+
+       free(arg);
+       return cfg;
+}
+
+/*
+ * Prints the run command usage.
+ */
+static
+void print_run_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] run [OPTIONS]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  -b, --base-params=PARAMS          Set PARAMS as the current base parameters\n");
+       fprintf(fp, "                                    for all the following components until\n");
+       fprintf(fp, "                                    --reset-base-params is encountered\n");
+       fprintf(fp, "                                    (see the expected format of PARAMS below)\n");
+       fprintf(fp, "  -c, --component=[NAME:]TYPE.PLUGIN.CLS\n");
+       fprintf(fp, "                                    Instantiate the component class CLS of type\n");
+       fprintf(fp, "                                    TYPE (`source`, `filter`, or `sink`) found\n");
+       fprintf(fp, "                                    in the plugin PLUGIN, add it to the graph,\n");
+       fprintf(fp, "                                    and optionally name it NAME (you can also\n");
+       fprintf(fp, "                                    specify the name with --name)\n");
+       fprintf(fp, "  -x, --connect=CONNECTION          Connect two created components (see the\n");
+       fprintf(fp, "                                    expected format of CONNECTION below)\n");
+       fprintf(fp, "  -n, --name=NAME                   Set the name of the current component\n");
+       fprintf(fp, "                                    to NAME (must be unique amongst all the\n");
+       fprintf(fp, "                                    names of the created components)\n");
+       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
+       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
+       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
+       fprintf(fp, "  -p, --params=PARAMS               Add initialization parameters PARAMS to the\n");
+       fprintf(fp, "                                    current component (see the expected format\n");
+       fprintf(fp, "                                    of PARAMS below)\n");
+       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
+       fprintf(fp, "                                    dynamic plugins can be loaded\n");
+       fprintf(fp, "  -r, --reset-base-params           Reset the current base parameters to an\n");
+       fprintf(fp, "                                    empty map\n");
+       fprintf(fp, "      --retry-duration=DUR          When babeltrace2(1) needs to retry to run\n");
+       fprintf(fp, "                                    the graph later, retry in DUR µs\n");
+       fprintf(fp, "                                    (default: 100000)\n");
+       fprintf(fp, "  -h, --help                        Show this help and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
+       fprintf(fp, "\n\n");
+       fprintf(fp, "Expected format of CONNECTION\n");
+       fprintf(fp, "-----------------------------\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    UPSTREAM[.UPSTREAM-PORT]:DOWNSTREAM[.DOWNSTREAM-PORT]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "UPSTREAM and DOWNSTREAM are names of the upstream and downstream\n");
+       fprintf(fp, "components to connect together. You must escape the following characters\n\n");
+       fprintf(fp, "with `\\`: `\\`, `.`, and `:`. You can set the name of the current\n");
+       fprintf(fp, "component with the --name option.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "UPSTREAM-PORT and DOWNSTREAM-PORT are optional globbing patterns to\n");
+       fprintf(fp, "identify the upstream and downstream ports to use for the connection.\n");
+       fprintf(fp, "When the port is not specified, `*` is used.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "When a component named UPSTREAM has an available port which matches the\n");
+       fprintf(fp, "UPSTREAM-PORT globbing pattern, it is connected to the first port which\n");
+       fprintf(fp, "matches the DOWNSTREAM-PORT globbing pattern of the component named\n");
+       fprintf(fp, "DOWNSTREAM.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "The only special character in UPSTREAM-PORT and DOWNSTREAM-PORT is `*`\n");
+       fprintf(fp, "which matches anything. You must escape the following characters\n");
+       fprintf(fp, "with `\\`: `\\`, `*`, `?`, `[`, `.`, and `:`.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "You can connect a source component to a filter or sink component. You\n");
+       fprintf(fp, "can connect a filter component to a sink component.\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Examples:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    my-src:my-sink\n");
+       fprintf(fp, "    ctf-fs.*stream*:utils-muxer:*\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run\n");
+       fprintf(fp, "babeltrace2 from a shell.\n");
+       fprintf(fp, "\n\n");
+       print_expected_params_format(fp);
+}
+
+/*
+ * Creates a Babeltrace config object from the arguments of a run
+ * command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+static
+struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
+               int *retcode, bool force_omit_system_plugin_path,
+               bool force_omit_home_plugin_path,
+               const bt_value *initial_plugin_paths)
+{
+       poptContext pc = NULL;
+       char *arg = NULL;
+       struct bt_config_component *cur_cfg_comp = NULL;
+       enum bt_config_component_dest cur_cfg_comp_dest =
+                       BT_CONFIG_COMPONENT_DEST_UNKNOWN;
+       bt_value *cur_base_params = NULL;
+       int opt, ret = 0;
+       struct bt_config *cfg = NULL;
+       bt_value *instance_names = NULL;
+       bt_value *connection_args = NULL;
+       char error_buf[256] = { 0 };
+       long retry_duration = -1;
+       bt_value_status status;
+       struct poptOption run_long_options[] = {
+               { "base-params", 'b', POPT_ARG_STRING, NULL, OPT_BASE_PARAMS, NULL, NULL },
+               { "component", 'c', POPT_ARG_STRING, NULL, OPT_COMPONENT, NULL, NULL },
+               { "connect", 'x', POPT_ARG_STRING, NULL, OPT_CONNECT, NULL, NULL },
+               { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+               { "name", 'n', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL },
+               { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
+               { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
+               { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
+               { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
+               { "reset-base-params", 'r', POPT_ARG_NONE, NULL, OPT_RESET_BASE_PARAMS, NULL, NULL },
+               { "retry-duration", '\0', POPT_ARG_LONG, &retry_duration, OPT_RETRY_DURATION, NULL, NULL },
+               { NULL, 0, '\0', NULL, 0, NULL, NULL },
+       };
+
+       *retcode = 0;
+
+       if (argc <= 1) {
+               print_run_usage(stdout);
+               *retcode = -1;
+               goto end;
+       }
+
+       cfg = bt_config_run_create(initial_plugin_paths);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->cmd_data.run.retry_duration_us = 100000;
+       cfg->omit_system_plugin_path = force_omit_system_plugin_path;
+       cfg->omit_home_plugin_path = force_omit_home_plugin_path;
+       cur_base_params = bt_value_map_create();
+       if (!cur_base_params) {
+               print_err_oom();
+               goto error;
+       }
+
+       instance_names = bt_value_map_create();
+       if (!instance_names) {
+               print_err_oom();
+               goto error;
+       }
+
+       connection_args = bt_value_array_create();
+       if (!connection_args) {
+               print_err_oom();
+               goto error;
+       }
+
+       ret = append_env_var_plugin_paths(cfg->plugin_paths);
+       if (ret) {
+               goto error;
+       }
+
+       /* Parse options */
+       pc = poptGetContext(NULL, argc, (const char **) argv,
+               run_long_options, 0);
+       if (!pc) {
+               printf_err("Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) > 0) {
+               arg = poptGetOptArg(pc);
+
+               switch (opt) {
+               case OPT_PLUGIN_PATH:
+                       if (bt_config_append_plugin_paths_check_setuid_setgid(
+                                       cfg->plugin_paths, arg)) {
+                               goto error;
+                       }
+                       break;
+               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+                       cfg->omit_system_plugin_path = true;
+                       break;
+               case OPT_OMIT_HOME_PLUGIN_PATH:
+                       cfg->omit_home_plugin_path = true;
+                       break;
+               case OPT_COMPONENT:
+               {
+                       enum bt_config_component_dest new_dest;
+
+                       if (cur_cfg_comp) {
+                               ret = add_run_cfg_comp_check_name(cfg,
+                                       cur_cfg_comp, cur_cfg_comp_dest,
+                                       instance_names);
+                               BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
+                               if (ret) {
+                                       goto error;
+                               }
+                       }
+
+                       cur_cfg_comp = bt_config_component_from_arg(arg);
+                       if (!cur_cfg_comp) {
+                               printf_err("Invalid format for --component option's argument:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       switch (cur_cfg_comp->type) {
+                       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                               new_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
+                               break;
+                       case BT_COMPONENT_CLASS_TYPE_FILTER:
+                               new_dest = BT_CONFIG_COMPONENT_DEST_FILTER;
+                               break;
+                       case BT_COMPONENT_CLASS_TYPE_SINK:
+                               new_dest = BT_CONFIG_COMPONENT_DEST_SINK;
+                               break;
+                       default:
+                               abort();
+                       }
+
+                       BT_ASSERT(cur_base_params);
+                       bt_value_put_ref(cur_cfg_comp->params);
+                       status = bt_value_copy(cur_base_params,
+                               &cur_cfg_comp->params);
+                       if (status != BT_VALUE_STATUS_OK) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       cur_cfg_comp_dest = new_dest;
+                       break;
+               }
+               case OPT_PARAMS:
+               {
+                       bt_value *params;
+                       bt_value *params_to_set;
+
+                       if (!cur_cfg_comp) {
+                               printf_err("Cannot add parameters to unavailable component:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       params = bt_value_from_arg(arg);
+                       if (!params) {
+                               printf_err("Invalid format for --params option's argument:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       status = bt_value_map_extend(cur_cfg_comp->params,
+                               params, &params_to_set);
+                       BT_VALUE_PUT_REF_AND_RESET(params);
+                       if (status != BT_VALUE_STATUS_OK) {
+                               printf_err("Cannot extend current component parameters with --params option's argument:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       BT_OBJECT_MOVE_REF(cur_cfg_comp->params, params_to_set);
+                       break;
+               }
+               case OPT_NAME:
+                       if (!cur_cfg_comp) {
+                               printf_err("Cannot set the name of unavailable component:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       g_string_assign(cur_cfg_comp->instance_name, arg);
+                       break;
+               case OPT_BASE_PARAMS:
+               {
+                       bt_value *params =
+                               bt_value_from_arg(arg);
+
+                       if (!params) {
+                               printf_err("Invalid format for --base-params option's argument:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       BT_OBJECT_MOVE_REF(cur_base_params, params);
+                       break;
+               }
+               case OPT_RESET_BASE_PARAMS:
+                       BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
+                       cur_base_params = bt_value_map_create();
+                       if (!cur_base_params) {
+                               print_err_oom();
+                               goto error;
+                       }
+                       break;
+               case OPT_CONNECT:
+                       if (bt_value_array_append_string_element(
+                                       connection_args, arg)) {
+                               print_err_oom();
+                               goto error;
+                       }
+                       break;
+               case OPT_RETRY_DURATION:
+                       if (retry_duration < 0) {
+                               printf_err("--retry-duration option's argument must be positive or 0: %ld\n",
+                                       retry_duration);
+                               goto error;
+                       }
+
+                       cfg->cmd_data.run.retry_duration_us =
+                               (uint64_t) retry_duration;
+                       break;
+               case OPT_HELP:
+                       print_run_usage(stdout);
+                       *retcode = -1;
+                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                       goto end;
+               default:
+                       printf_err("Unknown command-line option specified (option code %d)\n",
+                               opt);
+                       goto error;
+               }
+
+               free(arg);
+               arg = NULL;
+       }
+
+       /* Check for option parsing error */
+       if (opt < -1) {
+               printf_err("While parsing command-line options, at option %s: %s\n",
+                       poptBadOption(pc, 0), poptStrerror(opt));
+               goto error;
+       }
+
+       /* This command does not accept leftover arguments */
+       if (poptPeekArg(pc)) {
+               printf_err("Unexpected argument: %s\n", poptPeekArg(pc));
+               goto error;
+       }
+
+       /* Add current component */
+       if (cur_cfg_comp) {
+               ret = add_run_cfg_comp_check_name(cfg, cur_cfg_comp,
+                       cur_cfg_comp_dest, instance_names);
+               BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       if (cfg->cmd_data.run.sources->len == 0) {
+               printf_err("Incomplete graph: no source component\n");
+               goto error;
+       }
+
+       if (cfg->cmd_data.run.sinks->len == 0) {
+               printf_err("Incomplete graph: no sink component\n");
+               goto error;
+       }
+
+       if (append_home_and_system_plugin_paths_cfg(cfg)) {
+               goto error;
+       }
+
+       ret = bt_config_cli_args_create_connections(cfg,
+               connection_args,
+               error_buf, 256);
+       if (ret) {
+               printf_err("Cannot creation connections:\n%s", error_buf);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       *retcode = 1;
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       if (pc) {
+               poptFreeContext(pc);
+       }
+
+       free(arg);
+       BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
+       BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
+       BT_VALUE_PUT_REF_AND_RESET(instance_names);
+       BT_VALUE_PUT_REF_AND_RESET(connection_args);
+       return cfg;
+}
+
+static
+struct bt_config *bt_config_run_from_args_array(const bt_value *run_args,
+               int *retcode, bool force_omit_system_plugin_path,
+               bool force_omit_home_plugin_path,
+               const bt_value *initial_plugin_paths)
+{
+       struct bt_config *cfg = NULL;
+       const char **argv;
+       int64_t i, len;
+       const size_t argc = bt_value_array_get_size(run_args) + 1;
+
+       argv = calloc(argc, sizeof(*argv));
+       if (!argv) {
+               print_err_oom();
+               goto end;
+       }
+
+       argv[0] = "run";
+
+       len = bt_value_array_get_size(run_args);
+       if (len < 0) {
+               printf_err("Invalid executable arguments\n");
+               goto end;
+       }
+       for (i = 0; i < len; i++) {
+               const bt_value *arg_value =
+                       bt_value_array_borrow_element_by_index_const(run_args,
+                                                                    i);
+               const char *arg;
+
+               BT_ASSERT(arg_value);
+               arg = bt_value_string_get(arg_value);
+               BT_ASSERT(arg);
+               argv[i + 1] = arg;
+       }
+
+       cfg = bt_config_run_from_args(argc, argv, retcode,
+               force_omit_system_plugin_path, force_omit_home_plugin_path,
+               initial_plugin_paths);
+
+end:
+       free(argv);
+       return cfg;
+}
+
+/*
+ * Prints the convert command usage.
+ */
+static
+void print_convert_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [convert] [OPTIONS] [PATH/URL]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  -c, --component=[NAME:]TYPE.PLUGIN.CLS\n");
+       fprintf(fp, "                                    Instantiate the component class CLS of type\n");
+       fprintf(fp, "                                    TYPE (`source`, `filter`, or `sink`) found\n");
+       fprintf(fp, "                                    in the plugin PLUGIN, add it to the\n");
+       fprintf(fp, "                                    conversion graph, and optionally name it\n");
+       fprintf(fp, "                                    NAME (you can also specify the name with\n");
+       fprintf(fp, "                                    --name)\n");
+       fprintf(fp, "      --name=NAME                   Set the name of the current component\n");
+       fprintf(fp, "                                    to NAME (must be unique amongst all the\n");
+       fprintf(fp, "                                    names of the created components)\n");
+       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
+       fprintf(fp, "                                    (~/.local/lib/babeltrace2/plugins)\n");
+       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
+       fprintf(fp, "  -p, --params=PARAMS               Add initialization parameters PARAMS to the\n");
+       fprintf(fp, "                                    current component (see the expected format\n");
+       fprintf(fp, "                                    of PARAMS below)\n");
+       fprintf(fp, "  -P, --path=PATH                   Set the `path` string parameter of the\n");
+       fprintf(fp, "                                    current component to PATH\n");
+       fprintf(fp, "      --plugin-path=PATH[:PATH]...  Add PATH to the list of paths from which\n");
+       fprintf(fp, "      --retry-duration=DUR          When babeltrace2(1) needs to retry to run\n");
+       fprintf(fp, "                                    the graph later, retry in DUR µs\n");
+       fprintf(fp, "                                    (default: 100000)\n");
+       fprintf(fp, "                                    dynamic plugins can be loaded\n");
+       fprintf(fp, "      --run-args                    Print the equivalent arguments for the\n");
+       fprintf(fp, "                                    `run` command to the standard output,\n");
+       fprintf(fp, "                                    formatted for a shell, and quit\n");
+       fprintf(fp, "      --run-args-0                  Print the equivalent arguments for the\n");
+       fprintf(fp, "                                    `run` command to the standard output,\n");
+       fprintf(fp, "                                    formatted for `xargs -0`, and quit\n");
+       fprintf(fp, "      --stream-intersection         Only process events when all streams\n");
+       fprintf(fp, "                                    are active\n");
+       fprintf(fp, "  -u, --url=URL                     Set the `url` string parameter of the\n");
+       fprintf(fp, "                                    current component to URL\n");
+       fprintf(fp, "  -h, --help                        Show this help and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Implicit `source.ctf.fs` component options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --clock-offset=SEC            Set clock offset to SEC seconds\n");
+       fprintf(fp, "      --clock-offset-ns=NS          Set clock offset to NS ns\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Implicit `sink.text.pretty` component options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --clock-cycles                Print timestamps in clock cycles\n");
+       fprintf(fp, "      --clock-date                  Print timestamp dates\n");
+       fprintf(fp, "      --clock-gmt                   Print and parse timestamps in the GMT\n");
+       fprintf(fp, "                                    time zone instead of the local time zone\n");
+       fprintf(fp, "      --clock-seconds               Print the timestamps as `SEC.NS` instead\n");
+       fprintf(fp, "                                    of `hh:mm:ss.nnnnnnnnn`\n");
+       fprintf(fp, "      --color=(never | auto | always)\n");
+       fprintf(fp, "                                    Never, automatically, or always emit\n");
+       fprintf(fp, "                                    console color codes\n");
+       fprintf(fp, "  -f, --fields=FIELD[,FIELD]...     Print additional fields; FIELD can be:\n");
+       fprintf(fp, "                                      `all`, `trace`, `trace:hostname`,\n");
+       fprintf(fp, "                                      `trace:domain`, `trace:procname`,\n");
+       fprintf(fp, "                                      `trace:vpid`, `loglevel`, `emf`\n");
+       fprintf(fp, "  -n, --names=NAME[,NAME]...        Print field names; NAME can be:\n");
+       fprintf(fp, "                                      `payload` (or `arg` or `args`), `none`,\n");
+       fprintf(fp, "                                      `all`, `scope`, `header`, `context`\n");
+       fprintf(fp, "                                      (or `ctx`)\n");
+       fprintf(fp, "      --no-delta                    Do not print time delta between\n");
+       fprintf(fp, "                                    consecutive events\n");
+       fprintf(fp, "  -w, --output=PATH                 Write output text to PATH instead of\n");
+       fprintf(fp, "                                    the standard output\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Implicit `filter.utils.muxer` component options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --clock-force-correlate       Assume that clocks are inherently\n");
+       fprintf(fp, "                                    correlated across traces\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Implicit `filter.utils.trimmer` component options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  -b, --begin=BEGIN                 Set the beginning time of the conversion\n");
+       fprintf(fp, "                                    time range to BEGIN (see the format of\n");
+       fprintf(fp, "                                    BEGIN below)\n");
+       fprintf(fp, "  -e, --end=END                     Set the end time of the conversion time\n");
+       fprintf(fp, "                                    range to END (see the format of END below)\n");
+       fprintf(fp, "  -t, --timerange=TIMERANGE         Set conversion time range to TIMERANGE:\n");
+       fprintf(fp, "                                    BEGIN,END or [BEGIN,END] (literally `[` and\n");
+       fprintf(fp, "                                    `]`) (see the format of BEGIN/END below)\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Implicit `filter.lttng-utils.debug-info` component options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "      --debug-info                  Create an implicit\n");
+       fprintf(fp, "                                    `filter.lttng-utils.debug-info` component\n");
+       fprintf(fp, "      --debug-info-dir=DIR          Search for debug info in directory DIR\n");
+       fprintf(fp, "                                    instead of `/usr/lib/debug`\n");
+       fprintf(fp, "      --debug-info-full-path        Show full debug info source and\n");
+       fprintf(fp, "                                    binary paths instead of just names\n");
+       fprintf(fp, "      --debug-info-target-prefix=DIR\n");
+       fprintf(fp, "                                    Use directory DIR as a prefix when\n");
+       fprintf(fp, "                                    looking up executables during debug\n");
+       fprintf(fp, "                                    info analysis\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Legacy options that still work:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  -i, --input-format=(ctf | lttng-live)\n");
+       fprintf(fp, "                                    `ctf`:\n");
+       fprintf(fp, "                                      Create an implicit `source.ctf.fs`\n");
+       fprintf(fp, "                                      component\n");
+       fprintf(fp, "                                    `lttng-live`:\n");
+       fprintf(fp, "                                      Create an implicit `source.ctf.lttng-live`\n");
+       fprintf(fp, "                                      component\n");
+       fprintf(fp, "  -o, --output-format=(text | ctf | dummy | ctf-metadata)\n");
+       fprintf(fp, "                                    `text`:\n");
+       fprintf(fp, "                                      Create an implicit `sink.text.pretty`\n");
+       fprintf(fp, "                                      component\n");
+       fprintf(fp, "                                    `ctf`:\n");
+       fprintf(fp, "                                      Create an implicit `sink.ctf.fs`\n");
+       fprintf(fp, "                                      component\n");
+       fprintf(fp, "                                    `dummy`:\n");
+       fprintf(fp, "                                      Create an implicit `sink.utils.dummy`\n");
+       fprintf(fp, "                                      component\n");
+       fprintf(fp, "                                    `ctf-metadata`:\n");
+       fprintf(fp, "                                      Query the `source.ctf.fs` component class\n");
+       fprintf(fp, "                                      for metadata text and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
+       fprintf(fp, "\n\n");
+       fprintf(fp, "Format of BEGIN and END\n");
+       fprintf(fp, "-----------------------\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
+       fprintf(fp, "\n\n");
+       print_expected_params_format(fp);
+}
+
+static
+struct poptOption convert_long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       { "begin", 'b', POPT_ARG_STRING, NULL, OPT_BEGIN, NULL, NULL },
+       { "clock-cycles", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_CYCLES, NULL, NULL },
+       { "clock-date", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
+       { "clock-force-correlate", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
+       { "clock-gmt", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
+       { "clock-offset", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET, NULL, NULL },
+       { "clock-offset-ns", '\0', POPT_ARG_STRING, NULL, OPT_CLOCK_OFFSET_NS, NULL, NULL },
+       { "clock-seconds", '\0', POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
+       { "color", '\0', POPT_ARG_STRING, NULL, OPT_COLOR, NULL, NULL },
+       { "component", 'c', POPT_ARG_STRING, NULL, OPT_COMPONENT, NULL, NULL },
+       { "debug", 'd', POPT_ARG_NONE, NULL, OPT_DEBUG, NULL, NULL },
+       { "debug-info-dir", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_DIR, NULL, NULL },
+       { "debug-info-full-path", 0, POPT_ARG_NONE, NULL, OPT_DEBUG_INFO_FULL_PATH, NULL, NULL },
+       { "debug-info-target-prefix", 0, POPT_ARG_STRING, NULL, OPT_DEBUG_INFO_TARGET_PREFIX, NULL, NULL },
+       { "end", 'e', POPT_ARG_STRING, NULL, OPT_END, NULL, NULL },
+       { "fields", 'f', POPT_ARG_STRING, NULL, OPT_FIELDS, NULL, NULL },
+       { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+       { "input-format", 'i', POPT_ARG_STRING, NULL, OPT_INPUT_FORMAT, NULL, NULL },
+       { "name", '\0', POPT_ARG_STRING, NULL, OPT_NAME, NULL, NULL },
+       { "names", 'n', POPT_ARG_STRING, NULL, OPT_NAMES, NULL, NULL },
+       { "debug-info", '\0', POPT_ARG_NONE, NULL, OPT_DEBUG_INFO, NULL, NULL },
+       { "no-delta", '\0', POPT_ARG_NONE, NULL, OPT_NO_DELTA, NULL, NULL },
+       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
+       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
+       { "output", 'w', POPT_ARG_STRING, NULL, OPT_OUTPUT, NULL, NULL },
+       { "output-format", 'o', POPT_ARG_STRING, NULL, OPT_OUTPUT_FORMAT, NULL, NULL },
+       { "params", 'p', POPT_ARG_STRING, NULL, OPT_PARAMS, NULL, NULL },
+       { "path", 'P', POPT_ARG_STRING, NULL, OPT_PATH, NULL, NULL },
+       { "plugin-path", '\0', POPT_ARG_STRING, NULL, OPT_PLUGIN_PATH, NULL, NULL },
+       { "retry-duration", '\0', POPT_ARG_STRING, NULL, OPT_RETRY_DURATION, NULL, NULL },
+       { "run-args", '\0', POPT_ARG_NONE, NULL, OPT_RUN_ARGS, NULL, NULL },
+       { "run-args-0", '\0', POPT_ARG_NONE, NULL, OPT_RUN_ARGS_0, NULL, NULL },
+       { "stream-intersection", '\0', POPT_ARG_NONE, NULL, OPT_STREAM_INTERSECTION, NULL, NULL },
+       { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
+       { "url", 'u', POPT_ARG_STRING, NULL, OPT_URL, NULL, NULL },
+       { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
+       { NULL, 0, '\0', NULL, 0, NULL, NULL },
+};
+
+static
+GString *get_component_auto_name(const char *prefix,
+               const bt_value *existing_names)
+{
+       unsigned int i = 0;
+       GString *auto_name = g_string_new(NULL);
+
+       if (!auto_name) {
+               print_err_oom();
+               goto end;
+       }
+
+       if (!bt_value_map_has_entry(existing_names, prefix)) {
+               g_string_assign(auto_name, prefix);
+               goto end;
+       }
+
+       do {
+               g_string_printf(auto_name, "%s-%d", prefix, i);
+               i++;
+       } while (bt_value_map_has_entry(existing_names, auto_name->str));
+
+end:
+       return auto_name;
+}
+
+struct implicit_component_args {
+       bool exists;
+       GString *comp_arg;
+       GString *name_arg;
+       GString *params_arg;
+       bt_value *extra_params;
+};
+
+static
+int assign_name_to_implicit_component(struct implicit_component_args *args,
+               const char *prefix, bt_value *existing_names,
+               GList **comp_names, bool append_to_comp_names)
+{
+       int ret = 0;
+       GString *name = NULL;
+
+       if (!args->exists) {
+               goto end;
+       }
+
+       name = get_component_auto_name(prefix,
+               existing_names);
+
+       if (!name) {
+               ret = -1;
+               goto end;
+       }
+
+       g_string_assign(args->name_arg, name->str);
+
+       if (bt_value_map_insert_entry(existing_names, name->str,
+                       bt_value_null)) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       if (append_to_comp_names) {
+               *comp_names = g_list_append(*comp_names, name);
+               name = NULL;
+       }
+
+end:
+       if (name) {
+               g_string_free(name, TRUE);
+       }
+
+       return ret;
+}
+
+static
+int append_run_args_for_implicit_component(
+               struct implicit_component_args *impl_args,
+               bt_value *run_args)
+{
+       int ret = 0;
+       size_t i;
+
+       if (!impl_args->exists) {
+               goto end;
+       }
+
+       if (bt_value_array_append_string_element(run_args, "--component")) {
+               print_err_oom();
+               goto error;
+       }
+
+       if (bt_value_array_append_string_element(run_args, impl_args->comp_arg->str)) {
+               print_err_oom();
+               goto error;
+       }
+
+       if (bt_value_array_append_string_element(run_args, "--name")) {
+               print_err_oom();
+               goto error;
+       }
+
+       if (bt_value_array_append_string_element(run_args, impl_args->name_arg->str)) {
+               print_err_oom();
+               goto error;
+       }
+
+       if (impl_args->params_arg->len > 0) {
+               if (bt_value_array_append_string_element(run_args, "--params")) {
+                       print_err_oom();
+                       goto error;
+               }
+
+               if (bt_value_array_append_string_element(run_args,
+                               impl_args->params_arg->str)) {
+                       print_err_oom();
+                       goto error;
+               }
+       }
+
+       for (i = 0; i < bt_value_array_get_size(impl_args->extra_params);
+                       i++) {
+               const bt_value *elem;
+               const char *arg;
+
+               elem = bt_value_array_borrow_element_by_index(impl_args->extra_params,
+                                                             i);
+               if (!elem) {
+                       goto error;
+               }
+
+               BT_ASSERT(bt_value_is_string(elem));
+               arg = bt_value_string_get(elem);
+               ret = bt_value_array_append_string_element(run_args, arg);
+               if (ret) {
+                       print_err_oom();
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+void finalize_implicit_component_args(struct implicit_component_args *args)
+{
+       BT_ASSERT(args);
+
+       if (args->comp_arg) {
+               g_string_free(args->comp_arg, TRUE);
+       }
+
+       if (args->name_arg) {
+               g_string_free(args->name_arg, TRUE);
+       }
+
+       if (args->params_arg) {
+               g_string_free(args->params_arg, TRUE);
+       }
+
+       bt_value_put_ref(args->extra_params);
+}
+
+static
+int init_implicit_component_args(struct implicit_component_args *args,
+               const char *comp_arg, bool exists)
+{
+       int ret = 0;
+
+       args->exists = exists;
+       args->comp_arg = g_string_new(comp_arg);
+       args->name_arg = g_string_new(NULL);
+       args->params_arg = g_string_new(NULL);
+       args->extra_params = bt_value_array_create();
+
+       if (!args->comp_arg || !args->name_arg ||
+                       !args->params_arg || !args->extra_params) {
+               ret = -1;
+               finalize_implicit_component_args(args);
+               print_err_oom();
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+void append_implicit_component_param(struct implicit_component_args *args,
+       const char *key, const char *value)
+{
+       BT_ASSERT(args);
+       BT_ASSERT(key);
+       BT_ASSERT(value);
+       append_param_arg(args->params_arg, key, value);
+}
+
+/* Escape value to make it suitable to use as a string parameter value. */
+static
+gchar *escape_string_value(const char *value)
+{
+       GString *ret;
+       const char *in;
+
+       ret = g_string_new(NULL);
+       if (!ret) {
+               print_err_oom();
+               goto end;
+       }
+
+       in = value;
+       while (*in) {
+               switch (*in) {
+               case '"':
+               case '\\':
+                       g_string_append_c(ret, '\\');
+                       break;
+               }
+
+               g_string_append_c(ret, *in);
+
+               in++;
+       }
+
+end:
+       return g_string_free(ret, FALSE);
+}
+
+static
+int bt_value_to_cli_param_value_append(const bt_value *value, GString *buf)
+{
+       BT_ASSERT(buf);
+
+       int ret = -1;
+
+       switch (bt_value_get_type(value)) {
+       case BT_VALUE_TYPE_STRING:
+       {
+               const char *str_value = bt_value_string_get(value);
+               gchar *escaped_str_value;
+
+               escaped_str_value = escape_string_value(str_value);
+               if (!escaped_str_value) {
+                       goto end;
+               }
+
+               g_string_append_printf(buf, "\"%s\"", escaped_str_value);
+
+               g_free(escaped_str_value);
+               break;
+       }
+       case BT_VALUE_TYPE_ARRAY: {
+               g_string_append_c(buf, '[');
+               uint64_t sz = bt_value_array_get_size(value);
+               for (uint64_t i = 0; i < sz; i++) {
+                       const bt_value *item;
+                       int ret;
+
+                       if (i > 0) {
+                               g_string_append(buf, ", ");
+                       }
+
+                       item = bt_value_array_borrow_element_by_index_const(
+                               value, i);
+                       ret = bt_value_to_cli_param_value_append(item, buf);
+
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               g_string_append_c(buf, ']');
+               break;
+       }
+       default:
+               abort();
+       }
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+/*
+ * Convert `value` to its equivalent representation as a command line parameter
+ * value.
+ */
+
+static
+gchar *bt_value_to_cli_param_value(bt_value *value)
+{
+       GString *buf;
+       gchar *result = NULL;
+
+       buf = g_string_new(NULL);
+       if (!buf) {
+               print_err_oom();
+               goto error;
+       }
+
+       if (bt_value_to_cli_param_value_append(value, buf)) {
+               goto error;
+       }
+
+       result = g_string_free(buf, FALSE);
+       buf = NULL;
+
+       goto end;
+
+error:
+       if (buf) {
+               g_string_free(buf, TRUE);
+       }
+
+end:
+       return result;
+}
+
+static
+int append_parameter_to_args(bt_value *args, const char *key, bt_value *value)
+{
+       BT_ASSERT(args);
+       BT_ASSERT(bt_value_get_type(args) == BT_VALUE_TYPE_ARRAY);
+       BT_ASSERT(key);
+       BT_ASSERT(value);
+
+       int ret = 0;
+       gchar *str_value = NULL;
+       GString *parameter = NULL;
+
+       if (bt_value_array_append_string_element(args, "--params")) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       str_value = bt_value_to_cli_param_value(value);
+       if (!str_value) {
+               ret = -1;
+               goto end;
+       }
+
+       parameter = g_string_new(NULL);
+       if (!parameter) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       g_string_printf(parameter, "%s=%s", key, str_value);
+
+       if (bt_value_array_append_string_element(args, parameter->str)) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+end:
+       if (parameter) {
+               g_string_free(parameter, TRUE);
+               parameter = NULL;
+       }
+
+       if (str_value) {
+               g_free(str_value);
+               str_value = NULL;
+       }
+
+       return ret;
+}
+
+static
+int append_string_parameter_to_args(bt_value *args, const char *key, const char *value)
+{
+       bt_value *str_value;
+       int ret;
+
+       str_value = bt_value_string_create_init(value);
+
+       if (!str_value) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       ret = append_parameter_to_args(args, key, str_value);
+
+end:
+       BT_VALUE_PUT_REF_AND_RESET(str_value);
+       return ret;
+}
+
+static
+int append_implicit_component_extra_param(struct implicit_component_args *args,
+               const char *key, const char *value)
+{
+       return append_string_parameter_to_args(args->extra_params, key, value);
+}
+
+static
+int convert_append_name_param(enum bt_config_component_dest dest,
+               GString *cur_name, GString *cur_name_prefix,
+               bt_value *run_args,
+               bt_value *all_names,
+               GList **source_names, GList **filter_names,
+               GList **sink_names)
+{
+       int ret = 0;
+
+       if (cur_name_prefix->len > 0) {
+               /* We're after a --component option */
+               GString *name = NULL;
+               bool append_name_opt = false;
+
+               if (cur_name->len == 0) {
+                       /*
+                        * No explicit name was provided for the user
+                        * component.
+                        */
+                       name = get_component_auto_name(cur_name_prefix->str,
+                               all_names);
+                       append_name_opt = true;
+               } else {
+                       /*
+                        * An explicit name was provided for the user
+                        * component.
+                        */
+                       if (bt_value_map_has_entry(all_names,
+                                                  cur_name->str)) {
+                               printf_err("Duplicate component instance name:\n    %s\n",
+                                       cur_name->str);
+                               goto error;
+                       }
+
+                       name = g_string_new(cur_name->str);
+               }
+
+               if (!name) {
+                       print_err_oom();
+                       goto error;
+               }
+
+               /*
+                * Remember this name globally, for the uniqueness of
+                * all component names.
+                */
+               if (bt_value_map_insert_entry(all_names, name->str, bt_value_null)) {
+                       print_err_oom();
+                       goto error;
+               }
+
+               /*
+                * Append the --name option if necessary.
+                */
+               if (append_name_opt) {
+                       if (bt_value_array_append_string_element(run_args, "--name")) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args, name->str)) {
+                               print_err_oom();
+                               goto error;
+                       }
+               }
+
+               /*
+                * Remember this name specifically for the type of the
+                * component. This is to create connection arguments.
+                */
+               switch (dest) {
+               case BT_CONFIG_COMPONENT_DEST_SOURCE:
+                       *source_names = g_list_append(*source_names, name);
+                       break;
+               case BT_CONFIG_COMPONENT_DEST_FILTER:
+                       *filter_names = g_list_append(*filter_names, name);
+                       break;
+               case BT_CONFIG_COMPONENT_DEST_SINK:
+                       *sink_names = g_list_append(*sink_names, name);
+                       break;
+               default:
+                       abort();
+               }
+
+               g_string_assign(cur_name_prefix, "");
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+/*
+ * Escapes `.`, `:`, and `\` of `input` with `\`.
+ */
+static
+GString *escape_dot_colon(const char *input)
+{
+       GString *output = g_string_new(NULL);
+       const char *ch;
+
+       if (!output) {
+               print_err_oom();
+               goto end;
+       }
+
+       for (ch = input; *ch != '\0'; ch++) {
+               if (*ch == '\\' || *ch == '.' || *ch == ':') {
+                       g_string_append_c(output, '\\');
+               }
+
+               g_string_append_c(output, *ch);
+       }
+
+end:
+       return output;
+}
+
+/*
+ * Appends a --connect option to a list of arguments. `upstream_name`
+ * and `downstream_name` are escaped with escape_dot_colon() in this
+ * function.
+ */
+static
+int append_connect_arg(bt_value *run_args,
+               const char *upstream_name, const char *downstream_name)
+{
+       int ret = 0;
+       GString *e_upstream_name = escape_dot_colon(upstream_name);
+       GString *e_downstream_name = escape_dot_colon(downstream_name);
+       GString *arg = g_string_new(NULL);
+
+       if (!e_upstream_name || !e_downstream_name || !arg) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_value_array_append_string_element(run_args, "--connect");
+       if (ret) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+       g_string_append(arg, e_upstream_name->str);
+       g_string_append_c(arg, ':');
+       g_string_append(arg, e_downstream_name->str);
+       ret = bt_value_array_append_string_element(run_args, arg->str);
+       if (ret) {
+               print_err_oom();
+               ret = -1;
+               goto end;
+       }
+
+end:
+       if (arg) {
+               g_string_free(arg, TRUE);
+       }
+
+       if (e_upstream_name) {
+               g_string_free(e_upstream_name, TRUE);
+       }
+
+       if (e_downstream_name) {
+               g_string_free(e_downstream_name, TRUE);
+       }
+
+       return ret;
+}
+
+/*
+ * Appends the run command's --connect options for the convert command.
+ */
+static
+int convert_auto_connect(bt_value *run_args,
+               GList *source_names, GList *filter_names,
+               GList *sink_names)
+{
+       int ret = 0;
+       GList *source_at = source_names;
+       GList *filter_at = filter_names;
+       GList *filter_prev;
+       GList *sink_at = sink_names;
+
+       BT_ASSERT(source_names);
+       BT_ASSERT(filter_names);
+       BT_ASSERT(sink_names);
+
+       /* Connect all sources to the first filter */
+       for (source_at = source_names; source_at != NULL; source_at = g_list_next(source_at)) {
+               GString *source_name = source_at->data;
+               GString *filter_name = filter_at->data;
+
+               ret = append_connect_arg(run_args, source_name->str,
+                       filter_name->str);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       filter_prev = filter_at;
+       filter_at = g_list_next(filter_at);
+
+       /* Connect remaining filters */
+       for (; filter_at != NULL; filter_prev = filter_at, filter_at = g_list_next(filter_at)) {
+               GString *filter_name = filter_at->data;
+               GString *filter_prev_name = filter_prev->data;
+
+               ret = append_connect_arg(run_args, filter_prev_name->str,
+                       filter_name->str);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       /* Connect last filter to all sinks */
+       for (sink_at = sink_names; sink_at != NULL; sink_at = g_list_next(sink_at)) {
+               GString *filter_name = filter_prev->data;
+               GString *sink_name = sink_at->data;
+
+               ret = append_connect_arg(run_args, filter_name->str,
+                       sink_name->str);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int split_timerange(const char *arg, char **begin, char **end)
+{
+       int ret = 0;
+       const char *ch = arg;
+       size_t end_pos;
+       GString *g_begin = NULL;
+       GString *g_end = NULL;
+
+       BT_ASSERT(arg);
+
+       if (*ch == '[') {
+               ch++;
+       }
+
+       g_begin = bt_common_string_until(ch, "", ",", &end_pos);
+       if (!g_begin || ch[end_pos] != ',' || g_begin->len == 0) {
+               goto error;
+       }
+
+       ch += end_pos + 1;
+
+       g_end = bt_common_string_until(ch, "", "]", &end_pos);
+       if (!g_end || g_end->len == 0) {
+               goto error;
+       }
+
+       BT_ASSERT(begin);
+       BT_ASSERT(end);
+       *begin = g_begin->str;
+       *end = g_end->str;
+       g_string_free(g_begin, FALSE);
+       g_string_free(g_end, FALSE);
+       g_begin = NULL;
+       g_end = NULL;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       if (g_begin) {
+               g_string_free(g_begin, TRUE);
+       }
+
+       if (g_end) {
+               g_string_free(g_end, TRUE);
+       }
+
+       return ret;
+}
+
+static
+int g_list_prepend_gstring(GList **list, const char *string)
+{
+       int ret = 0;
+       GString *gs = g_string_new(string);
+
+       BT_ASSERT(list);
+
+       if (!gs) {
+               print_err_oom();
+               goto end;
+       }
+
+       *list = g_list_prepend(*list, gs);
+
+end:
+       return ret;
+}
+
+/*
+ * Creates a Babeltrace config object from the arguments of a convert
+ * command.
+ *
+ * *retcode is set to the appropriate exit code to use.
+ */
+static
+struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
+               int *retcode, bool force_omit_system_plugin_path,
+               bool force_omit_home_plugin_path,
+               const bt_value *initial_plugin_paths, char *log_level)
+{
+       poptContext pc = NULL;
+       char *arg = NULL;
+       enum bt_config_component_dest cur_comp_dest =
+                       BT_CONFIG_COMPONENT_DEST_UNKNOWN;
+       int opt, ret = 0;
+       struct bt_config *cfg = NULL;
+       bool got_input_format_opt = false;
+       bool got_output_format_opt = false;
+       bool trimmer_has_begin = false;
+       bool trimmer_has_end = false;
+       bool stream_intersection_mode = false;
+       GString *cur_name = NULL;
+       GString *cur_name_prefix = NULL;
+       const char *leftover = NULL;
+       bool print_run_args = false;
+       bool print_run_args_0 = false;
+       bool print_ctf_metadata = false;
+       bt_value *run_args = NULL;
+       bt_value *all_names = NULL;
+       GList *source_names = NULL;
+       GList *filter_names = NULL;
+       GList *sink_names = NULL;
+       bt_value *leftovers = NULL;
+       struct implicit_component_args implicit_ctf_input_args = { 0 };
+       struct implicit_component_args implicit_ctf_output_args = { 0 };
+       struct implicit_component_args implicit_lttng_live_args = { 0 };
+       struct implicit_component_args implicit_dummy_args = { 0 };
+       struct implicit_component_args implicit_text_args = { 0 };
+       struct implicit_component_args implicit_debug_info_args = { 0 };
+       struct implicit_component_args implicit_muxer_args = { 0 };
+       struct implicit_component_args implicit_trimmer_args = { 0 };
+       bt_value *plugin_paths;
+       char error_buf[256] = { 0 };
+       size_t i;
+       struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
+       char *output = NULL;
+
+       (void) bt_value_copy(initial_plugin_paths, &plugin_paths);
+
+       *retcode = 0;
+
+       if (argc <= 1) {
+               print_convert_usage(stdout);
+               *retcode = -1;
+               goto end;
+       }
+
+       if (init_implicit_component_args(&implicit_ctf_input_args,
+                       "source.ctf.fs", false)) {
+               goto error;
+       }
+
+       if (init_implicit_component_args(&implicit_ctf_output_args,
+                       "sink.ctf.fs", false)) {
+               goto error;
+       }
+
+       if (init_implicit_component_args(&implicit_lttng_live_args,
+                       "source.ctf.lttng-live", false)) {
+               goto error;
+       }
+
+       if (init_implicit_component_args(&implicit_text_args,
+                       "sink.text.pretty", false)) {
+               goto error;
+       }
+
+       if (init_implicit_component_args(&implicit_dummy_args,
+                       "sink.utils.dummy", false)) {
+               goto error;
+       }
+
+       if (init_implicit_component_args(&implicit_debug_info_args,
+                       "filter.lttng-utils.debug-info", false)) {
+               goto error;
+       }
+
+       if (init_implicit_component_args(&implicit_muxer_args,
+                       "filter.utils.muxer", true)) {
+               goto error;
+       }
+
+       if (init_implicit_component_args(&implicit_trimmer_args,
+                       "filter.utils.trimmer", false)) {
+               goto error;
+       }
+
+       all_names = bt_value_map_create();
+       if (!all_names) {
+               print_err_oom();
+               goto error;
+       }
+
+       run_args = bt_value_array_create();
+       if (!run_args) {
+               print_err_oom();
+               goto error;
+       }
+
+       cur_name = g_string_new(NULL);
+       if (!cur_name) {
+               print_err_oom();
+               goto error;
+       }
+
+       cur_name_prefix = g_string_new(NULL);
+       if (!cur_name_prefix) {
+               print_err_oom();
+               goto error;
+       }
+
+       ret = append_env_var_plugin_paths(plugin_paths);
+       if (ret) {
+               goto error;
+       }
+
+       leftovers = bt_value_array_create();
+       if (!leftovers) {
+               print_err_oom();
+               goto error;
+       }
+
+       /*
+        * First pass: collect all arguments which need to be passed
+        * as is to the run command. This pass can also add --name
+        * arguments if needed to automatically name unnamed component
+        * instances. Also it does the following transformations:
+        *
+        *     --path=PATH -> --params=path="PATH"
+        *     --url=URL   -> --params=url="URL"
+        *
+        * Also it appends the plugin paths of --plugin-path to
+        * `plugin_paths`.
+        */
+       pc = poptGetContext(NULL, argc, (const char **) argv,
+               convert_long_options, 0);
+       if (!pc) {
+               printf_err("Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) > 0) {
+               char *name = NULL;
+               char *plugin_name = NULL;
+               char *comp_cls_name = NULL;
+
+               arg = poptGetOptArg(pc);
+
+               switch (opt) {
+               case OPT_COMPONENT:
+               {
+                       bt_component_class_type type;
+                       const char *type_prefix;
+
+                       /* Append current component's name if needed */
+                       ret = convert_append_name_param(cur_comp_dest, cur_name,
+                               cur_name_prefix, run_args, all_names,
+                               &source_names, &filter_names, &sink_names);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       /* Parse the argument */
+                       plugin_comp_cls_names(arg, &name, &plugin_name,
+                               &comp_cls_name, &type);
+                       if (!plugin_name || !comp_cls_name) {
+                               printf_err("Invalid format for --component option's argument:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       if (name) {
+                               g_string_assign(cur_name, name);
+                       } else {
+                               g_string_assign(cur_name, "");
+                       }
+
+                       switch (type) {
+                       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                               cur_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
+                               type_prefix = "source";
+                               break;
+                       case BT_COMPONENT_CLASS_TYPE_FILTER:
+                               cur_comp_dest = BT_CONFIG_COMPONENT_DEST_FILTER;
+                               type_prefix = "filter";
+                               break;
+                       case BT_COMPONENT_CLASS_TYPE_SINK:
+                               cur_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
+                               type_prefix = "sink";
+                               break;
+                       default:
+                               abort();
+                       }
+
+                       if (bt_value_array_append_string_element(run_args,
+                                       "--component")) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args, arg)) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       g_string_assign(cur_name_prefix, "");
+                       g_string_append_printf(cur_name_prefix, "%s.%s.%s",
+                               type_prefix, plugin_name, comp_cls_name);
+                       free(name);
+                       free(plugin_name);
+                       free(comp_cls_name);
+                       name = NULL;
+                       plugin_name = NULL;
+                       comp_cls_name = NULL;
+                       break;
+               }
+               case OPT_PARAMS:
+                       if (cur_name_prefix->len == 0) {
+                               printf_err("No current component of which to set parameters:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args,
+                                       "--params")) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args, arg)) {
+                               print_err_oom();
+                               goto error;
+                       }
+                       break;
+               case OPT_PATH:
+                       if (cur_name_prefix->len == 0) {
+                               printf_err("No current component of which to set `path` parameter:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       if (append_string_parameter_to_args(run_args, "path", arg)) {
+                               goto error;
+                       }
+                       break;
+               case OPT_URL:
+                       if (cur_name_prefix->len == 0) {
+                               printf_err("No current component of which to set `url` parameter:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+
+                       if (append_string_parameter_to_args(run_args, "url", arg)) {
+                               goto error;
+                       }
+                       break;
+               case OPT_NAME:
+                       if (cur_name_prefix->len == 0) {
+                               printf_err("No current component to name:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args, "--name")) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args, arg)) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       g_string_assign(cur_name, arg);
+                       break;
+               case OPT_OMIT_HOME_PLUGIN_PATH:
+                       force_omit_home_plugin_path = true;
+
+                       if (bt_value_array_append_string_element(run_args,
+                                       "--omit-home-plugin-path")) {
+                               print_err_oom();
+                               goto error;
+                       }
+                       break;
+               case OPT_RETRY_DURATION:
+                       if (bt_value_array_append_string_element(run_args,
+                                       "--retry-duration")) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args, arg)) {
+                               print_err_oom();
+                               goto error;
+                       }
+                       break;
+               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+                       force_omit_system_plugin_path = true;
+
+                       if (bt_value_array_append_string_element(run_args,
+                                       "--omit-system-plugin-path")) {
+                               print_err_oom();
+                               goto error;
+                       }
+                       break;
+               case OPT_PLUGIN_PATH:
+                       if (bt_config_append_plugin_paths_check_setuid_setgid(
+                                       plugin_paths, arg)) {
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args,
+                                       "--plugin-path")) {
+                               print_err_oom();
+                               goto error;
+                       }
+
+                       if (bt_value_array_append_string_element(run_args, arg)) {
+                               print_err_oom();
+                               goto error;
+                       }
+                       break;
+               case OPT_HELP:
+                       print_convert_usage(stdout);
+                       *retcode = -1;
+                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                       goto end;
+               case OPT_BEGIN:
+               case OPT_CLOCK_CYCLES:
+               case OPT_CLOCK_DATE:
+               case OPT_CLOCK_FORCE_CORRELATE:
+               case OPT_CLOCK_GMT:
+               case OPT_CLOCK_OFFSET:
+               case OPT_CLOCK_OFFSET_NS:
+               case OPT_CLOCK_SECONDS:
+               case OPT_COLOR:
+               case OPT_DEBUG:
+               case OPT_DEBUG_INFO:
+               case OPT_DEBUG_INFO_DIR:
+               case OPT_DEBUG_INFO_FULL_PATH:
+               case OPT_DEBUG_INFO_TARGET_PREFIX:
+               case OPT_END:
+               case OPT_FIELDS:
+               case OPT_INPUT_FORMAT:
+               case OPT_NAMES:
+               case OPT_NO_DELTA:
+               case OPT_OUTPUT_FORMAT:
+               case OPT_OUTPUT:
+               case OPT_RUN_ARGS:
+               case OPT_RUN_ARGS_0:
+               case OPT_STREAM_INTERSECTION:
+               case OPT_TIMERANGE:
+               case OPT_VERBOSE:
+                       /* Ignore in this pass */
+                       break;
+               default:
+                       printf_err("Unknown command-line option specified (option code %d)\n",
+                               opt);
+                       goto error;
+               }
+
+               free(arg);
+               arg = NULL;
+       }
+
+       /* Append current component's name if needed */
+       ret = convert_append_name_param(cur_comp_dest, cur_name,
+               cur_name_prefix, run_args, all_names, &source_names,
+               &filter_names, &sink_names);
+       if (ret) {
+               goto error;
+       }
+
+       /* Check for option parsing error */
+       if (opt < -1) {
+               printf_err("While parsing command-line options, at option %s: %s\n",
+                       poptBadOption(pc, 0), poptStrerror(opt));
+               goto error;
+       }
+
+       poptFreeContext(pc);
+       free(arg);
+       arg = NULL;
+
+       /*
+        * Second pass: transform the convert-specific options and
+        * arguments into implicit component instances for the run
+        * command.
+        */
+       pc = poptGetContext(NULL, argc, (const char **) argv,
+               convert_long_options, 0);
+       if (!pc) {
+               printf_err("Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) > 0) {
+               arg = poptGetOptArg(pc);
+
+               switch (opt) {
+               case OPT_BEGIN:
+                       if (trimmer_has_begin) {
+                               printf("At --begin option: --begin or --timerange option already specified\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       trimmer_has_begin = true;
+                       ret = append_implicit_component_extra_param(
+                               &implicit_trimmer_args, "begin", arg);
+                       implicit_trimmer_args.exists = true;
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               case OPT_END:
+                       if (trimmer_has_end) {
+                               printf("At --end option: --end or --timerange option already specified\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       trimmer_has_end = true;
+                       ret = append_implicit_component_extra_param(
+                               &implicit_trimmer_args, "end", arg);
+                       implicit_trimmer_args.exists = true;
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               case OPT_TIMERANGE:
+               {
+                       char *begin;
+                       char *end;
+
+                       if (trimmer_has_begin || trimmer_has_end) {
+                               printf("At --timerange option: --begin, --end, or --timerange option already specified\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       ret = split_timerange(arg, &begin, &end);
+                       if (ret) {
+                               printf_err("Invalid --timerange option's argument: expecting BEGIN,END or [BEGIN,END]:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+
+                       ret = append_implicit_component_extra_param(
+                               &implicit_trimmer_args, "begin", begin);
+                       ret |= append_implicit_component_extra_param(
+                               &implicit_trimmer_args, "end", end);
+                       implicit_trimmer_args.exists = true;
+                       free(begin);
+                       free(end);
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               }
+               case OPT_CLOCK_CYCLES:
+                       append_implicit_component_param(
+                               &implicit_text_args, "clock-cycles", "yes");
+                       implicit_text_args.exists = true;
+                       break;
+               case OPT_CLOCK_DATE:
+                       append_implicit_component_param(
+                               &implicit_text_args, "clock-date", "yes");
+                       implicit_text_args.exists = true;
+                       break;
+               case OPT_CLOCK_FORCE_CORRELATE:
+                       append_implicit_component_param(
+                               &implicit_muxer_args,
+                               "assume-absolute-clock-classes", "yes");
+                       break;
+               case OPT_CLOCK_GMT:
+                       append_implicit_component_param(
+                               &implicit_text_args, "clock-gmt", "yes");
+                       append_implicit_component_param(
+                               &implicit_trimmer_args, "gmt", "yes");
+                       implicit_text_args.exists = true;
+                       break;
+               case OPT_CLOCK_OFFSET:
+                       implicit_ctf_input_args.exists = true;
+                       append_implicit_component_param(
+                                       &implicit_ctf_input_args,
+                                       "clock-class-offset-s", arg);
+                       break;
+               case OPT_CLOCK_OFFSET_NS:
+                       implicit_ctf_input_args.exists = true;
+                       append_implicit_component_param(
+                                       &implicit_ctf_input_args,
+                                       "clock-class-offset-ns", arg);
+                       break;
+               case OPT_CLOCK_SECONDS:
+                       append_implicit_component_param(
+                               &implicit_text_args, "clock-seconds", "yes");
+                       implicit_text_args.exists = true;
+                       break;
+               case OPT_COLOR:
+                       implicit_text_args.exists = true;
+                       ret = append_implicit_component_extra_param(
+                               &implicit_text_args, "color", arg);
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               case OPT_DEBUG_INFO:
+                       implicit_debug_info_args.exists = true;
+                       break;
+               case OPT_DEBUG_INFO_DIR:
+                       implicit_debug_info_args.exists = true;
+                       ret = append_implicit_component_extra_param(
+                               &implicit_debug_info_args, "debug-info-dir", arg);
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               case OPT_DEBUG_INFO_FULL_PATH:
+                       implicit_debug_info_args.exists = true;
+                       append_implicit_component_param(
+                               &implicit_debug_info_args, "full-path", "yes");
+                       break;
+               case OPT_DEBUG_INFO_TARGET_PREFIX:
+                       implicit_debug_info_args.exists = true;
+                       ret = append_implicit_component_extra_param(
+                               &implicit_debug_info_args,
+                               "target-prefix", arg);
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               case OPT_FIELDS:
+               {
+                       bt_value *fields = fields_from_arg(arg);
+
+                       if (!fields) {
+                               goto error;
+                       }
+
+                       implicit_text_args.exists = true;
+                       ret = insert_flat_params_from_array(
+                               implicit_text_args.params_arg,
+                               fields, "field");
+                       bt_value_put_ref(fields);
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               }
+               case OPT_NAMES:
+               {
+                       bt_value *names = names_from_arg(arg);
+
+                       if (!names) {
+                               goto error;
+                       }
+
+                       implicit_text_args.exists = true;
+                       ret = insert_flat_params_from_array(
+                               implicit_text_args.params_arg,
+                               names, "name");
+                       bt_value_put_ref(names);
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               }
+               case OPT_NO_DELTA:
+                       append_implicit_component_param(
+                               &implicit_text_args, "no-delta", "yes");
+                       implicit_text_args.exists = true;
+                       break;
+               case OPT_INPUT_FORMAT:
+                       if (got_input_format_opt) {
+                               printf_err("Duplicate --input-format option\n");
+                               goto error;
+                       }
+
+                       got_input_format_opt = true;
+
+                       if (strcmp(arg, "ctf") == 0) {
+                               implicit_ctf_input_args.exists = true;
+                       } else if (strcmp(arg, "lttng-live") == 0) {
+                               implicit_lttng_live_args.exists = true;
+                       } else {
+                               printf_err("Unknown legacy input format:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+                       break;
+               case OPT_OUTPUT_FORMAT:
+                       if (got_output_format_opt) {
+                               printf_err("Duplicate --output-format option\n");
+                               goto error;
+                       }
+
+                       got_output_format_opt = true;
+
+                       if (strcmp(arg, "text") == 0) {
+                               implicit_text_args.exists = true;
+                       } else if (strcmp(arg, "ctf") == 0) {
+                               implicit_ctf_output_args.exists = true;
+                       } else if (strcmp(arg, "dummy") == 0) {
+                               implicit_dummy_args.exists = true;
+                       } else if (strcmp(arg, "ctf-metadata") == 0) {
+                               print_ctf_metadata = true;
+                       } else {
+                               printf_err("Unknown legacy output format:\n    %s\n",
+                                       arg);
+                               goto error;
+                       }
+                       break;
+               case OPT_OUTPUT:
+                       if (output) {
+                               printf_err("Duplicate --output option\n");
+                               goto error;
+                       }
+
+                       output = strdup(arg);
+                       if (!output) {
+                               print_err_oom();
+                               goto error;
+                       }
+                       break;
+               case OPT_RUN_ARGS:
+                       if (print_run_args_0) {
+                               printf_err("Cannot specify --run-args and --run-args-0\n");
+                               goto error;
+                       }
+
+                       print_run_args = true;
+                       break;
+               case OPT_RUN_ARGS_0:
+                       if (print_run_args) {
+                               printf_err("Cannot specify --run-args and --run-args-0\n");
+                               goto error;
+                       }
+
+                       print_run_args_0 = true;
+                       break;
+               case OPT_STREAM_INTERSECTION:
+                       /*
+                        * Applies to all traces implementing the trace-info
+                        * query.
+                        */
+                       stream_intersection_mode = true;
+                       break;
+               case OPT_VERBOSE:
+                       if (*log_level != 'V' && *log_level != 'D') {
+                               *log_level = 'I';
+                       }
+                       break;
+               case OPT_DEBUG:
+                       *log_level = 'V';
+                       break;
+               }
+
+               free(arg);
+               arg = NULL;
+       }
+
+       /* Check for option parsing error */
+       if (opt < -1) {
+               printf_err("While parsing command-line options, at option %s: %s\n",
+                       poptBadOption(pc, 0), poptStrerror(opt));
+               goto error;
+       }
+
+       /*
+        * Legacy behaviour: --verbose used to make the `text` output
+        * format print more information. --verbose is now equivalent to
+        * the INFO log level, which is why we compare to 'I' here.
+        */
+       if (*log_level == 'I') {
+               append_implicit_component_param(&implicit_text_args,
+                       "verbose", "yes");
+       }
+
+       /*
+        * Append home and system plugin paths now that we possibly got
+        * --plugin-path.
+        */
+       if (append_home_and_system_plugin_paths(plugin_paths,
+                       force_omit_system_plugin_path,
+                       force_omit_home_plugin_path)) {
+               goto error;
+       }
+
+       /* Consume and keep leftover arguments */
+       while ((leftover = poptGetArg(pc))) {
+               bt_value_status status = bt_value_array_append_string_element(leftovers, leftover);
+               if (status != BT_VALUE_STATUS_OK) {
+                       print_err_oom();
+                       goto error;
+               }
+       }
+
+       /* Print CTF metadata or print LTTng live sessions */
+       if (print_ctf_metadata) {
+               const bt_value *bt_val_leftover;
+
+               if (bt_value_array_is_empty(leftovers)) {
+                       printf_err("--output-format=ctf-metadata specified without a path\n");
+                       goto error;
+               }
+
+               if (bt_value_array_get_size(leftovers) > 1) {
+                       printf_err("Too many paths specified for --output-format=ctf-metadata\n");
+                       goto error;
+               }
+
+               cfg = bt_config_print_ctf_metadata_create(plugin_paths);
+               if (!cfg) {
+                       goto error;
+               }
+
+               bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0);
+               g_string_assign(cfg->cmd_data.print_ctf_metadata.path,
+                               bt_value_string_get(bt_val_leftover));
+
+               if (output) {
+                       g_string_assign(
+                               cfg->cmd_data.print_ctf_metadata.output_path,
+                               output);
+               }
+
+               goto end;
+       }
+
+       /*
+        * If -o ctf was specified, make sure an output path (--output)
+        * was also specified. --output does not imply -o ctf because
+        * it's also used for the default, implicit -o text if -o ctf
+        * is not specified.
+        */
+       if (implicit_ctf_output_args.exists) {
+               if (!output) {
+                       printf_err("--output-format=ctf specified without --output (trace output path)\n");
+                       goto error;
+               }
+
+               /*
+                * At this point we know that -o ctf AND --output were
+                * specified. Make sure that no options were specified
+                * which would imply -o text because --output would be
+                * ambiguous in this case. For example, this is wrong:
+                *
+                *     babeltrace2 --names=all -o ctf --output=/tmp/path my-trace
+                *
+                * because --names=all implies -o text, and --output
+                * could apply to both the sink.text.pretty and
+                * sink.ctf.fs implicit components.
+                */
+               if (implicit_text_args.exists) {
+                       printf_err("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text\n");
+                       goto error;
+               }
+       }
+
+       /*
+        * If -o dummy and -o ctf were not specified, and if there are
+        * no explicit sink components, then use an implicit
+        * `sink.text.pretty` component.
+        */
+       if (!implicit_dummy_args.exists && !implicit_ctf_output_args.exists &&
+                       !sink_names) {
+               implicit_text_args.exists = true;
+       }
+
+       /*
+        * Set implicit `sink.text.pretty` or `sink.ctf.fs` component's
+        * `path` parameter if --output was specified.
+        */
+       if (output) {
+               if (implicit_text_args.exists) {
+                       append_implicit_component_extra_param(&implicit_text_args,
+                               "path", output);
+               } else if (implicit_ctf_output_args.exists) {
+                       append_implicit_component_extra_param(&implicit_ctf_output_args,
+                               "path", output);
+               }
+       }
+
+       /* Decide where the leftover argument(s) go */
+       if (bt_value_array_get_size(leftovers) > 0) {
+               if (implicit_lttng_live_args.exists) {
+                       const bt_value *bt_val_leftover;
+
+                       if (bt_value_array_get_size(leftovers) > 1) {
+                               printf_err("Too many URLs specified for --output-format=lttng-live\n");
+                               goto error;
+                       }
+
+                       bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0);
+                       lttng_live_url_parts =
+                               bt_common_parse_lttng_live_url(bt_value_string_get(bt_val_leftover),
+                                       error_buf, sizeof(error_buf));
+                       if (!lttng_live_url_parts.proto) {
+                               printf_err("Invalid LTTng live URL format: %s\n",
+                                       error_buf);
+                               goto error;
+                       }
+
+                       if (!lttng_live_url_parts.session_name) {
+                               /* Print LTTng live sessions */
+                               cfg = bt_config_print_lttng_live_sessions_create(
+                                       plugin_paths);
+                               if (!cfg) {
+                                       goto error;
+                               }
+
+                               g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url,
+                                       bt_value_string_get(bt_val_leftover));
+
+                               if (output) {
+                                       g_string_assign(
+                                               cfg->cmd_data.print_lttng_live_sessions.output_path,
+                                               output);
+                               }
+
+                               goto end;
+                       }
+
+                       ret = append_implicit_component_extra_param(
+                               &implicit_lttng_live_args, "url",
+                               bt_value_string_get(bt_val_leftover));
+                       if (ret) {
+                               goto error;
+                       }
+
+                       ret = append_implicit_component_extra_param(
+                               &implicit_lttng_live_args,
+                               "session-not-found-action", "end");
+                       if (ret) {
+                               goto error;
+                       }
+               } else {
+                       /*
+                        * Create one source.ctf.fs component, pass it an array
+                        * with the leftovers.
+                        * Note that it still has to be named later.
+                        */
+                       implicit_ctf_input_args.exists = true;
+                       ret = append_parameter_to_args(implicit_ctf_input_args.extra_params,
+                                       "paths", leftovers);
+                       if (ret) {
+                               goto error;
+                       }
+               }
+       }
+
+       /*
+        * Ensure mutual exclusion between implicit `source.ctf.fs` and
+        * `source.ctf.lttng-live` components.
+        */
+       if (implicit_ctf_input_args.exists && implicit_lttng_live_args.exists) {
+               printf_err("Cannot create both implicit `%s` and `%s` components\n",
+                       implicit_ctf_input_args.comp_arg->str,
+                       implicit_lttng_live_args.comp_arg->str);
+               goto error;
+       }
+
+       /*
+        * If the implicit `source.ctf.fs` or `source.ctf.lttng-live`
+        * components exists, make sure there's at least one leftover
+        * (which is the path or URL).
+        */
+       if (implicit_ctf_input_args.exists && bt_value_array_is_empty(leftovers)) {
+               printf_err("Missing path for implicit `%s` component\n",
+                       implicit_ctf_input_args.comp_arg->str);
+               goto error;
+       }
+
+       if (implicit_lttng_live_args.exists && bt_value_array_is_empty(leftovers)) {
+               printf_err("Missing URL for implicit `%s` component\n",
+                       implicit_lttng_live_args.comp_arg->str);
+               goto error;
+       }
+
+       /* Assign names to implicit components */
+       ret = assign_name_to_implicit_component(&implicit_ctf_input_args,
+               "source-ctf-fs", all_names, &source_names, true);
+       if (ret) {
+               goto error;
+       }
+
+       ret = assign_name_to_implicit_component(&implicit_lttng_live_args,
+               "lttng-live", all_names, &source_names, true);
+       if (ret) {
+               goto error;
+       }
+
+       ret = assign_name_to_implicit_component(&implicit_text_args,
+               "pretty", all_names, &sink_names, true);
+       if (ret) {
+               goto error;
+       }
+
+       ret = assign_name_to_implicit_component(&implicit_ctf_output_args,
+               "sink-ctf-fs", all_names, &sink_names, true);
+       if (ret) {
+               goto error;
+       }
+
+       ret = assign_name_to_implicit_component(&implicit_dummy_args,
+               "dummy", all_names, &sink_names, true);
+       if (ret) {
+               goto error;
+       }
+
+       ret = assign_name_to_implicit_component(&implicit_muxer_args,
+               "muxer", all_names, NULL, false);
+       if (ret) {
+               goto error;
+       }
+
+       ret = assign_name_to_implicit_component(&implicit_trimmer_args,
+               "trimmer", all_names, NULL, false);
+       if (ret) {
+               goto error;
+       }
+
+       ret = assign_name_to_implicit_component(&implicit_debug_info_args,
+               "debug-info", all_names, NULL, false);
+       if (ret) {
+               goto error;
+       }
+
+       /* Make sure there's at least one source and one sink */
+       if (!source_names) {
+               printf_err("No source component\n");
+               goto error;
+       }
+
+       if (!sink_names) {
+               printf_err("No sink component\n");
+               goto error;
+       }
+
+       /*
+        * Prepend the muxer, the trimmer, and the debug info to the
+        * filter chain so that we have:
+        *
+        *     sources -> muxer -> [trimmer] -> [debug info] ->
+        *                [user filters] -> sinks
+        */
+       if (implicit_debug_info_args.exists) {
+               if (g_list_prepend_gstring(&filter_names,
+                               implicit_debug_info_args.name_arg->str)) {
+                       goto error;
+               }
+       }
+
+       if (implicit_trimmer_args.exists) {
+               if (g_list_prepend_gstring(&filter_names,
+                               implicit_trimmer_args.name_arg->str)) {
+                       goto error;
+               }
+       }
+
+       if (g_list_prepend_gstring(&filter_names,
+                       implicit_muxer_args.name_arg->str)) {
+               goto error;
+       }
+
+       /*
+        * Append the equivalent run arguments for the implicit
+        * components.
+        */
+       ret = append_run_args_for_implicit_component(&implicit_ctf_input_args, run_args);
+       if (ret) {
+               goto error;
+       }
+
+       ret = append_run_args_for_implicit_component(&implicit_lttng_live_args,
+               run_args);
+       if (ret) {
+               goto error;
+       }
+
+       ret = append_run_args_for_implicit_component(&implicit_text_args,
+               run_args);
+       if (ret) {
+               goto error;
+       }
+
+       ret = append_run_args_for_implicit_component(&implicit_ctf_output_args,
+               run_args);
+       if (ret) {
+               goto error;
+       }
+
+       ret = append_run_args_for_implicit_component(&implicit_dummy_args,
+               run_args);
+       if (ret) {
+               goto error;
+       }
+
+       ret = append_run_args_for_implicit_component(&implicit_muxer_args,
+               run_args);
+       if (ret) {
+               goto error;
+       }
+
+       ret = append_run_args_for_implicit_component(&implicit_trimmer_args,
+               run_args);
+       if (ret) {
+               goto error;
+       }
+
+       ret = append_run_args_for_implicit_component(&implicit_debug_info_args,
+               run_args);
+       if (ret) {
+               goto error;
+       }
+
+       /* Auto-connect components */
+       ret = convert_auto_connect(run_args, source_names, filter_names,
+                       sink_names);
+       if (ret) {
+               printf_err("Cannot auto-connect components\n");
+               goto error;
+       }
+
+       /*
+        * We have all the run command arguments now. Depending on
+        * --run-args, we pass this to the run command or print them
+        * here.
+        */
+       if (print_run_args || print_run_args_0) {
+               if (stream_intersection_mode) {
+                       printf_err("Cannot specify --stream-intersection with --run-args or --run-args-0\n");
+                       goto error;
+               }
+
+               for (i = 0; i < bt_value_array_get_size(run_args); i++) {
+                       const bt_value *arg_value =
+                               bt_value_array_borrow_element_by_index(run_args,
+                                                                      i);
+                       const char *arg;
+                       GString *quoted = NULL;
+                       const char *arg_to_print;
+
+                       BT_ASSERT(arg_value);
+                       arg = bt_value_string_get(arg_value);
+
+                       if (print_run_args) {
+                               quoted = bt_common_shell_quote(arg, true);
+                               if (!quoted) {
+                                       goto error;
+                               }
+
+                               arg_to_print = quoted->str;
+                       } else {
+                               arg_to_print = arg;
+                       }
+
+                       printf("%s", arg_to_print);
+
+                       if (quoted) {
+                               g_string_free(quoted, TRUE);
+                       }
+
+                       if (i < bt_value_array_get_size(run_args) - 1) {
+                               if (print_run_args) {
+                                       putchar(' ');
+                               } else {
+                                       putchar('\0');
+                               }
+                       }
+               }
+
+               *retcode = -1;
+               BT_OBJECT_PUT_REF_AND_RESET(cfg);
+               goto end;
+       }
+
+       cfg = bt_config_run_from_args_array(run_args, retcode,
+                                           force_omit_system_plugin_path,
+                                           force_omit_home_plugin_path,
+                                           initial_plugin_paths);
+       if (!cfg) {
+               goto error;
+       }
+
+       cfg->cmd_data.run.stream_intersection_mode = stream_intersection_mode;
+       goto end;
+
+error:
+       *retcode = 1;
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+
+end:
+       if (pc) {
+               poptFreeContext(pc);
+       }
+
+       free(arg);
+       free(output);
+
+       if (cur_name) {
+               g_string_free(cur_name, TRUE);
+       }
+
+       if (cur_name_prefix) {
+               g_string_free(cur_name_prefix, TRUE);
+       }
+
+       bt_value_put_ref(run_args);
+       bt_value_put_ref(all_names);
+       destroy_glist_of_gstring(source_names);
+       destroy_glist_of_gstring(filter_names);
+       destroy_glist_of_gstring(sink_names);
+       bt_value_put_ref(leftovers);
+       finalize_implicit_component_args(&implicit_ctf_input_args);
+       finalize_implicit_component_args(&implicit_ctf_output_args);
+       finalize_implicit_component_args(&implicit_lttng_live_args);
+       finalize_implicit_component_args(&implicit_dummy_args);
+       finalize_implicit_component_args(&implicit_text_args);
+       finalize_implicit_component_args(&implicit_debug_info_args);
+       finalize_implicit_component_args(&implicit_muxer_args);
+       finalize_implicit_component_args(&implicit_trimmer_args);
+       bt_value_put_ref(plugin_paths);
+       bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
+       return cfg;
+}
+
+/*
+ * Prints the Babeltrace 2.x general usage.
+ */
+static
+void print_gen_usage(FILE *fp)
+{
+       fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [COMMAND] [COMMAND ARGUMENTS]\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "General options:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "  -d, --debug          Enable debug mode (same as --log-level=V)\n");
+       fprintf(fp, "  -h, --help           Show this help and quit\n");
+       fprintf(fp, "  -l, --log-level=LVL  Set all log levels to LVL (`N`, `V`, `D`,\n");
+       fprintf(fp, "                       `I`, `W` (default), `E`, or `F`)\n");
+       fprintf(fp, "  -v, --verbose        Enable verbose mode (same as --log-level=I)\n");
+       fprintf(fp, "  -V, --version        Show version and quit\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Available commands:\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "    convert       Convert and trim traces (default)\n");
+       fprintf(fp, "    help          Get help for a plugin or a component class\n");
+       fprintf(fp, "    list-plugins  List available plugins and their content\n");
+       fprintf(fp, "    query         Query objects from a component class\n");
+       fprintf(fp, "    run           Build a processing graph and run it\n");
+       fprintf(fp, "\n");
+       fprintf(fp, "Use `babeltrace2 COMMAND --help` to show the help of COMMAND.\n");
+}
+
+static
+char log_level_from_arg(const char *arg)
+{
+       char level = 'U';
+
+       if (strcmp(arg, "VERBOSE") == 0 ||
+                       strcmp(arg, "V") == 0) {
+               level = 'V';
+       } else if (strcmp(arg, "DEBUG") == 0 ||
+                       strcmp(arg, "D") == 0) {
+               level = 'D';
+       } else if (strcmp(arg, "INFO") == 0 ||
+                       strcmp(arg, "I") == 0) {
+               level = 'I';
+       } else if (strcmp(arg, "WARN") == 0 ||
+                       strcmp(arg, "WARNING") == 0 ||
+                       strcmp(arg, "W") == 0) {
+               level = 'W';
+       } else if (strcmp(arg, "ERROR") == 0 ||
+                       strcmp(arg, "E") == 0) {
+               level = 'E';
+       } else if (strcmp(arg, "FATAL") == 0 ||
+                       strcmp(arg, "F") == 0) {
+               level = 'F';
+       } else if (strcmp(arg, "NONE") == 0 ||
+                       strcmp(arg, "N") == 0) {
+               level = 'N';
+       }
+
+       return level;
+}
+
+struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
+               int *retcode, bool force_omit_system_plugin_path,
+               bool force_omit_home_plugin_path,
+               const bt_value *initial_plugin_paths)
+{
+       struct bt_config *config = NULL;
+       int i;
+       const char **command_argv = NULL;
+       int command_argc = -1;
+       const char *command_name = NULL;
+       char log_level = 'U';
+
+       enum command_type {
+               COMMAND_TYPE_NONE = -1,
+               COMMAND_TYPE_RUN = 0,
+               COMMAND_TYPE_CONVERT,
+               COMMAND_TYPE_LIST_PLUGINS,
+               COMMAND_TYPE_HELP,
+               COMMAND_TYPE_QUERY,
+       } command_type = COMMAND_TYPE_NONE;
+
+       *retcode = -1;
+
+       if (!initial_plugin_paths) {
+               initial_plugin_paths = bt_value_array_create();
+               if (!initial_plugin_paths) {
+                       *retcode = 1;
+                       goto end;
+               }
+       } else {
+               bt_value_get_ref(initial_plugin_paths);
+       }
+
+       if (argc <= 1) {
+               print_version();
+               puts("");
+               print_gen_usage(stdout);
+               goto end;
+       }
+
+       for (i = 1; i < argc; i++) {
+               const char *cur_arg = argv[i];
+               const char *next_arg = i == (argc - 1) ? NULL : argv[i + 1];
+
+               if (strcmp(cur_arg, "-d") == 0 ||
+                               strcmp(cur_arg, "--debug") == 0) {
+                       log_level = 'V';
+               } else if (strcmp(cur_arg, "-v") == 0 ||
+                               strcmp(cur_arg, "--verbose") == 0) {
+                       if (log_level != 'V' && log_level != 'D') {
+                               /*
+                                * Legacy: do not override a previous
+                                * --debug because --verbose and --debug
+                                * can be specified together (in this
+                                * case we want the lowest log level to
+                                * apply, VERBOSE).
+                                */
+                               log_level = 'I';
+                       }
+               } else if (strcmp(cur_arg, "--log-level") == 0 ||
+                               strcmp(cur_arg, "-l") == 0) {
+                       if (!next_arg) {
+                               printf_err("Missing log level value for --log-level option\n");
+                               *retcode = 1;
+                               goto end;
+                       }
+
+                       log_level = log_level_from_arg(next_arg);
+                       if (log_level == 'U') {
+                               printf_err("Invalid argument for --log-level option:\n    %s\n",
+                                       next_arg);
+                               *retcode = 1;
+                               goto end;
+                       }
+
+                       i++;
+               } else if (strncmp(cur_arg, "--log-level=", 12) == 0) {
+                       const char *arg = &cur_arg[12];
+
+                       log_level = log_level_from_arg(arg);
+                       if (log_level == 'U') {
+                               printf_err("Invalid argument for --log-level option:\n    %s\n",
+                                       arg);
+                               *retcode = 1;
+                               goto end;
+                       }
+               } else if (strncmp(cur_arg, "-l", 2) == 0) {
+                       const char *arg = &cur_arg[2];
+
+                       log_level = log_level_from_arg(arg);
+                       if (log_level == 'U') {
+                               printf_err("Invalid argument for --log-level option:\n    %s\n",
+                                       arg);
+                               *retcode = 1;
+                               goto end;
+                       }
+               } else if (strcmp(cur_arg, "-V") == 0 ||
+                               strcmp(cur_arg, "--version") == 0) {
+                       print_version();
+                       goto end;
+               } else if (strcmp(cur_arg, "-h") == 0 ||
+                               strcmp(cur_arg, "--help") == 0) {
+                       print_gen_usage(stdout);
+                       goto end;
+               } else {
+                       /*
+                        * First unknown argument: is it a known command
+                        * name?
+                        */
+                       command_argv = &argv[i];
+                       command_argc = argc - i;
+
+                       if (strcmp(cur_arg, "convert") == 0) {
+                               command_type = COMMAND_TYPE_CONVERT;
+                       } else if (strcmp(cur_arg, "list-plugins") == 0) {
+                               command_type = COMMAND_TYPE_LIST_PLUGINS;
+                       } else if (strcmp(cur_arg, "help") == 0) {
+                               command_type = COMMAND_TYPE_HELP;
+                       } else if (strcmp(cur_arg, "query") == 0) {
+                               command_type = COMMAND_TYPE_QUERY;
+                       } else if (strcmp(cur_arg, "run") == 0) {
+                               command_type = COMMAND_TYPE_RUN;
+                       } else {
+                               /*
+                                * Unknown argument, but not a known
+                                * command name: assume the default
+                                * `convert` command.
+                                */
+                               command_type = COMMAND_TYPE_CONVERT;
+                               command_name = "convert";
+                               command_argv = &argv[i - 1];
+                               command_argc = argc - i + 1;
+                       }
+                       break;
+               }
+       }
+
+       if (command_type == COMMAND_TYPE_NONE) {
+               /*
+                * We only got non-help, non-version general options
+                * like --verbose and --debug, without any other
+                * arguments, so we can't do anything useful: print the
+                * usage and quit.
+                */
+               print_gen_usage(stdout);
+               goto end;
+       }
+
+       BT_ASSERT(command_argv);
+       BT_ASSERT(command_argc >= 0);
+
+       switch (command_type) {
+       case COMMAND_TYPE_RUN:
+               config = bt_config_run_from_args(command_argc, command_argv,
+                       retcode, force_omit_system_plugin_path,
+                       force_omit_home_plugin_path, initial_plugin_paths);
+               break;
+       case COMMAND_TYPE_CONVERT:
+               config = bt_config_convert_from_args(command_argc, command_argv,
+                       retcode, force_omit_system_plugin_path,
+                       force_omit_home_plugin_path,
+                       initial_plugin_paths, &log_level);
+               break;
+       case COMMAND_TYPE_LIST_PLUGINS:
+               config = bt_config_list_plugins_from_args(command_argc,
+                       command_argv, retcode, force_omit_system_plugin_path,
+                       force_omit_home_plugin_path, initial_plugin_paths);
+               break;
+       case COMMAND_TYPE_HELP:
+               config = bt_config_help_from_args(command_argc,
+                       command_argv, retcode, force_omit_system_plugin_path,
+                       force_omit_home_plugin_path, initial_plugin_paths);
+               break;
+       case COMMAND_TYPE_QUERY:
+               config = bt_config_query_from_args(command_argc,
+                       command_argv, retcode, force_omit_system_plugin_path,
+                       force_omit_home_plugin_path, initial_plugin_paths);
+               break;
+       default:
+               abort();
+       }
+
+       if (config) {
+               if (log_level == 'U') {
+                       log_level = 'W';
+               }
+
+               config->log_level = log_level;
+               config->command_name = command_name;
+       }
+
+end:
+       bt_value_put_ref(initial_plugin_paths);
+       return config;
+}
diff --git a/src/cli/babeltrace2-cfg-cli-args.h b/src/cli/babeltrace2-cfg-cli-args.h
new file mode 100644 (file)
index 0000000..8a458c2
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef CLI_BABELTRACE_CFG_CLI_ARGS_H
+#define CLI_BABELTRACE_CFG_CLI_ARGS_H
+
+/*
+ * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <babeltrace2/value.h>
+#include "lib/object.h"
+#include "compat/compiler.h"
+#include <babeltrace2/graph/component-class.h>
+#include <glib.h>
+
+#include "babeltrace2-cfg.h"
+
+struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
+               int *retcode, bool force_omit_system_plugin_path,
+               bool force_omit_home_plugin_path,
+               const bt_value *initial_plugin_paths);
+
+#endif /* CLI_BABELTRACE_CFG_CLI_ARGS_H */
diff --git a/src/cli/babeltrace2-cfg.c b/src/cli/babeltrace2-cfg.c
new file mode 100644 (file)
index 0000000..4c764a9
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Babeltrace trace converter - parameter parsing
+ *
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/common.h"
+#include <babeltrace2/babeltrace.h>
+#include <glib.h>
+#include "babeltrace2-cfg.h"
+
+static
+void destroy_gstring(void *data)
+{
+       g_string_free(data, TRUE);
+}
+
+/*
+ * Extracts the various paths from the string arg, delimited by ':',
+ * and appends them to the array value object plugin_paths.
+ */
+int bt_config_append_plugin_paths(
+               bt_value *plugin_paths, const char *arg)
+{
+       int ret = 0;
+       GPtrArray *dirs = g_ptr_array_new_with_free_func(destroy_gstring);
+       size_t i;
+
+       if (!dirs) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_common_append_plugin_path_dirs(arg, dirs);
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < dirs->len; i++) {
+               GString *dir = g_ptr_array_index(dirs, i);
+
+               ret = bt_value_array_append_string_element(
+                       plugin_paths, dir->str);
+               if (ret != BT_VALUE_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+end:
+       g_ptr_array_free(dirs, TRUE);
+       return ret;
+}
+
+void bt_config_connection_destroy(struct bt_config_connection *connection)
+{
+       if (!connection) {
+               return;
+       }
+
+       if (connection->upstream_comp_name) {
+               g_string_free(connection->upstream_comp_name, TRUE);
+       }
+
+       if (connection->downstream_comp_name) {
+               g_string_free(connection->downstream_comp_name, TRUE);
+       }
+
+       if (connection->upstream_port_glob) {
+               g_string_free(connection->upstream_port_glob, TRUE);
+       }
+
+       if (connection->downstream_port_glob) {
+               g_string_free(connection->downstream_port_glob, TRUE);
+       }
+
+       if (connection->arg) {
+               g_string_free(connection->arg, TRUE);
+       }
+
+       g_free(connection);
+}
diff --git a/src/cli/babeltrace2-cfg.h b/src/cli/babeltrace2-cfg.h
new file mode 100644 (file)
index 0000000..a5cc7fc
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef CLI_BABELTRACE_CFG_H
+#define CLI_BABELTRACE_CFG_H
+
+/*
+ * Babeltrace trace converter - CLI tool's configuration
+ *
+ * Copyright 2016-2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <babeltrace2/value.h>
+#include "lib/object.h"
+#include "compat/compiler.h"
+#include <babeltrace2/graph/component-class.h>
+#include <glib.h>
+
+enum bt_config_command {
+       BT_CONFIG_COMMAND_RUN,
+       BT_CONFIG_COMMAND_PRINT_CTF_METADATA,
+       BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS,
+       BT_CONFIG_COMMAND_LIST_PLUGINS,
+       BT_CONFIG_COMMAND_HELP,
+       BT_CONFIG_COMMAND_QUERY,
+};
+
+struct bt_config_component {
+       bt_object base;
+       bt_component_class_type type;
+       GString *plugin_name;
+       GString *comp_cls_name;
+       bt_value *params;
+       GString *instance_name;
+};
+
+struct bt_config_connection {
+       GString *upstream_comp_name;
+       GString *downstream_comp_name;
+       GString *upstream_port_glob;
+       GString *downstream_port_glob;
+       GString *arg;
+};
+
+struct bt_config {
+       bt_object base;
+       bool debug;
+       bool verbose;
+       bt_value *plugin_paths;
+       bool omit_system_plugin_path;
+       bool omit_home_plugin_path;
+       bool command_needs_plugins;
+       const char *command_name;
+       char log_level;
+       enum bt_config_command command;
+       union {
+               /* BT_CONFIG_COMMAND_RUN */
+               struct {
+                       /* Array of pointers to struct bt_config_component */
+                       GPtrArray *sources;
+
+                       /* Array of pointers to struct bt_config_component */
+                       GPtrArray *filters;
+
+                       /* Array of pointers to struct bt_config_component */
+                       GPtrArray *sinks;
+
+                       /* Array of pointers to struct bt_config_connection */
+                       GPtrArray *connections;
+
+                       /*
+                        * Number of microseconds to sleep when we need
+                        * to retry to run the graph.
+                        */
+                       uint64_t retry_duration_us;
+
+                       /*
+                        * Whether or not to trim the source trace to the
+                        * intersection of its streams.
+                        */
+                       bool stream_intersection_mode;
+               } run;
+
+               /* BT_CONFIG_COMMAND_HELP */
+               struct {
+                       struct bt_config_component *cfg_component;
+               } help;
+
+               /* BT_CONFIG_COMMAND_QUERY */
+               struct {
+                       GString *object;
+                       struct bt_config_component *cfg_component;
+               } query;
+
+               /* BT_CONFIG_COMMAND_PRINT_CTF_METADATA */
+               struct {
+                       GString *path;
+                       GString *output_path;
+               } print_ctf_metadata;
+
+               /* BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS */
+               struct {
+                       GString *url;
+                       GString *output_path;
+               } print_lttng_live_sessions;
+       } cmd_data;
+};
+
+static inline
+struct bt_config_component *bt_config_get_component(GPtrArray *array,
+               size_t index)
+{
+       struct bt_config_component *comp = g_ptr_array_index(array, index);
+
+       bt_object_get_ref(comp);
+       return comp;
+}
+
+int bt_config_append_plugin_paths(bt_value *plugin_paths,
+               const char *arg);
+
+void bt_config_connection_destroy(struct bt_config_connection *connection);
+
+#endif /* CLI_BABELTRACE_CFG_H */
diff --git a/src/cli/babeltrace2-log.c b/src/cli/babeltrace2-log.c
new file mode 100644 (file)
index 0000000..59f34e5
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include "common/assert.h"
+#include <babeltrace2/babeltrace.h>
+#include <popt.h>
+#include <glib.h>
+
+static
+void print_usage(FILE *fp)
+{
+       fprintf(stderr, "Usage: babeltrace2-log [OPTIONS] OUTPUT-PATH\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Options:\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "  -t, --with-timestamps  Extract timestamps from lines and map them to\n");
+       fprintf(stderr, "                         a CTF clock class\n");
+}
+
+static
+int parse_params(int argc, char *argv[], char **output_path,
+               bool *no_extract_ts)
+{
+       enum {
+               OPT_WITH_TIMESTAMPS = 1,
+               OPT_HELP = 2,
+       };
+       static struct poptOption opts[] = {
+               { "with-timestamps", 't', POPT_ARG_NONE, NULL, OPT_WITH_TIMESTAMPS, NULL, NULL },
+               { "help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL },
+               { NULL, '\0', 0, NULL, 0, NULL, NULL },
+       };
+       poptContext pc = NULL;
+       int opt;
+       int ret = 0;
+       const char *leftover;
+
+       *no_extract_ts = true;
+       pc = poptGetContext(NULL, argc, (const char **) argv, opts, 0);
+       if (!pc) {
+               fprintf(stderr, "Cannot get popt context\n");
+               goto error;
+       }
+
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) > 0) {
+               switch (opt) {
+               case OPT_HELP:
+                       print_usage(stdout);
+                       goto end;
+               case OPT_WITH_TIMESTAMPS:
+                       *no_extract_ts = false;
+                       break;
+               default:
+                       fprintf(stderr, "Unknown command-line option specified (option code %d)\n",
+                               opt);
+                       goto error;
+               }
+       }
+
+       if (opt < -1) {
+               fprintf(stderr, "While parsing command-line options, at option %s: %s\n",
+                       poptBadOption(pc, 0), poptStrerror(opt));
+               goto error;
+       }
+
+       leftover = poptGetArg(pc);
+       if (!leftover) {
+               fprintf(stderr, "Command line error: Missing output path\n");
+               print_usage(stderr);
+               goto error;
+       }
+
+       *output_path = strdup(leftover);
+       BT_ASSERT(*output_path);
+       goto end;
+
+error:
+       ret = 1;
+
+end:
+       if (pc) {
+               poptFreeContext(pc);
+       }
+
+       return ret;
+}
+
+int main(int argc, char *argv[])
+{
+       char *output_path = NULL;
+       bool no_extract_ts;
+       int retcode;
+       GError *error = NULL;
+       gchar *bt_argv[] = {
+               BT_CLI_PATH,
+               "run",
+               "--component",
+               "dmesg:src.text.dmesg",
+               "--params",
+               NULL, /* no-extract-timestamp=? placeholder */
+               "--component",
+               "ctf:sink.ctf.fs",
+               "--key",
+               "path",
+               "--value",
+               NULL, /* output path placeholder */
+               "--params",
+               "single-trace=yes",
+               "--connect",
+               "dmesg:ctf",
+               NULL, /* sentinel */
+       };
+
+       retcode = parse_params(argc, argv, &output_path, &no_extract_ts);
+       if (retcode) {
+               goto end;
+       }
+
+       if (no_extract_ts) {
+               bt_argv[5] = "no-extract-timestamp=yes";
+       } else {
+               bt_argv[5] = "no-extract-timestamp=no";
+       }
+
+       bt_argv[11] = output_path;
+       (void) g_spawn_sync(NULL, bt_argv, NULL,
+               G_SPAWN_CHILD_INHERITS_STDIN, NULL, NULL,
+               NULL, NULL, &retcode, &error);
+
+       if (error) {
+               fprintf(stderr, "Failed to execute \"%s\": %s (%d)\n",
+                       bt_argv[0], error->message, error->code);
+       }
+
+end:
+       free(output_path);
+
+       if (error) {
+               g_error_free(error);
+       }
+
+       return retcode;
+}
diff --git a/src/cli/babeltrace2.c b/src/cli/babeltrace2.c
new file mode 100644 (file)
index 0000000..b4285e5
--- /dev/null
@@ -0,0 +1,2950 @@
+/*
+ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
+ *
+ * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CLI"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/common.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <popt.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <signal.h>
+#include "babeltrace2-cfg.h"
+#include "babeltrace2-cfg-cli-args.h"
+#include "babeltrace2-cfg-cli-args-default.h"
+
+#define ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH "BABELTRACE_CLI_WARN_COMMAND_NAME_DIRECTORY_CLASH"
+#define ENV_BABELTRACE_CLI_LOG_LEVEL "BABELTRACE_CLI_LOG_LEVEL"
+#define NSEC_PER_SEC   1000000000LL
+
+/*
+ * Known environment variable names for the log levels of the project's
+ * modules.
+ */
+static const char* log_level_env_var_names[] = {
+       "BABELTRACE_COMMON_LOG_LEVEL",
+       "BABELTRACE_COMPAT_LOG_LEVEL",
+       "BABELTRACE_CTFSER_LOG_LEVEL",
+       "BABELTRACE_FD_CACHE_LOG_LEVEL",
+       "BABELTRACE_FLT_LTTNG_UTILS_DEBUG_INFO_LOG_LEVEL",
+       "BABELTRACE_FLT_UTILS_COUNTER_LOG_LEVEL",
+       "BABELTRACE_FLT_UTILS_MUXER_LOG_LEVEL",
+       "BABELTRACE_FLT_UTILS_TRIMMER_LOG_LEVEL",
+       "BABELTRACE_PLUGIN_CTF_BFCR_LOG_LEVEL",
+       "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL",
+       "BABELTRACE_PLUGIN_CTF_MSG_ITER_LOG_LEVEL",
+       "BABELTRACE_PLUGIN_CTF_UTILS_LOG_LEVEL",
+       "BABELTRACE_PYTHON_BT2_LOG_LEVEL",
+       "BABELTRACE_SINK_CTF_FS_LOG_LEVEL",
+       "BABELTRACE_SINK_TEXT_PRETTY_LOG_LEVEL",
+       "BABELTRACE_SRC_CTF_FS_LOG_LEVEL",
+       "BABELTRACE_SRC_CTF_LTTNG_LIVE_LOG_LEVEL",
+       "BABELTRACE_SRC_TEXT_DMESG_LOG_LEVEL",
+       NULL,
+};
+
+/* Application's processing graph (weak) */
+static bt_graph *the_graph;
+static bt_query_executor *the_query_executor;
+static bool canceled = false;
+
+GPtrArray *loaded_plugins;
+
+#ifdef __MINGW32__
+
+#include <windows.h>
+
+static
+BOOL WINAPI signal_handler(DWORD signal) {
+       if (the_graph) {
+               bt_graph_cancel(the_graph);
+       }
+
+       canceled = true;
+
+       return TRUE;
+}
+
+static
+void set_signal_handler(void)
+{
+       if (!SetConsoleCtrlHandler(signal_handler, TRUE)) {
+               BT_LOGE("Failed to set the ctrl+c handler.");
+       }
+}
+
+#else /* __MINGW32__ */
+
+static
+void signal_handler(int signum)
+{
+       if (signum != SIGINT) {
+               return;
+       }
+
+       if (the_graph) {
+               bt_graph_cancel(the_graph);
+       }
+
+       if (the_query_executor) {
+               bt_query_executor_cancel(the_query_executor);
+       }
+
+       canceled = true;
+}
+
+static
+void set_signal_handler(void)
+{
+       struct sigaction new_action, old_action;
+
+       new_action.sa_handler = signal_handler;
+       sigemptyset(&new_action.sa_mask);
+       new_action.sa_flags = 0;
+       sigaction(SIGINT, NULL, &old_action);
+
+       if (old_action.sa_handler != SIG_IGN) {
+               sigaction(SIGINT, &new_action, NULL);
+       }
+}
+
+#endif /* __MINGW32__ */
+
+static
+void init_static_data(void)
+{
+       loaded_plugins = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_put_ref);
+}
+
+static
+void fini_static_data(void)
+{
+       g_ptr_array_free(loaded_plugins, TRUE);
+}
+
+static
+int create_the_query_executor(void)
+{
+       int ret = 0;
+
+       the_query_executor = bt_query_executor_create();
+       if (!the_query_executor) {
+               BT_LOGE_STR("Cannot create a query executor.");
+               ret = -1;
+       }
+
+       return ret;
+}
+
+static
+void destroy_the_query_executor(void)
+{
+       BT_QUERY_EXECUTOR_PUT_REF_AND_RESET(the_query_executor);
+}
+
+static
+int query(const bt_component_class *comp_cls, const char *obj,
+               const bt_value *params, const bt_value **user_result,
+               const char **fail_reason)
+{
+       const bt_value *result = NULL;
+       bt_query_executor_status status;
+       *fail_reason = "unknown error";
+       int ret = 0;
+
+       BT_ASSERT(fail_reason);
+       BT_ASSERT(user_result);
+       ret = create_the_query_executor();
+       if (ret) {
+               /* create_the_query_executor() logs errors */
+               goto end;
+       }
+
+       if (canceled) {
+               BT_LOGI("Canceled by user before executing the query: "
+                       "comp-cls-addr=%p, comp-cls-name=\"%s\", "
+                       "query-obj=\"%s\"", comp_cls,
+                       bt_component_class_get_name(comp_cls), obj);
+               *fail_reason = "canceled by user";
+               goto error;
+       }
+
+       while (true) {
+               status = bt_query_executor_query(the_query_executor,
+                       comp_cls, obj, params, &result);
+               switch (status) {
+               case BT_QUERY_EXECUTOR_STATUS_OK:
+                       goto ok;
+               case BT_QUERY_EXECUTOR_STATUS_AGAIN:
+               {
+                       const uint64_t sleep_time_us = 100000;
+
+                       /* Wait 100 ms and retry */
+                       BT_LOGV("Got BT_QUERY_EXECUTOR_STATUS_AGAIN: sleeping: "
+                               "time-us=%" PRIu64, sleep_time_us);
+
+                       if (usleep(sleep_time_us)) {
+                               if (bt_query_executor_is_canceled(the_query_executor)) {
+                                       BT_LOGI("Query was canceled by user: "
+                                               "comp-cls-addr=%p, comp-cls-name=\"%s\", "
+                                               "query-obj=\"%s\"", comp_cls,
+                                               bt_component_class_get_name(comp_cls),
+                                               obj);
+                                       *fail_reason = "canceled by user";
+                                       goto error;
+                               }
+                       }
+
+                       continue;
+               }
+               case BT_QUERY_EXECUTOR_STATUS_CANCELED:
+                       *fail_reason = "canceled by user";
+                       goto error;
+               case BT_QUERY_EXECUTOR_STATUS_ERROR:
+                       goto error;
+               case BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT:
+                       *fail_reason = "invalid or unknown query object";
+                       goto error;
+               case BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS:
+                       *fail_reason = "invalid query parameters";
+                       goto error;
+               case BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED:
+                       *fail_reason = "unsupported action";
+                       goto error;
+               case BT_QUERY_EXECUTOR_STATUS_NOMEM:
+                       *fail_reason = "not enough memory";
+                       goto error;
+               default:
+                       BT_LOGF("Unknown query status: status=%d", status);
+                       abort();
+               }
+       }
+
+ok:
+       *user_result = result;
+       result = NULL;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       destroy_the_query_executor();
+       bt_value_put_ref(result);
+       return ret;
+}
+
+static
+const bt_plugin *find_plugin(const char *name)
+{
+       int i;
+       const bt_plugin *plugin = NULL;
+
+       BT_ASSERT(name);
+       BT_LOGD("Finding plugin: name=\"%s\"", name);
+
+       for (i = 0; i < loaded_plugins->len; i++) {
+               plugin = g_ptr_array_index(loaded_plugins, i);
+
+               if (strcmp(name, bt_plugin_get_name(plugin)) == 0) {
+                       break;
+               }
+
+               plugin = NULL;
+       }
+
+       if (BT_LOG_ON_DEBUG) {
+               if (plugin) {
+                       BT_LOGD("Found plugin: plugin-addr=%p", plugin);
+               } else {
+                       BT_LOGD("Cannot find plugin.");
+               }
+       }
+
+       bt_plugin_get_ref(plugin);
+       return plugin;
+}
+
+typedef const void *(*plugin_borrow_comp_cls_func_t)(
+               const bt_plugin *, const char *);
+
+static
+const void *find_component_class_from_plugin(const char *plugin_name,
+               const char *comp_class_name,
+               plugin_borrow_comp_cls_func_t plugin_borrow_comp_cls_func)
+{
+       const void *comp_class = NULL;
+       const bt_plugin *plugin;
+
+       BT_LOGD("Finding component class: plugin-name=\"%s\", "
+               "comp-cls-name=\"%s\"", plugin_name, comp_class_name);
+
+       plugin = find_plugin(plugin_name);
+       if (!plugin) {
+               goto end;
+       }
+
+       comp_class = plugin_borrow_comp_cls_func(plugin, comp_class_name);
+       bt_object_get_ref(comp_class);
+       BT_PLUGIN_PUT_REF_AND_RESET(plugin);
+
+end:
+       if (BT_LOG_ON_DEBUG) {
+               if (comp_class) {
+                       BT_LOGD("Found component class: comp-cls-addr=%p",
+                               comp_class);
+               } else {
+                       BT_LOGD("Cannot find source component class.");
+               }
+       }
+
+       return comp_class;
+}
+
+static
+const bt_component_class_source *find_source_component_class(
+               const char *plugin_name, const char *comp_class_name)
+{
+       return (const void *) find_component_class_from_plugin(
+               plugin_name, comp_class_name,
+               (plugin_borrow_comp_cls_func_t)
+                       bt_plugin_borrow_source_component_class_by_name_const);
+}
+
+static
+const bt_component_class_filter *find_filter_component_class(
+               const char *plugin_name, const char *comp_class_name)
+{
+       return (const void *) find_component_class_from_plugin(
+               plugin_name, comp_class_name,
+               (plugin_borrow_comp_cls_func_t)
+                       bt_plugin_borrow_filter_component_class_by_name_const);
+}
+
+static
+const bt_component_class_sink *find_sink_component_class(
+               const char *plugin_name, const char *comp_class_name)
+{
+       return (const void *) find_component_class_from_plugin(plugin_name,
+               comp_class_name,
+               (plugin_borrow_comp_cls_func_t)
+                       bt_plugin_borrow_sink_component_class_by_name_const);
+}
+
+static
+const bt_component_class *find_component_class(const char *plugin_name,
+               const char *comp_class_name,
+               bt_component_class_type comp_class_type)
+{
+       const bt_component_class *comp_cls = NULL;
+
+       switch (comp_class_type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+               comp_cls = bt_component_class_source_as_component_class_const(find_source_component_class(plugin_name, comp_class_name));
+               break;
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+               comp_cls = bt_component_class_filter_as_component_class_const(find_filter_component_class(plugin_name, comp_class_name));
+               break;
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+               comp_cls = bt_component_class_sink_as_component_class_const(find_sink_component_class(plugin_name, comp_class_name));
+               break;
+       default:
+               abort();
+       }
+
+       return comp_cls;
+}
+
+static
+void print_indent(FILE *fp, size_t indent)
+{
+       size_t i;
+
+       for (i = 0; i < indent; i++) {
+               fprintf(fp, " ");
+       }
+}
+
+static
+const char *component_type_str(bt_component_class_type type)
+{
+       switch (type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+               return "source";
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+               return "sink";
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+               return "filter";
+       default:
+               return "(unknown)";
+       }
+}
+
+static
+void print_plugin_comp_cls_opt(FILE *fh, const char *plugin_name,
+               const char *comp_cls_name, bt_component_class_type type)
+{
+       GString *shell_plugin_name = NULL;
+       GString *shell_comp_cls_name = NULL;
+
+       shell_plugin_name = bt_common_shell_quote(plugin_name, false);
+       if (!shell_plugin_name) {
+               goto end;
+       }
+
+       shell_comp_cls_name = bt_common_shell_quote(comp_cls_name, false);
+       if (!shell_comp_cls_name) {
+               goto end;
+       }
+
+       fprintf(fh, "'%s%s%s%s.%s%s%s.%s%s%s'",
+               bt_common_color_bold(),
+               bt_common_color_fg_cyan(),
+               component_type_str(type),
+               bt_common_color_fg_default(),
+               bt_common_color_fg_blue(),
+               shell_plugin_name->str,
+               bt_common_color_fg_default(),
+               bt_common_color_fg_yellow(),
+               shell_comp_cls_name->str,
+               bt_common_color_reset());
+
+end:
+       if (shell_plugin_name) {
+               g_string_free(shell_plugin_name, TRUE);
+       }
+
+       if (shell_comp_cls_name) {
+               g_string_free(shell_comp_cls_name, TRUE);
+       }
+}
+
+static
+void print_value(FILE *, const bt_value *, size_t);
+
+static
+void print_value_rec(FILE *, const bt_value *, size_t);
+
+struct print_map_value_data {
+       size_t indent;
+       FILE *fp;
+};
+
+static
+bt_bool print_map_value(const char *key, const bt_value *object,
+               void *data)
+{
+       struct print_map_value_data *print_map_value_data = data;
+
+       print_indent(print_map_value_data->fp, print_map_value_data->indent);
+       fprintf(print_map_value_data->fp, "%s: ", key);
+       BT_ASSERT(object);
+
+       if (bt_value_is_array(object) &&
+                       bt_value_array_is_empty(object)) {
+               fprintf(print_map_value_data->fp, "[ ]\n");
+               return true;
+       }
+
+       if (bt_value_is_map(object) &&
+                       bt_value_map_is_empty(object)) {
+               fprintf(print_map_value_data->fp, "{ }\n");
+               return true;
+       }
+
+       if (bt_value_is_array(object) ||
+                       bt_value_is_map(object)) {
+               fprintf(print_map_value_data->fp, "\n");
+       }
+
+       print_value_rec(print_map_value_data->fp, object,
+               print_map_value_data->indent + 2);
+       return BT_TRUE;
+}
+
+static
+void print_value_rec(FILE *fp, const bt_value *value, size_t indent)
+{
+       bt_bool bool_val;
+       int64_t int_val;
+       uint64_t uint_val;
+       double dbl_val;
+       const char *str_val;
+       int size;
+       int i;
+
+       if (!value) {
+               return;
+       }
+
+       switch (bt_value_get_type(value)) {
+       case BT_VALUE_TYPE_NULL:
+               fprintf(fp, "%snull%s\n", bt_common_color_bold(),
+                       bt_common_color_reset());
+               break;
+       case BT_VALUE_TYPE_BOOL:
+               bool_val = bt_value_bool_get(value);
+               fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
+                       bt_common_color_fg_cyan(), bool_val ? "yes" : "no",
+                       bt_common_color_reset());
+               break;
+       case BT_VALUE_TYPE_UNSIGNED_INTEGER:
+               uint_val = bt_value_unsigned_integer_get(value);
+               fprintf(fp, "%s%s%" PRIu64 "%s\n", bt_common_color_bold(),
+                       bt_common_color_fg_red(), uint_val,
+                       bt_common_color_reset());
+               break;
+       case BT_VALUE_TYPE_SIGNED_INTEGER:
+               int_val = bt_value_signed_integer_get(value);
+               fprintf(fp, "%s%s%" PRId64 "%s\n", bt_common_color_bold(),
+                       bt_common_color_fg_red(), int_val,
+                       bt_common_color_reset());
+               break;
+       case BT_VALUE_TYPE_REAL:
+               dbl_val = bt_value_real_get(value);
+               fprintf(fp, "%s%s%lf%s\n", bt_common_color_bold(),
+                       bt_common_color_fg_red(), dbl_val,
+                       bt_common_color_reset());
+               break;
+       case BT_VALUE_TYPE_STRING:
+               str_val = bt_value_string_get(value);
+               fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
+                       bt_common_color_fg_green(), str_val,
+                       bt_common_color_reset());
+               break;
+       case BT_VALUE_TYPE_ARRAY:
+               size = bt_value_array_get_size(value);
+               if (size < 0) {
+                       goto error;
+               }
+
+               if (size == 0) {
+                       print_indent(fp, indent);
+                       fprintf(fp, "[ ]\n");
+                       break;
+               }
+
+               for (i = 0; i < size; i++) {
+                       const bt_value *element =
+                               bt_value_array_borrow_element_by_index_const(
+                                       value, i);
+
+                       if (!element) {
+                               goto error;
+                       }
+                       print_indent(fp, indent);
+                       fprintf(fp, "- ");
+
+                       if (bt_value_is_array(element) &&
+                                       bt_value_array_is_empty(element)) {
+                               fprintf(fp, "[ ]\n");
+                               continue;
+                       }
+
+                       if (bt_value_is_map(element) &&
+                                       bt_value_map_is_empty(element)) {
+                               fprintf(fp, "{ }\n");
+                               continue;
+                       }
+
+                       if (bt_value_is_array(element) ||
+                                       bt_value_is_map(element)) {
+                               fprintf(fp, "\n");
+                       }
+
+                       print_value_rec(fp, element, indent + 2);
+               }
+               break;
+       case BT_VALUE_TYPE_MAP:
+       {
+               struct print_map_value_data data = {
+                       .indent = indent,
+                       .fp = fp,
+               };
+
+               if (bt_value_map_is_empty(value)) {
+                       print_indent(fp, indent);
+                       fprintf(fp, "{ }\n");
+                       break;
+               }
+
+               bt_value_map_foreach_entry_const(value, print_map_value, &data);
+               break;
+       }
+       default:
+               abort();
+       }
+       return;
+
+error:
+       BT_LOGE("Error printing value of type %s.",
+               bt_common_value_type_string(bt_value_get_type(value)));
+}
+
+static
+void print_value(FILE *fp, const bt_value *value, size_t indent)
+{
+       if (!bt_value_is_array(value) && !bt_value_is_map(value)) {
+               print_indent(fp, indent);
+       }
+
+       print_value_rec(fp, value, indent);
+}
+
+static
+void print_bt_config_component(struct bt_config_component *bt_config_component)
+{
+       fprintf(stderr, "    ");
+       print_plugin_comp_cls_opt(stderr, bt_config_component->plugin_name->str,
+               bt_config_component->comp_cls_name->str,
+               bt_config_component->type);
+       fprintf(stderr, ":\n");
+
+       if (bt_config_component->instance_name->len > 0) {
+               fprintf(stderr, "      Name: %s\n",
+                       bt_config_component->instance_name->str);
+       }
+
+       fprintf(stderr, "      Parameters:\n");
+       print_value(stderr, bt_config_component->params, 8);
+}
+
+static
+void print_bt_config_components(GPtrArray *array)
+{
+       size_t i;
+
+       for (i = 0; i < array->len; i++) {
+               struct bt_config_component *cfg_component =
+                               bt_config_get_component(array, i);
+               print_bt_config_component(cfg_component);
+               BT_OBJECT_PUT_REF_AND_RESET(cfg_component);
+       }
+}
+
+static
+void print_plugin_paths(const bt_value *plugin_paths)
+{
+       fprintf(stderr, "  Plugin paths:\n");
+       print_value(stderr, plugin_paths, 4);
+}
+
+static
+void print_cfg_run(struct bt_config *cfg)
+{
+       size_t i;
+
+       print_plugin_paths(cfg->plugin_paths);
+       fprintf(stderr, "  Source component instances:\n");
+       print_bt_config_components(cfg->cmd_data.run.sources);
+
+       if (cfg->cmd_data.run.filters->len > 0) {
+               fprintf(stderr, "  Filter component instances:\n");
+               print_bt_config_components(cfg->cmd_data.run.filters);
+       }
+
+       fprintf(stderr, "  Sink component instances:\n");
+       print_bt_config_components(cfg->cmd_data.run.sinks);
+       fprintf(stderr, "  Connections:\n");
+
+       for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
+               struct bt_config_connection *cfg_connection =
+                       g_ptr_array_index(cfg->cmd_data.run.connections,
+                               i);
+
+               fprintf(stderr, "    %s%s%s -> %s%s%s\n",
+                       cfg_connection->upstream_comp_name->str,
+                       cfg_connection->upstream_port_glob->len > 0 ? "." : "",
+                       cfg_connection->upstream_port_glob->str,
+                       cfg_connection->downstream_comp_name->str,
+                       cfg_connection->downstream_port_glob->len > 0 ? "." : "",
+                       cfg_connection->downstream_port_glob->str);
+       }
+}
+
+static
+void print_cfg_list_plugins(struct bt_config *cfg)
+{
+       print_plugin_paths(cfg->plugin_paths);
+}
+
+static
+void print_cfg_help(struct bt_config *cfg)
+{
+       print_plugin_paths(cfg->plugin_paths);
+}
+
+static
+void print_cfg_print_ctf_metadata(struct bt_config *cfg)
+{
+       print_plugin_paths(cfg->plugin_paths);
+       fprintf(stderr, "  Path: %s\n",
+               cfg->cmd_data.print_ctf_metadata.path->str);
+}
+
+static
+void print_cfg_print_lttng_live_sessions(struct bt_config *cfg)
+{
+       print_plugin_paths(cfg->plugin_paths);
+       fprintf(stderr, "  URL: %s\n",
+               cfg->cmd_data.print_lttng_live_sessions.url->str);
+}
+
+static
+void print_cfg_query(struct bt_config *cfg)
+{
+       print_plugin_paths(cfg->plugin_paths);
+       fprintf(stderr, "  Object: `%s`\n", cfg->cmd_data.query.object->str);
+       fprintf(stderr, "  Component class:\n");
+       print_bt_config_component(cfg->cmd_data.query.cfg_component);
+}
+
+static
+void print_cfg(struct bt_config *cfg)
+{
+       if (!BT_LOG_ON_INFO) {
+               return;
+       }
+
+       BT_LOGI_STR("Configuration:");
+       fprintf(stderr, "  Debug mode: %s\n", cfg->debug ? "yes" : "no");
+       fprintf(stderr, "  Verbose mode: %s\n", cfg->verbose ? "yes" : "no");
+
+       switch (cfg->command) {
+       case BT_CONFIG_COMMAND_RUN:
+               print_cfg_run(cfg);
+               break;
+       case BT_CONFIG_COMMAND_LIST_PLUGINS:
+               print_cfg_list_plugins(cfg);
+               break;
+       case BT_CONFIG_COMMAND_HELP:
+               print_cfg_help(cfg);
+               break;
+       case BT_CONFIG_COMMAND_QUERY:
+               print_cfg_query(cfg);
+               break;
+       case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
+               print_cfg_print_ctf_metadata(cfg);
+               break;
+       case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
+               print_cfg_print_lttng_live_sessions(cfg);
+               break;
+       default:
+               abort();
+       }
+}
+
+static
+void add_to_loaded_plugins(const bt_plugin_set *plugin_set)
+{
+       int64_t i;
+       int64_t count;
+
+       count = bt_plugin_set_get_plugin_count(plugin_set);
+       BT_ASSERT(count >= 0);
+
+       for (i = 0; i < count; i++) {
+               const bt_plugin *plugin =
+                       bt_plugin_set_borrow_plugin_by_index_const(plugin_set, i);
+               const bt_plugin *loaded_plugin =
+                       find_plugin(bt_plugin_get_name(plugin));
+
+               BT_ASSERT(plugin);
+
+               if (loaded_plugin) {
+                       BT_LOGI("Not using plugin: another one already exists with the same name: "
+                               "plugin-name=\"%s\", plugin-path=\"%s\", "
+                               "existing-plugin-path=\"%s\"",
+                               bt_plugin_get_name(plugin),
+                               bt_plugin_get_path(plugin),
+                               bt_plugin_get_path(loaded_plugin));
+                       bt_plugin_put_ref(loaded_plugin);
+               } else {
+                       /* Add to global array. */
+                       BT_LOGD("Adding plugin to loaded plugins: plugin-path=\"%s\"",
+                               bt_plugin_get_name(plugin));
+                       bt_plugin_get_ref(plugin);
+                       g_ptr_array_add(loaded_plugins, (void *) plugin);
+               }
+       }
+}
+
+static
+int load_dynamic_plugins(const bt_value *plugin_paths)
+{
+       int nr_paths, i, ret = 0;
+
+       nr_paths = bt_value_array_get_size(plugin_paths);
+       if (nr_paths < 0) {
+               BT_LOGE_STR("Cannot load dynamic plugins: no plugin path.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGI("Loading dynamic plugins.");
+
+       for (i = 0; i < nr_paths; i++) {
+               const bt_value *plugin_path_value = NULL;
+               const char *plugin_path;
+               const bt_plugin_set *plugin_set;
+
+               plugin_path_value =
+                       bt_value_array_borrow_element_by_index_const(
+                               plugin_paths, i);
+               plugin_path = bt_value_string_get(plugin_path_value);
+
+               /*
+                * Skip this if the directory does not exist because
+                * bt_plugin_find_all_from_dir() expects an existing
+                * directory.
+                */
+               if (!g_file_test(plugin_path, G_FILE_TEST_IS_DIR)) {
+                       BT_LOGV("Skipping nonexistent directory path: "
+                               "path=\"%s\"", plugin_path);
+                       continue;
+               }
+
+               plugin_set = bt_plugin_find_all_from_dir(plugin_path, false);
+               if (!plugin_set) {
+                       BT_LOGD("Unable to load dynamic plugins: path=\"%s\"",
+                               plugin_path);
+                       continue;
+               }
+
+               add_to_loaded_plugins(plugin_set);
+               bt_plugin_set_put_ref(plugin_set);
+       }
+end:
+       return ret;
+}
+
+static
+int load_static_plugins(void)
+{
+       int ret = 0;
+       const bt_plugin_set *plugin_set;
+
+       BT_LOGI("Loading static plugins.");
+       plugin_set = bt_plugin_find_all_from_static();
+       if (!plugin_set) {
+               BT_LOGE("Unable to load static plugins.");
+               ret = -1;
+               goto end;
+       }
+
+       add_to_loaded_plugins(plugin_set);
+       bt_plugin_set_put_ref(plugin_set);
+end:
+       return ret;
+}
+
+static
+int load_all_plugins(const bt_value *plugin_paths)
+{
+       int ret = 0;
+
+       if (load_dynamic_plugins(plugin_paths)) {
+               ret = -1;
+               goto end;
+       }
+
+       if (load_static_plugins()) {
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGI("Loaded all plugins: count=%u", loaded_plugins->len);
+
+end:
+       return ret;
+}
+
+static
+void print_plugin_info(const bt_plugin *plugin)
+{
+       unsigned int major, minor, patch;
+       const char *extra;
+       bt_property_availability version_avail;
+       const char *plugin_name;
+       const char *path;
+       const char *author;
+       const char *license;
+       const char *plugin_description;
+
+       plugin_name = bt_plugin_get_name(plugin);
+       path = bt_plugin_get_path(plugin);
+       author = bt_plugin_get_author(plugin);
+       license = bt_plugin_get_license(plugin);
+       plugin_description = bt_plugin_get_description(plugin);
+       version_avail = bt_plugin_get_version(plugin, &major, &minor,
+               &patch, &extra);
+       printf("%s%s%s%s:\n", bt_common_color_bold(),
+               bt_common_color_fg_blue(), plugin_name,
+               bt_common_color_reset());
+       if (path) {
+               printf("  %sPath%s: %s\n", bt_common_color_bold(),
+                       bt_common_color_reset(), path);
+       } else {
+               puts("  Built-in");
+       }
+
+       if (version_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
+               printf("  %sVersion%s: %u.%u.%u",
+                       bt_common_color_bold(), bt_common_color_reset(),
+                       major, minor, patch);
+
+               if (extra) {
+                       printf("%s", extra);
+               }
+
+               printf("\n");
+       }
+
+       printf("  %sDescription%s: %s\n", bt_common_color_bold(),
+               bt_common_color_reset(),
+               plugin_description ? plugin_description : "(None)");
+       printf("  %sAuthor%s: %s\n", bt_common_color_bold(),
+               bt_common_color_reset(), author ? author : "(Unknown)");
+       printf("  %sLicense%s: %s\n", bt_common_color_bold(),
+               bt_common_color_reset(),
+               license ? license : "(Unknown)");
+}
+
+static
+int cmd_query(struct bt_config *cfg)
+{
+       int ret = 0;
+       const bt_component_class *comp_cls = NULL;
+       const bt_value *results = NULL;
+       const char *fail_reason = NULL;
+
+       comp_cls = find_component_class(
+               cfg->cmd_data.query.cfg_component->plugin_name->str,
+               cfg->cmd_data.query.cfg_component->comp_cls_name->str,
+               cfg->cmd_data.query.cfg_component->type);
+       if (!comp_cls) {
+               BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
+                       "comp-cls-name=\"%s\", comp-cls-type=%d",
+                       cfg->cmd_data.query.cfg_component->plugin_name->str,
+                       cfg->cmd_data.query.cfg_component->comp_cls_name->str,
+                       cfg->cmd_data.query.cfg_component->type);
+               fprintf(stderr, "%s%sCannot find component class %s",
+                       bt_common_color_bold(),
+                       bt_common_color_fg_red(),
+                       bt_common_color_reset());
+               print_plugin_comp_cls_opt(stderr,
+                       cfg->cmd_data.query.cfg_component->plugin_name->str,
+                       cfg->cmd_data.query.cfg_component->comp_cls_name->str,
+                       cfg->cmd_data.query.cfg_component->type);
+               fprintf(stderr, "\n");
+               ret = -1;
+               goto end;
+       }
+
+       ret = query(comp_cls, cfg->cmd_data.query.object->str,
+               cfg->cmd_data.query.cfg_component->params,
+               &results, &fail_reason);
+       if (ret) {
+               goto failed;
+       }
+
+       print_value(stdout, results, 0);
+       goto end;
+
+failed:
+       BT_LOGE("Failed to query component class: %s: plugin-name=\"%s\", "
+               "comp-cls-name=\"%s\", comp-cls-type=%d "
+               "object=\"%s\"", fail_reason,
+               cfg->cmd_data.query.cfg_component->plugin_name->str,
+               cfg->cmd_data.query.cfg_component->comp_cls_name->str,
+               cfg->cmd_data.query.cfg_component->type,
+               cfg->cmd_data.query.object->str);
+       fprintf(stderr, "%s%sFailed to query info to %s",
+               bt_common_color_bold(),
+               bt_common_color_fg_red(),
+               bt_common_color_reset());
+       print_plugin_comp_cls_opt(stderr,
+               cfg->cmd_data.query.cfg_component->plugin_name->str,
+               cfg->cmd_data.query.cfg_component->comp_cls_name->str,
+               cfg->cmd_data.query.cfg_component->type);
+       fprintf(stderr, "%s%s with object `%s`: %s%s\n",
+               bt_common_color_bold(),
+               bt_common_color_fg_red(),
+               cfg->cmd_data.query.object->str,
+               fail_reason,
+               bt_common_color_reset());
+       ret = -1;
+
+end:
+       bt_component_class_put_ref(comp_cls);
+       bt_value_put_ref(results);
+       return ret;
+}
+
+static
+void print_component_class_help(const char *plugin_name,
+               const bt_component_class *comp_cls)
+{
+       const char *comp_class_name =
+               bt_component_class_get_name(comp_cls);
+       const char *comp_class_description =
+               bt_component_class_get_description(comp_cls);
+       const char *comp_class_help =
+               bt_component_class_get_help(comp_cls);
+       bt_component_class_type type =
+               bt_component_class_get_type(comp_cls);
+
+       print_plugin_comp_cls_opt(stdout, plugin_name, comp_class_name, type);
+       printf("\n");
+       printf("  %sDescription%s: %s\n", bt_common_color_bold(),
+               bt_common_color_reset(),
+               comp_class_description ? comp_class_description : "(None)");
+
+       if (comp_class_help) {
+               printf("\n%s\n", comp_class_help);
+       }
+}
+
+static
+int cmd_help(struct bt_config *cfg)
+{
+       int ret = 0;
+       const bt_plugin *plugin = NULL;
+       const bt_component_class *needed_comp_cls = NULL;
+
+       plugin = find_plugin(cfg->cmd_data.help.cfg_component->plugin_name->str);
+       if (!plugin) {
+               BT_LOGE("Cannot find plugin: plugin-name=\"%s\"",
+                       cfg->cmd_data.help.cfg_component->plugin_name->str);
+               fprintf(stderr, "%s%sCannot find plugin %s%s%s\n",
+                       bt_common_color_bold(), bt_common_color_fg_red(),
+                       bt_common_color_fg_blue(),
+                       cfg->cmd_data.help.cfg_component->plugin_name->str,
+                       bt_common_color_reset());
+               ret = -1;
+               goto end;
+       }
+
+       print_plugin_info(plugin);
+       printf("  %sSource component classes%s: %d\n",
+                       bt_common_color_bold(),
+                       bt_common_color_reset(),
+                       (int) bt_plugin_get_source_component_class_count(plugin));
+       printf("  %sFilter component classes%s: %d\n",
+                       bt_common_color_bold(),
+                       bt_common_color_reset(),
+                       (int) bt_plugin_get_filter_component_class_count(plugin));
+       printf("  %sSink component classes%s: %d\n",
+                       bt_common_color_bold(),
+                       bt_common_color_reset(),
+                       (int) bt_plugin_get_sink_component_class_count(plugin));
+
+       if (strlen(cfg->cmd_data.help.cfg_component->comp_cls_name->str) == 0) {
+               /* Plugin help only */
+               goto end;
+       }
+
+       needed_comp_cls = find_component_class(
+               cfg->cmd_data.help.cfg_component->plugin_name->str,
+               cfg->cmd_data.help.cfg_component->comp_cls_name->str,
+               cfg->cmd_data.help.cfg_component->type);
+       if (!needed_comp_cls) {
+               BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
+                       "comp-cls-name=\"%s\", comp-cls-type=%d",
+                       cfg->cmd_data.help.cfg_component->plugin_name->str,
+                       cfg->cmd_data.help.cfg_component->comp_cls_name->str,
+                       cfg->cmd_data.help.cfg_component->type);
+               fprintf(stderr, "\n%s%sCannot find component class %s",
+                       bt_common_color_bold(),
+                       bt_common_color_fg_red(),
+                       bt_common_color_reset());
+               print_plugin_comp_cls_opt(stderr,
+                       cfg->cmd_data.help.cfg_component->plugin_name->str,
+                       cfg->cmd_data.help.cfg_component->comp_cls_name->str,
+                       cfg->cmd_data.help.cfg_component->type);
+               fprintf(stderr, "\n");
+               ret = -1;
+               goto end;
+       }
+
+       printf("\n");
+       print_component_class_help(
+               cfg->cmd_data.help.cfg_component->plugin_name->str,
+               needed_comp_cls);
+
+end:
+       bt_component_class_put_ref(needed_comp_cls);
+       bt_plugin_put_ref(plugin);
+       return ret;
+}
+
+typedef void *(* plugin_borrow_comp_cls_by_index_func_t)(const bt_plugin *,
+       uint64_t);
+typedef const bt_component_class *(* spec_comp_cls_borrow_comp_cls_func_t)(
+       void *);
+
+void cmd_list_plugins_print_component_classes(const bt_plugin *plugin,
+               const char *cc_type_name, uint64_t count,
+               plugin_borrow_comp_cls_by_index_func_t borrow_comp_cls_by_index_func,
+               spec_comp_cls_borrow_comp_cls_func_t spec_comp_cls_borrow_comp_cls_func)
+{
+       uint64_t i;
+
+       if (count == 0) {
+               printf("  %s%s component classes%s: (none)\n",
+                       bt_common_color_bold(),
+                       cc_type_name,
+                       bt_common_color_reset());
+               goto end;
+       } else {
+               printf("  %s%s component classes%s:\n",
+                       bt_common_color_bold(),
+                       cc_type_name,
+                       bt_common_color_reset());
+       }
+
+       for (i = 0; i < count; i++) {
+               const bt_component_class *comp_class =
+                       spec_comp_cls_borrow_comp_cls_func(
+                               borrow_comp_cls_by_index_func(plugin, i));
+               const char *comp_class_name =
+                       bt_component_class_get_name(comp_class);
+               const char *comp_class_description =
+                       bt_component_class_get_description(comp_class);
+               bt_component_class_type type =
+                       bt_component_class_get_type(comp_class);
+
+               printf("    ");
+               print_plugin_comp_cls_opt(stdout,
+                       bt_plugin_get_name(plugin), comp_class_name,
+                       type);
+
+               if (comp_class_description) {
+                       printf(": %s", comp_class_description);
+               }
+
+               printf("\n");
+       }
+
+end:
+       return;
+}
+
+static
+int cmd_list_plugins(struct bt_config *cfg)
+{
+       int ret = 0;
+       int plugins_count, component_classes_count = 0, i;
+
+       printf("From the following plugin paths:\n\n");
+       print_value(stdout, cfg->plugin_paths, 2);
+       printf("\n");
+       plugins_count = loaded_plugins->len;
+       if (plugins_count == 0) {
+               printf("No plugins found.\n");
+               goto end;
+       }
+
+       for (i = 0; i < plugins_count; i++) {
+               const bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
+
+               component_classes_count +=
+                       bt_plugin_get_source_component_class_count(plugin) +
+                       bt_plugin_get_filter_component_class_count(plugin) +
+                       bt_plugin_get_sink_component_class_count(plugin);
+       }
+
+       printf("Found %s%d%s component classes in %s%d%s plugins.\n",
+               bt_common_color_bold(),
+               component_classes_count,
+               bt_common_color_reset(),
+               bt_common_color_bold(),
+               plugins_count,
+               bt_common_color_reset());
+
+       for (i = 0; i < plugins_count; i++) {
+               const bt_plugin *plugin = g_ptr_array_index(loaded_plugins, i);
+
+               printf("\n");
+               print_plugin_info(plugin);
+               cmd_list_plugins_print_component_classes(plugin, "Source",
+                       bt_plugin_get_source_component_class_count(plugin),
+                       (plugin_borrow_comp_cls_by_index_func_t)
+                               bt_plugin_borrow_source_component_class_by_index_const,
+                       (spec_comp_cls_borrow_comp_cls_func_t)
+                               bt_component_class_source_as_component_class);
+               cmd_list_plugins_print_component_classes(plugin, "Filter",
+                       bt_plugin_get_filter_component_class_count(plugin),
+                       (plugin_borrow_comp_cls_by_index_func_t)
+                               bt_plugin_borrow_filter_component_class_by_index_const,
+                       (spec_comp_cls_borrow_comp_cls_func_t)
+                               bt_component_class_filter_as_component_class);
+               cmd_list_plugins_print_component_classes(plugin, "Sink",
+                       bt_plugin_get_sink_component_class_count(plugin),
+                       (plugin_borrow_comp_cls_by_index_func_t)
+                               bt_plugin_borrow_sink_component_class_by_index_const,
+                       (spec_comp_cls_borrow_comp_cls_func_t)
+                               bt_component_class_sink_as_component_class);
+       }
+
+end:
+       return ret;
+}
+
+static
+int cmd_print_lttng_live_sessions(struct bt_config *cfg)
+{
+       int ret = 0;
+       const bt_component_class *comp_cls = NULL;
+       const bt_value *results = NULL;
+       bt_value *params = NULL;
+       const bt_value *map = NULL;
+       const bt_value *v = NULL;
+       static const char * const plugin_name = "ctf";
+       static const char * const comp_cls_name = "lttng-live";
+       static const bt_component_class_type comp_cls_type =
+               BT_COMPONENT_CLASS_TYPE_SOURCE;
+       int64_t array_size, i;
+       const char *fail_reason = NULL;
+       FILE *out_stream = stdout;
+
+       BT_ASSERT(cfg->cmd_data.print_lttng_live_sessions.url);
+       comp_cls = find_component_class(plugin_name, comp_cls_name,
+               comp_cls_type);
+       if (!comp_cls) {
+               BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
+                       "comp-cls-name=\"%s\", comp-cls-type=%d",
+                       plugin_name, comp_cls_name,
+                       BT_COMPONENT_CLASS_TYPE_SOURCE);
+               fprintf(stderr, "%s%sCannot find component class %s",
+                       bt_common_color_bold(),
+                       bt_common_color_fg_red(),
+                       bt_common_color_reset());
+               print_plugin_comp_cls_opt(stderr, plugin_name,
+                       comp_cls_name, comp_cls_type);
+               fprintf(stderr, "\n");
+               goto error;
+       }
+
+       params = bt_value_map_create();
+       if (!params) {
+               goto error;
+       }
+
+       ret = bt_value_map_insert_string_entry(params, "url",
+               cfg->cmd_data.print_lttng_live_sessions.url->str);
+       if (ret) {
+               goto error;
+       }
+
+       ret = query(comp_cls, "sessions", params,
+                   &results, &fail_reason);
+       if (ret) {
+               goto failed;
+       }
+
+       BT_ASSERT(results);
+
+       if (!bt_value_is_array(results)) {
+               BT_LOGE_STR("Expecting an array for sessions query.");
+               fprintf(stderr, "%s%sUnexpected type returned by session query%s\n",
+                       bt_common_color_bold(),
+                       bt_common_color_fg_red(),
+                       bt_common_color_reset());
+               goto error;
+       }
+
+       if (cfg->cmd_data.print_lttng_live_sessions.output_path->len > 0) {
+               out_stream =
+                       fopen(cfg->cmd_data.print_lttng_live_sessions.output_path->str,
+                               "w");
+               if (!out_stream) {
+                       ret = -1;
+                       BT_LOGE_ERRNO("Cannot open file for writing",
+                               ": path=\"%s\"",
+                               cfg->cmd_data.print_lttng_live_sessions.output_path->str);
+                       goto end;
+               }
+       }
+
+       array_size = bt_value_array_get_size(results);
+       for (i = 0; i < array_size; i++) {
+               const char *url_text;
+               int64_t timer_us, streams, clients;
+
+               map = bt_value_array_borrow_element_by_index_const(results, i);
+               if (!map) {
+                       BT_LOGE_STR("Unexpected empty array entry.");
+                       goto error;
+               }
+               if (!bt_value_is_map(map)) {
+                       BT_LOGE_STR("Unexpected entry type.");
+                       goto error;
+               }
+
+               v = bt_value_map_borrow_entry_value_const(map, "url");
+               if (!v) {
+                       BT_LOGE_STR("Unexpected empty array \"url\" entry.");
+                       goto error;
+               }
+               url_text = bt_value_string_get(v);
+               fprintf(out_stream, "%s", url_text);
+               v = bt_value_map_borrow_entry_value_const(map, "timer-us");
+               if (!v) {
+                       BT_LOGE_STR("Unexpected empty array \"timer-us\" entry.");
+                       goto error;
+               }
+               timer_us = bt_value_signed_integer_get(v);
+               fprintf(out_stream, " (timer = %" PRIu64 ", ", timer_us);
+               v = bt_value_map_borrow_entry_value_const(map, "stream-count");
+               if (!v) {
+                       BT_LOGE_STR("Unexpected empty array \"stream-count\" entry.");
+                       goto error;
+               }
+               streams = bt_value_signed_integer_get(v);
+               fprintf(out_stream, "%" PRIu64 " stream(s), ", streams);
+               v = bt_value_map_borrow_entry_value_const(map, "client-count");
+               if (!v) {
+                       BT_LOGE_STR("Unexpected empty array \"client-count\" entry.");
+                       goto error;
+               }
+               clients = bt_value_signed_integer_get(v);
+               fprintf(out_stream, "%" PRIu64 " client(s) connected)\n", clients);
+       }
+
+       goto end;
+
+failed:
+       BT_LOGE("Failed to query for sessions: %s", fail_reason);
+       fprintf(stderr, "%s%sFailed to request sessions: %s%s\n",
+               bt_common_color_bold(),
+               bt_common_color_fg_red(),
+               fail_reason,
+               bt_common_color_reset());
+
+error:
+       ret = -1;
+
+end:
+       bt_value_put_ref(results);
+       bt_value_put_ref(params);
+       bt_component_class_put_ref(comp_cls);
+
+       if (out_stream && out_stream != stdout) {
+               int fclose_ret = fclose(out_stream);
+
+               if (fclose_ret) {
+                       BT_LOGE_ERRNO("Cannot close file stream",
+                               ": path=\"%s\"",
+                               cfg->cmd_data.print_lttng_live_sessions.output_path->str);
+               }
+       }
+
+       return ret;
+}
+
+static
+int cmd_print_ctf_metadata(struct bt_config *cfg)
+{
+       int ret = 0;
+       const bt_component_class *comp_cls = NULL;
+       const bt_value *results = NULL;
+       bt_value *params = NULL;
+       const bt_value *metadata_text_value = NULL;
+       const char *metadata_text = NULL;
+       static const char * const plugin_name = "ctf";
+       static const char * const comp_cls_name = "fs";
+       static const bt_component_class_type comp_cls_type =
+               BT_COMPONENT_CLASS_TYPE_SOURCE;
+       const char *fail_reason = NULL;
+       FILE *out_stream = stdout;
+
+       BT_ASSERT(cfg->cmd_data.print_ctf_metadata.path);
+       comp_cls = find_component_class(plugin_name, comp_cls_name,
+               comp_cls_type);
+       if (!comp_cls) {
+               BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
+                       "comp-cls-name=\"%s\", comp-cls-type=%d",
+                       plugin_name, comp_cls_name,
+                       BT_COMPONENT_CLASS_TYPE_SOURCE);
+               fprintf(stderr, "%s%sCannot find component class %s",
+                       bt_common_color_bold(),
+                       bt_common_color_fg_red(),
+                       bt_common_color_reset());
+               print_plugin_comp_cls_opt(stderr, plugin_name,
+                       comp_cls_name, comp_cls_type);
+               fprintf(stderr, "\n");
+               ret = -1;
+               goto end;
+       }
+
+       params = bt_value_map_create();
+       if (!params) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_value_map_insert_string_entry(params, "path",
+               cfg->cmd_data.print_ctf_metadata.path->str);
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = query(comp_cls, "metadata-info",
+               params, &results, &fail_reason);
+       if (ret) {
+               goto failed;
+       }
+
+       metadata_text_value = bt_value_map_borrow_entry_value_const(results,
+                                                                   "text");
+       if (!metadata_text_value) {
+               BT_LOGE_STR("Cannot find `text` string value in the resulting metadata info object.");
+               ret = -1;
+               goto end;
+       }
+
+       metadata_text = bt_value_string_get(metadata_text_value);
+
+       if (cfg->cmd_data.print_ctf_metadata.output_path->len > 0) {
+               out_stream =
+                       fopen(cfg->cmd_data.print_ctf_metadata.output_path->str,
+                               "w");
+               if (!out_stream) {
+                       ret = -1;
+                       BT_LOGE_ERRNO("Cannot open file for writing",
+                               ": path=\"%s\"",
+                               cfg->cmd_data.print_ctf_metadata.output_path->str);
+                       goto end;
+               }
+       }
+
+       ret = fprintf(out_stream, "%s\n", metadata_text);
+       if (ret < 0) {
+               BT_LOGE("Cannot write whole metadata text to output stream: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       ret = 0;
+
+       goto end;
+
+failed:
+       ret = -1;
+       BT_LOGE("Failed to query for metadata info: %s", fail_reason);
+       fprintf(stderr, "%s%sFailed to request metadata info: %s%s\n",
+               bt_common_color_bold(),
+               bt_common_color_fg_red(),
+               fail_reason,
+               bt_common_color_reset());
+
+end:
+       bt_value_put_ref(results);
+       bt_value_put_ref(params);
+       bt_component_class_put_ref(comp_cls);
+
+       if (out_stream && out_stream != stdout) {
+               int fclose_ret = fclose(out_stream);
+
+               if (fclose_ret) {
+                       BT_LOGE_ERRNO("Cannot close file stream",
+                               ": path=\"%s\"",
+                               cfg->cmd_data.print_ctf_metadata.output_path->str);
+               }
+       }
+
+       return ret;
+}
+
+struct port_id {
+       char *instance_name;
+       char *port_name;
+};
+
+struct trace_range {
+       uint64_t intersection_range_begin_ns;
+       uint64_t intersection_range_end_ns;
+};
+
+static
+guint port_id_hash(gconstpointer v)
+{
+       const struct port_id *id = v;
+
+       BT_ASSERT(id->instance_name);
+       BT_ASSERT(id->port_name);
+
+       return g_str_hash(id->instance_name) ^ g_str_hash(id->port_name);
+}
+
+static
+gboolean port_id_equal(gconstpointer v1, gconstpointer v2)
+{
+       const struct port_id *id1 = v1;
+       const struct port_id *id2 = v2;
+
+       return !strcmp(id1->instance_name, id2->instance_name) &&
+               !strcmp(id1->port_name, id2->port_name);
+}
+
+static
+void port_id_destroy(gpointer data)
+{
+       struct port_id *id = data;
+
+       free(id->instance_name);
+       free(id->port_name);
+       free(id);
+}
+
+static
+void trace_range_destroy(gpointer data)
+{
+       free(data);
+}
+
+struct cmd_run_ctx {
+       /* Owned by this */
+       GHashTable *src_components;
+
+       /* Owned by this */
+       GHashTable *flt_components;
+
+       /* Owned by this */
+       GHashTable *sink_components;
+
+       /* Owned by this */
+       bt_graph *graph;
+
+       /* Weak */
+       struct bt_config *cfg;
+
+       bool connect_ports;
+
+       bool stream_intersection_mode;
+
+       /*
+        * Association of struct port_id -> struct trace_range.
+        */
+       GHashTable *intersections;
+};
+
+/* Returns a timestamp of the form "(-)s.ns" */
+static
+char *s_from_ns(int64_t ns)
+{
+       int ret;
+       char *s_ret = NULL;
+       bool is_negative;
+       int64_t ts_sec_abs, ts_nsec_abs;
+       int64_t ts_sec = ns / NSEC_PER_SEC;
+       int64_t ts_nsec = ns % NSEC_PER_SEC;
+
+       if (ts_sec >= 0 && ts_nsec >= 0) {
+               is_negative = false;
+               ts_sec_abs = ts_sec;
+               ts_nsec_abs = ts_nsec;
+       } else if (ts_sec > 0 && ts_nsec < 0) {
+               is_negative = false;
+               ts_sec_abs = ts_sec - 1;
+               ts_nsec_abs = NSEC_PER_SEC + ts_nsec;
+       } else if (ts_sec == 0 && ts_nsec < 0) {
+               is_negative = true;
+               ts_sec_abs = ts_sec;
+               ts_nsec_abs = -ts_nsec;
+       } else if (ts_sec < 0 && ts_nsec > 0) {
+               is_negative = true;
+               ts_sec_abs = -(ts_sec + 1);
+               ts_nsec_abs = NSEC_PER_SEC - ts_nsec;
+       } else if (ts_sec < 0 && ts_nsec == 0) {
+               is_negative = true;
+               ts_sec_abs = -ts_sec;
+               ts_nsec_abs = ts_nsec;
+       } else {        /* (ts_sec < 0 && ts_nsec < 0) */
+               is_negative = true;
+               ts_sec_abs = -ts_sec;
+               ts_nsec_abs = -ts_nsec;
+       }
+
+       ret = asprintf(&s_ret, "%s%" PRId64 ".%09" PRId64,
+               is_negative ? "-" : "", ts_sec_abs, ts_nsec_abs);
+       if (ret < 0) {
+               s_ret = NULL;
+       }
+       return s_ret;
+}
+
+static
+int cmd_run_ctx_connect_upstream_port_to_downstream_component(
+               struct cmd_run_ctx *ctx,
+               const bt_component *upstream_comp,
+               const bt_port_output *out_upstream_port,
+               struct bt_config_connection *cfg_conn)
+{
+       typedef uint64_t (*input_port_count_func_t)(void *);
+       typedef const bt_port_input *(*borrow_input_port_by_index_func_t)(
+               const void *, uint64_t);
+       const bt_port *upstream_port =
+               bt_port_output_as_port_const(out_upstream_port);
+
+       int ret = 0;
+       GQuark downstreamp_comp_name_quark;
+       void *downstream_comp;
+       uint64_t downstream_port_count;
+       uint64_t i;
+       input_port_count_func_t port_count_fn;
+       borrow_input_port_by_index_func_t port_by_index_fn;
+       bt_graph_status status = BT_GRAPH_STATUS_ERROR;
+       bool insert_trimmer = false;
+       bt_value *trimmer_params = NULL;
+       char *intersection_begin = NULL;
+       char *intersection_end = NULL;
+       const bt_component_filter *trimmer = NULL;
+       const bt_component_class_filter *trimmer_class = NULL;
+       const bt_port_input *trimmer_input = NULL;
+       const bt_port_output *trimmer_output = NULL;
+
+       if (ctx->intersections &&
+               bt_component_get_class_type(upstream_comp) ==
+                       BT_COMPONENT_CLASS_TYPE_SOURCE) {
+               struct trace_range *range;
+               struct port_id port_id = {
+                       .instance_name = (char *) bt_component_get_name(upstream_comp),
+                       .port_name = (char *) bt_port_get_name(upstream_port)
+               };
+
+               if (!port_id.instance_name || !port_id.port_name) {
+                       goto error;
+               }
+
+               range = (struct trace_range *) g_hash_table_lookup(
+                       ctx->intersections, &port_id);
+               if (range) {
+                       bt_value_status status;
+
+                       intersection_begin = s_from_ns(
+                               range->intersection_range_begin_ns);
+                       intersection_end = s_from_ns(
+                               range->intersection_range_end_ns);
+                       if (!intersection_begin || !intersection_end) {
+                               BT_LOGE_STR("Cannot create trimmer argument timestamp string.");
+                               goto error;
+                       }
+
+                       insert_trimmer = true;
+                       trimmer_params = bt_value_map_create();
+                       if (!trimmer_params) {
+                               goto error;
+                       }
+
+                       status = bt_value_map_insert_string_entry(
+                               trimmer_params, "begin", intersection_begin);
+                       if (status != BT_VALUE_STATUS_OK) {
+                               goto error;
+                       }
+                       status = bt_value_map_insert_string_entry(
+                               trimmer_params,
+                               "end", intersection_end);
+                       if (status != BT_VALUE_STATUS_OK) {
+                               goto error;
+                       }
+               }
+
+               trimmer_class = find_filter_component_class("utils", "trimmer");
+               if (!trimmer_class) {
+                       goto error;
+               }
+       }
+
+       BT_LOGI("Connecting upstream port to the next available downstream port: "
+               "upstream-port-addr=%p, upstream-port-name=\"%s\", "
+               "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
+               upstream_port, bt_port_get_name(upstream_port),
+               cfg_conn->downstream_comp_name->str,
+               cfg_conn->arg->str);
+       downstreamp_comp_name_quark = g_quark_from_string(
+               cfg_conn->downstream_comp_name->str);
+       BT_ASSERT(downstreamp_comp_name_quark > 0);
+       downstream_comp = g_hash_table_lookup(ctx->flt_components,
+               GUINT_TO_POINTER(downstreamp_comp_name_quark));
+       port_count_fn = (input_port_count_func_t)
+               bt_component_filter_get_input_port_count;
+       port_by_index_fn = (borrow_input_port_by_index_func_t)
+               bt_component_filter_borrow_input_port_by_index_const;
+
+       if (!downstream_comp) {
+               downstream_comp = g_hash_table_lookup(ctx->sink_components,
+                       GUINT_TO_POINTER(downstreamp_comp_name_quark));
+               port_count_fn = (input_port_count_func_t)
+                       bt_component_sink_get_input_port_count;
+               port_by_index_fn = (borrow_input_port_by_index_func_t)
+                       bt_component_sink_borrow_input_port_by_index_const;
+       }
+
+       if (!downstream_comp) {
+               BT_LOGE("Cannot find downstream component:  comp-name=\"%s\", "
+                       "conn-arg=\"%s\"", cfg_conn->downstream_comp_name->str,
+                       cfg_conn->arg->str);
+               fprintf(stderr, "Cannot create connection: cannot find downstream component: %s\n",
+                       cfg_conn->arg->str);
+               goto error;
+       }
+
+       downstream_port_count = port_count_fn(downstream_comp);
+
+       for (i = 0; i < downstream_port_count; i++) {
+               const bt_port_input *in_downstream_port =
+                       port_by_index_fn(downstream_comp, i);
+               const bt_port *downstream_port =
+                       bt_port_input_as_port_const(in_downstream_port);
+               const char *upstream_port_name;
+               const char *downstream_port_name;
+
+               BT_ASSERT(downstream_port);
+
+               /* Skip port if it's already connected. */
+               if (bt_port_is_connected(downstream_port)) {
+                       BT_LOGD("Skipping downstream port: already connected: "
+                               "port-addr=%p, port-name=\"%s\"",
+                               downstream_port,
+                               bt_port_get_name(downstream_port));
+                       continue;
+               }
+
+               downstream_port_name = bt_port_get_name(downstream_port);
+               BT_ASSERT(downstream_port_name);
+               upstream_port_name = bt_port_get_name(upstream_port);
+               BT_ASSERT(upstream_port_name);
+
+               if (!bt_common_star_glob_match(
+                               cfg_conn->downstream_port_glob->str, SIZE_MAX,
+                               downstream_port_name, SIZE_MAX)) {
+                       continue;
+               }
+
+               if (insert_trimmer) {
+                       /*
+                        * In order to insert the trimmer between the
+                        * two components that were being connected, we
+                        * create a connection configuration entry which
+                        * describes a connection from the trimmer's
+                        * output to the original input that was being
+                        * connected.
+                        *
+                        * Hence, the creation of the trimmer will cause
+                        * the graph "new port" listener to establish
+                        * all downstream connections as its output port
+                        * is connected. We will then establish the
+                        * connection between the original upstream
+                        * source and the trimmer.
+                        */
+                       char *trimmer_name = NULL;
+                       bt_graph_status graph_status;
+
+                       ret = asprintf(&trimmer_name,
+                               "stream-intersection-trimmer-%s",
+                               upstream_port_name);
+                       if (ret < 0) {
+                               goto error;
+                       }
+                       ret = 0;
+
+                       ctx->connect_ports = false;
+                       graph_status = bt_graph_add_filter_component(
+                               ctx->graph, trimmer_class, trimmer_name,
+                               trimmer_params, &trimmer);
+                       free(trimmer_name);
+                       if (graph_status != BT_GRAPH_STATUS_OK) {
+                               goto error;
+                       }
+                       BT_ASSERT(trimmer);
+
+                       trimmer_input =
+                               bt_component_filter_borrow_input_port_by_index_const(
+                                       trimmer, 0);
+                       if (!trimmer_input) {
+                               goto error;
+                       }
+                       trimmer_output =
+                               bt_component_filter_borrow_output_port_by_index_const(
+                                       trimmer, 0);
+                       if (!trimmer_output) {
+                               goto error;
+                       }
+
+                       /*
+                        * Replace the current downstream port by the trimmer's
+                        * upstream port.
+                        */
+                       in_downstream_port = trimmer_input;
+                       downstream_port =
+                               bt_port_input_as_port_const(in_downstream_port);
+                       downstream_port_name = bt_port_get_name(
+                               downstream_port);
+                       BT_ASSERT(downstream_port_name);
+               }
+
+               /* We have a winner! */
+               status = bt_graph_connect_ports(ctx->graph,
+                       out_upstream_port, in_downstream_port, NULL);
+               downstream_port = NULL;
+               switch (status) {
+               case BT_GRAPH_STATUS_OK:
+                       break;
+               case BT_GRAPH_STATUS_CANCELED:
+                       BT_LOGI_STR("Graph was canceled by user.");
+                       status = BT_GRAPH_STATUS_OK;
+                       break;
+               case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
+                       BT_LOGE("A component refused a connection to one of its ports: "
+                               "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
+                               "upstream-port-addr=%p, upstream-port-name=\"%s\", "
+                               "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
+                               "downstream-port-addr=%p, downstream-port-name=\"%s\", "
+                               "conn-arg=\"%s\"",
+                               upstream_comp, bt_component_get_name(upstream_comp),
+                               upstream_port, bt_port_get_name(upstream_port),
+                               downstream_comp, cfg_conn->downstream_comp_name->str,
+                               downstream_port, downstream_port_name,
+                               cfg_conn->arg->str);
+                       fprintf(stderr,
+                               "A component refused a connection to one of its ports (`%s` to `%s`): %s\n",
+                               bt_port_get_name(upstream_port),
+                               downstream_port_name,
+                               cfg_conn->arg->str);
+                       break;
+               default:
+                       BT_LOGE("Cannot create connection: graph refuses to connect ports: "
+                               "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
+                               "upstream-port-addr=%p, upstream-port-name=\"%s\", "
+                               "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
+                               "downstream-port-addr=%p, downstream-port-name=\"%s\", "
+                               "conn-arg=\"%s\"",
+                               upstream_comp, bt_component_get_name(upstream_comp),
+                               upstream_port, bt_port_get_name(upstream_port),
+                               downstream_comp, cfg_conn->downstream_comp_name->str,
+                               downstream_port, downstream_port_name,
+                               cfg_conn->arg->str);
+                       fprintf(stderr,
+                               "Cannot create connection: graph refuses to connect ports (`%s` to `%s`): %s\n",
+                               bt_port_get_name(upstream_port),
+                               downstream_port_name,
+                               cfg_conn->arg->str);
+                       goto error;
+               }
+
+               BT_LOGI("Connected component ports: "
+                       "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
+                       "upstream-port-addr=%p, upstream-port-name=\"%s\", "
+                       "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
+                       "downstream-port-addr=%p, downstream-port-name=\"%s\", "
+                       "conn-arg=\"%s\"",
+                       upstream_comp, bt_component_get_name(upstream_comp),
+                       upstream_port, bt_port_get_name(upstream_port),
+                       downstream_comp, cfg_conn->downstream_comp_name->str,
+                       downstream_port, downstream_port_name,
+                       cfg_conn->arg->str);
+
+               if (insert_trimmer) {
+                       /*
+                        * The first connection, from the source to the trimmer,
+                        * has been done. We now connect the trimmer to the
+                        * original downstream port.
+                        */
+                       ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
+                               ctx,
+                               bt_component_filter_as_component_const(trimmer),
+                               trimmer_output, cfg_conn);
+                       if (ret) {
+                               goto error;
+                       }
+                       ctx->connect_ports = true;
+               }
+
+               /*
+                * We found a matching downstream port: the search is
+                * over.
+                */
+               goto end;
+       }
+
+       /* No downstream port found */
+       BT_LOGE("Cannot create connection: cannot find a matching downstream port for upstream port: "
+               "upstream-port-addr=%p, upstream-port-name=\"%s\", "
+               "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
+               upstream_port, bt_port_get_name(upstream_port),
+               cfg_conn->downstream_comp_name->str,
+               cfg_conn->arg->str);
+       fprintf(stderr,
+               "Cannot create connection: cannot find a matching downstream port for upstream port `%s`: %s\n",
+               bt_port_get_name(upstream_port), cfg_conn->arg->str);
+
+error:
+       ret = -1;
+
+end:
+       free(intersection_begin);
+       free(intersection_end);
+       BT_VALUE_PUT_REF_AND_RESET(trimmer_params);
+       BT_COMPONENT_CLASS_FILTER_PUT_REF_AND_RESET(trimmer_class);
+       BT_COMPONENT_FILTER_PUT_REF_AND_RESET(trimmer);
+       return ret;
+}
+
+static
+int cmd_run_ctx_connect_upstream_port(struct cmd_run_ctx *ctx,
+               const bt_port_output *upstream_port)
+{
+       int ret = 0;
+       const char *upstream_port_name;
+       const char *upstream_comp_name;
+       const bt_component *upstream_comp = NULL;
+       size_t i;
+
+       BT_ASSERT(ctx);
+       BT_ASSERT(upstream_port);
+       upstream_port_name = bt_port_get_name(
+               bt_port_output_as_port_const(upstream_port));
+       BT_ASSERT(upstream_port_name);
+       upstream_comp = bt_port_borrow_component_const(
+               bt_port_output_as_port_const(upstream_port));
+       if (!upstream_comp) {
+               BT_LOGW("Upstream port to connect is not part of a component: "
+                       "port-addr=%p, port-name=\"%s\"",
+                       upstream_port, upstream_port_name);
+               ret = -1;
+               goto end;
+       }
+
+       upstream_comp_name = bt_component_get_name(upstream_comp);
+       BT_ASSERT(upstream_comp_name);
+       BT_LOGI("Connecting upstream port: comp-addr=%p, comp-name=\"%s\", "
+               "port-addr=%p, port-name=\"%s\"",
+               upstream_comp, upstream_comp_name,
+               upstream_port, upstream_port_name);
+
+       for (i = 0; i < ctx->cfg->cmd_data.run.connections->len; i++) {
+               struct bt_config_connection *cfg_conn =
+                       g_ptr_array_index(
+                               ctx->cfg->cmd_data.run.connections, i);
+
+               if (strcmp(cfg_conn->upstream_comp_name->str,
+                               upstream_comp_name)) {
+                       continue;
+               }
+
+               if (!bt_common_star_glob_match(
+                           cfg_conn->upstream_port_glob->str,
+                           SIZE_MAX, upstream_port_name, SIZE_MAX)) {
+                       continue;
+               }
+
+               ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
+                       ctx, upstream_comp, upstream_port, cfg_conn);
+               if (ret) {
+                       BT_LOGE("Cannot connect upstream port: "
+                               "port-addr=%p, port-name=\"%s\"",
+                               upstream_port,
+                               upstream_port_name);
+                       fprintf(stderr,
+                               "Cannot connect port `%s` of component `%s` to a downstream port: %s\n",
+                               upstream_port_name,
+                               upstream_comp_name,
+                               cfg_conn->arg->str);
+                       goto error;
+               }
+               goto end;
+       }
+
+       BT_LOGE("Cannot connect upstream port: port does not match any connection argument: "
+               "port-addr=%p, port-name=\"%s\"", upstream_port,
+               upstream_port_name);
+       fprintf(stderr,
+               "Cannot create connection: upstream port `%s` does not match any connection\n",
+               upstream_port_name);
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+bt_graph_listener_status
+graph_output_port_added_listener(struct cmd_run_ctx *ctx,
+               const bt_port_output *out_port)
+{
+       const bt_component *comp;
+       const bt_port *port = bt_port_output_as_port_const(out_port);
+       bt_graph_listener_status ret = BT_GRAPH_LISTENER_STATUS_OK;
+
+       comp = bt_port_borrow_component_const(port);
+       BT_LOGI("Port added to a graph's component: comp-addr=%p, "
+               "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
+               comp, comp ? bt_component_get_name(comp) : "",
+               port, bt_port_get_name(port));
+
+       if (!ctx->connect_ports) {
+               goto end;
+       }
+
+       if (!comp) {
+               BT_LOGW_STR("Port has no component.");
+               goto end;
+       }
+
+       if (bt_port_is_connected(port)) {
+               BT_LOGW_STR("Port is already connected.");
+               goto end;
+       }
+
+       if (cmd_run_ctx_connect_upstream_port(ctx, out_port)) {
+               BT_LOGF_STR("Cannot connect upstream port.");
+               fprintf(stderr, "Added port could not be connected: aborting\n");
+               ret = BT_GRAPH_LISTENER_STATUS_ERROR;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_graph_listener_status graph_source_output_port_added_listener(
+               const bt_component_source *component,
+               const bt_port_output *port, void *data)
+{
+       return graph_output_port_added_listener(data, port);
+}
+
+static
+bt_graph_listener_status graph_filter_output_port_added_listener(
+               const bt_component_filter *component,
+               const bt_port_output *port, void *data)
+{
+       return graph_output_port_added_listener(data, port);
+}
+
+static
+void cmd_run_ctx_destroy(struct cmd_run_ctx *ctx)
+{
+       if (!ctx) {
+               return;
+       }
+
+       if (ctx->src_components) {
+               g_hash_table_destroy(ctx->src_components);
+               ctx->src_components = NULL;
+       }
+
+       if (ctx->flt_components) {
+               g_hash_table_destroy(ctx->flt_components);
+               ctx->flt_components = NULL;
+       }
+
+       if (ctx->sink_components) {
+               g_hash_table_destroy(ctx->sink_components);
+               ctx->sink_components = NULL;
+       }
+
+       if (ctx->intersections) {
+               g_hash_table_destroy(ctx->intersections);
+               ctx->intersections = NULL;
+       }
+
+       BT_GRAPH_PUT_REF_AND_RESET(ctx->graph);
+       the_graph = NULL;
+       ctx->cfg = NULL;
+}
+
+static
+int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg)
+{
+       int ret = 0;
+       bt_graph_status status;
+
+       ctx->cfg = cfg;
+       ctx->connect_ports = false;
+       ctx->src_components = g_hash_table_new_full(g_direct_hash,
+               g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
+       if (!ctx->src_components) {
+               goto error;
+       }
+
+       ctx->flt_components = g_hash_table_new_full(g_direct_hash,
+               g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
+       if (!ctx->flt_components) {
+               goto error;
+       }
+
+       ctx->sink_components = g_hash_table_new_full(g_direct_hash,
+               g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
+       if (!ctx->sink_components) {
+               goto error;
+       }
+
+       if (cfg->cmd_data.run.stream_intersection_mode) {
+               ctx->stream_intersection_mode = true;
+               ctx->intersections = g_hash_table_new_full(port_id_hash,
+                       port_id_equal, port_id_destroy, trace_range_destroy);
+               if (!ctx->intersections) {
+                       goto error;
+               }
+       }
+
+       ctx->graph = bt_graph_create();
+       if (!ctx->graph) {
+               goto error;
+       }
+
+       the_graph = ctx->graph;
+       status = bt_graph_add_source_component_output_port_added_listener(
+               ctx->graph, graph_source_output_port_added_listener, NULL, ctx,
+               NULL);
+       if (status != BT_GRAPH_STATUS_OK) {
+               BT_LOGE_STR("Cannot add \"port added\" listener to graph.");
+               goto error;
+       }
+
+       status = bt_graph_add_filter_component_output_port_added_listener(
+               ctx->graph, graph_filter_output_port_added_listener, NULL, ctx,
+               NULL);
+       if (status != BT_GRAPH_STATUS_OK) {
+               BT_LOGE_STR("Cannot add \"port added\" listener to graph.");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       cmd_run_ctx_destroy(ctx);
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int set_stream_intersections(struct cmd_run_ctx *ctx,
+               struct bt_config_component *cfg_comp,
+               const bt_component_class_source *src_comp_cls)
+{
+       int ret = 0;
+       uint64_t trace_idx;
+       int64_t trace_count;
+       const char *path = NULL;
+       const bt_value *query_result = NULL;
+       const bt_value *trace_info = NULL;
+       const bt_value *intersection_range = NULL;
+       const bt_value *intersection_begin = NULL;
+       const bt_value *intersection_end = NULL;
+       const bt_value *stream_infos = NULL;
+       const bt_value *stream_info = NULL;
+       struct port_id *port_id = NULL;
+       struct trace_range *trace_range = NULL;
+       const char *fail_reason = NULL;
+       const bt_component_class *comp_cls =
+               bt_component_class_source_as_component_class_const(src_comp_cls);
+
+       ret = query(comp_cls, "trace-info",
+               cfg_comp->params, &query_result,
+               &fail_reason);
+       if (ret) {
+               BT_LOGD("Component class does not support the `trace-info` query: %s: "
+                       "comp-class-name=\"%s\"", fail_reason,
+                       bt_component_class_get_name(comp_cls));
+               ret = -1;
+               goto error;
+       }
+
+       BT_ASSERT(query_result);
+
+       if (!bt_value_is_array(query_result)) {
+               BT_LOGD("Unexpected format of \'trace-info\' query result: "
+                       "component-class-name=%s",
+                       bt_component_class_get_name(comp_cls));
+               ret = -1;
+               goto error;
+       }
+
+       trace_count = bt_value_array_get_size(query_result);
+       if (trace_count < 0) {
+               ret = -1;
+               goto error;
+       }
+
+       for (trace_idx = 0; trace_idx < trace_count; trace_idx++) {
+               int64_t begin, end;
+               uint64_t stream_idx;
+               int64_t stream_count;
+
+               trace_info = bt_value_array_borrow_element_by_index_const(
+                       query_result, trace_idx);
+               if (!trace_info || !bt_value_is_map(trace_info)) {
+                       ret = -1;
+                       BT_LOGD_STR("Cannot retrieve trace from query result.");
+                       goto error;
+               }
+
+               intersection_range = bt_value_map_borrow_entry_value_const(
+                       trace_info, "intersection-range-ns");
+               if (!intersection_range) {
+                       ret = -1;
+                       BT_LOGD_STR("Cannot retrieve \'intersetion-range-ns\' field from query result.");
+                       goto error;
+               }
+
+               intersection_begin = bt_value_map_borrow_entry_value_const(intersection_range,
+                                                                          "begin");
+               if (!intersection_begin) {
+                       ret = -1;
+                       BT_LOGD_STR("Cannot retrieve intersection-range-ns \'begin\' field from query result.");
+                       goto error;
+               }
+
+               intersection_end = bt_value_map_borrow_entry_value_const(intersection_range,
+                                                                        "end");
+               if (!intersection_end) {
+                       ret = -1;
+                       BT_LOGD_STR("Cannot retrieve intersection-range-ns \'end\' field from query result.");
+                       goto error;
+               }
+
+               begin = bt_value_signed_integer_get(intersection_begin);
+               end = bt_value_signed_integer_get(intersection_end);
+
+               if (begin < 0 || end < 0 || end < begin) {
+                       BT_LOGW("Invalid trace stream intersection values: "
+                               "intersection-range-ns:begin=%" PRId64
+                               ", intersection-range-ns:end=%" PRId64,
+                               begin, end);
+                       ret = -1;
+                       goto error;
+               }
+
+               stream_infos = bt_value_map_borrow_entry_value_const(trace_info,
+                                                                    "streams");
+               if (!stream_infos || !bt_value_is_array(stream_infos)) {
+                       ret = -1;
+                       BT_LOGD_STR("Cannot retrieve stream information from trace in query result.");
+                       goto error;
+               }
+
+               stream_count = bt_value_array_get_size(stream_infos);
+               if (stream_count < 0) {
+                       ret = -1;
+                       goto error;
+               }
+
+               for (stream_idx = 0; stream_idx < stream_count; stream_idx++) {
+                       const bt_value *port_name;
+
+                       port_id = g_new0(struct port_id, 1);
+                       if (!port_id) {
+                               ret = -1;
+                               BT_LOGE_STR("Cannot allocate memory for port_id structure.");
+                               goto error;
+                       }
+                       port_id->instance_name = strdup(cfg_comp->instance_name->str);
+                       if (!port_id->instance_name) {
+                               ret = -1;
+                               BT_LOGE_STR("Cannot allocate memory for port_id component instance name.");
+                               goto error;
+                       }
+
+                       trace_range = g_new0(struct trace_range, 1);
+                       if (!trace_range) {
+                               ret = -1;
+                               BT_LOGE_STR("Cannot allocate memory for trace_range structure.");
+                               goto error;
+                       }
+                       trace_range->intersection_range_begin_ns = begin;
+                       trace_range->intersection_range_end_ns = end;
+
+                       stream_info = bt_value_array_borrow_element_by_index_const(
+                               stream_infos, stream_idx);
+                       if (!stream_info || !bt_value_is_map(stream_info)) {
+                               ret = -1;
+                               BT_LOGD_STR("Cannot retrieve stream informations from trace in query result.");
+                               goto error;
+                       }
+
+                       port_name = bt_value_map_borrow_entry_value_const(stream_info, "port-name");
+                       if (!port_name || !bt_value_is_string(port_name)) {
+                               ret = -1;
+                               BT_LOGD_STR("Cannot retrieve port name in query result.");
+                               goto error;
+                       }
+
+                       port_id->port_name = g_strdup(bt_value_string_get(port_name));
+                       if (!port_id->port_name) {
+                               ret = -1;
+                               BT_LOGE_STR("Cannot allocate memory for port_id port_name.");
+                               goto error;
+                       }
+
+                       BT_LOGD("Inserting stream intersection ");
+
+                       g_hash_table_insert(ctx->intersections, port_id, trace_range);
+
+                       port_id = NULL;
+                       trace_range = NULL;
+               }
+       }
+
+       goto end;
+
+error:
+       fprintf(stderr, "%s%sCannot determine stream intersection of trace at path \'%s\'.%s\n",
+               bt_common_color_bold(),
+               bt_common_color_fg_yellow(),
+               path ? path : "(unknown)",
+               bt_common_color_reset());
+end:
+       bt_value_put_ref(query_result);
+       g_free(port_id);
+       g_free(trace_range);
+       return ret;
+}
+
+static
+int cmd_run_ctx_create_components_from_config_components(
+               struct cmd_run_ctx *ctx, GPtrArray *cfg_components)
+{
+       size_t i;
+       const void *comp_cls = NULL;
+       const void *comp = NULL;
+       int ret = 0;
+
+       for (i = 0; i < cfg_components->len; i++) {
+               struct bt_config_component *cfg_comp =
+                       g_ptr_array_index(cfg_components, i);
+               GQuark quark;
+
+               switch (cfg_comp->type) {
+               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                       comp_cls = find_source_component_class(
+                               cfg_comp->plugin_name->str,
+                               cfg_comp->comp_cls_name->str);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       comp_cls = find_filter_component_class(
+                               cfg_comp->plugin_name->str,
+                               cfg_comp->comp_cls_name->str);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       comp_cls = find_sink_component_class(
+                               cfg_comp->plugin_name->str,
+                               cfg_comp->comp_cls_name->str);
+                       break;
+               default:
+                       abort();
+               }
+
+               if (!comp_cls) {
+                       BT_LOGE("Cannot find component class: plugin-name=\"%s\", "
+                               "comp-cls-name=\"%s\", comp-cls-type=%d",
+                               cfg_comp->plugin_name->str,
+                               cfg_comp->comp_cls_name->str,
+                               cfg_comp->type);
+                       fprintf(stderr, "%s%sCannot find component class %s",
+                               bt_common_color_bold(),
+                               bt_common_color_fg_red(),
+                               bt_common_color_reset());
+                       print_plugin_comp_cls_opt(stderr,
+                               cfg_comp->plugin_name->str,
+                               cfg_comp->comp_cls_name->str,
+                               cfg_comp->type);
+                       fprintf(stderr, "\n");
+                       goto error;
+               }
+
+               switch (cfg_comp->type) {
+               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                       ret = bt_graph_add_source_component(ctx->graph,
+                               comp_cls, cfg_comp->instance_name->str,
+                               cfg_comp->params,
+                               (void *) &comp);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       ret = bt_graph_add_filter_component(ctx->graph,
+                               comp_cls, cfg_comp->instance_name->str,
+                               cfg_comp->params,
+                               (void *) &comp);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       ret = bt_graph_add_sink_component(ctx->graph,
+                               comp_cls, cfg_comp->instance_name->str,
+                               cfg_comp->params,
+                               (void *) &comp);
+                       break;
+               default:
+                       abort();
+               }
+
+               if (ret) {
+                       BT_LOGE("Cannot create component: plugin-name=\"%s\", "
+                               "comp-cls-name=\"%s\", comp-cls-type=%d, "
+                               "comp-name=\"%s\"",
+                               cfg_comp->plugin_name->str,
+                               cfg_comp->comp_cls_name->str,
+                               cfg_comp->type, cfg_comp->instance_name->str);
+                       fprintf(stderr, "%s%sCannot create component `%s`%s\n",
+                               bt_common_color_bold(),
+                               bt_common_color_fg_red(),
+                               cfg_comp->instance_name->str,
+                               bt_common_color_reset());
+                       goto error;
+               }
+
+               if (ctx->stream_intersection_mode &&
+                               cfg_comp->type == BT_COMPONENT_CLASS_TYPE_SOURCE) {
+                       ret = set_stream_intersections(ctx, cfg_comp, comp_cls);
+                       if (ret) {
+                               goto error;
+                       }
+               }
+
+               BT_LOGI("Created and inserted component: comp-addr=%p, comp-name=\"%s\"",
+                       comp, cfg_comp->instance_name->str);
+               quark = g_quark_from_string(cfg_comp->instance_name->str);
+               BT_ASSERT(quark > 0);
+
+               switch (cfg_comp->type) {
+               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                       g_hash_table_insert(ctx->src_components,
+                               GUINT_TO_POINTER(quark), (void *) comp);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       g_hash_table_insert(ctx->flt_components,
+                               GUINT_TO_POINTER(quark), (void *) comp);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       g_hash_table_insert(ctx->sink_components,
+                               GUINT_TO_POINTER(quark), (void *) comp);
+                       break;
+               default:
+                       abort();
+               }
+
+               comp = NULL;
+               BT_OBJECT_PUT_REF_AND_RESET(comp_cls);
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       bt_object_put_ref(comp);
+       bt_object_put_ref(comp_cls);
+       return ret;
+}
+
+static
+int cmd_run_ctx_create_components(struct cmd_run_ctx *ctx)
+{
+       int ret = 0;
+
+       /*
+        * Make sure that, during this phase, our graph's "port added"
+        * listener does not connect ports while we are creating the
+        * components because we have a special, initial phase for
+        * this.
+        */
+       ctx->connect_ports = false;
+
+       ret = cmd_run_ctx_create_components_from_config_components(
+               ctx, ctx->cfg->cmd_data.run.sources);
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = cmd_run_ctx_create_components_from_config_components(
+               ctx, ctx->cfg->cmd_data.run.filters);
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = cmd_run_ctx_create_components_from_config_components(
+               ctx, ctx->cfg->cmd_data.run.sinks);
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+typedef uint64_t (*output_port_count_func_t)(const void *);
+typedef const bt_port_output *(*borrow_output_port_by_index_func_t)(
+       const void *, uint64_t);
+
+static
+int cmd_run_ctx_connect_comp_ports(struct cmd_run_ctx *ctx,
+               void *comp, output_port_count_func_t port_count_fn,
+               borrow_output_port_by_index_func_t port_by_index_fn)
+{
+       int ret = 0;
+       uint64_t count;
+       uint64_t i;
+
+       count = port_count_fn(comp);
+
+       for (i = 0; i < count; i++) {
+               const bt_port_output *upstream_port = port_by_index_fn(comp, i);
+
+               BT_ASSERT(upstream_port);
+               ret = cmd_run_ctx_connect_upstream_port(ctx, upstream_port);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int cmd_run_ctx_connect_ports(struct cmd_run_ctx *ctx)
+{
+       int ret = 0;
+       GHashTableIter iter;
+       gpointer g_name_quark, g_comp;
+
+       ctx->connect_ports = true;
+       g_hash_table_iter_init(&iter, ctx->src_components);
+
+       while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
+               ret = cmd_run_ctx_connect_comp_ports(ctx, g_comp,
+                       (output_port_count_func_t)
+                               bt_component_source_get_output_port_count,
+                       (borrow_output_port_by_index_func_t)
+                               bt_component_source_borrow_output_port_by_index_const);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       g_hash_table_iter_init(&iter, ctx->flt_components);
+
+       while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
+               ret = cmd_run_ctx_connect_comp_ports(ctx, g_comp,
+                       (output_port_count_func_t)
+                               bt_component_filter_get_output_port_count,
+                       (borrow_output_port_by_index_func_t)
+                               bt_component_filter_borrow_output_port_by_index_const);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static inline
+const char *bt_graph_status_str(bt_graph_status status)
+{
+       switch (status) {
+       case BT_GRAPH_STATUS_OK:
+               return "BT_GRAPH_STATUS_OK";
+       case BT_GRAPH_STATUS_END:
+               return "BT_GRAPH_STATUS_END";
+       case BT_GRAPH_STATUS_AGAIN:
+               return "BT_GRAPH_STATUS_AGAIN";
+       case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
+               return "BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION";
+       case BT_GRAPH_STATUS_CANCELED:
+               return "BT_GRAPH_STATUS_CANCELED";
+       case BT_GRAPH_STATUS_ERROR:
+               return "BT_GRAPH_STATUS_ERROR";
+       case BT_GRAPH_STATUS_NOMEM:
+               return "BT_GRAPH_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+}
+
+static
+int cmd_run(struct bt_config *cfg)
+{
+       int ret = 0;
+       struct cmd_run_ctx ctx = { 0 };
+
+       /* Initialize the command's context and the graph object */
+       if (cmd_run_ctx_init(&ctx, cfg)) {
+               BT_LOGE_STR("Cannot initialize the command's context.");
+               fprintf(stderr, "Cannot initialize the command's context\n");
+               goto error;
+       }
+
+       if (canceled) {
+               BT_LOGI_STR("Canceled by user before creating components.");
+               goto error;
+       }
+
+       BT_LOGI_STR("Creating components.");
+
+       /* Create the requested component instances */
+       if (cmd_run_ctx_create_components(&ctx)) {
+               BT_LOGE_STR("Cannot create components.");
+               fprintf(stderr, "Cannot create components\n");
+               goto error;
+       }
+
+       if (canceled) {
+               BT_LOGI_STR("Canceled by user before connecting components.");
+               goto error;
+       }
+
+       BT_LOGI_STR("Connecting components.");
+
+       /* Connect the initially visible component ports */
+       if (cmd_run_ctx_connect_ports(&ctx)) {
+               BT_LOGE_STR("Cannot connect initial component ports.");
+               fprintf(stderr, "Cannot connect initial component ports\n");
+               goto error;
+       }
+
+       if (canceled) {
+               BT_LOGI_STR("Canceled by user before running the graph.");
+               goto error;
+       }
+
+       BT_LOGI_STR("Running the graph.");
+
+       /* Run the graph */
+       while (true) {
+               bt_graph_status graph_status = bt_graph_run(ctx.graph);
+
+               /*
+                * Reset console in case something messed with console
+                * codes during the graph's execution.
+                */
+               printf("%s", bt_common_color_reset());
+               fflush(stdout);
+               fprintf(stderr, "%s", bt_common_color_reset());
+               BT_LOGV("bt_graph_run() returned: status=%s",
+                       bt_graph_status_str(graph_status));
+
+               switch (graph_status) {
+               case BT_GRAPH_STATUS_OK:
+                       break;
+               case BT_GRAPH_STATUS_CANCELED:
+                       BT_LOGI_STR("Graph was canceled by user.");
+                       goto error;
+               case BT_GRAPH_STATUS_AGAIN:
+                       if (bt_graph_is_canceled(ctx.graph)) {
+                               BT_LOGI_STR("Graph was canceled by user.");
+                               goto error;
+                       }
+
+                       if (cfg->cmd_data.run.retry_duration_us > 0) {
+                               BT_LOGV("Got BT_GRAPH_STATUS_AGAIN: sleeping: "
+                                       "time-us=%" PRIu64,
+                                       cfg->cmd_data.run.retry_duration_us);
+
+                               if (usleep(cfg->cmd_data.run.retry_duration_us)) {
+                                       if (bt_graph_is_canceled(ctx.graph)) {
+                                               BT_LOGI_STR("Graph was canceled by user.");
+                                               goto error;
+                                       }
+                               }
+                       }
+                       break;
+               case BT_GRAPH_STATUS_END:
+                       goto end;
+               default:
+                       BT_LOGE_STR("Graph failed to complete successfully");
+                       fprintf(stderr, "Graph failed to complete successfully\n");
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       if (ret == 0) {
+               ret = -1;
+       }
+
+end:
+       cmd_run_ctx_destroy(&ctx);
+       return ret;
+}
+
+static
+void warn_command_name_and_directory_clash(struct bt_config *cfg)
+{
+       const char *env_clash;
+
+       if (!cfg->command_name) {
+               return;
+       }
+
+       env_clash = getenv(ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH);
+       if (env_clash && strcmp(env_clash, "0") == 0) {
+               return;
+       }
+
+       if (g_file_test(cfg->command_name,
+                       G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
+               fprintf(stderr, "\nNOTE: The `%s` command was executed. If you meant to convert a\n",
+                       cfg->command_name);
+               fprintf(stderr, "trace located in the local `%s` directory, please use:\n",
+                       cfg->command_name);
+               fprintf(stderr, "\n");
+               fprintf(stderr, "    babeltrace2 convert %s [OPTIONS]\n",
+                       cfg->command_name);
+       }
+}
+
+static
+void init_log_level(void)
+{
+       bt_cli_log_level = bt_log_get_level_from_env(ENV_BABELTRACE_CLI_LOG_LEVEL);
+}
+
+static
+void set_auto_log_levels(struct bt_config *cfg)
+{
+       const char **env_var_name;
+
+       /*
+        * Override the configuration's default log level if
+        * BABELTRACE_VERBOSE or BABELTRACE_DEBUG environment variables
+        * are found for backward compatibility with legacy Babetrace 1.
+        */
+       if (getenv("BABELTRACE_DEBUG") &&
+                       strcmp(getenv("BABELTRACE_DEBUG"), "1") == 0) {
+               cfg->log_level = 'V';
+       } else if (getenv("BABELTRACE_VERBOSE") &&
+                       strcmp(getenv("BABELTRACE_VERBOSE"), "1") == 0) {
+               cfg->log_level = 'I';
+       }
+
+       /*
+        * Set log levels according to --debug or --verbose. For
+        * backward compatibility, --debug is more verbose than
+        * --verbose. So:
+        *
+        *     --verbose: INFO log level
+        *     --debug:   VERBOSE log level (includes DEBUG, which is
+        *                is less verbose than VERBOSE in the internal
+        *                logging framework)
+        */
+       if (!getenv("BABELTRACE_LOGGING_GLOBAL_LEVEL")) {
+               if (cfg->verbose) {
+                       bt_logging_set_global_level(BT_LOGGING_LEVEL_INFO);
+               } else if (cfg->debug) {
+                       bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE);
+               } else {
+                       /*
+                        * Set library's default log level if not
+                        * explicitly specified.
+                        */
+                       switch (cfg->log_level) {
+                       case 'N':
+                               bt_logging_set_global_level(BT_LOGGING_LEVEL_NONE);
+                               break;
+                       case 'V':
+                               bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE);
+                               break;
+                       case 'D':
+                               bt_logging_set_global_level(BT_LOGGING_LEVEL_DEBUG);
+                               break;
+                       case 'I':
+                               bt_logging_set_global_level(BT_LOGGING_LEVEL_INFO);
+                               break;
+                       case 'W':
+                               bt_logging_set_global_level(BT_LOGGING_LEVEL_WARN);
+                               break;
+                       case 'E':
+                               bt_logging_set_global_level(BT_LOGGING_LEVEL_ERROR);
+                               break;
+                       case 'F':
+                               bt_logging_set_global_level(BT_LOGGING_LEVEL_FATAL);
+                               break;
+                       default:
+                               abort();
+                       }
+               }
+       }
+
+       if (!getenv(ENV_BABELTRACE_CLI_LOG_LEVEL)) {
+               if (cfg->verbose) {
+                       bt_cli_log_level = BT_LOG_INFO;
+               } else if (cfg->debug) {
+                       bt_cli_log_level = BT_LOG_VERBOSE;
+               } else {
+                       /*
+                        * Set CLI's default log level if not explicitly
+                        * specified.
+                        */
+                       switch (cfg->log_level) {
+                       case 'N':
+                               bt_cli_log_level = BT_LOG_NONE;
+                               break;
+                       case 'V':
+                               bt_cli_log_level = BT_LOG_VERBOSE;
+                               break;
+                       case 'D':
+                               bt_cli_log_level = BT_LOG_DEBUG;
+                               break;
+                       case 'I':
+                               bt_cli_log_level = BT_LOG_INFO;
+                               break;
+                       case 'W':
+                               bt_cli_log_level = BT_LOG_WARN;
+                               break;
+                       case 'E':
+                               bt_cli_log_level = BT_LOG_ERROR;
+                               break;
+                       case 'F':
+                               bt_cli_log_level = BT_LOG_FATAL;
+                               break;
+                       default:
+                               abort();
+                       }
+               }
+       }
+
+       env_var_name = log_level_env_var_names;
+
+       while (*env_var_name) {
+               if (!getenv(*env_var_name)) {
+                       if (cfg->verbose) {
+                               g_setenv(*env_var_name, "I", 1);
+                       } else if (cfg->debug) {
+                               g_setenv(*env_var_name, "V", 1);
+                       } else {
+                               char val[2] = { 0 };
+
+                               /*
+                                * Set module's default log level if not
+                                * explicitly specified.
+                                */
+                               val[0] = cfg->log_level;
+                               g_setenv(*env_var_name, val, 1);
+                       }
+               }
+
+               env_var_name++;
+       }
+}
+
+int main(int argc, const char **argv)
+{
+       int ret;
+       int retcode;
+       struct bt_config *cfg;
+
+       init_log_level();
+       set_signal_handler();
+       init_static_data();
+       cfg = bt_config_cli_args_create_with_default(argc, argv, &retcode);
+
+       if (retcode < 0) {
+               /* Quit without errors; typically usage/version */
+               retcode = 0;
+               BT_LOGI_STR("Quitting without errors.");
+               goto end;
+       }
+
+       if (retcode > 0) {
+               BT_LOGE("Command-line error: retcode=%d", retcode);
+               goto end;
+       }
+
+       if (!cfg) {
+               BT_LOGE_STR("Failed to create a valid Babeltrace configuration.");
+               fprintf(stderr, "Failed to create Babeltrace configuration\n");
+               retcode = 1;
+               goto end;
+       }
+
+       set_auto_log_levels(cfg);
+       print_cfg(cfg);
+
+       if (cfg->command_needs_plugins) {
+               ret = load_all_plugins(cfg->plugin_paths);
+               if (ret) {
+                       BT_LOGE("Failed to load plugins: ret=%d", ret);
+                       retcode = 1;
+                       goto end;
+               }
+       }
+
+       BT_LOGI("Executing command: cmd=%d, command-name=\"%s\"",
+               cfg->command, cfg->command_name);
+
+       switch (cfg->command) {
+       case BT_CONFIG_COMMAND_RUN:
+               ret = cmd_run(cfg);
+               break;
+       case BT_CONFIG_COMMAND_LIST_PLUGINS:
+               ret = cmd_list_plugins(cfg);
+               break;
+       case BT_CONFIG_COMMAND_HELP:
+               ret = cmd_help(cfg);
+               break;
+       case BT_CONFIG_COMMAND_QUERY:
+               ret = cmd_query(cfg);
+               break;
+       case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
+               ret = cmd_print_ctf_metadata(cfg);
+               break;
+       case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
+               ret = cmd_print_lttng_live_sessions(cfg);
+               break;
+       default:
+               BT_LOGF("Invalid/unknown command: cmd=%d", cfg->command);
+               abort();
+       }
+
+       BT_LOGI("Command completed: cmd=%d, command-name=\"%s\", ret=%d",
+               cfg->command, cfg->command_name, ret);
+       warn_command_name_and_directory_clash(cfg);
+       retcode = ret ? 1 : 0;
+
+end:
+       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+       fini_static_data();
+       return retcode;
+}
diff --git a/src/cli/logging.c b/src/cli/logging.c
new file mode 100644 (file)
index 0000000..9286948
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_cli_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_cli_log_level, "BABELTRACE_CLI_LOG_LEVEL");
diff --git a/src/cli/logging.h b/src/cli/logging.h
new file mode 100644 (file)
index 0000000..dd6c1d0
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef CLI_LOGGING_H
+#define CLI_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_cli_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_cli_log_level);
+
+#endif /* CLI_LOGGING_H */
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
new file mode 100644 (file)
index 0000000..1a73672
--- /dev/null
@@ -0,0 +1,89 @@
+AM_CPPFLAGS += -DINSTALL_LIBDIR=\"$(libdir)\"
+
+noinst_LTLIBRARIES = libbabeltrace2-common.la
+
+libbabeltrace2_common_la_SOURCES = \
+       assert.h \
+       assert.c \
+       common.c \
+       common.h \
+       logging.c \
+       logging.h
+
+noinst_HEADERS = \
+       align.h \
+       babeltrace.h \
+       list.h \
+       mmap-align.h \
+       version.h \
+       version.i
+
+##
+## This target generates an include file that contains the git version
+## string of the current branch, it must be continuously updated when
+## we build in the git repo and shipped in dist tarballs to reflect the
+## status of the tree when it was generated. If the tree is clean and
+## the current commit is tag a starting with "v", consider this a
+## release version and set an empty git version.
+##
+## Here is what the inline script does:
+##
+## First, delete any stale "version.i.tmp" file.
+##
+## If "bootstrap" and ".git" exists in the top source directory and the git
+## executable is available, get the current git version string in the form:
+##
+##  "latest_tag"(-"number_of_commits_on_top")(-g"latest_commit_hash")(-dirty)
+##
+## And store it in "version.i.tmp", if the current commit is tagged, the tag
+## starts with "v" and the tree is clean, consider this a release version and
+## overwrite the git version with an empty string in "version.i.tmp".
+##
+## If we don't have a "version.i.tmp" nor a "version.i", generate an empty
+## string as a failover.
+##
+## If we don't have a "version.i" or we have both files and they are different,
+## copy "version.i.tmp" over "version.i". This way the dependent targets are
+## only rebuilt when the version string changes.
+##
+
+version_verbose = $(version_verbose_@AM_V@)
+version_verbose_ = $(version_verbose_@AM_DEFAULT_V@)
+version_verbose_0 = @echo "  GEN     " $@;
+
+version.i:
+       $(version_verbose)rm -f version.i.tmp; \
+       if (test -r "$(top_srcdir)/bootstrap" && test -r "$(top_srcdir)/.git") && \
+                       test -x "`which git 2>&1;true`"; then \
+               GIT_VERSION_STR="`cd "$(top_srcdir)" && git describe --tags --dirty`"; \
+               GIT_CURRENT_TAG="`cd "$(top_srcdir)" && git describe --tags --exact-match --match="v[0-9]*" HEAD 2> /dev/null`"; \
+               echo "#define GIT_VERSION \"$$GIT_VERSION_STR\"" > version.i.tmp; \
+               if ! $(GREP) -- "-dirty" version.i.tmp > /dev/null && \
+                               test "x$$GIT_CURRENT_TAG" != "x"; then \
+                       echo "#define GIT_VERSION \"\"" > version.i.tmp; \
+               fi; \
+       fi; \
+       if test ! -f version.i.tmp; then \
+               if test ! -f version.i; then \
+                       echo '#define GIT_VERSION ""' > version.i; \
+               fi; \
+       elif test ! -f version.i || \
+                       test x"`cat version.i.tmp`" != x"`cat version.i`"; then \
+               mv version.i.tmp version.i; \
+       fi; \
+       rm -f version.i.tmp; \
+       true
+
+##
+## version.i is defined as a .PHONY target even if it's a real file,
+## we want the target to be re-run on every make.
+##
+.PHONY: version.i
+
+CLEANFILES = version.i.tmp
+
+##
+## Only clean "version.i" on dist-clean, we need to keep it on regular
+## clean when it's part of a dist tarball.
+##
+DISTCLEANFILES = version.i
diff --git a/src/common/align.h b/src/common/align.h
new file mode 100644 (file)
index 0000000..d27b5b5
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef _BABELTRACE_ALIGN_H
+#define _BABELTRACE_ALIGN_H
+
+/*
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "compat/compiler.h"
+#include "compat/limits.h"
+
+#define ALIGN(x, a)            __ALIGN_MASK(x, (typeof(x))(a) - 1)
+#define __ALIGN_MASK(x, mask)  (((x) + (mask)) & ~(mask))
+#define PTR_ALIGN(p, a)                ((typeof(p)) ALIGN((unsigned long) (p), a))
+#define ALIGN_FLOOR(x, a)      __ALIGN_FLOOR_MASK(x, (typeof(x)) (a) - 1)
+#define __ALIGN_FLOOR_MASK(x, mask)    ((x) & ~(mask))
+#define PTR_ALIGN_FLOOR(p, a) \
+                       ((typeof(p)) ALIGN_FLOOR((unsigned long) (p), a))
+#define IS_ALIGNED(x, a)       (((x) & ((typeof(x)) (a) - 1)) == 0)
+
+/*
+ * Align pointer on natural object alignment.
+ */
+#define object_align(obj)      PTR_ALIGN(obj, __alignof__(*(obj)))
+#define object_align_floor(obj)        PTR_ALIGN_FLOOR(obj, __alignof__(*(obj)))
+
+/**
+ * offset_align - Calculate the offset needed to align an object on its natural
+ *                alignment towards higher addresses.
+ * @align_drift:  object offset from an "alignment"-aligned address.
+ * @alignment:    natural object alignment. Must be non-zero, power of 2.
+ *
+ * Returns the offset that must be added to align towards higher
+ * addresses.
+ */
+#define offset_align(align_drift, alignment)                                  \
+       ({                                                                     \
+               MAYBE_BUILD_BUG_ON((alignment) == 0                            \
+                                  || ((alignment) & ((alignment) - 1)));      \
+               (((alignment) - (align_drift)) & ((alignment) - 1));           \
+       })
+
+/**
+ * offset_align_floor - Calculate the offset needed to align an object
+ *                      on its natural alignment towards lower addresses.
+ * @align_drift:  object offset from an "alignment"-aligned address.
+ * @alignment:    natural object alignment. Must be non-zero, power of 2.
+ *
+ * Returns the offset that must be substracted to align towards lower addresses.
+ */
+#define offset_align_floor(align_drift, alignment)                            \
+       ({                                                                     \
+               MAYBE_BUILD_BUG_ON((alignment) == 0                            \
+                                  || ((alignment) & ((alignment) - 1)));      \
+               (((align_drift) - (alignment)) & ((alignment) - 1));           \
+       })
+
+#endif /* _BABELTRACE_ALIGN_H */
diff --git a/src/common/assert.c b/src/common/assert.c
new file mode 100644 (file)
index 0000000..056e2f2
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 EfficiOS Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/assert.h"
+#include "common/common.h"
+
+void bt_common_assert_failed(const char *file, int line, const char *func,
+               const char *assertion)
+{
+       fprintf(stderr,
+               "%s\n%s%s%s (╯°□°)╯︵ ┻━┻ %s %s%s%s%s:%s%d%s: %s%s()%s: "
+               "%sAssertion %s`%s`%s%s failed.%s\n",
+               bt_common_color_reset(),
+               bt_common_color_bold(),
+               bt_common_color_bg_yellow(),
+               bt_common_color_fg_red(),
+               bt_common_color_reset(),
+               bt_common_color_bold(),
+               bt_common_color_fg_magenta(),
+               file,
+               bt_common_color_reset(),
+               bt_common_color_fg_green(),
+               line,
+               bt_common_color_reset(),
+               bt_common_color_fg_cyan(),
+               func,
+               bt_common_color_reset(),
+               bt_common_color_fg_red(),
+               bt_common_color_bold(),
+               assertion,
+               bt_common_color_reset(),
+               bt_common_color_fg_red(),
+               bt_common_color_reset());
+       abort();
+}
diff --git a/src/common/assert.h b/src/common/assert.h
new file mode 100644 (file)
index 0000000..27fdead
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef BABELTRACE_ASSERT_INTERNAL_H
+#define BABELTRACE_ASSERT_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+#include "common/babeltrace.h"
+
+#ifdef BT_DEBUG_MODE
+
+extern void bt_common_assert_failed(const char *file, int line,
+       const char *func, const char *assertion) __attribute__((noreturn));
+
+/*
+ * Internal assertion (to detect logic errors on which the library user
+ * has no influence). Use BT_ASSERT_PRE() to check a precondition which
+ * must be directly or indirectly satisfied by the library user.
+ */
+#define BT_ASSERT(_cond)                                                       \
+       do {                                                                   \
+               if (!(_cond)) {                                                \
+                       bt_common_assert_failed(__FILE__, __LINE__, __func__,  \
+                               TOSTRING(_cond));                              \
+               }                                                              \
+       } while (0)
+
+/*
+ * Marks a function as being only used within a BT_ASSERT() context.
+ */
+# define BT_ASSERT_FUNC
+#else
+/*
+ * When BT_DEBUG_MODE is not defined, define BT_ASSERT() macro to the following
+ * to trick the compiler into thinking that the variable passed as condition to
+ * the assertion is used. This is to prevent set-but-not-used warnings from the
+ * compiler when assertions are disabled. The `sizeof` operator also makes sure
+ * that the `_cond` expression is not evaluated, thus preventing unwanted side
+ * effects.
+ *
+ * In-depth explanation: https://stackoverflow.com/questions/37411809/how-to-elegantly-fix-this-unused-variable-warning/37412551#37412551
+ */
+# define BT_ASSERT(_cond)      ((void) sizeof((void) (_cond), 0))
+# define BT_ASSERT_FUNC                BT_UNUSED
+#endif /* BT_DEBUG_MODE */
+
+#endif /* BABELTRACE_ASSERT_INTERNAL_H */
diff --git a/src/common/babeltrace.h b/src/common/babeltrace.h
new file mode 100644 (file)
index 0000000..49dfb1b
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef _BABELTRACE_INTERNAL_H
+#define _BABELTRACE_INTERNAL_H
+
+/*
+ * Copyright 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <stdio.h>
+#include <glib.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include "compat/string.h"
+#include <babeltrace2/types.h>
+
+#define PERROR_BUFLEN  200
+
+#ifndef likely
+# ifdef __GNUC__
+#  define likely(x)      __builtin_expect(!!(x), 1)
+# else
+#  define likely(x)      (!!(x))
+# endif
+#endif
+
+#ifndef unlikely
+# ifdef __GNUC__
+#  define unlikely(x)    __builtin_expect(!!(x), 0)
+# else
+#  define unlikely(x)    (!!(x))
+# endif
+#endif
+
+#ifndef min
+#define min(a, b)      (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef max
+#define max(a, b)      (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef max_t
+#define max_t(type, a, b)      \
+       ((type) (a) > (type) (b) ? (type) (a) : (type) (b))
+#endif
+
+static inline
+bool bt_safe_to_mul_int64(int64_t a, int64_t b)
+{
+       if (a == 0 || b == 0) {
+               return true;
+       }
+
+       return a < INT64_MAX / b;
+}
+
+static inline
+bool bt_safe_to_mul_uint64(uint64_t a, uint64_t b)
+{
+       if (a == 0 || b == 0) {
+               return true;
+       }
+
+       return a < UINT64_MAX / b;
+}
+
+static inline
+bool bt_safe_to_add_int64(int64_t a, int64_t b)
+{
+       return a <= INT64_MAX - b;
+}
+
+static inline
+bool bt_safe_to_add_uint64(uint64_t a, uint64_t b)
+{
+       return a <= UINT64_MAX - b;
+}
+
+/*
+ * Memory allocation zeroed
+ */
+#define zmalloc(x) calloc(1, x)
+
+/*
+ * BT_HIDDEN: set the hidden attribute for internal functions
+ * On Windows, symbols are local unless explicitly exported,
+ * see https://gcc.gnu.org/wiki/Visibility
+ */
+#if defined(_WIN32) || defined(__CYGWIN__)
+#define BT_HIDDEN
+#else
+#define BT_HIDDEN __attribute__((visibility("hidden")))
+#endif
+
+#ifndef __STRINGIFY
+#define __STRINGIFY(x) #x
+#endif
+
+#define TOSTRING(x)    __STRINGIFY(x)
+
+#define BT_UNUSED      __attribute__((unused))
+
+#endif
diff --git a/src/common/common.c b/src/common/common.c
new file mode 100644 (file)
index 0000000..f37bec4
--- /dev/null
@@ -0,0 +1,1569 @@
+/*
+ * Babeltrace common functions
+ *
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COMMON"
+#include "logging.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "common/assert.h"
+#include <stdarg.h>
+#include <ctype.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdbool.h>
+#include "common/babeltrace.h"
+#include "common/common.h"
+#include "compat/unistd.h"
+
+#ifndef __MINGW32__
+#include <pwd.h>
+#endif
+
+#define SYSTEM_PLUGIN_PATH     INSTALL_LIBDIR "/babeltrace2/plugins"
+#define HOME_ENV_VAR           "HOME"
+#define HOME_PLUGIN_SUBPATH    "/.local/lib/babeltrace2/plugins"
+
+static const char *bt_common_color_code_reset = "";
+static const char *bt_common_color_code_bold = "";
+static const char *bt_common_color_code_fg_default = "";
+static const char *bt_common_color_code_fg_red = "";
+static const char *bt_common_color_code_fg_green = "";
+static const char *bt_common_color_code_fg_yellow = "";
+static const char *bt_common_color_code_fg_blue = "";
+static const char *bt_common_color_code_fg_magenta = "";
+static const char *bt_common_color_code_fg_cyan = "";
+static const char *bt_common_color_code_fg_light_gray = "";
+static const char *bt_common_color_code_bg_default = "";
+static const char *bt_common_color_code_bg_red = "";
+static const char *bt_common_color_code_bg_green = "";
+static const char *bt_common_color_code_bg_yellow = "";
+static const char *bt_common_color_code_bg_blue = "";
+static const char *bt_common_color_code_bg_magenta = "";
+static const char *bt_common_color_code_bg_cyan = "";
+static const char *bt_common_color_code_bg_light_gray = "";
+
+static
+void __attribute__((constructor)) bt_common_color_ctor(void)
+{
+       if (bt_common_colors_supported()) {
+               bt_common_color_code_reset = BT_COMMON_COLOR_RESET;
+               bt_common_color_code_bold = BT_COMMON_COLOR_BOLD;
+               bt_common_color_code_fg_default = BT_COMMON_COLOR_FG_DEFAULT;
+               bt_common_color_code_fg_red = BT_COMMON_COLOR_FG_RED;
+               bt_common_color_code_fg_green = BT_COMMON_COLOR_FG_GREEN;
+               bt_common_color_code_fg_yellow = BT_COMMON_COLOR_FG_YELLOW;
+               bt_common_color_code_fg_blue = BT_COMMON_COLOR_FG_BLUE;
+               bt_common_color_code_fg_magenta = BT_COMMON_COLOR_FG_MAGENTA;
+               bt_common_color_code_fg_cyan = BT_COMMON_COLOR_FG_CYAN;
+               bt_common_color_code_fg_light_gray = BT_COMMON_COLOR_FG_LIGHT_GRAY;
+               bt_common_color_code_bg_default = BT_COMMON_COLOR_BG_DEFAULT;
+               bt_common_color_code_bg_red = BT_COMMON_COLOR_BG_RED;
+               bt_common_color_code_bg_green = BT_COMMON_COLOR_BG_GREEN;
+               bt_common_color_code_bg_yellow = BT_COMMON_COLOR_BG_YELLOW;
+               bt_common_color_code_bg_blue = BT_COMMON_COLOR_BG_BLUE;
+               bt_common_color_code_bg_magenta = BT_COMMON_COLOR_BG_MAGENTA;
+               bt_common_color_code_bg_cyan = BT_COMMON_COLOR_BG_CYAN;
+               bt_common_color_code_bg_light_gray = BT_COMMON_COLOR_BG_LIGHT_GRAY;
+       }
+}
+
+BT_HIDDEN
+const char *bt_common_get_system_plugin_path(void)
+{
+       return SYSTEM_PLUGIN_PATH;
+}
+
+#ifdef __MINGW32__
+BT_HIDDEN
+bool bt_common_is_setuid_setgid(void)
+{
+       return false;
+}
+#else /* __MINGW32__ */
+BT_HIDDEN
+bool bt_common_is_setuid_setgid(void)
+{
+       return (geteuid() != getuid() || getegid() != getgid());
+}
+#endif /* __MINGW32__ */
+
+static
+char *bt_secure_getenv(const char *name)
+{
+       if (bt_common_is_setuid_setgid()) {
+               BT_LOGD("Disregarding environment variable for setuid/setgid binary: "
+                       "name=\"%s\"", name);
+               return NULL;
+       }
+       return getenv(name);
+}
+
+#ifdef __MINGW32__
+static
+const char *bt_get_home_dir(void)
+{
+       return g_get_home_dir();
+}
+#else /* __MINGW32__ */
+static
+const char *bt_get_home_dir(void)
+{
+       char *val = NULL;
+       struct passwd *pwd;
+
+       val = bt_secure_getenv(HOME_ENV_VAR);
+       if (val) {
+               goto end;
+       }
+       /* Fallback on password file. */
+       pwd = getpwuid(getuid());
+       if (!pwd) {
+               goto end;
+       }
+       val = pwd->pw_dir;
+end:
+       return val;
+}
+#endif /* __MINGW32__ */
+
+BT_HIDDEN
+char *bt_common_get_home_plugin_path(void)
+{
+       char *path = NULL;
+       const char *home_dir;
+       size_t length;
+
+       home_dir = bt_get_home_dir();
+       if (!home_dir) {
+               goto end;
+       }
+
+       length = strlen(home_dir) + strlen(HOME_PLUGIN_SUBPATH) + 1;
+
+       if (length >= PATH_MAX) {
+               BT_LOGW("Home directory path is too long: length=%zu",
+                       length);
+               goto end;
+       }
+
+       path = malloc(PATH_MAX);
+       if (!path) {
+               goto end;
+       }
+
+       strcpy(path, home_dir);
+       strcat(path, HOME_PLUGIN_SUBPATH);
+
+end:
+       return path;
+}
+
+BT_HIDDEN
+int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs)
+{
+       int ret = 0;
+       const char *at;
+       const char *end;
+       size_t init_dirs_len;
+
+       BT_ASSERT(dirs);
+       init_dirs_len = dirs->len;
+
+       if (!paths) {
+               /* Nothing to append */
+               goto end;
+       }
+
+       at = paths;
+       end = paths + strlen(paths);
+
+       while (at < end) {
+               GString *path;
+               const char *next_sep;
+
+               next_sep = strchr(at, G_SEARCHPATH_SEPARATOR);
+               if (next_sep == at) {
+                       /*
+                        * Empty path: try next character (supported
+                        * to conform to the typical parsing of $PATH).
+                        */
+                       at++;
+                       continue;
+               } else if (!next_sep) {
+                       /* No more separator: use the remaining */
+                       next_sep = paths + strlen(paths);
+               }
+
+               path = g_string_new(NULL);
+               if (!path) {
+                       goto error;
+               }
+
+               g_string_append_len(path, at, next_sep - at);
+               at = next_sep + 1;
+               g_ptr_array_add(dirs, path);
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+       /* Remove the new entries in dirs */
+       while (dirs->len > init_dirs_len) {
+               g_ptr_array_remove_index(dirs, init_dirs_len);
+       }
+
+end:
+       return ret;
+}
+
+static
+bool isarealtty(int fd)
+{
+       bool istty = false;
+       struct stat tty_stats;
+
+       if (!isatty(fd)) {
+               /* Not a TTY */
+               goto end;
+       }
+
+       if (fstat(fd, &tty_stats) == 0) {
+               if (!S_ISCHR(tty_stats.st_mode)) {
+                       /* Not a character device: not a TTY */
+                       goto end;
+               }
+       }
+
+       istty = true;
+
+end:
+       return istty;
+}
+
+BT_HIDDEN
+bool bt_common_colors_supported(void)
+{
+       static bool supports_colors = false;
+       static bool supports_colors_set = false;
+       const char *term_env_var;
+       const char *term_color_env_var;
+
+       if (supports_colors_set) {
+               goto end;
+       }
+
+       supports_colors_set = true;
+
+       /*
+        * `BABELTRACE_TERM_COLOR` environment variable always overrides
+        * the automatic color support detection.
+        */
+       term_color_env_var = getenv("BABELTRACE_TERM_COLOR");
+       if (term_color_env_var) {
+               if (g_ascii_strcasecmp(term_color_env_var, "always") == 0) {
+                       /* Force colors */
+                       supports_colors = true;
+               } else if (g_ascii_strcasecmp(term_color_env_var, "never") == 0) {
+                       /* Force no colors */
+                       goto end;
+               }
+       }
+
+       /* We need a compatible, known terminal */
+       term_env_var = getenv("TERM");
+       if (!term_env_var) {
+               goto end;
+       }
+
+       if (strncmp(term_env_var, "xterm", 5) != 0 &&
+                       strncmp(term_env_var, "rxvt", 4) != 0 &&
+                       strncmp(term_env_var, "konsole", 7) != 0 &&
+                       strncmp(term_env_var, "gnome", 5) != 0 &&
+                       strncmp(term_env_var, "screen", 5) != 0 &&
+                       strncmp(term_env_var, "tmux", 4) != 0 &&
+                       strncmp(term_env_var, "putty", 5) != 0) {
+               goto end;
+       }
+
+       /* Both standard output and error streams need to be TTYs */
+       if (!isarealtty(STDOUT_FILENO) || !isarealtty(STDERR_FILENO)) {
+               goto end;
+       }
+
+       supports_colors = true;
+
+end:
+       return supports_colors;
+}
+
+BT_HIDDEN
+const char *bt_common_color_reset(void)
+{
+       return bt_common_color_code_reset;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bold(void)
+{
+       return bt_common_color_code_bold;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_default(void)
+{
+       return bt_common_color_code_fg_default;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_red(void)
+{
+       return bt_common_color_code_fg_red;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_green(void)
+{
+       return bt_common_color_code_fg_green;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_yellow(void)
+{
+       return bt_common_color_code_fg_yellow;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_blue(void)
+{
+       return bt_common_color_code_fg_blue;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_magenta(void)
+{
+       return bt_common_color_code_fg_magenta;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_cyan(void)
+{
+       return bt_common_color_code_fg_cyan;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_light_gray(void)
+{
+       return bt_common_color_code_fg_light_gray;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_default(void)
+{
+       return bt_common_color_code_bg_default;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_red(void)
+{
+       return bt_common_color_code_bg_red;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_green(void)
+{
+       return bt_common_color_code_bg_green;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_yellow(void)
+{
+       return bt_common_color_code_bg_yellow;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_blue(void)
+{
+       return bt_common_color_code_bg_blue;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_magenta(void)
+{
+       return bt_common_color_code_bg_magenta;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_cyan(void)
+{
+       return bt_common_color_code_bg_cyan;
+}
+
+BT_HIDDEN
+const char *bt_common_color_bg_light_gray(void)
+{
+       return bt_common_color_code_bg_light_gray;
+}
+
+BT_HIDDEN
+GString *bt_common_string_until(const char *input, const char *escapable_chars,
+               const char *end_chars, size_t *end_pos)
+{
+       GString *output = g_string_new(NULL);
+       const char *ch;
+       const char *es_char;
+       const char *end_char;
+
+       if (!output) {
+               goto error;
+       }
+
+       for (ch = input; *ch != '\0'; ch++) {
+               if (*ch == '\\') {
+                       bool continue_loop = false;
+
+                       if (ch[1] == '\0') {
+                               /* `\` at the end of the string: append `\` */
+                               g_string_append_c(output, *ch);
+                               ch++;
+                               goto set_end_pos;
+                       }
+
+                       for (es_char = escapable_chars; *es_char != '\0'; es_char++) {
+                               if (ch[1] == *es_char) {
+                                       /*
+                                        * `\` followed by an escapable
+                                        * character: append the escaped
+                                        * character only.
+                                        */
+                                       g_string_append_c(output, ch[1]);
+                                       ch++;
+                                       continue_loop = true;
+                                       break;
+                               }
+                       }
+
+                       if (continue_loop) {
+                               continue;
+                       }
+
+                       /*
+                        * `\` followed by a non-escapable character:
+                        * append `\` and the character.
+                        */
+                       g_string_append_c(output, *ch);
+                       g_string_append_c(output, ch[1]);
+                       ch++;
+                       continue;
+               } else {
+                       for (end_char = end_chars; *end_char != '\0'; end_char++) {
+                               if (*ch == *end_char) {
+                                       /*
+                                        * End character found:
+                                        * terminate this loop.
+                                        */
+                                       goto set_end_pos;
+                               }
+                       }
+
+                       /* Normal character: append */
+                       g_string_append_c(output, *ch);
+               }
+       }
+
+set_end_pos:
+       if (end_pos) {
+               *end_pos = ch - input;
+       }
+
+       goto end;
+
+error:
+       if (output) {
+               g_string_free(output, TRUE);
+       }
+
+end:
+       return output;
+}
+
+BT_HIDDEN
+GString *bt_common_shell_quote(const char *input, bool with_single_quotes)
+{
+       GString *output = g_string_new(NULL);
+       const char *ch;
+       bool no_quote = true;
+
+       if (!output) {
+               goto end;
+       }
+
+       if (strlen(input) == 0) {
+               if (with_single_quotes) {
+                       g_string_assign(output, "''");
+               }
+
+               goto end;
+       }
+
+       for (ch = input; *ch != '\0'; ch++) {
+               const char c = *ch;
+
+               if (!g_ascii_isalpha(c) && !g_ascii_isdigit(c) && c != '_' &&
+                               c != '@' && c != '%' && c != '+' && c != '=' &&
+                               c != ':' && c != ',' && c != '.' && c != '/' &&
+                               c != '-') {
+                       no_quote = false;
+                       break;
+               }
+       }
+
+       if (no_quote) {
+               g_string_assign(output, input);
+               goto end;
+       }
+
+       if (with_single_quotes) {
+               g_string_assign(output, "'");
+       }
+
+       for (ch = input; *ch != '\0'; ch++) {
+               if (*ch == '\'') {
+                       g_string_append(output, "'\"'\"'");
+               } else {
+                       g_string_append_c(output, *ch);
+               }
+       }
+
+       if (with_single_quotes) {
+               g_string_append_c(output, '\'');
+       }
+
+end:
+       return output;
+}
+
+BT_HIDDEN
+bool bt_common_string_is_printable(const char *input)
+{
+       const char *ch;
+       bool printable = true;
+       BT_ASSERT(input);
+
+       for (ch = input; *ch != '\0'; ch++) {
+               if (!isprint(*ch) && *ch != '\n' && *ch != '\r' &&
+                               *ch != '\t' && *ch != '\v') {
+                       printable = false;
+                       goto end;
+               }
+       }
+
+end:
+       return printable;
+}
+
+BT_HIDDEN
+void bt_common_destroy_lttng_live_url_parts(
+               struct bt_common_lttng_live_url_parts *parts)
+{
+       if (!parts) {
+               goto end;
+       }
+
+       if (parts->proto) {
+               g_string_free(parts->proto, TRUE);
+               parts->proto = NULL;
+       }
+
+       if (parts->hostname) {
+               g_string_free(parts->hostname, TRUE);
+               parts->hostname = NULL;
+       }
+
+       if (parts->target_hostname) {
+               g_string_free(parts->target_hostname, TRUE);
+               parts->target_hostname = NULL;
+       }
+
+       if (parts->session_name) {
+               g_string_free(parts->session_name, TRUE);
+               parts->session_name = NULL;
+       }
+
+end:
+       return;
+}
+
+BT_HIDDEN
+struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
+               const char *url, char *error_buf, size_t error_buf_size)
+{
+       struct bt_common_lttng_live_url_parts parts;
+       const char *at = url;
+       size_t end_pos;
+
+       BT_ASSERT(url);
+       memset(&parts, 0, sizeof(parts));
+       parts.port = -1;
+
+       /* Protocol */
+       parts.proto = bt_common_string_until(at, "", ":", &end_pos);
+       if (!parts.proto || parts.proto->len == 0) {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size, "Missing protocol");
+               }
+
+               goto error;
+       }
+
+       if (strcmp(parts.proto->str, "net") == 0) {
+               g_string_assign(parts.proto, "net4");
+       }
+
+       if (strcmp(parts.proto->str, "net4") != 0 &&
+                       strcmp(parts.proto->str, "net6") != 0) {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size,
+                               "Unknown protocol: `%s`", parts.proto->str);
+               }
+
+               goto error;
+       }
+
+       if (at[end_pos] != ':') {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size,
+                               "Expecting `:` after `%s`", parts.proto->str);
+               }
+
+               goto error;
+       }
+
+       at += end_pos;
+
+       /* :// */
+       if (strncmp(at, "://", 3) != 0) {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size,
+                               "Expecting `://` after protocol");
+               }
+
+               goto error;
+       }
+
+       at += 3;
+
+       /* Hostname */
+       parts.hostname = bt_common_string_until(at, "", ":/", &end_pos);
+       if (!parts.hostname || parts.hostname->len == 0) {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size, "Missing hostname");
+               }
+
+               goto error;
+       }
+
+       if (at[end_pos] == ':') {
+               /* Port */
+               GString *port;
+
+               at += end_pos + 1;
+               port = bt_common_string_until(at, "", "/", &end_pos);
+               if (!port || port->len == 0) {
+                       if (error_buf) {
+                               snprintf(error_buf, error_buf_size, "Missing port");
+                       }
+
+                       goto error;
+               }
+
+               if (sscanf(port->str, "%d", &parts.port) != 1) {
+                       if (error_buf) {
+                               snprintf(error_buf, error_buf_size,
+                                       "Invalid port: `%s`", port->str);
+                       }
+
+                       g_string_free(port, TRUE);
+                       goto error;
+               }
+
+               g_string_free(port, TRUE);
+
+               if (parts.port < 0 || parts.port >= 65536) {
+                       if (error_buf) {
+                               snprintf(error_buf, error_buf_size,
+                                       "Invalid port: %d", parts.port);
+                       }
+
+                       goto error;
+               }
+       }
+
+       if (at[end_pos] == '\0') {
+               goto end;
+       }
+
+       at += end_pos;
+
+       /* /host/ */
+       if (strncmp(at, "/host/", 6) != 0) {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size,
+                               "Expecting `/host/` after hostname or port");
+               }
+
+               goto error;
+       }
+
+       at += 6;
+
+       /* Target hostname */
+       parts.target_hostname = bt_common_string_until(at, "", "/", &end_pos);
+       if (!parts.target_hostname || parts.target_hostname->len == 0) {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size,
+                               "Missing target hostname");
+               }
+
+               goto error;
+       }
+
+       if (at[end_pos] == '\0') {
+               goto end;
+       }
+
+       at += end_pos + 1;
+
+       /* Session name */
+       parts.session_name = bt_common_string_until(at, "", "/", &end_pos);
+       if (!parts.session_name || parts.session_name->len == 0) {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size,
+                               "Missing session name");
+               }
+
+               goto error;
+       }
+
+       if (at[end_pos] == '/') {
+               if (error_buf) {
+                       snprintf(error_buf, error_buf_size,
+                               "Unexpected `/` after session name (`%s`)",
+                               parts.session_name->str);
+               }
+
+               goto error;
+       }
+
+       goto end;
+
+error:
+       bt_common_destroy_lttng_live_url_parts(&parts);
+
+end:
+       return parts;
+}
+
+BT_HIDDEN
+void bt_common_normalize_star_glob_pattern(char *pattern)
+{
+       const char *p;
+       char *np;
+       bool got_star = false;
+
+       BT_ASSERT(pattern);
+
+       for (p = pattern, np = pattern; *p != '\0'; p++) {
+               switch (*p) {
+               case '*':
+                       if (got_star) {
+                               /* Avoid consecutive stars. */
+                               continue;
+                       }
+
+                       got_star = true;
+                       break;
+               case '\\':
+                       /* Copy backslash character. */
+                       *np = *p;
+                       np++;
+                       p++;
+
+                       if (*p == '\0') {
+                               goto end;
+                       }
+
+                       /* fall-through */
+               default:
+                       got_star = false;
+                       break;
+               }
+
+               /* Copy single character. */
+               *np = *p;
+               np++;
+       }
+
+end:
+       *np = '\0';
+}
+
+static inline
+bool at_end_of_pattern(const char *p, const char *pattern, size_t pattern_len)
+{
+       return (p - pattern) == pattern_len || *p == '\0';
+}
+
+/*
+ * Globbing matching function with the star feature only (`?` and
+ * character sets are not supported). This matches `candidate` (plain
+ * string) against `pattern`. A literal star can be escaped with `\` in
+ * `pattern`.
+ *
+ * `pattern_len` or `candidate_len` can be greater than the actual
+ * string length of `pattern` or `candidate` if the string is
+ * null-terminated.
+ */
+BT_HIDDEN
+bool bt_common_star_glob_match(const char *pattern, size_t pattern_len,
+               const char *candidate, size_t candidate_len) {
+       const char *retry_c = candidate, *retry_p = pattern, *c, *p;
+       bool got_a_star = false;
+
+retry:
+       c = retry_c;
+       p = retry_p;
+
+       /*
+        * The concept here is to retry a match in the specific case
+        * where we already got a star. The retry position for the
+        * pattern is just after the most recent star, and the retry
+        * position for the candidate is the character following the
+        * last try's first character.
+        *
+        * Example:
+        *
+        *     candidate: hi ev every onyx one
+        *                ^
+        *     pattern:   hi*every*one
+        *                ^
+        *
+        *     candidate: hi ev every onyx one
+        *                 ^
+        *     pattern:   hi*every*one
+        *                 ^
+        *
+        *     candidate: hi ev every onyx one
+        *                  ^
+        *     pattern:   hi*every*one
+        *                  ^
+        *
+        *     candidate: hi ev every onyx one
+        *                  ^
+        *     pattern:   hi*every*one
+        *                   ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                   ^
+        *     pattern:   hi*every*one
+        *                   ^
+        *
+        *     candidate: hi ev every onyx one
+        *                   ^^
+        *     pattern:   hi*every*one
+        *                   ^^
+        *
+        *     candidate: hi ev every onyx one
+        *                   ^ ^
+        *     pattern:   hi*every*one
+        *                   ^ ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                    ^
+        *     pattern:   hi*every*one
+        *                   ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                     ^
+        *     pattern:   hi*every*one
+        *                   ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                      ^
+        *     pattern:   hi*every*one
+        *                   ^
+        *
+        *     candidate: hi ev every onyx one
+        *                      ^^
+        *     pattern:   hi*every*one
+        *                   ^^
+        *
+        *     candidate: hi ev every onyx one
+        *                      ^ ^
+        *     pattern:   hi*every*one
+        *                   ^ ^
+        *
+        *     candidate: hi ev every onyx one
+        *                      ^  ^
+        *     pattern:   hi*every*one
+        *                   ^  ^
+        *
+        *     candidate: hi ev every onyx one
+        *                      ^   ^
+        *     pattern:   hi*every*one
+        *                   ^   ^
+        *
+        *     candidate: hi ev every onyx one
+        *                           ^
+        *     pattern:   hi*every*one
+        *                        ^
+        *
+        *     candidate: hi ev every onyx one
+        *                           ^
+        *     pattern:   hi*every*one
+        *                         ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                            ^
+        *     pattern:   hi*every*one
+        *                         ^
+        *
+        *     candidate: hi ev every onyx one
+        *                            ^^
+        *     pattern:   hi*every*one
+        *                         ^^
+        *
+        *     candidate: hi ev every onyx one
+        *                            ^ ^
+        *     pattern:   hi*every*one
+        *                         ^ ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                             ^
+        *     pattern:   hi*every*one
+        *                         ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                              ^
+        *     pattern:   hi*every*one
+        *                         ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                               ^
+        *     pattern:   hi*every*one
+        *                         ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                                ^
+        *     pattern:   hi*every*one
+        *                         ^ MISMATCH
+        *
+        *     candidate: hi ev every onyx one
+        *                                 ^
+        *     pattern:   hi*every*one
+        *                         ^
+        *
+        *     candidate: hi ev every onyx one
+        *                                 ^^
+        *     pattern:   hi*every*one
+        *                         ^^
+        *
+        *     candidate: hi ev every onyx one
+        *                                 ^ ^
+        *     pattern:   hi*every*one
+        *                         ^ ^
+        *
+        *     candidate: hi ev every onyx one
+        *                                 ^  ^
+        *     pattern:   hi*every*one
+        *                         ^  ^ SUCCESS
+        */
+       while ((c - candidate) < candidate_len && *c != '\0') {
+               BT_ASSERT(*c);
+
+               if (at_end_of_pattern(p, pattern, pattern_len)) {
+                       goto end_of_pattern;
+               }
+
+               switch (*p) {
+               case '*':
+                       got_a_star = true;
+
+                       /*
+                        * Our first try starts at the current candidate
+                        * character and after the star in the pattern.
+                        */
+                       retry_c = c;
+                       retry_p = p + 1;
+
+                       if (at_end_of_pattern(retry_p, pattern, pattern_len)) {
+                               /*
+                                * Star at the end of the pattern at
+                                * this point: automatic match.
+                                */
+                               return true;
+                       }
+
+                       goto retry;
+               case '\\':
+                       /* Go to escaped character. */
+                       p++;
+
+                       /*
+                        * Fall through the default case which compares
+                        * the escaped character now.
+                        */
+                       /* fall-through */
+               default:
+                       if (at_end_of_pattern(p, pattern, pattern_len) ||
+                                       *c != *p) {
+end_of_pattern:
+                               /* Character mismatch OR end of pattern. */
+                               if (!got_a_star) {
+                                       /*
+                                        * We didn't get any star yet,
+                                        * so this first mismatch
+                                        * automatically makes the whole
+                                        * test fail.
+                                        */
+                                       return false;
+                               }
+
+                               /*
+                                * Next try: next candidate character,
+                                * original pattern character (following
+                                * the most recent star).
+                                */
+                               retry_c++;
+                               goto retry;
+                       }
+                       break;
+               }
+
+               /* Next pattern and candidate characters. */
+               c++;
+               p++;
+       }
+
+       /*
+        * We checked every candidate character and we're still in a
+        * success state: the only pattern character allowed to remain
+        * is a star.
+        */
+       if (at_end_of_pattern(p, pattern, pattern_len)) {
+               return true;
+       }
+
+       p++;
+       return p[-1] == '*' && at_end_of_pattern(p, pattern, pattern_len);
+}
+
+static
+void append_path_parts(const char *path, GPtrArray *parts)
+{
+       const char *ch = path;
+       const char *last = path;
+
+       while (true) {
+               if (*ch == G_DIR_SEPARATOR || *ch == '\0') {
+                       if (ch - last > 0) {
+                               GString *part = g_string_new(NULL);
+
+                               BT_ASSERT(part);
+                               g_string_append_len(part, last, ch - last);
+                               g_ptr_array_add(parts, part);
+                       }
+
+                       if (*ch == '\0') {
+                               break;
+                       }
+
+                       last = ch + 1;
+               }
+
+               ch++;
+       }
+}
+
+static
+void destroy_gstring(void *gstring)
+{
+       (void) g_string_free(gstring, TRUE);
+}
+
+#ifdef __MINGW32__
+BT_HIDDEN
+GString *bt_common_normalize_path(const char *path, const char *wd)
+{
+       char *tmp;
+       GString *norm_path = NULL;
+
+       BT_ASSERT(path);
+
+       tmp = _fullpath(NULL, path, PATH_MAX);
+       if (!tmp) {
+               goto error;
+       }
+
+       norm_path = g_string_new(tmp);
+       if (!norm_path) {
+               goto error;
+       }
+
+       goto end;
+error:
+       if (norm_path) {
+               g_string_free(norm_path, TRUE);
+               norm_path = NULL;
+       }
+end:
+       if (tmp) {
+               free(tmp);
+       }
+       return norm_path;
+}
+#else
+BT_HIDDEN
+GString *bt_common_normalize_path(const char *path, const char *wd)
+{
+       size_t i;
+       GString *norm_path;
+       GPtrArray *parts = NULL;
+
+       BT_ASSERT(path);
+       norm_path = g_string_new(G_DIR_SEPARATOR_S);
+       if (!norm_path) {
+               goto error;
+       }
+
+       parts = g_ptr_array_new_with_free_func(destroy_gstring);
+       if (!parts) {
+               goto error;
+       }
+
+       if (path[0] != G_DIR_SEPARATOR) {
+               /* Relative path: start with working directory */
+               if (wd) {
+                       append_path_parts(wd, parts);
+               } else {
+                       gchar *cd = g_get_current_dir();
+
+                       append_path_parts(cd, parts);
+                       g_free(cd);
+               }
+       }
+
+       /* Append parts of the path parameter */
+       append_path_parts(path, parts);
+
+       /* Resolve special `..` and `.` parts */
+       for (i = 0; i < parts->len; i++) {
+               GString *part = g_ptr_array_index(parts, i);
+
+               if (strcmp(part->str, "..") == 0) {
+                       if (i == 0) {
+                               /*
+                                * First part of absolute path is `..`:
+                                * this is invalid.
+                                */
+                               goto error;
+                       }
+
+                       /* Remove `..` and previous part */
+                       g_ptr_array_remove_index(parts, i - 1);
+                       g_ptr_array_remove_index(parts, i - 1);
+                       i -= 2;
+               } else if (strcmp(part->str, ".") == 0) {
+                       /* Remove `.` */
+                       g_ptr_array_remove_index(parts, i);
+                       i -= 1;
+               }
+       }
+
+       /* Create normalized path with what's left */
+       for (i = 0; i < parts->len; i++) {
+               GString *part = g_ptr_array_index(parts, i);
+
+               g_string_append(norm_path, part->str);
+
+               if (i < parts->len - 1) {
+                       g_string_append_c(norm_path, G_DIR_SEPARATOR);
+               }
+       }
+
+       goto end;
+
+error:
+       if (norm_path) {
+               g_string_free(norm_path, TRUE);
+               norm_path = NULL;
+       }
+
+end:
+       if (parts) {
+               g_ptr_array_free(parts, TRUE);
+       }
+
+       return norm_path;
+}
+#endif
+
+BT_HIDDEN
+size_t bt_common_get_page_size(void)
+{
+       int page_size;
+
+       page_size = bt_sysconf(_SC_PAGESIZE);
+       if (page_size < 0) {
+               BT_LOGF("Cannot get system's page size: ret=%d",
+                       page_size);
+               abort();
+       }
+
+       return page_size;
+}
+
+#define BUF_STD_APPEND(...)                                            \
+       do {                                                            \
+               char _tmp_fmt[64];                                      \
+               int _count;                                             \
+               size_t _size = buf_size - (size_t) (*buf_ch - buf);     \
+               size_t _tmp_fmt_size = (size_t) (fmt_ch - *out_fmt_ch); \
+               strncpy(_tmp_fmt, *out_fmt_ch, _tmp_fmt_size);          \
+               _tmp_fmt[_tmp_fmt_size] = '\0';                         \
+               _count = snprintf(*buf_ch, _size, _tmp_fmt, __VA_ARGS__); \
+               BT_ASSERT(_count >= 0);                                 \
+               *buf_ch += MIN(_count, _size);                          \
+       } while (0)
+
+#define BUF_STD_APPEND_SINGLE_ARG(_type)                               \
+       do {                                                            \
+               _type _arg = va_arg(*args, _type);                      \
+               BUF_STD_APPEND(_arg);                                   \
+       } while (0)
+
+static inline void handle_conversion_specifier_std(char *buf, char **buf_ch,
+               size_t buf_size, const char **out_fmt_ch, va_list *args)
+{
+       const char *fmt_ch = *out_fmt_ch;
+       enum LENGTH_MODIFIER {
+               LENGTH_MOD_H,
+               LENGTH_MOD_HH,
+               LENGTH_MOD_NONE,
+               LENGTH_MOD_LOW_L,
+               LENGTH_MOD_LOW_LL,
+               LENGTH_MOD_UP_L,
+               LENGTH_MOD_Z,
+       } length_mod = LENGTH_MOD_NONE;
+
+       /* skip '%' */
+       fmt_ch++;
+
+       if (*fmt_ch == '%') {
+               fmt_ch++;
+               **buf_ch = '%';
+               (*buf_ch)++;
+               goto update_rw_fmt;
+       }
+
+       /* flags */
+       for (;;) {
+               switch (*fmt_ch) {
+                       case '-':
+                       case '+':
+                       case ' ':
+                       case '#':
+                       case '0':
+                       case '\'':
+                               fmt_ch++;
+                               continue;
+                       default:
+                               break;
+               }
+               break;
+       }
+
+       /* width */
+       for (;;) {
+               if (*fmt_ch < '0' || *fmt_ch > '9') {
+                       break;
+               }
+
+               fmt_ch++;
+       }
+
+       /* precision */
+       if (*fmt_ch == '.') {
+               fmt_ch++;
+
+               for (;;) {
+                       if (*fmt_ch < '0' || *fmt_ch > '9') {
+                               break;
+                       }
+
+                       fmt_ch++;
+               }
+       }
+
+       /* format (PRI*64) */
+       if (strncmp(fmt_ch, PRId64, sizeof(PRId64) - 1) == 0) {
+               fmt_ch += sizeof(PRId64) - 1;
+               BUF_STD_APPEND_SINGLE_ARG(int64_t);
+               goto update_rw_fmt;
+       } else if (strncmp(fmt_ch, PRIu64, sizeof(PRIu64) - 1) == 0) {
+               fmt_ch += sizeof(PRIu64) - 1;
+               BUF_STD_APPEND_SINGLE_ARG(uint64_t);
+               goto update_rw_fmt;
+       } else if (strncmp(fmt_ch, PRIx64, sizeof(PRIx64) - 1) == 0) {
+               fmt_ch += sizeof(PRIx64) - 1;
+               BUF_STD_APPEND_SINGLE_ARG(uint64_t);
+               goto update_rw_fmt;
+       } else if (strncmp(fmt_ch, PRIX64, sizeof(PRIX64) - 1) == 0) {
+               fmt_ch += sizeof(PRIX64) - 1;
+               BUF_STD_APPEND_SINGLE_ARG(uint64_t);
+               goto update_rw_fmt;
+       } else if (strncmp(fmt_ch, PRIo64, sizeof(PRIo64) - 1) == 0) {
+               fmt_ch += sizeof(PRIo64) - 1;
+               BUF_STD_APPEND_SINGLE_ARG(uint64_t);
+               goto update_rw_fmt;
+       } else if (strncmp(fmt_ch, PRIi64, sizeof(PRIi64) - 1) == 0) {
+               fmt_ch += sizeof(PRIi64) - 1;
+               BUF_STD_APPEND_SINGLE_ARG(int64_t);
+               goto update_rw_fmt;
+       }
+
+       // length modifier
+       switch (*fmt_ch) {
+               case 'h':
+                       length_mod = LENGTH_MOD_H;
+                       fmt_ch++;
+
+                       if (*fmt_ch == 'h') {
+                               length_mod = LENGTH_MOD_HH;
+                               fmt_ch++;
+                               break;
+                       }
+                       break;
+               case 'l':
+                       length_mod = LENGTH_MOD_LOW_L;
+                       fmt_ch++;
+
+                       if (*fmt_ch == 'l') {
+                               length_mod = LENGTH_MOD_LOW_LL;
+                               fmt_ch++;
+                               break;
+                       }
+                       break;
+               case 'L':
+                       length_mod = LENGTH_MOD_UP_L;
+                       fmt_ch++;
+                       break;
+               case 'z':
+                       length_mod = LENGTH_MOD_Z;
+                       fmt_ch++;
+                       break;
+               default:
+                       break;
+       }
+
+       // format
+       switch (*fmt_ch) {
+       case 'c':
+       {
+               fmt_ch++;
+
+               switch (length_mod) {
+               case LENGTH_MOD_NONE:
+                       BUF_STD_APPEND_SINGLE_ARG(int);
+                       break;
+               case LENGTH_MOD_LOW_L:
+                       BUF_STD_APPEND_SINGLE_ARG(wint_t);
+                       break;
+               default:
+                       abort();
+               }
+               break;
+       }
+       case 's':
+               fmt_ch++;
+
+               switch (length_mod) {
+               case LENGTH_MOD_NONE:
+                       BUF_STD_APPEND_SINGLE_ARG(char *);
+                       break;
+               case LENGTH_MOD_LOW_L:
+                       BUF_STD_APPEND_SINGLE_ARG(wchar_t *);
+                       break;
+               default:
+                       abort();
+               }
+               break;
+       case 'd':
+       case 'i':
+               fmt_ch++;
+
+               switch (length_mod) {
+               case LENGTH_MOD_NONE:
+               case LENGTH_MOD_H:
+               case LENGTH_MOD_HH:
+                       BUF_STD_APPEND_SINGLE_ARG(int);
+                       break;
+               case LENGTH_MOD_LOW_L:
+                       BUF_STD_APPEND_SINGLE_ARG(long);
+                       break;
+               case LENGTH_MOD_LOW_LL:
+                       BUF_STD_APPEND_SINGLE_ARG(long long);
+                       break;
+               case LENGTH_MOD_Z:
+                       BUF_STD_APPEND_SINGLE_ARG(size_t);
+                       break;
+               default:
+                       abort();
+               }
+               break;
+       case 'o':
+       case 'x':
+       case 'X':
+       case 'u':
+               fmt_ch++;
+
+               switch (length_mod) {
+               case LENGTH_MOD_NONE:
+               case LENGTH_MOD_H:
+               case LENGTH_MOD_HH:
+                       BUF_STD_APPEND_SINGLE_ARG(unsigned int);
+                       break;
+               case LENGTH_MOD_LOW_L:
+                       BUF_STD_APPEND_SINGLE_ARG(unsigned long);
+                       break;
+               case LENGTH_MOD_LOW_LL:
+                       BUF_STD_APPEND_SINGLE_ARG(unsigned long long);
+                       break;
+               case LENGTH_MOD_Z:
+                       BUF_STD_APPEND_SINGLE_ARG(size_t);
+                       break;
+               default:
+                       abort();
+               }
+               break;
+       case 'f':
+       case 'F':
+       case 'e':
+       case 'E':
+       case 'g':
+       case 'G':
+               fmt_ch++;
+
+               switch (length_mod) {
+               case LENGTH_MOD_NONE:
+                       BUF_STD_APPEND_SINGLE_ARG(double);
+                       break;
+               case LENGTH_MOD_UP_L:
+                       BUF_STD_APPEND_SINGLE_ARG(long double);
+                       break;
+               default:
+                       abort();
+               }
+               break;
+       case 'p':
+               fmt_ch++;
+
+               if (length_mod == LENGTH_MOD_NONE) {
+                       BUF_STD_APPEND_SINGLE_ARG(void *);
+               } else {
+                       abort();
+               }
+               break;
+       default:
+               abort();
+       }
+
+update_rw_fmt:
+       *out_fmt_ch = fmt_ch;
+}
+
+BT_HIDDEN
+void bt_common_custom_vsnprintf(char *buf, size_t buf_size,
+               char intro,
+               bt_common_handle_custom_specifier_func handle_specifier,
+               void *priv_data, const char *fmt, va_list *args)
+{
+       const char *fmt_ch = fmt;
+       char *buf_ch = buf;
+
+       BT_ASSERT(buf);
+       BT_ASSERT(fmt);
+
+       while (*fmt_ch != '\0') {
+               switch (*fmt_ch) {
+               case '%':
+                       BT_ASSERT(fmt_ch[1] != '\0');
+
+                       if (fmt_ch[1] == intro) {
+                               handle_specifier(priv_data, &buf_ch,
+                                       buf_size - (size_t) (buf_ch - buf),
+                                       &fmt_ch, args);
+                       } else {
+                               handle_conversion_specifier_std(buf, &buf_ch,
+                                       buf_size, &fmt_ch, args);
+                       }
+
+                       if (buf_ch >= buf + buf_size - 1) {
+                               fmt_ch = "";
+                       }
+                       break;
+               default:
+                       *buf_ch = *fmt_ch;
+                       buf_ch++;
+                       if (buf_ch >= buf + buf_size - 1) {
+                               fmt_ch = "";
+                       }
+
+                       fmt_ch++;
+               }
+       }
+
+       *buf_ch = '\0';
+}
+
+BT_HIDDEN
+void bt_common_custom_snprintf(char *buf, size_t buf_size,
+               char intro,
+               bt_common_handle_custom_specifier_func handle_specifier,
+               void *priv_data, const char *fmt, ...)
+{
+       va_list args;
+       va_start(args, fmt);
+       bt_common_custom_vsnprintf(buf, buf_size, intro, handle_specifier,
+               priv_data, fmt, &args);
+       va_end(args);
+}
diff --git a/src/common/common.h b/src/common/common.h
new file mode 100644 (file)
index 0000000..13dbaf4
--- /dev/null
@@ -0,0 +1,641 @@
+#ifndef BABELTRACE_COMMON_INTERNAL_H
+#define BABELTRACE_COMMON_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "common/assert.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/trace-ir/field-class-const.h>
+#include <babeltrace2/trace-ir/field-path-const.h>
+#include <babeltrace2/trace-ir/event-class-const.h>
+#include <babeltrace2/graph/self-message-iterator.h>
+#include <babeltrace2/value.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <glib.h>
+
+#define BT_COMMON_COLOR_RESET              "\033[0m"
+#define BT_COMMON_COLOR_BOLD               "\033[1m"
+#define BT_COMMON_COLOR_FG_DEFAULT         "\033[39m"
+#define BT_COMMON_COLOR_FG_RED             "\033[31m"
+#define BT_COMMON_COLOR_FG_GREEN           "\033[32m"
+#define BT_COMMON_COLOR_FG_YELLOW          "\033[33m"
+#define BT_COMMON_COLOR_FG_BLUE            "\033[34m"
+#define BT_COMMON_COLOR_FG_MAGENTA         "\033[35m"
+#define BT_COMMON_COLOR_FG_CYAN            "\033[36m"
+#define BT_COMMON_COLOR_FG_LIGHT_GRAY      "\033[37m"
+#define BT_COMMON_COLOR_BG_DEFAULT         "\033[49m"
+#define BT_COMMON_COLOR_BG_RED             "\033[41m"
+#define BT_COMMON_COLOR_BG_GREEN           "\033[42m"
+#define BT_COMMON_COLOR_BG_YELLOW          "\033[43m"
+#define BT_COMMON_COLOR_BG_BLUE            "\033[44m"
+#define BT_COMMON_COLOR_BG_MAGENTA         "\033[45m"
+#define BT_COMMON_COLOR_BG_CYAN            "\033[46m"
+#define BT_COMMON_COLOR_BG_LIGHT_GRAY      "\033[47m"
+
+struct bt_common_lttng_live_url_parts {
+       GString *proto;
+       GString *hostname;
+       GString *target_hostname;
+       GString *session_name;
+
+       /* -1 means default port */
+       int port;
+};
+
+/*
+ * Checks if the current process has setuid or setgid access rights.
+ * Returns `true` if so.
+ */
+BT_HIDDEN
+bool bt_common_is_setuid_setgid(void);
+
+/*
+ * Returns the system-wide plugin path, e.g.
+ * `/usr/lib/babeltrace2/plugins`. Do not free the return value.
+ */
+BT_HIDDEN
+const char *bt_common_get_system_plugin_path(void);
+
+/*
+ * Returns the user plugin path, e.g.
+ * `/home/user/.local/lib/babeltrace2/plugins`. You need to free the
+ * return value.
+ */
+BT_HIDDEN
+char *bt_common_get_home_plugin_path(void);
+
+/*
+ * Appends the list of directories in `paths` to the array `dirs`.
+ * `paths` is a list of directories separated by `:`. Returns 0 on
+ * success.
+ */
+BT_HIDDEN
+int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs);
+
+/*
+ * Returns `true` if terminal color codes are supported for this
+ * process.
+ */
+BT_HIDDEN
+bool bt_common_colors_supported(void);
+
+BT_HIDDEN
+const char *bt_common_color_reset(void);
+
+BT_HIDDEN
+const char *bt_common_color_bold(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_default(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_red(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_green(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_yellow(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_blue(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_magenta(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_cyan(void);
+
+BT_HIDDEN
+const char *bt_common_color_fg_light_gray(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_default(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_red(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_green(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_yellow(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_blue(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_magenta(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_cyan(void);
+
+BT_HIDDEN
+const char *bt_common_color_bg_light_gray(void);
+
+/*
+ * Returns the substring from `input` to the first character found
+ * in the list of characters `end_chars`, unescaping any character
+ * found in `escapable_chars`, and sets `*end_pos` to the position of
+ * the end (from `input`). The caller owns the returned GString.
+ */
+BT_HIDDEN
+GString *bt_common_string_until(const char *input, const char *escapable_chars,
+                    const char *end_chars, size_t *end_pos);
+
+/*
+ * Returns the quoted version of `input` for a shell. If
+ * `with_single_quotes` is `true`, prepends and appends the `'` prefix
+ * and suffix to the returned string; otherwise the caller should
+ * prepend and append them manually, although they are not always
+ * required. The caller owns the returned GString.
+ */
+BT_HIDDEN
+GString *bt_common_shell_quote(const char *input, bool with_single_quotes);
+
+/*
+ * Returns `true` if `input` is a string made only of printable
+ * characters.
+ */
+BT_HIDDEN
+bool bt_common_string_is_printable(const char *input);
+
+/*
+ * Destroys the parts of an LTTng live URL as returned by
+ * bt_common_parse_lttng_live_url().
+ */
+BT_HIDDEN
+void bt_common_destroy_lttng_live_url_parts(
+               struct bt_common_lttng_live_url_parts *parts);
+
+/*
+ * Parses the LTTng live URL `url` and returns its different parts.
+ * If there's an error, writes the error message into `*error_buf`
+ * up to `error_buf_size` bytes. You must destroy the returned value
+ * with bt_common_destroy_lttng_live_url_parts().
+ */
+BT_HIDDEN
+struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url(
+               const char *url, char *error_buf, size_t error_buf_size);
+
+/*
+ * Normalizes (in place) a star globbing pattern to be used with
+ * bt_common_star_glob_match(). This function always succeeds.
+ */
+BT_HIDDEN
+void bt_common_normalize_star_glob_pattern(char *pattern);
+
+/*
+ * Returns `true` if `candidate` (of size `candidate_len`) matches
+ * the star globbing pattern `pattern` (of size `pattern_len`).
+ */
+BT_HIDDEN
+bool bt_common_star_glob_match(const char *pattern, size_t pattern_len,
+                const char *candidate, size_t candidate_len);
+
+/*
+ * Normalizes the path `path`:
+ *
+ * * If it's a relative path, converts it to an absolute path using
+ *   `wd` as the working directory (or the current working directory
+ *   if `wd` is NULL).
+ * * Removes consecutive and trailing slashes.
+ * * Resolves `..` and `.` in the path (both in `path` and in `wd`).
+ * * Does NOT resolve symbolic links.
+ *
+ * The caller owns the returned GString.
+ */
+BT_HIDDEN
+GString *bt_common_normalize_path(const char *path, const char *wd);
+
+typedef void (* bt_common_handle_custom_specifier_func)(void *priv_data,
+               char **buf, size_t avail_size, const char **fmt, va_list *args);
+
+/*
+ * This is a custom vsnprintf() which handles the standard conversion
+ * specifier as well as custom ones.
+ *
+ * `fmt` is a typical printf()-style format string, with the following
+ * limitations:
+ *
+ * * The `*` width specifier is not accepted.
+ * * The `*` precision specifier is not accepted.
+ * * The `j` and `t` length modifiers are not accepted.
+ * * The `n` format specifier is not accepted.
+ * * The format specifiers defined in <inttypes.h> are not accepted
+ *   except for `PRId64`, `PRIu64`, `PRIx64`, `PRIX64`, `PRIo64`, and
+ *   `PRIi64`.
+ *
+ * `intro` specifies which special character immediately following an
+ * introductory `%` character in `fmt` is used to indicate a custom
+ * conversion specifier. For example, if `intro` is '@', then any `%@`
+ * sequence in `fmt` is the beginning of a custom conversion specifier.
+ *
+ * When a custom conversion specifier is encountered in `fmt`,
+ * the function calls `handle_specifier`. This callback receives:
+ *
+ * `priv_data`:
+ *     Custom, private data.
+ *
+ * `buf`:
+ *     Address of the current buffer pointer. `*buf` is the position to
+ *     append new data. The callback must update `*buf` when appending
+ *     new data. The callback must ensure not to write passed the whole
+ *     buffer passed to bt_common_custom_vsnprintf().
+ *
+ * `avail_size`:
+ *     Number of bytes left in whole buffer from the `*buf` point.
+ *
+ * `fmt`:
+ *     Address of the current format string pointer. `*fmt` points to
+ *     the introductory `%` character, which is followed by the
+ *     character `intro`. The callback must update `*fmt` so that it
+ *     points after the whole custom conversion specifier.
+ *
+ * `args`:
+ *     Variable argument list. Use va_arg() to get new arguments from
+ *     this list and update it at the same time.
+ *
+ * Because this is an internal utility, this function and its callback
+ * do not return error codes: they abort when there's any error (bad
+ * format string, for example).
+ */
+BT_HIDDEN
+void bt_common_custom_vsnprintf(char *buf, size_t buf_size,
+               char intro,
+               bt_common_handle_custom_specifier_func handle_specifier,
+               void *priv_data, const char *fmt, va_list *args);
+
+/*
+ * Variadic form of bt_common_custom_vsnprintf().
+ */
+BT_HIDDEN
+void bt_common_custom_snprintf(char *buf, size_t buf_size,
+               char intro,
+               bt_common_handle_custom_specifier_func handle_specifier,
+               void *priv_data, const char *fmt, ...);
+
+/*
+ * Returns the system page size.
+ */
+BT_HIDDEN
+size_t bt_common_get_page_size(void);
+
+/*
+ * Wraps read() function to handle EINTR and partial reads.
+ * On success, it returns `count` received as parameter. On error, it returns a
+ * value smaller than the requested `count`.
+ */
+static inline
+ssize_t bt_common_read(int fd, void *buf, size_t count)
+{
+       size_t i = 0;
+       ssize_t ret;
+
+       BT_ASSERT(buf);
+
+       /* Never return an overflow value. */
+       BT_ASSERT(count <= SSIZE_MAX);
+
+       do {
+               ret = read(fd, buf + i, count - i);
+               if (ret < 0) {
+                       if (errno == EINTR) {
+#ifdef BT_LOGD_STR
+                               BT_LOGD_STR("read() call interrupted. Retrying...");
+#endif
+                               /* retry operation */
+                               continue;
+                       } else {
+#ifdef BT_LOGE_ERRNO
+                               BT_LOGE_ERRNO("Error while reading", ": fd=%d",
+                                       fd);
+#endif
+                               goto end;
+                       }
+               }
+               i += ret;
+               BT_ASSERT(i <= count);
+       } while (count - i > 0 && ret > 0);
+
+end:
+       if (ret >= 0) {
+               if (i == 0) {
+                       ret = -1;
+               } else {
+                       ret = i;
+               }
+       }
+
+       return ret;
+}
+
+static inline
+const char *bt_common_field_class_type_string(enum bt_field_class_type class_type)
+{
+       switch (class_type) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
+               return "BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER";
+       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
+               return "BT_FIELD_CLASS_TYPE_SIGNED_INTEGER";
+       case BT_FIELD_CLASS_TYPE_REAL:
+               return "BT_FIELD_CLASS_TYPE_REAL";
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+               return "BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION";
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+               return "BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION";
+       case BT_FIELD_CLASS_TYPE_STRING:
+               return "BT_FIELD_CLASS_TYPE_STRING";
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+               return "BT_FIELD_CLASS_TYPE_STRUCTURE";
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+               return "BT_FIELD_CLASS_TYPE_STATIC_ARRAY";
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+               return "BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY";
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+               return "BT_FIELD_CLASS_TYPE_VARIANT";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline
+const char *bt_common_field_class_integer_preferred_display_base_string(enum bt_field_class_integer_preferred_display_base base)
+{
+       switch (base) {
+       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
+               return "BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY";
+       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
+               return "BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL";
+       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
+               return "BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL";
+       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
+               return "BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+const char *bt_common_scope_string(enum bt_scope scope)
+{
+       switch (scope) {
+       case BT_SCOPE_PACKET_CONTEXT:
+               return "BT_SCOPE_PACKET_CONTEXT";
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               return "BT_SCOPE_EVENT_COMMON_CONTEXT";
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               return "BT_SCOPE_EVENT_SPECIFIC_CONTEXT";
+       case BT_SCOPE_EVENT_PAYLOAD:
+               return "BT_SCOPE_EVENT_PAYLOAD";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+const char *bt_common_event_class_log_level_string(
+               enum bt_event_class_log_level level)
+{
+       switch (level) {
+       case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
+               return "BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY";
+       case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
+               return "BT_EVENT_CLASS_LOG_LEVEL_ALERT";
+       case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
+               return "BT_EVENT_CLASS_LOG_LEVEL_CRITICAL";
+       case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
+               return "BT_EVENT_CLASS_LOG_LEVEL_ERROR";
+       case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
+               return "BT_EVENT_CLASS_LOG_LEVEL_WARNING";
+       case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
+               return "BT_EVENT_CLASS_LOG_LEVEL_NOTICE";
+       case BT_EVENT_CLASS_LOG_LEVEL_INFO:
+               return "BT_EVENT_CLASS_LOG_LEVEL_INFO";
+       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
+               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM";
+       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
+               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM";
+       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
+               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS";
+       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
+               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE";
+       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
+               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT";
+       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
+               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION";
+       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
+               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE";
+       case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
+               return "BT_EVENT_CLASS_LOG_LEVEL_DEBUG";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline
+const char *bt_common_value_type_string(enum bt_value_type type)
+{
+       switch (type) {
+       case BT_VALUE_TYPE_NULL:
+               return "BT_VALUE_TYPE_NULL";
+       case BT_VALUE_TYPE_BOOL:
+               return "BT_VALUE_TYPE_BOOL";
+       case BT_VALUE_TYPE_UNSIGNED_INTEGER:
+               return "BT_VALUE_TYPE_UNSIGNED_INTEGER";
+       case BT_VALUE_TYPE_SIGNED_INTEGER:
+               return "BT_VALUE_TYPE_SIGNED_INTEGER";
+       case BT_VALUE_TYPE_REAL:
+               return "BT_VALUE_TYPE_REAL";
+       case BT_VALUE_TYPE_STRING:
+               return "BT_VALUE_TYPE_STRING";
+       case BT_VALUE_TYPE_ARRAY:
+               return "BT_VALUE_TYPE_ARRAY";
+       case BT_VALUE_TYPE_MAP:
+               return "BT_VALUE_TYPE_MAP";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline
+GString *bt_common_field_path_string(struct bt_field_path *path)
+{
+       GString *str = g_string_new(NULL);
+       uint64_t i;
+
+       BT_ASSERT(path);
+
+       if (!str) {
+               goto end;
+       }
+
+       g_string_append_printf(str, "[%s", bt_common_scope_string(
+               bt_field_path_get_root_scope(path)));
+
+       for (i = 0; i < bt_field_path_get_item_count(path); i++) {
+               const struct bt_field_path_item *fp_item =
+                       bt_field_path_borrow_item_by_index_const(path, i);
+
+               switch (bt_field_path_item_get_type(fp_item)) {
+               case BT_FIELD_PATH_ITEM_TYPE_INDEX:
+                       g_string_append_printf(str, ", %" PRIu64,
+                               bt_field_path_item_index_get_index(fp_item));
+                       break;
+               case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
+                       g_string_append(str, ", <CUR>");
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       g_string_append(str, "]");
+
+end:
+       return str;
+}
+
+static inline
+const char *bt_common_self_message_iterator_status_string(
+               enum bt_self_message_iterator_status status)
+{
+       switch (status) {
+       case BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN:
+               return "BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN";
+       case BT_SELF_MESSAGE_ITERATOR_STATUS_END:
+               return "BT_SELF_MESSAGE_ITERATOR_STATUS_END";
+       case BT_SELF_MESSAGE_ITERATOR_STATUS_OK:
+               return "BT_SELF_MESSAGE_ITERATOR_STATUS_OK";
+       case BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR:
+               return "BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR";
+       case BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM:
+               return "BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+};
+
+#define NS_PER_S_I     INT64_C(1000000000)
+#define NS_PER_S_U     UINT64_C(1000000000)
+
+static inline
+int bt_common_clock_value_from_ns_from_origin(
+               int64_t cc_offset_seconds, uint64_t cc_offset_cycles,
+               uint64_t cc_freq, int64_t ns_from_origin,
+               uint64_t *raw_value)
+{
+       int ret = 0;
+       int64_t offset_in_ns;
+       uint64_t value_in_ns;
+       uint64_t rem_value_in_ns;
+       uint64_t value_periods;
+       uint64_t value_period_cycles;
+       int64_t ns_to_add;
+
+       BT_ASSERT(raw_value);
+
+       /* Compute offset part of requested value, in nanoseconds */
+       if (!bt_safe_to_mul_int64(cc_offset_seconds, NS_PER_S_I)) {
+               ret = -1;
+               goto end;
+       }
+
+       offset_in_ns = cc_offset_seconds * NS_PER_S_I;
+
+       if (cc_freq == NS_PER_S_U) {
+               ns_to_add = (int64_t) cc_offset_cycles;
+       } else {
+               if (!bt_safe_to_mul_int64((int64_t) cc_offset_cycles,
+                               NS_PER_S_I)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               ns_to_add = ((int64_t) cc_offset_cycles * NS_PER_S_I) /
+                       (int64_t) cc_freq;
+       }
+
+       if (!bt_safe_to_add_int64(offset_in_ns, ns_to_add)) {
+               ret = -1;
+               goto end;
+       }
+
+       offset_in_ns += ns_to_add;
+
+       /* Value part in nanoseconds */
+       if (ns_from_origin < offset_in_ns) {
+               ret = -1;
+               goto end;
+       }
+
+       value_in_ns = (uint64_t) (ns_from_origin - offset_in_ns);
+
+       /* Number of whole clock periods in `value_in_ns` */
+       value_periods = value_in_ns / NS_PER_S_U;
+
+       /* Remaining nanoseconds in cycles + whole clock periods in cycles */
+       rem_value_in_ns = value_in_ns - value_periods * NS_PER_S_U;
+
+       if (value_periods > UINT64_MAX / cc_freq) {
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_safe_to_mul_uint64(value_periods, cc_freq)) {
+               ret = -1;
+               goto end;
+       }
+
+       value_period_cycles = value_periods * cc_freq;
+
+       if (!bt_safe_to_mul_uint64(cc_freq, rem_value_in_ns)) {
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_safe_to_add_uint64(cc_freq * rem_value_in_ns / NS_PER_S_U,
+                       value_period_cycles)) {
+               ret = -1;
+               goto end;
+       }
+
+       *raw_value = cc_freq * rem_value_in_ns / NS_PER_S_U +
+               value_period_cycles;
+
+end:
+       return ret;
+}
+
+static inline
+enum bt_self_message_iterator_status bt_common_message_iterator_status_to_self(
+               enum bt_message_iterator_status status)
+{
+       return (int) status;
+}
+#endif /* BABELTRACE_COMMON_INTERNAL_H */
diff --git a/src/common/list.h b/src/common/list.h
new file mode 100644 (file)
index 0000000..48d9bbb
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2002 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ * Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; only
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _BT_LIST_H
+#define _BT_LIST_H     1
+
+/* The definitions of this file are adopted from those which can be
+   found in the Linux kernel headers to enable people familiar with
+   the latter find their way in these sources as well.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Basic type for the double-link list.  */
+struct bt_list_head
+{
+  struct bt_list_head *next;
+  struct bt_list_head *prev;
+};
+
+
+/* Define a variable with the head and tail of the list.  */
+#define BT_LIST_HEAD(name) \
+  struct bt_list_head name = { &(name), &(name) }
+
+/* Initialize a new list head.  */
+#define BT_INIT_LIST_HEAD(ptr) \
+  (ptr)->next = (ptr)->prev = (ptr)
+
+#define BT_LIST_HEAD_INIT(name) { .prev = &(name), .next = &(name) }
+
+/* Add new element at the head of the list.  */
+static inline void
+bt_list_add (struct bt_list_head *newp, struct bt_list_head *head)
+{
+  head->next->prev = newp;
+  newp->next = head->next;
+  newp->prev = head;
+  head->next = newp;
+}
+
+
+/* Add new element at the tail of the list.  */
+static inline void
+bt_list_add_tail (struct bt_list_head *newp, struct bt_list_head *head)
+{
+  head->prev->next = newp;
+  newp->next = head;
+  newp->prev = head->prev;
+  head->prev = newp;
+}
+
+
+/* Remove element from list.  */
+static inline void
+__bt_list_del (struct bt_list_head *prev, struct bt_list_head *next)
+{
+  next->prev = prev;
+  prev->next = next;
+}
+
+/* Remove element from list.  */
+static inline void
+bt_list_del (struct bt_list_head *elem)
+{
+  __bt_list_del (elem->prev, elem->next);
+}
+
+/* delete from list, add to another list as head */
+static inline void
+bt_list_move (struct bt_list_head *elem, struct bt_list_head *head)
+{
+  __bt_list_del (elem->prev, elem->next);
+  bt_list_add (elem, head);
+}
+
+/* replace an old entry.
+ */
+static inline void
+bt_list_replace(struct bt_list_head *old, struct bt_list_head *_new)
+{
+       _new->next = old->next;
+       _new->prev = old->prev;
+       _new->prev->next = _new;
+       _new->next->prev = _new;
+}
+
+/* Join two lists.  */
+static inline void
+bt_list_splice (struct bt_list_head *add, struct bt_list_head *head)
+{
+  /* Do nothing if the list which gets added is empty.  */
+  if (add != add->next)
+    {
+      add->next->prev = head;
+      add->prev->next = head->next;
+      head->next->prev = add->prev;
+      head->next = add->next;
+    }
+}
+
+
+/* Get typed element from list at a given position.  */
+#define bt_list_entry(ptr, type, member) \
+  ((type *) ((char *) (ptr) - (uintptr_t) (&((type *) 0)->member)))
+
+
+
+/* Iterate forward over the elements of the list.  */
+#define bt_list_for_each(pos, head) \
+  for (pos = (head)->next; pos != (head); pos = pos->next)
+
+
+/* Iterate forward over the elements of the list.  */
+#define bt_list_for_each_prev(pos, head) \
+  for (pos = (head)->prev; pos != (head); pos = pos->prev)
+
+
+/* Iterate backwards over the elements list.  The list elements can be
+   removed from the list while doing this.  */
+#define bt_list_for_each_prev_safe(pos, p, head) \
+  for (pos = (head)->prev, p = pos->prev; \
+       pos != (head); \
+       pos = p, p = pos->prev)
+
+#define bt_list_for_each_entry(pos, head, member)                              \
+       for (pos = bt_list_entry((head)->next, typeof(*pos), member);   \
+            &pos->member != (head);                                    \
+            pos = bt_list_entry(pos->member.next, typeof(*pos), member))
+
+#define bt_list_for_each_entry_reverse(pos, head, member)                      \
+       for (pos = bt_list_entry((head)->prev, typeof(*pos), member);   \
+            &pos->member != (head);                                    \
+            pos = bt_list_entry(pos->member.prev, typeof(*pos), member))
+
+#define bt_list_for_each_entry_safe(pos, p, head, member)                      \
+       for (pos = bt_list_entry((head)->next, typeof(*pos), member),   \
+                    p = bt_list_entry(pos->member.next,typeof(*pos), member); \
+            &pos->member != (head);                                    \
+            pos = p, p = bt_list_entry(pos->member.next, typeof(*pos), member))
+
+static inline int bt_list_empty(struct bt_list_head *head)
+{
+       return head == head->next;
+}
+
+static inline void bt_list_replace_init(struct bt_list_head *old,
+                                    struct bt_list_head *_new)
+{
+       struct bt_list_head *head = old->next;
+       bt_list_del(old);
+       bt_list_add_tail(_new, head);
+       BT_INIT_LIST_HEAD(old);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BT_LIST_H */
diff --git a/src/common/logging.c b/src/common/logging.c
new file mode 100644 (file)
index 0000000..7af804b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_common_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_common_log_level, "BABELTRACE_COMMON_LOG_LEVEL");
diff --git a/src/common/logging.h b/src/common/logging.h
new file mode 100644 (file)
index 0000000..48e1f7b
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef COMMON_LOGGING_H
+#define COMMON_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_common_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_common_log_level);
+
+#endif /* COMMON_LOGGING_H */
diff --git a/src/common/mmap-align.h b/src/common/mmap-align.h
new file mode 100644 (file)
index 0000000..1bb2b72
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef _BABELTRACE_MMAP_ALIGN_H
+#define _BABELTRACE_MMAP_ALIGN_H
+
+/*
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/align.h"
+#include <stdlib.h>
+#include <stdint.h>
+#include "compat/mman.h"
+#include "common/common.h"
+
+/*
+ * This header implements a wrapper over mmap (mmap_align) that memory
+ * maps a file region that is not necessarily multiple of the page size.
+ * It returns a structure (instead of a pointer) that contains the mmap
+ * pointer (page-aligned) and a pointer to the offset requested within
+ * that page. Note: in the current implementation, the "addr" parameter
+ * cannot be forced, so we allocate at an address chosen by the OS.
+ */
+
+struct mmap_align {
+       void *page_aligned_addr;        /* mmap address, aligned to floor */
+       size_t page_aligned_length;     /* mmap length, containing range */
+
+       void *addr;                     /* virtual mmap address */
+       size_t length;                  /* virtual mmap length */
+};
+
+#ifdef __WIN32__
+#include <windows.h>
+
+/*
+ * On windows the memory mapping offset must be aligned to the memory
+ * allocator allocation granularity and not the page size.
+ */
+static inline
+off_t get_page_aligned_offset(off_t offset, size_t page_size)
+{
+       SYSTEM_INFO sysinfo;
+
+       GetNativeSystemInfo(&sysinfo);
+
+       return ALIGN_FLOOR(offset, sysinfo.dwAllocationGranularity);
+}
+#else
+static inline
+off_t get_page_aligned_offset(off_t offset, size_t page_size)
+{
+       return ALIGN_FLOOR(offset, page_size);
+}
+#endif
+
+static inline
+struct mmap_align *mmap_align(size_t length, int prot,
+               int flags, int fd, off_t offset)
+{
+       struct mmap_align *mma;
+       off_t page_aligned_offset;      /* mmap offset, aligned to floor */
+       size_t page_size;
+
+       page_size = bt_common_get_page_size();
+
+       mma = malloc(sizeof(*mma));
+       if (!mma)
+               return MAP_FAILED;
+       mma->length = length;
+       page_aligned_offset = get_page_aligned_offset(offset, page_size);
+       /*
+        * Page aligned length needs to contain the requested range.
+        * E.g., for a small range that fits within a single page, we might
+        * require a 2 pages page_aligned_length if the range crosses a page
+        * boundary.
+        */
+       mma->page_aligned_length = ALIGN(length + offset - page_aligned_offset, page_size);
+       mma->page_aligned_addr = bt_mmap(NULL, mma->page_aligned_length,
+               prot, flags, fd, page_aligned_offset);
+       if (mma->page_aligned_addr == MAP_FAILED) {
+               free(mma);
+               return MAP_FAILED;
+       }
+       mma->addr = ((uint8_t *) mma->page_aligned_addr) + (offset - page_aligned_offset);
+       return mma;
+}
+
+static inline
+int munmap_align(struct mmap_align *mma)
+{
+       void *page_aligned_addr;
+       size_t page_aligned_length;
+
+       page_aligned_addr = mma->page_aligned_addr;
+       page_aligned_length = mma->page_aligned_length;
+       free(mma);
+       return bt_munmap(page_aligned_addr, page_aligned_length);
+}
+
+static inline
+void *mmap_align_addr(struct mmap_align *mma)
+{
+       return mma->addr;
+}
+
+/*
+ * Helper for special-cases, normally unused.
+ */
+static inline
+void mmap_align_set_addr(struct mmap_align *mma, void *addr)
+{
+       mma->addr = addr;
+}
+
+#endif /* _BABELTRACE_MMAP_ALIGN_H */
diff --git a/src/common/version.h b/src/common/version.h
new file mode 100644 (file)
index 0000000..acae2c4
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+/*
+ * Copyright (C) 2018 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/version.i"
+
+#endif /* VERSION_H */
diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am
new file mode 100644 (file)
index 0000000..040ccc8
--- /dev/null
@@ -0,0 +1,32 @@
+noinst_LTLIBRARIES = libcompat.la
+
+libcompat_la_SOURCES = \
+       logging.c \
+       logging.h \
+       mman.c \
+       mman.h \
+       uuid.c \
+       uuid.h
+
+libcompat_la_LDFLAGS = \
+       $(LD_NO_AS_NEEDED)
+
+if BABELTRACE_BUILD_WITH_MINGW
+libcompat_la_LDFLAGS += -lrpcrt4
+endif
+
+noinst_HEADERS = \
+       bitfield.h \
+       compiler.h \
+       endian.h \
+       fcntl.h \
+       glib.h \
+       limits.h \
+       memstream.h \
+       socket.h \
+       stdio.h \
+       stdlib.h \
+       string.h \
+       time.h \
+       unistd.h \
+       utc.h
diff --git a/src/compat/bitfield.h b/src/compat/bitfield.h
new file mode 100644 (file)
index 0000000..a24904b
--- /dev/null
@@ -0,0 +1,551 @@
+#ifndef _BABELTRACE_BITFIELD_H
+#define _BABELTRACE_BITFIELD_H
+
+/*
+ * Copyright 2010-2019 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>    /* C99 5.2.4.2 Numerical limits */
+#include <stdbool.h>   /* C99 7.16 bool type */
+#include "compat/limits.h"     /* C99 5.2.4.2 Numerical limits */
+#include "compat/endian.h"     /* Non-standard BIG_ENDIAN, LITTLE_ENDIAN, BYTE_ORDER */
+
+/*
+ * This header strictly follows the C99 standard, except for use of the
+ * compiler-specific __typeof__.
+ */
+
+/*
+ * This bitfield header requires the compiler representation of signed
+ * integers to be two's complement.
+ */
+#if (-1 != ~0)
+#error "bitfield.h requires the compiler representation of signed integers to be two's complement."
+#endif
+
+/*
+ * _bt_is_signed_type() willingly generates comparison of unsigned
+ * expression < 0, which is always false. Silence compiler warnings.
+ */
+#ifdef __GNUC__
+# define _BT_DIAG_PUSH                 _Pragma("GCC diagnostic push")
+# define _BT_DIAG_POP                  _Pragma("GCC diagnostic pop")
+
+# define _BT_DIAG_STRINGIFY_1(x)       #x
+# define _BT_DIAG_STRINGIFY(x)         _BT_DIAG_STRINGIFY_1(x)
+
+# define _BT_DIAG_IGNORE(option)       \
+       _Pragma(_BT_DIAG_STRINGIFY(GCC diagnostic ignored option))
+# define _BT_DIAG_IGNORE_TYPE_LIMITS   _BT_DIAG_IGNORE("-Wtype-limits")
+#else
+# define _BT_DIAG_PUSH
+# define _BT_DIAG_POP
+# define _BT_DIAG_IGNORE
+#endif
+
+#define _bt_is_signed_type(type)       ((type) -1 < (type) 0)
+
+/*
+ * Produce a build-time error if the condition `cond` is non-zero.
+ * Evaluates as a size_t expression.
+ */
+#define _BT_BUILD_ASSERT(cond)                                 \
+       sizeof(struct { int f:(2 * !!(cond) - 1); })
+
+/*
+ * Cast value `v` to an unsigned integer of the same size as `v`.
+ */
+#define _bt_cast_value_to_unsigned(v)                                  \
+       (sizeof(v) == sizeof(uint8_t) ? (uint8_t) (v) :                 \
+       sizeof(v) == sizeof(uint16_t) ? (uint16_t) (v) :                \
+       sizeof(v) == sizeof(uint32_t) ? (uint32_t) (v) :                \
+       sizeof(v) == sizeof(uint64_t) ? (uint64_t) (v) :                \
+       _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t)))
+
+/*
+ * Cast value `v` to an unsigned integer type of the size of type `type`
+ * *without* sign-extension.
+ *
+ * The unsigned cast ensures that we're not shifting a negative value,
+ * which is undefined in C. However, this limits the maximum type size
+ * of `type` to 64-bit. Generate a compile-time error if the size of
+ * `type` is larger than 64-bit.
+ */
+#define _bt_cast_value_to_unsigned_type(type, v)                       \
+       (sizeof(type) == sizeof(uint8_t) ?                              \
+               (uint8_t) _bt_cast_value_to_unsigned(v) :               \
+       sizeof(type) == sizeof(uint16_t) ?                              \
+               (uint16_t) _bt_cast_value_to_unsigned(v) :              \
+       sizeof(type) == sizeof(uint32_t) ?                              \
+               (uint32_t) _bt_cast_value_to_unsigned(v) :              \
+       sizeof(type) == sizeof(uint64_t) ?                              \
+               (uint64_t) _bt_cast_value_to_unsigned(v) :              \
+       _BT_BUILD_ASSERT(sizeof(v) <= sizeof(uint64_t)))
+
+/*
+ * _bt_fill_mask evaluates to a "type" integer with all bits set.
+ */
+#define _bt_fill_mask(type)    ((type) ~(type) 0)
+
+/*
+ * Left shift a value `v` of `shift` bits.
+ *
+ * The type of `v` can be signed or unsigned integer.
+ * The value of `shift` must be less than the size of `v` (in bits),
+ * otherwise the behavior is undefined.
+ * Evaluates to the result of the shift operation.
+ *
+ * According to the C99 standard, left shift of a left hand-side signed
+ * type is undefined if it has a negative value or if the result cannot
+ * be represented in the result type. This bitfield header discards the
+ * bits that are left-shifted beyond the result type representation,
+ * which is the behavior of an unsigned type left shift operation.
+ * Therefore, always perform left shift on an unsigned type.
+ *
+ * This macro should not be used if `shift` can be greater or equal than
+ * the bitwidth of `v`. See `_bt_safe_lshift`.
+ */
+#define _bt_lshift(v, shift)                                           \
+       ((__typeof__(v)) (_bt_cast_value_to_unsigned(v) << (shift)))
+
+/*
+ * Generate a mask of type `type` with the `length` least significant bits
+ * cleared, and the most significant bits set.
+ */
+#define _bt_make_mask_complement(type, length)                         \
+       _bt_lshift(_bt_fill_mask(type), length)
+
+/*
+ * Generate a mask of type `type` with the `length` least significant bits
+ * set, and the most significant bits cleared.
+ */
+#define _bt_make_mask(type, length)                                    \
+       ((type) ~_bt_make_mask_complement(type, length))
+
+/*
+ * Right shift a value `v` of `shift` bits.
+ *
+ * The type of `v` can be signed or unsigned integer.
+ * The value of `shift` must be less than the size of `v` (in bits),
+ * otherwise the behavior is undefined.
+ * Evaluates to the result of the shift operation.
+ *
+ * According to the C99 standard, right shift of a left hand-side signed
+ * type which has a negative value is implementation defined. This
+ * bitfield header relies on the right shift implementation carrying the
+ * sign bit. If the compiler implementation has a different behavior,
+ * emulate carrying the sign bit.
+ *
+ * This macro should not be used if `shift` can be greater or equal than
+ * the bitwidth of `v`. See `_bt_safe_rshift`.
+ */
+#if ((-1 >> 1) == -1)
+#define _bt_rshift(v, shift)   ((v) >> (shift))
+#else
+#define _bt_rshift(v, shift)                                           \
+       ((__typeof__(v)) ((_bt_cast_value_to_unsigned(v) >> (shift)) |  \
+               ((v) < 0 ? _bt_make_mask_complement(__typeof__(v),      \
+                       sizeof(v) * CHAR_BIT - (shift)) : 0)))
+#endif
+
+/*
+ * Right shift a signed or unsigned integer with `shift` value being an
+ * arbitrary number of bits. `v` is modified by this macro. The shift
+ * is transformed into a sequence of `_nr_partial_shifts` consecutive
+ * shift operations, each of a number of bits smaller than the bitwidth
+ * of `v`, ending with a shift of the number of left over bits.
+ */
+#define _bt_safe_rshift(v, shift)                                      \
+do {                                                                   \
+       unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \
+       unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \
+                                                                       \
+       for (; _nr_partial_shifts; _nr_partial_shifts--)                \
+               (v) = _bt_rshift(v, sizeof(v) * CHAR_BIT - 1);          \
+       (v) = _bt_rshift(v, _leftover_bits);                            \
+} while (0)
+
+/*
+ * Left shift a signed or unsigned integer with `shift` value being an
+ * arbitrary number of bits. `v` is modified by this macro. The shift
+ * is transformed into a sequence of `_nr_partial_shifts` consecutive
+ * shift operations, each of a number of bits smaller than the bitwidth
+ * of `v`, ending with a shift of the number of left over bits.
+ */
+#define _bt_safe_lshift(v, shift)                                      \
+do {                                                                   \
+       unsigned long _nr_partial_shifts = (shift) / (sizeof(v) * CHAR_BIT - 1); \
+       unsigned long _leftover_bits = (shift) % (sizeof(v) * CHAR_BIT - 1); \
+                                                                       \
+       for (; _nr_partial_shifts; _nr_partial_shifts--)                \
+               (v) = _bt_lshift(v, sizeof(v) * CHAR_BIT - 1);          \
+       (v) = _bt_lshift(v, _leftover_bits);                            \
+} while (0)
+
+/*
+ * bt_bitfield_write - write integer to a bitfield in native endianness
+ *
+ * Save integer to the bitfield, which starts at the "start" bit, has "len"
+ * bits.
+ * The inside of a bitfield is from high bits to low bits.
+ * Uses native endianness.
+ * For unsigned "v", pad MSB with 0 if bitfield is larger than v.
+ * For signed "v", sign-extend v if bitfield is larger than v.
+ *
+ * On little endian, bytes are placed from the less significant to the most
+ * significant. Also, consecutive bitfields are placed from lower bits to higher
+ * bits.
+ *
+ * On big endian, bytes are places from most significant to less significant.
+ * Also, consecutive bitfields are placed from higher to lower bits.
+ */
+
+#define _bt_bitfield_write_le(ptr, type, start, length, v)             \
+do {                                                                   \
+       __typeof__(v) _v = (v);                                 \
+       type *_ptr = (void *) (ptr);                                    \
+       unsigned long _start = (start), _length = (length);             \
+       type _mask, _cmask;                                             \
+       unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */    \
+       unsigned long _start_unit, _end_unit, _this_unit;               \
+       unsigned long _end, _cshift; /* _cshift is "complement shift" */ \
+                                                                       \
+       if (!_length)                                                   \
+               break;                                                  \
+                                                                       \
+       _end = _start + _length;                                        \
+       _start_unit = _start / _ts;                                     \
+       _end_unit = (_end + (_ts - 1)) / _ts;                           \
+                                                                       \
+       /* Trim v high bits */                                          \
+       if (_length < sizeof(_v) * CHAR_BIT)                            \
+               _v &= _bt_make_mask(__typeof__(_v), _length);           \
+                                                                       \
+       /* We can now append v with a simple "or", shift it piece-wise */ \
+       _this_unit = _start_unit;                                       \
+       if (_start_unit == _end_unit - 1) {                             \
+               _mask = _bt_make_mask(type, _start % _ts);              \
+               if (_end % _ts)                                         \
+                       _mask |= _bt_make_mask_complement(type, _end % _ts); \
+               _cmask = _bt_lshift((type) (_v), _start % _ts);         \
+               _cmask &= ~_mask;                                       \
+               _ptr[_this_unit] &= _mask;                              \
+               _ptr[_this_unit] |= _cmask;                             \
+               break;                                                  \
+       }                                                               \
+       if (_start % _ts) {                                             \
+               _cshift = _start % _ts;                                 \
+               _mask = _bt_make_mask(type, _cshift);                   \
+               _cmask = _bt_lshift((type) (_v), _cshift);              \
+               _cmask &= ~_mask;                                       \
+               _ptr[_this_unit] &= _mask;                              \
+               _ptr[_this_unit] |= _cmask;                             \
+               _bt_safe_rshift(_v, _ts - _cshift);                     \
+               _start += _ts - _cshift;                                \
+               _this_unit++;                                           \
+       }                                                               \
+       for (; _this_unit < _end_unit - 1; _this_unit++) {              \
+               _ptr[_this_unit] = (type) _v;                           \
+               _bt_safe_rshift(_v, _ts);                               \
+               _start += _ts;                                          \
+       }                                                               \
+       if (_end % _ts) {                                               \
+               _mask = _bt_make_mask_complement(type, _end % _ts);     \
+               _cmask = (type) _v;                                     \
+               _cmask &= ~_mask;                                       \
+               _ptr[_this_unit] &= _mask;                              \
+               _ptr[_this_unit] |= _cmask;                             \
+       } else                                                          \
+               _ptr[_this_unit] = (type) _v;                           \
+} while (0)
+
+#define _bt_bitfield_write_be(ptr, type, start, length, v)             \
+do {                                                                   \
+       __typeof__(v) _v = (v);                                         \
+       type *_ptr = (void *) (ptr);                                    \
+       unsigned long _start = (start), _length = (length);             \
+       type _mask, _cmask;                                             \
+       unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */    \
+       unsigned long _start_unit, _end_unit, _this_unit;               \
+       unsigned long _end, _cshift; /* _cshift is "complement shift" */ \
+                                                                       \
+       if (!_length)                                                   \
+               break;                                                  \
+                                                                       \
+       _end = _start + _length;                                        \
+       _start_unit = _start / _ts;                                     \
+       _end_unit = (_end + (_ts - 1)) / _ts;                           \
+                                                                       \
+       /* Trim v high bits */                                          \
+       if (_length < sizeof(_v) * CHAR_BIT)                            \
+               _v &= _bt_make_mask(__typeof__(_v), _length);           \
+                                                                       \
+       /* We can now append v with a simple "or", shift it piece-wise */ \
+       _this_unit = _end_unit - 1;                                     \
+       if (_start_unit == _end_unit - 1) {                             \
+               _mask = _bt_make_mask(type, (_ts - (_end % _ts)) % _ts); \
+               if (_start % _ts)                                       \
+                       _mask |= _bt_make_mask_complement(type, _ts - (_start % _ts)); \
+               _cmask = _bt_lshift((type) (_v), (_ts - (_end % _ts)) % _ts); \
+               _cmask &= ~_mask;                                       \
+               _ptr[_this_unit] &= _mask;                              \
+               _ptr[_this_unit] |= _cmask;                             \
+               break;                                                  \
+       }                                                               \
+       if (_end % _ts) {                                               \
+               _cshift = _end % _ts;                                   \
+               _mask = _bt_make_mask(type, _ts - _cshift);             \
+               _cmask = _bt_lshift((type) (_v), _ts - _cshift);        \
+               _cmask &= ~_mask;                                       \
+               _ptr[_this_unit] &= _mask;                              \
+               _ptr[_this_unit] |= _cmask;                             \
+               _bt_safe_rshift(_v, _cshift);                           \
+               _end -= _cshift;                                        \
+               _this_unit--;                                           \
+       }                                                               \
+       for (; (long) _this_unit >= (long) _start_unit + 1; _this_unit--) { \
+               _ptr[_this_unit] = (type) _v;                           \
+               _bt_safe_rshift(_v, _ts);                               \
+               _end -= _ts;                                            \
+       }                                                               \
+       if (_start % _ts) {                                             \
+               _mask = _bt_make_mask_complement(type, _ts - (_start % _ts)); \
+               _cmask = (type) _v;                                     \
+               _cmask &= ~_mask;                                       \
+               _ptr[_this_unit] &= _mask;                              \
+               _ptr[_this_unit] |= _cmask;                             \
+       } else                                                          \
+               _ptr[_this_unit] = (type) _v;                           \
+} while (0)
+
+/*
+ * bt_bitfield_write - write integer to a bitfield in native endianness
+ * bt_bitfield_write_le - write integer to a bitfield in little endian
+ * bt_bitfield_write_be - write integer to a bitfield in big endian
+ */
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+
+#define bt_bitfield_write(ptr, type, start, length, v)                 \
+       _bt_bitfield_write_le(ptr, type, start, length, v)
+
+#define bt_bitfield_write_le(ptr, type, start, length, v)              \
+       _bt_bitfield_write_le(ptr, type, start, length, v)
+
+#define bt_bitfield_write_be(ptr, type, start, length, v)              \
+       _bt_bitfield_write_be(ptr, unsigned char, start, length, v)
+
+#elif (BYTE_ORDER == BIG_ENDIAN)
+
+#define bt_bitfield_write(ptr, type, start, length, v)                 \
+       _bt_bitfield_write_be(ptr, type, start, length, v)
+
+#define bt_bitfield_write_le(ptr, type, start, length, v)              \
+       _bt_bitfield_write_le(ptr, unsigned char, start, length, v)
+
+#define bt_bitfield_write_be(ptr, type, start, length, v)              \
+       _bt_bitfield_write_be(ptr, type, start, length, v)
+
+#else /* (BYTE_ORDER == PDP_ENDIAN) */
+
+#error "Byte order not supported"
+
+#endif
+
+#define _bt_bitfield_read_le(ptr, type, start, length, vptr)           \
+do {                                                                   \
+       __typeof__(*(vptr)) *_vptr = (vptr);                            \
+       __typeof__(*_vptr) _v;                                          \
+       type *_ptr = (void *) (ptr);                                    \
+       unsigned long _start = (start), _length = (length);             \
+       type _mask, _cmask;                                             \
+       unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */    \
+       unsigned long _start_unit, _end_unit, _this_unit;               \
+       unsigned long _end, _cshift; /* _cshift is "complement shift" */ \
+       bool _is_signed_type;                                           \
+                                                                       \
+       if (!_length) {                                                 \
+               *_vptr = 0;                                             \
+               break;                                                  \
+       }                                                               \
+                                                                       \
+       _end = _start + _length;                                        \
+       _start_unit = _start / _ts;                                     \
+       _end_unit = (_end + (_ts - 1)) / _ts;                           \
+                                                                       \
+       _this_unit = _end_unit - 1;                                     \
+       _BT_DIAG_PUSH                                                   \
+       _BT_DIAG_IGNORE_TYPE_LIMITS                                     \
+       _is_signed_type = _bt_is_signed_type(__typeof__(_v));           \
+       _BT_DIAG_POP                                                    \
+       if (_is_signed_type                                             \
+           && (_ptr[_this_unit] & _bt_lshift((type) 1, (_end % _ts ? _end % _ts : _ts) - 1))) \
+               _v = ~(__typeof__(_v)) 0;                               \
+       else                                                            \
+               _v = 0;                                                 \
+       if (_start_unit == _end_unit - 1) {                             \
+               _cmask = _ptr[_this_unit];                              \
+               _cmask = _bt_rshift(_cmask, _start % _ts);              \
+               if ((_end - _start) % _ts) {                            \
+                       _mask = _bt_make_mask(type, _end - _start);     \
+                       _cmask &= _mask;                                \
+               }                                                       \
+               _bt_safe_lshift(_v, _end - _start);                     \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
+               *_vptr = _v;                                            \
+               break;                                                  \
+       }                                                               \
+       if (_end % _ts) {                                               \
+               _cshift = _end % _ts;                                   \
+               _mask = _bt_make_mask(type, _cshift);                   \
+               _cmask = _ptr[_this_unit];                              \
+               _cmask &= _mask;                                        \
+               _bt_safe_lshift(_v, _cshift);                           \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
+               _end -= _cshift;                                        \
+               _this_unit--;                                           \
+       }                                                               \
+       for (; (long) _this_unit >= (long) _start_unit + 1; _this_unit--) { \
+               _bt_safe_lshift(_v, _ts);                               \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \
+               _end -= _ts;                                            \
+       }                                                               \
+       if (_start % _ts) {                                             \
+               _mask = _bt_make_mask(type, _ts - (_start % _ts));      \
+               _cmask = _ptr[_this_unit];                              \
+               _cmask = _bt_rshift(_cmask, _start % _ts);              \
+               _cmask &= _mask;                                        \
+               _bt_safe_lshift(_v, _ts - (_start % _ts));              \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
+       } else {                                                        \
+               _bt_safe_lshift(_v, _ts);                               \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \
+       }                                                               \
+       *_vptr = _v;                                                    \
+} while (0)
+
+#define _bt_bitfield_read_be(ptr, type, start, length, vptr)           \
+do {                                                                   \
+       __typeof__(*(vptr)) *_vptr = (vptr);                            \
+       __typeof__(*_vptr) _v;                                          \
+       type *_ptr = (void *) (ptr);                                    \
+       unsigned long _start = (start), _length = (length);             \
+       type _mask, _cmask;                                             \
+       unsigned long _ts = sizeof(type) * CHAR_BIT; /* type size */    \
+       unsigned long _start_unit, _end_unit, _this_unit;               \
+       unsigned long _end, _cshift; /* _cshift is "complement shift" */ \
+       bool _is_signed_type;                                           \
+                                                                       \
+       if (!_length) {                                                 \
+               *_vptr = 0;                                             \
+               break;                                                  \
+       }                                                               \
+                                                                       \
+       _end = _start + _length;                                        \
+       _start_unit = _start / _ts;                                     \
+       _end_unit = (_end + (_ts - 1)) / _ts;                           \
+                                                                       \
+       _this_unit = _start_unit;                                       \
+       _BT_DIAG_PUSH                                                   \
+       _BT_DIAG_IGNORE_TYPE_LIMITS                                     \
+       _is_signed_type = _bt_is_signed_type(__typeof__(_v));           \
+       _BT_DIAG_POP                                                    \
+       if (_is_signed_type                                             \
+           && (_ptr[_this_unit] & _bt_lshift((type) 1, _ts - (_start % _ts) - 1))) \
+               _v = ~(__typeof__(_v)) 0;                               \
+       else                                                            \
+               _v = 0;                                                 \
+       if (_start_unit == _end_unit - 1) {                             \
+               _cmask = _ptr[_this_unit];                              \
+               _cmask = _bt_rshift(_cmask, (_ts - (_end % _ts)) % _ts); \
+               if ((_end - _start) % _ts) {                            \
+                       _mask = _bt_make_mask(type, _end - _start);     \
+                       _cmask &= _mask;                                \
+               }                                                       \
+               _bt_safe_lshift(_v, _end - _start);                     \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
+               *_vptr = _v;                                            \
+               break;                                                  \
+       }                                                               \
+       if (_start % _ts) {                                             \
+               _cshift = _start % _ts;                                 \
+               _mask = _bt_make_mask(type, _ts - _cshift);             \
+               _cmask = _ptr[_this_unit];                              \
+               _cmask &= _mask;                                        \
+               _bt_safe_lshift(_v, _ts - _cshift);                     \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
+               _start += _ts - _cshift;                                \
+               _this_unit++;                                           \
+       }                                                               \
+       for (; _this_unit < _end_unit - 1; _this_unit++) {              \
+               _bt_safe_lshift(_v, _ts);                               \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \
+               _start += _ts;                                          \
+       }                                                               \
+       if (_end % _ts) {                                               \
+               _mask = _bt_make_mask(type, _end % _ts);                \
+               _cmask = _ptr[_this_unit];                              \
+               _cmask = _bt_rshift(_cmask, _ts - (_end % _ts));        \
+               _cmask &= _mask;                                        \
+               _bt_safe_lshift(_v, _end % _ts);                        \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _cmask); \
+       } else {                                                        \
+               _bt_safe_lshift(_v, _ts);                               \
+               _v |= _bt_cast_value_to_unsigned_type(__typeof__(_v), _ptr[_this_unit]); \
+       }                                                               \
+       *_vptr = _v;                                                    \
+} while (0)
+
+/*
+ * bt_bitfield_read - read integer from a bitfield in native endianness
+ * bt_bitfield_read_le - read integer from a bitfield in little endian
+ * bt_bitfield_read_be - read integer from a bitfield in big endian
+ */
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+
+#define bt_bitfield_read(ptr, type, start, length, vptr)               \
+       _bt_bitfield_read_le(ptr, type, start, length, vptr)
+
+#define bt_bitfield_read_le(ptr, type, start, length, vptr)            \
+       _bt_bitfield_read_le(ptr, type, start, length, vptr)
+
+#define bt_bitfield_read_be(ptr, type, start, length, vptr)            \
+       _bt_bitfield_read_be(ptr, unsigned char, start, length, vptr)
+
+#elif (BYTE_ORDER == BIG_ENDIAN)
+
+#define bt_bitfield_read(ptr, type, start, length, vptr)               \
+       _bt_bitfield_read_be(ptr, type, start, length, vptr)
+
+#define bt_bitfield_read_le(ptr, type, start, length, vptr)            \
+       _bt_bitfield_read_le(ptr, unsigned char, start, length, vptr)
+
+#define bt_bitfield_read_be(ptr, type, start, length, vptr)            \
+       _bt_bitfield_read_be(ptr, type, start, length, vptr)
+
+#else /* (BYTE_ORDER == PDP_ENDIAN) */
+
+#error "Byte order not supported"
+
+#endif
+
+#endif /* _BABELTRACE_BITFIELD_H */
diff --git a/src/compat/compiler.h b/src/compat/compiler.h
new file mode 100644 (file)
index 0000000..c4c72cc
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _BABELTRACE_COMPILER_H
+#define _BABELTRACE_COMPILER_H
+
+/*
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stddef.h>    /* for offsetof */
+
+#define MAYBE_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
+
+#ifndef container_of
+#define container_of(ptr, type, member)                                        \
+       ({                                                              \
+               const typeof(((type *)NULL)->member) * __ptr = (ptr);   \
+               (type *)((char *)__ptr - offsetof(type, member));       \
+       })
+#endif
+
+#define BT_ARRAY_SIZE(arr)     (sizeof(arr) / sizeof((arr)[0]))
+
+#endif /* _BABELTRACE_COMPILER_H */
diff --git a/src/compat/endian.h b/src/compat/endian.h
new file mode 100644 (file)
index 0000000..5c74c35
--- /dev/null
@@ -0,0 +1,240 @@
+#ifndef _BABELTRACE_ENDIAN_H
+#define _BABELTRACE_ENDIAN_H
+
+/*
+ * Copyright 2012 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * endian.h compatibility layer.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef __FreeBSD__
+#include <machine/endian.h>
+
+#elif defined(__sun__)
+#include <sys/byteorder.h>
+
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#endif
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+
+#ifdef _LITTLE_ENDIAN
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
+#ifdef _BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#endif
+
+#define LITTLE_ENDIAN  __LITTLE_ENDIAN
+#define BIG_ENDIAN     __BIG_ENDIAN
+#define BYTE_ORDER     __BYTE_ORDER
+
+#define betoh16(x) BE_16(x)
+#define letoh16(x) LE_16(x)
+#define betoh32(x) BE_32(x)
+#define letoh32(x) LE_32(x)
+#define betoh64(x) BE_64(x)
+#define letoh64(x) LE_64(x)
+#define htobe16(x) BE_16(x)
+#define be16toh(x) BE_16(x)
+#define htobe32(x) BE_32(x)
+#define be32toh(x) BE_32(x)
+#define htobe64(x) BE_64(x)
+#define be64toh(x) BE_64(x)
+
+#elif defined(__MINGW32__)
+#include <stdint.h>
+
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#endif
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
+#define LITTLE_ENDIAN  __LITTLE_ENDIAN
+#define BIG_ENDIAN     __BIG_ENDIAN
+#define PDP_ENDIAN     __PDP_ENDIAN
+#define BYTE_ORDER     __BYTE_ORDER
+
+#define htobe16(x) (uint16_t) _byteswap_ushort(x)
+#define htole16(x) (x)
+#define be16toh(x) (uint16_t) _byteswap_ushort(x)
+#define le16toh(x) (x)
+
+#define htobe32(x) (uint32_t) _byteswap_ulong(x)
+#define htole32(x) (x)
+#define be32toh(x) (uint32_t) _byteswap_ulong(x)
+#define le32toh(x) (x)
+
+#define htobe64(x) (uint64_t) _byteswap_uint64(x)
+#define htole64(x) (x)
+#define be64toh(x) (uint64_t) _byteswap_uint64(x)
+#define le64toh(x) (x)
+
+#elif defined(__APPLE__)
+# include <machine/endian.h>
+# include <libkern/OSByteOrder.h>
+
+# if BYTE_ORDER == LITTLE_ENDIAN
+#  define htobe16(x) OSSwapConstInt16(x)
+#  define htole16(x) (x)
+#  define be16toh(x) OSSwapConstInt16(x)
+#  define le16toh(x) (x)
+
+#  define htobe32(x) OSSwapConstInt32(x)
+#  define htole32(x) (x)
+#  define be32toh(x) OSSwapConstInt32(x)
+#  define le32toh(x) (x)
+
+#  define htobe64(x) OSSwapConstInt64(x)
+#  define htole64(x) (x)
+#  define be64toh(x) OSSwapConstInt64(x)
+#  define le64toh(x) (x)
+
+# else /* BYTE_ORDER == LITTLE_ENDIAN */
+#  define htobe16(x) (x)
+#  define htole16(x) OSSwapConstInt16(x)
+#  define be16toh(x) (x)
+#  define le16toh(x) OSSwapConstInt16(x)
+
+#  define htobe32(x) (x)
+#  define htole32(x) OSSwapConstInt32(x)
+#  define be32toh(x) (x)
+#  define le32toh(x) OSSwapConstInt32(x)
+
+#  define htobe64(x) (x)
+#  define htole64(x) OSSwapConstInt64(x)
+#  define be64toh(x) (x)
+#  define le64toh(x) OSSwapConstInt64(x)
+#  endif
+
+#else
+#include <endian.h>
+
+/*
+ * htobe/betoh are not defined for glibc < 2.9, so add them explicitly
+ * if they are missing.
+ */
+# ifdef __USE_BSD
+/* Conversion interfaces. */
+#  include <byteswap.h>
+
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+#   ifndef htobe16
+#    define htobe16(x) __bswap_16(x)
+#   endif
+#   ifndef htole16
+#    define htole16(x) (x)
+#   endif
+#   ifndef be16toh
+#    define be16toh(x) __bswap_16(x)
+#   endif
+#   ifndef le16toh
+#    define le16toh(x) (x)
+#   endif
+
+#   ifndef htobe32
+#    define htobe32(x) __bswap_32(x)
+#   endif
+#   ifndef htole32
+#    define htole32(x) (x)
+#   endif
+#   ifndef be32toh
+#    define be32toh(x) __bswap_32(x)
+#   endif
+#   ifndef le32toh
+#    define le32toh(x) (x)
+#   endif
+
+#   ifndef htobe64
+#    define htobe64(x) __bswap_64(x)
+#   endif
+#   ifndef htole64
+#    define htole64(x) (x)
+#   endif
+#   ifndef be64toh
+#    define be64toh(x) __bswap_64(x)
+#   endif
+#   ifndef le64toh
+#    define le64toh(x) (x)
+#   endif
+
+#  else /* __BYTE_ORDER == __LITTLE_ENDIAN */
+#   ifndef htobe16
+#    define htobe16(x) (x)
+#   endif
+#   ifndef htole16
+#    define htole16(x) __bswap_16(x)
+#   endif
+#   ifndef be16toh
+#    define be16toh(x) (x)
+#   endif
+#   ifndef le16toh
+#    define le16toh(x) __bswap_16(x)
+#   endif
+
+#   ifndef htobe32
+#    define htobe32(x) (x)
+#   endif
+#   ifndef htole32
+#    define htole32(x) __bswap_32(x)
+#   endif
+#   ifndef be32toh
+#    define be32toh(x) (x)
+#   endif
+#   ifndef le32toh
+#    define le32toh(x) __bswap_32(x)
+#   endif
+
+#   ifndef htobe64
+#    define htobe64(x) (x)
+#   endif
+#   ifndef htole64
+#    define htole64(x) __bswap_64(x)
+#   endif
+#   ifndef be64toh
+#    define be64toh(x) (x)
+#   endif
+#   ifndef le64toh
+#    define le64toh(x) __bswap_64(x)
+#   endif
+
+#  endif /* __BYTE_ORDER == __LITTLE_ENDIAN */
+# endif /* __USE_BSD */
+#endif /* else -- __FreeBSD__ */
+
+#ifndef FLOAT_WORD_ORDER
+#ifdef __FLOAT_WORD_ORDER
+#define FLOAT_WORD_ORDER       __FLOAT_WORD_ORDER
+#else /* __FLOAT_WORD_ORDER */
+#define FLOAT_WORD_ORDER       BYTE_ORDER
+#endif /* __FLOAT_WORD_ORDER */
+#endif /* FLOAT_WORD_ORDER */
+
+#endif /* _BABELTRACE_ENDIAN_H */
diff --git a/src/compat/fcntl.h b/src/compat/fcntl.h
new file mode 100644 (file)
index 0000000..c528943
--- /dev/null
@@ -0,0 +1,233 @@
+#ifndef _BABELTRACE_COMPAT_FCNTL_H
+#define _BABELTRACE_COMPAT_FCNTL_H
+
+/*
+ * Copyright 2015 (c) - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * fcntl compatibility layer.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef BABELTRACE_HAVE_POSIX_FALLOCATE
+
+#include <fcntl.h>
+
+static inline
+int bt_posix_fallocate(int fd, off_t offset, off_t len)
+{
+       return posix_fallocate(fd, offset, len);
+}
+
+#elif defined(__MINGW32__) /* #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
+
+#include <stdlib.h>
+#include <windows.h>
+#include <fcntl.h>
+
+static inline
+int bt_posix_fallocate(int fd, off_t offset, off_t len)
+{
+       HANDLE handle;
+       LARGE_INTEGER pos, file_pos, orig_end_offset, range_end;
+       int ret = 0;
+       char zero = 0;
+       DWORD byteswritten;
+
+       if (offset < 0 || len <= 0) {
+               ret = EINVAL;
+               goto end;
+       }
+
+       range_end.QuadPart = (__int64) offset + (__int64) len;
+
+       /* Get a handle from the fd */
+       handle = (HANDLE) _get_osfhandle(fd);
+       if (handle == INVALID_HANDLE_VALUE) {
+               ret = EBADF;
+               goto end;
+       }
+
+       /* Get the file original end offset */
+       ret = GetFileSizeEx(handle, &orig_end_offset);
+       if (ret == 0) {
+               ret = EBADF;
+               goto end;
+       }
+
+       /* Make sure we don't truncate the file */
+       if (orig_end_offset.QuadPart >= range_end.QuadPart) {
+               ret = 0;
+               goto end;
+       }
+
+       /* Get the current file pointer position */
+       pos.QuadPart = 0;
+       ret = SetFilePointerEx(handle, pos, &file_pos, FILE_CURRENT);
+       if (ret == 0) {
+               ret = EBADF;
+               goto end;
+       }
+
+       /* Move the file pointer to the new end offset */
+       ret = SetFilePointerEx(handle, range_end, NULL, FILE_BEGIN);
+       if (ret == 0) {
+               ret = EBADF;
+               goto end;
+       }
+
+       /* Sets the physical file size to the current position */
+       ret = SetEndOfFile(handle);
+       if (ret == 0) {
+               ret = EINVAL;
+               goto restore;
+       }
+
+       /*
+        * Move the file pointer back 1 byte, and write a single 0 at the
+        * last byte of the new end offset, the operating system will zero
+        * fill the file.
+        */
+       pos.QuadPart = -1;
+       ret = SetFilePointerEx(handle, pos, NULL, FILE_END);
+       if (ret == 0) {
+               ret = EBADF;
+               goto end;
+       }
+
+       ret = WriteFile(handle, &zero, 1, &byteswritten, NULL);
+       if (ret == 0 || byteswritten != 1) {
+               ret = ENOSPC;
+       } else {
+               ret = 0;
+       }
+
+restore:
+       /* Restore the original file pointer position */
+       if (!SetFilePointerEx(handle, file_pos, NULL, FILE_BEGIN)) {
+               /* We moved the file pointer but failed to restore it. */
+               abort();
+       }
+
+end:
+       return ret;
+}
+
+#else
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#define BABELTRACE_FALLOCATE_BUFLEN    256
+
+#ifndef min_t
+#define min_t(type, a, b)      \
+       ((type) (a) < (type) (b) ? (type) (a) : (type) (b))
+#endif
+
+static inline
+int bt_posix_fallocate(int fd, off_t offset, off_t len)
+{
+       int ret = 0;
+       ssize_t copy_len;
+       char buf[BABELTRACE_FALLOCATE_BUFLEN];
+       off_t i, file_pos, orig_end_offset, range_end;
+
+       if (offset < 0 || len < 0) {
+               ret = EINVAL;
+               goto end;
+       }
+
+       range_end = offset + len;
+       if (range_end < 0) {
+               ret = EFBIG;
+               goto end;
+       }
+
+       file_pos = lseek(fd, 0, SEEK_CUR);
+       if (file_pos < 0) {
+               ret = errno;
+               goto end;
+       }
+
+       orig_end_offset = lseek(fd, 0, SEEK_END);
+       if (orig_end_offset < 0) {
+               ret = errno;
+               goto end;
+       }
+
+       /* Seek back to original position. */
+       ret = lseek(fd, file_pos, SEEK_SET);
+       if (ret) {
+               ret = errno;
+               goto end;
+       }
+
+       /*
+        * The file may not need to grow, but we want to ensure the
+        * space has actually been reserved by the file system. First, copy
+        * the "existing" region of the file, then grow the file if needed.
+        */
+       for (i = file_pos; i < min_t(off_t, range_end, orig_end_offset);
+                       i += copy_len) {
+               ssize_t copy_ret;
+
+               copy_len = min_t(size_t, BABELTRACE_FALLOCATE_BUFLEN,
+                               min_t(off_t, range_end - i,
+                                       orig_end_offset - i));
+               copy_ret = pread(fd, &buf, copy_len, i);
+               if (copy_ret < copy_len) {
+                       /*
+                        * The caller must handle any EINTR.
+                        * POSIX_FALLOCATE(3) does not mention EINTR.
+                        * However, glibc does forward to fallocate()
+                        * directly on Linux, which may be interrupted.
+                        */
+                       ret = errno;
+                       goto end;
+               }
+
+               copy_ret = pwrite(fd, &buf, copy_len, i);
+               if (copy_ret < copy_len) {
+                       /* Same caveat as noted at pread() */
+                       ret = errno;
+                       goto end;
+               }
+       }
+
+       /* Grow file, as necessary. */
+       memset(&buf, 0, BABELTRACE_FALLOCATE_BUFLEN);
+       for (i = orig_end_offset; i < range_end; i += copy_len) {
+               ssize_t write_ret;
+
+               copy_len = min_t(size_t, BABELTRACE_FALLOCATE_BUFLEN,
+                               range_end - i);
+               write_ret = pwrite(fd, &buf, copy_len, i);
+               if (write_ret < copy_len) {
+                       ret = errno;
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+#endif /* #else #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
+
+#endif /* _BABELTRACE_COMPAT_FCNTL_H */
diff --git a/src/compat/glib.h b/src/compat/glib.h
new file mode 100644 (file)
index 0000000..e956280
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _BABELTRACE_COMPAT_GLIB_H
+#define _BABELTRACE_COMPAT_GLIB_H
+
+/*
+ * Copyright (C) 2015 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+
+#if GLIB_CHECK_VERSION(2,31,8)
+
+static inline gboolean
+bt_g_hash_table_contains(GHashTable *hash_table, gconstpointer key)
+{
+       return g_hash_table_contains(hash_table, key);
+}
+
+#else
+
+static inline gboolean
+bt_g_hash_table_contains(GHashTable *hash_table, gconstpointer key)
+{
+       gpointer orig_key;
+       gpointer value;
+
+       return g_hash_table_lookup_extended(hash_table, key, &orig_key,
+               &value);
+}
+
+#endif
+
+
+#if GLIB_CHECK_VERSION(2,29,16)
+
+static inline GPtrArray *
+bt_g_ptr_array_new_full(guint reserved_size,
+               GDestroyNotify element_free_func)
+{
+       return g_ptr_array_new_full(reserved_size, element_free_func);
+}
+
+#else
+
+static inline GPtrArray *
+bt_g_ptr_array_new_full(guint reserved_size,
+               GDestroyNotify element_free_func)
+{
+       GPtrArray *array;
+
+       array = g_ptr_array_sized_new(reserved_size);
+       if (!array) {
+              goto end;
+       }
+       g_ptr_array_set_free_func(array, element_free_func);
+end:
+       return array;
+}
+#endif
+
+#endif /* _BABELTRACE_COMPAT_GLIB_H */
diff --git a/src/compat/limits.h b/src/compat/limits.h
new file mode 100644 (file)
index 0000000..b276183
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _BABELTRACE_LIMITS_H
+#define _BABELTRACE_LIMITS_H
+
+/*
+ * Copyright (C) 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <limits.h>
+
+#ifdef __linux__
+
+#define BABELTRACE_HOST_NAME_MAX HOST_NAME_MAX
+
+#elif defined(__FreeBSD__)
+
+#define BABELTRACE_HOST_NAME_MAX MAXHOSTNAMELEN
+
+#elif defined(_POSIX_HOST_NAME_MAX)
+
+#define BABELTRACE_HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+
+#else
+
+#define BABELTRACE_HOST_NAME_MAX 256
+
+#endif /* __linux__, __FreeBSD__, _POSIX_HOST_NAME_MAX */
+
+#endif /* _BABELTRACE_LIMITS_H */
diff --git a/src/compat/logging.c b/src/compat/logging.c
new file mode 100644 (file)
index 0000000..a79cc10
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_compat_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_compat_log_level, "BABELTRACE_COMPAT_LOG_LEVEL");
diff --git a/src/compat/logging.h b/src/compat/logging.h
new file mode 100644 (file)
index 0000000..ccb77a9
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef COMPAT_LOGGING_H
+#define COMPAT_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_compat_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_compat_log_level);
+
+#endif /* COMPAT_LOGGING_H */
diff --git a/src/compat/memstream.h b/src/compat/memstream.h
new file mode 100644 (file)
index 0000000..8dea7a4
--- /dev/null
@@ -0,0 +1,356 @@
+#ifndef _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
+#define _BABELTRACE_FORMAT_CTF_MEMSTREAM_H
+
+/*
+ * Copyright 2012 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * memstream compatibility layer.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef BABELTRACE_HAVE_FMEMOPEN
+#include <stdio.h>
+
+static inline
+FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
+{
+       return fmemopen(buf, size, mode);
+}
+
+#else /* BABELTRACE_HAVE_FMEMOPEN */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "compat/endian.h"
+
+#ifdef __MINGW32__
+
+#include <io.h>
+#include <glib.h>
+
+/*
+ * Fallback for systems which don't have fmemopen. Copy buffer to a
+ * temporary file, and use that file as FILE * input.
+ */
+static inline
+FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
+{
+       char *tmpname;
+       size_t len;
+       FILE *fp;
+       int ret;
+
+       /*
+        * Support reading only.
+        */
+       if (strcmp(mode, "rb") != 0) {
+               return NULL;
+       }
+
+       /* Build a temporary filename */
+       tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
+       if (_mktemp(tmpname) == NULL) {
+               goto error_free;
+       }
+
+       /*
+        * Open as a read/write binary temporary deleted on close file.
+        * Will be deleted when the last file pointer is closed.
+        */
+       fp = fopen(tmpname, "w+bTD");
+       if (!fp) {
+               goto error_free;
+       }
+
+       /* Copy the entire buffer to the file */
+       len = fwrite(buf, sizeof(char), size, fp);
+       if (len != size) {
+               goto error_close;
+       }
+
+       /* Set the file pointer to the start of file */
+       ret = fseek(fp, 0L, SEEK_SET);
+       if (ret < 0) {
+               perror("fseek");
+               goto error_close;
+       }
+
+       g_free(tmpname);
+       return fp;
+
+error_close:
+       ret = fclose(fp);
+       if (ret < 0) {
+               perror("close");
+       }
+error_free:
+       g_free(tmpname);
+       return NULL;
+}
+
+#else /* __MINGW32__ */
+
+/*
+ * Fallback for systems which don't have fmemopen. Copy buffer to a
+ * temporary file, and use that file as FILE * input.
+ */
+static inline
+FILE *bt_fmemopen(void *buf, size_t size, const char *mode)
+{
+       char *tmpname;
+       size_t len;
+       FILE *fp;
+       int ret;
+
+       /*
+        * Support reading only.
+        */
+       if (strcmp(mode, "rb") != 0) {
+               return NULL;
+       }
+
+       tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
+       ret = mkstemp(tmpname);
+       if (ret < 0) {
+               g_free(tmpname);
+               return NULL;
+       }
+       /*
+        * We need to write to the file.
+        */
+       fp = fdopen(ret, "wb+");
+       if (!fp) {
+               goto error_unlink;
+       }
+       /* Copy the entire buffer to the file */
+       len = fwrite(buf, sizeof(char), size, fp);
+       if (len != size) {
+               goto error_close;
+       }
+       ret = fseek(fp, 0L, SEEK_SET);
+       if (ret < 0) {
+               perror("fseek");
+               goto error_close;
+       }
+       /* We keep the handle open, but can unlink the file on the VFS. */
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               perror("unlink");
+       }
+       g_free(tmpname);
+       return fp;
+
+error_close:
+       ret = fclose(fp);
+       if (ret < 0) {
+               perror("close");
+       }
+error_unlink:
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               perror("unlink");
+       }
+       g_free(tmpname);
+       return NULL;
+}
+
+#endif /* __MINGW32__ */
+
+#endif /* BABELTRACE_HAVE_FMEMOPEN */
+
+
+#ifdef BABELTRACE_HAVE_OPEN_MEMSTREAM
+
+#include <stdio.h>
+
+static inline
+FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
+{
+       return open_memstream(ptr, sizeloc);
+}
+
+static inline
+int bt_close_memstream(char **buf, size_t *size, FILE *fp)
+{
+       return fclose(fp);
+}
+
+#else /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+
+#ifdef __MINGW32__
+
+/*
+ * Fallback for systems which don't have open_memstream. Create FILE *
+ * with bt_open_memstream, but require call to
+ * bt_close_memstream to flush all data written to the FILE *
+ * into the buffer (which we allocate).
+ */
+static inline
+FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
+{
+       char *tmpname;
+       FILE *fp;
+
+       tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
+
+       if (_mktemp(tmpname) == NULL) {
+               goto error_free;
+       }
+
+       /*
+        * Open as a read/write binary temporary deleted on close file.
+        * Will be deleted when the last file pointer is closed.
+        */
+       fp = fopen(tmpname, "w+bTD");
+       if (!fp) {
+               goto error_free;
+       }
+
+       g_free(tmpname);
+       return fp;
+
+error_free:
+       g_free(tmpname);
+       return NULL;
+}
+
+#else /* __MINGW32__ */
+
+/*
+ * Fallback for systems which don't have open_memstream. Create FILE *
+ * with bt_open_memstream, but require call to
+ * bt_close_memstream to flush all data written to the FILE *
+ * into the buffer (which we allocate).
+ */
+static inline
+FILE *bt_open_memstream(char **ptr, size_t *sizeloc)
+{
+       char *tmpname;
+       int ret;
+       FILE *fp;
+
+       tmpname = g_build_filename(g_get_tmp_dir(), "babeltrace-tmp-XXXXXX", NULL);
+
+       ret = mkstemp(tmpname);
+       if (ret < 0) {
+               perror("mkstemp");
+               g_free(tmpname);
+               return NULL;
+       }
+       fp = fdopen(ret, "wb+");
+       if (!fp) {
+               goto error_unlink;
+       }
+       /*
+        * babeltrace_flush_memstream will update the buffer content
+        * with read from fp. No need to keep the file around, just the
+        * handle.
+        */
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               perror("unlink");
+       }
+       g_free(tmpname);
+       return fp;
+
+error_unlink:
+       ret = unlink(tmpname);
+       if (ret < 0) {
+               perror("unlink");
+       }
+       g_free(tmpname);
+       return NULL;
+}
+
+#endif /* __MINGW32__ */
+
+/* Get file size, allocate buffer, copy. */
+static inline
+int bt_close_memstream(char **buf, size_t *size, FILE *fp)
+{
+       size_t len, n;
+       long pos;
+       int ret;
+
+       ret = fflush(fp);
+       if (ret < 0) {
+               perror("fflush");
+               return ret;
+       }
+       ret = fseek(fp, 0L, SEEK_END);
+       if (ret < 0) {
+               perror("fseek");
+               return ret;
+       }
+       pos = ftell(fp);
+       if (ret < 0) {
+               perror("ftell");
+               return ret;
+       }
+       *size = pos;
+       /* add final \0 */
+       *buf = calloc(pos + 1, sizeof(char));
+       if (!*buf) {
+               return -ENOMEM;
+       }
+       ret = fseek(fp, 0L, SEEK_SET);
+       if (ret < 0) {
+               perror("fseek");
+               goto error_free;
+       }
+       /* Copy the entire file into the buffer */
+       n = 0;
+       clearerr(fp);
+       while (!feof(fp) && !ferror(fp) && (*size - n > 0)) {
+               len = fread(*buf, sizeof(char), *size - n, fp);
+               n += len;
+       }
+       if (n != *size) {
+               ret = -1;
+               goto error_close;
+       }
+       ret = fclose(fp);
+       if (ret < 0) {
+               perror("fclose");
+               return ret;
+       }
+       return 0;
+
+error_close:
+       ret = fclose(fp);
+       if (ret < 0) {
+               perror("fclose");
+       }
+error_free:
+       free(*buf);
+       *buf = NULL;
+       return ret;
+}
+
+#endif /* BABELTRACE_HAVE_OPEN_MEMSTREAM */
+
+#endif /* _BABELTRACE_FORMAT_CTF_MEMSTREAM_H */
diff --git a/src/compat/mman.c b/src/compat/mman.c
new file mode 100644 (file)
index 0000000..d0cea9d
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * compat/compat_mman.h
+ *
+ * Copyright (C) 2013   JP Ikaheimonen <jp_ikaheimonen@mentor.com>
+ *               2016   Michael Jeanson <mjeanson@efficios.com>
+ *
+ * These sources are based on ftp://g.oswego.edu/pub/misc/malloc.c
+ * file by Doug Lea, released to the public domain.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COMPAT-MMAN"
+#include "logging.h"
+
+#ifdef __APPLE__
+/*
+ * On macOS, we need a dummy symbol so that the linker won't
+ * complain of an empty table of contents.
+ */
+BT_HIDDEN
+int bt_mman_dummy_symbol;
+#endif /* __APPLE__ */
+
+#ifdef __MINGW32__
+
+#include <errno.h>
+#include <io.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <windows.h>
+#include "compat/mman.h"
+
+struct mmap_mapping {
+       /* The duplicated handle. */
+       HANDLE file_handle;
+       /* Handle returned by CreateFileMapping. */
+       HANDLE map_handle;
+};
+
+static
+GHashTable *mmap_mappings = NULL;
+
+/*
+ * This mutex protects the hashtable of memory mappings.
+ */
+static pthread_mutex_t mmap_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static
+struct mmap_mapping *mapping_create(void)
+{
+       struct mmap_mapping *mapping;
+
+       mapping = malloc(sizeof(struct mmap_mapping));
+       if (mapping != NULL) {
+               mapping->file_handle = NULL;
+               mapping->map_handle = NULL;
+       }
+
+       return mapping;
+}
+
+static
+void mapping_clean(struct mmap_mapping *mapping)
+{
+       if (mapping) {
+               if (!CloseHandle(mapping->map_handle)) {
+                       BT_LOGF_STR("Failed to close mmap map_handle.");
+                       abort();
+               }
+               if (!CloseHandle(mapping->file_handle)) {
+                       BT_LOGF_STR("Failed to close mmap file_handle.");
+                       abort();
+               }
+               free(mapping);
+               mapping = NULL;
+       }
+}
+
+static
+void addr_clean(void *addr)
+{
+       /* Cleanup of handles should never fail. */
+       if (!UnmapViewOfFile(addr)) {
+               BT_LOGF_STR("Failed to unmap mmap mapping.");
+               abort();
+       }
+}
+
+static
+void mmap_lock(void)
+{
+       if (pthread_mutex_lock(&mmap_mutex)) {
+               BT_LOGF_STR("Failed to acquire mmap_mutex.");
+               abort();
+       }
+}
+
+static
+void mmap_unlock(void)
+{
+       if (pthread_mutex_unlock(&mmap_mutex)) {
+               BT_LOGF_STR("Failed to release mmap_mutex.");
+               abort();
+       }
+}
+
+/*
+ * Convert mmap memory protection flags to CreateFileMapping page protection
+ * flag and MapViewOfFile desired access flag.
+ */
+static
+DWORD map_prot_flags(int prot, DWORD *dwDesiredAccess)
+{
+       if (prot & PROT_READ) {
+               if (prot & PROT_WRITE) {
+                       *dwDesiredAccess = FILE_MAP_WRITE;
+                       if (prot & PROT_EXEC) {
+                               return PAGE_EXECUTE_READWRITE;
+                       }
+                       return PAGE_READWRITE;
+               }
+               if (prot & PROT_EXEC) {
+                       *dwDesiredAccess = FILE_MAP_EXECUTE;
+                       return PAGE_EXECUTE_READ;
+               }
+               *dwDesiredAccess = FILE_MAP_READ;
+               return PAGE_READONLY;
+       }
+       if (prot & PROT_WRITE) {
+               *dwDesiredAccess = FILE_MAP_COPY;
+               return PAGE_WRITECOPY;
+       }
+       if (prot & PROT_EXEC) {
+               *dwDesiredAccess = FILE_MAP_EXECUTE;
+               return PAGE_EXECUTE_READ;
+       }
+
+       /* Mapping failed. */
+       *dwDesiredAccess = 0;
+       return 0;
+}
+
+BT_HIDDEN
+void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
+               off_t offset)
+{
+       struct mmap_mapping *mapping = NULL;
+       void *mapping_addr;
+       DWORD dwDesiredAccess;
+       DWORD flProtect;
+       HANDLE handle;
+
+       /* Check for a valid fd. */
+       if (fd == -1) {
+               _set_errno(EBADF);
+               goto error;
+       }
+
+       /* We don't support this at the moment. */
+       if (flags == MAP_FIXED) {
+               _set_errno(ENOTSUP);
+               goto error;
+       }
+
+       /* Map mmap flags to those of the Windows API. */
+       flProtect = map_prot_flags(prot, &dwDesiredAccess);
+       if (flProtect == 0) {
+               _set_errno(EINVAL);
+               goto error;
+       }
+
+       /* Allocate the mapping struct. */
+       mapping = mapping_create();
+       if (!mapping) {
+               BT_LOGE_STR("Failed to allocate mmap mapping.");
+               _set_errno(ENOMEM);
+               goto error;
+       }
+
+       /* Get a handle from the fd. */
+       handle = (HANDLE) _get_osfhandle(fd);
+
+       /* Duplicate the handle and store it in 'mapping.file_handle'. */
+       if (!DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(),
+                       &mapping->file_handle, 0, FALSE,
+                       DUPLICATE_SAME_ACCESS)) {
+               _set_errno(ENOMEM);
+               goto error;
+       }
+
+       /*
+        * Create a file mapping object with a maximum size
+        * of 'offset' + 'length'.
+        */
+       mapping->map_handle = CreateFileMapping(mapping->file_handle, NULL,
+                       flProtect, 0, offset + length, NULL);
+       if (mapping->map_handle == 0) {
+               _set_errno(EACCES);
+               goto error;
+       }
+
+       /* Map the requested block starting at 'offset' for 'length' bytes. */
+       mapping_addr = MapViewOfFile(mapping->map_handle, dwDesiredAccess, 0,
+                       offset, length);
+       if (mapping_addr == 0) {
+               DWORD dwLastErr = GetLastError();
+               if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
+                       _set_errno(EINVAL);
+               } else {
+                       _set_errno(EACCES);
+               }
+               goto error;
+       }
+
+       mmap_lock();
+
+       /* If we have never done any mappings, allocate the hashtable. */
+       if (!mmap_mappings) {
+               mmap_mappings = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, (GDestroyNotify) addr_clean,
+                       (GDestroyNotify) mapping_clean);
+               if (!mmap_mappings) {
+                       BT_LOGE_STR("Failed to allocate mmap hashtable.");
+                       _set_errno(ENOMEM);
+                       goto error_mutex_unlock;
+               }
+       }
+
+       /* Add the new mapping to the hashtable. */
+       g_hash_table_insert(mmap_mappings, mapping_addr, mapping);
+
+       mmap_unlock();
+
+       return mapping_addr;
+
+error_mutex_unlock:
+       mmap_unlock();
+error:
+       mapping_clean(mapping);
+       return MAP_FAILED;
+}
+
+BT_HIDDEN
+int bt_munmap(void *addr, size_t length)
+{
+       int ret = 0;
+
+       mmap_lock();
+
+       /* Check if the mapping exists in the hashtable. */
+       if (g_hash_table_lookup(mmap_mappings, addr) == NULL) {
+               _set_errno(EINVAL);
+               ret = -1;
+               goto end;
+       }
+
+       /* Remove it. */
+       if (!g_hash_table_remove(mmap_mappings, addr)) {
+               BT_LOGF_STR("Failed to remove mapping from hashtable.");
+               abort();
+       }
+
+end:
+       mmap_unlock();
+       return ret;
+}
+
+#endif
diff --git a/src/compat/mman.h b/src/compat/mman.h
new file mode 100644 (file)
index 0000000..9f49452
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _BABELTRACE_COMPAT_MMAN_H
+#define _BABELTRACE_COMPAT_MMAN_H
+
+/*
+ * Copyright (C) 2015-2016  Michael Jeanson <mjeanson@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef __MINGW32__
+
+#include <sys/types.h>
+
+#define PROT_NONE      0x0
+#define PROT_READ      0x1
+#define PROT_WRITE     0x2
+#define PROT_EXEC      0x4
+
+#define MAP_FILE       0
+#define MAP_SHARED     1
+#define MAP_PRIVATE    2
+#define MAP_TYPE       0xF
+#define MAP_FIXED      0x10
+#define MAP_ANONYMOUS  0x20
+#define MAP_ANON       MAP_ANONYMOUS
+#define MAP_FAILED     ((void *) -1)
+
+/*
+ * Note that some platforms (e.g. Windows) do not allow read-only
+ * mappings to exceed the file's size (even within a page).
+ */
+void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
+       off_t offset);
+
+int bt_munmap(void *addr, size_t length);
+
+#else /* __MINGW32__ */
+
+#include <sys/mman.h>
+
+static inline
+void *bt_mmap(void *addr, size_t length, int prot, int flags, int fd,
+       off_t offset)
+{
+       return (void *) mmap(addr, length, prot, flags, fd, offset);
+}
+
+static inline
+int bt_munmap(void *addr, size_t length)
+{
+       return munmap(addr, length);
+}
+#endif /* __MINGW32__ */
+
+#ifndef MAP_ANONYMOUS
+# ifdef MAP_ANON
+#   define MAP_ANONYMOUS MAP_ANON
+# endif
+#endif
+
+#endif /* _BABELTRACE_COMPAT_MMAN_H */
diff --git a/src/compat/socket.h b/src/compat/socket.h
new file mode 100644 (file)
index 0000000..b1fe159
--- /dev/null
@@ -0,0 +1,419 @@
+#ifndef _BABELTRACE_COMPAT_SOCKET_H
+#define _BABELTRACE_COMPAT_SOCKET_H
+
+/*
+ * Copyright (C) 2015-2017  Michael Jeanson <mjeanson@efficios.com>
+ *               2015  Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef __MINGW32__
+
+#include <winsock2.h>
+
+#define BT_INVALID_SOCKET INVALID_SOCKET
+#define BT_SOCKET_ERROR SOCKET_ERROR
+#define BT_SOCKET SOCKET
+
+static inline
+int bt_socket_init(void)
+{
+       WORD verreq;
+       WSADATA wsa;
+       int ret;
+
+       /* Request winsock 2.2 support */
+       verreq = MAKEWORD(2, 2);
+
+       ret = WSAStartup(verreq, &wsa);
+       if (ret != 0) {
+#ifdef BT_LOGE
+               BT_LOGE("Winsock init failed with error: %d", ret);
+#endif
+               goto end;
+       }
+
+       if (LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 2) {
+#ifdef BT_LOGE_STR
+               BT_LOGE_STR("Could not init winsock 2.2 support");
+#endif
+               WSACleanup();
+               ret = -1;
+       }
+
+end:
+       return ret;
+}
+
+static inline
+int bt_socket_fini(void)
+{
+       return WSACleanup();
+}
+
+static inline
+int bt_socket_send(int sockfd, const void *buf, size_t len, int flags)
+{
+       return send(sockfd, buf, len, flags);
+}
+
+static inline
+int bt_socket_recv(int sockfd, void *buf, size_t len, int flags)
+{
+       return recv(sockfd, buf, len, flags);
+}
+
+static inline
+int bt_socket_close(int fd)
+{
+       return closesocket(fd);
+}
+
+static inline
+bool bt_socket_interrupted(void)
+{
+       /* There is no equivalent to EINTR in winsock 2.2 */
+       return false;
+}
+
+static inline
+const char *bt_socket_errormsg(void)
+{
+       const char *errstr;
+       int error = WSAGetLastError();
+
+       switch (error) {
+       case WSAEINTR:
+               errstr = "Call interrupted";
+               break;
+       case WSAEBADF:
+               errstr = "Bad file";
+               break;
+       case WSAEACCES:
+               errstr = "Bad access";
+               break;
+       case WSAEFAULT:
+               errstr = "Bad argument";
+               break;
+       case WSAEINVAL:
+               errstr = "Invalid arguments";
+               break;
+       case WSAEMFILE:
+               errstr = "Out of file descriptors";
+               break;
+       case WSAEWOULDBLOCK:
+               errstr = "Call would block";
+               break;
+       case WSAEINPROGRESS:
+       case WSAEALREADY:
+               errstr = "Blocking call in progress";
+               break;
+       case WSAENOTSOCK:
+               errstr = "Descriptor is not a socket";
+               break;
+       case WSAEDESTADDRREQ:
+               errstr = "Need destination address";
+               break;
+       case WSAEMSGSIZE:
+               errstr = "Bad message size";
+               break;
+       case WSAEPROTOTYPE:
+               errstr = "Bad protocol";
+               break;
+       case WSAENOPROTOOPT:
+               errstr = "Protocol option is unsupported";
+               break;
+       case WSAEPROTONOSUPPORT:
+               errstr = "Protocol is unsupported";
+               break;
+       case WSAESOCKTNOSUPPORT:
+               errstr = "Socket is unsupported";
+               break;
+       case WSAEOPNOTSUPP:
+               errstr = "Operation not supported";
+               break;
+       case WSAEAFNOSUPPORT:
+               errstr = "Address family not supported";
+               break;
+       case WSAEPFNOSUPPORT:
+               errstr = "Protocol family not supported";
+               break;
+       case WSAEADDRINUSE:
+               errstr = "Address already in use";
+               break;
+       case WSAEADDRNOTAVAIL:
+               errstr = "Address not available";
+               break;
+       case WSAENETDOWN:
+               errstr = "Network down";
+               break;
+       case WSAENETUNREACH:
+               errstr = "Network unreachable";
+               break;
+       case WSAENETRESET:
+               errstr = "Network has been reset";
+               break;
+       case WSAECONNABORTED:
+               errstr = "Connection was aborted";
+               break;
+       case WSAECONNRESET:
+               errstr = "Connection was reset";
+               break;
+       case WSAENOBUFS:
+               errstr = "No buffer space";
+               break;
+       case WSAEISCONN:
+               errstr = "Socket is already connected";
+               break;
+       case WSAENOTCONN:
+               errstr = "Socket is not connected";
+               break;
+       case WSAESHUTDOWN:
+               errstr = "Socket has been shut down";
+               break;
+       case WSAETOOMANYREFS:
+               errstr = "Too many references";
+               break;
+       case WSAETIMEDOUT:
+               errstr = "Timed out";
+               break;
+       case WSAECONNREFUSED:
+               errstr = "Connection refused";
+               break;
+       case WSAELOOP:
+               errstr = "Loop??";
+               break;
+       case WSAENAMETOOLONG:
+               errstr = "Name too long";
+               break;
+       case WSAEHOSTDOWN:
+               errstr = "Host down";
+               break;
+       case WSAEHOSTUNREACH:
+               errstr = "Host unreachable";
+               break;
+       case WSAENOTEMPTY:
+               errstr = "Not empty";
+               break;
+       case WSAEPROCLIM:
+               errstr = "Process limit reached";
+               break;
+       case WSAEUSERS:
+               errstr = "Too many users";
+               break;
+       case WSAEDQUOT:
+               errstr = "Bad quota";
+               break;
+       case WSAESTALE:
+               errstr = "Something is stale";
+               break;
+       case WSAEREMOTE:
+               errstr = "Remote error";
+               break;
+       case WSAEDISCON:
+               errstr = "Disconnected";
+               break;
+
+       /* Extended Winsock errors */
+       case WSASYSNOTREADY:
+               errstr = "Winsock library is not ready";
+               break;
+       case WSANOTINITIALISED:
+               errstr = "Winsock library not initialised";
+               break;
+       case WSAVERNOTSUPPORTED:
+               errstr = "Winsock version not supported";
+               break;
+
+       /* getXbyY() errors (already handled in herrmsg):
+        * Authoritative Answer: Host not found */
+       case WSAHOST_NOT_FOUND:
+               errstr = "Host not found";
+               break;
+
+       /* Non-Authoritative: Host not found, or SERVERFAIL */
+       case WSATRY_AGAIN:
+               errstr = "Host not found, try again";
+               break;
+
+       /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+       case WSANO_RECOVERY:
+               errstr = "Unrecoverable error in call to nameserver";
+               break;
+
+       /* Valid name, no data record of requested type */
+       case WSANO_DATA:
+               errstr = "No data record of requested type";
+               break;
+
+       default:
+               errstr = "Unknown error";
+       }
+
+       return errstr;
+}
+
+#else /* __MINGW32__ */
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#define BT_INVALID_SOCKET -1
+#define BT_SOCKET_ERROR -1
+#define BT_SOCKET int
+
+static inline
+int bt_socket_init(void)
+{
+       return 0;
+}
+
+static inline
+int bt_socket_fini(void)
+{
+       return 0;
+}
+
+static inline
+int bt_socket_send(int sockfd, const void *buf, size_t len, int flags)
+{
+       return send(sockfd, buf, len, flags);
+}
+
+static inline
+int bt_socket_recv(int sockfd, void *buf, size_t len, int flags)
+{
+       return recv(sockfd, buf, len, flags);
+}
+
+static inline
+int bt_socket_close(int fd)
+{
+       return close(fd);
+}
+
+static inline
+bool bt_socket_interrupted(void)
+{
+       return (errno == EINTR);
+}
+
+static inline
+const char *bt_socket_errormsg(void)
+{
+       return g_strerror(errno);
+}
+#endif
+
+
+/*
+ * This wrapper is used on platforms that have no way of ignoring SIGPIPE
+ * during a send().
+ */
+
+#ifndef MSG_NOSIGNAL
+# ifdef SO_NOSIGPIPE
+#   define MSG_NOSIGNAL SO_NOSIGPIPE
+# elif defined(__MINGW32__)
+#   define MSG_NOSIGNAL 0
+# endif
+#endif
+
+#if defined(MSG_NOSIGNAL)
+static inline
+ssize_t bt_socket_send_nosigpipe(int fd, const void *buffer, size_t size)
+{
+       return bt_socket_send(fd, buffer, size, MSG_NOSIGNAL);
+}
+#else
+
+#include <signal.h>
+
+static inline
+ssize_t bt_socket_send_nosigpipe(int fd, const void *buffer, size_t size)
+{
+       ssize_t sent;
+       int saved_err;
+       sigset_t sigpipe_set, pending_set, old_set;
+       int sigpipe_was_pending;
+
+       /*
+        * Discard the SIGPIPE from send(), not disturbing any SIGPIPE
+        * that might be already pending. If a bogus SIGPIPE is sent to
+        * the entire process concurrently by a malicious user, it may
+        * be simply discarded.
+        */
+       if (sigemptyset(&pending_set)) {
+               return -1;
+       }
+       /*
+        * sigpending returns the mask of signals that are _both_
+        * blocked for the thread _and_ pending for either the thread or
+        * the entire process.
+        */
+       if (sigpending(&pending_set)) {
+               return -1;
+       }
+       sigpipe_was_pending = sigismember(&pending_set, SIGPIPE);
+       /*
+        * If sigpipe was pending, it means it was already blocked, so
+        * no need to block it.
+        */
+       if (!sigpipe_was_pending) {
+               if (sigemptyset(&sigpipe_set)) {
+                       return -1;
+               }
+               if (sigaddset(&sigpipe_set, SIGPIPE)) {
+                       return -1;
+               }
+               if (pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set)) {
+                       return -1;
+               }
+       }
+
+       /* Send and save errno. */
+       sent = bt_socket_send(fd, buffer, size, 0);
+       saved_err = errno;
+
+       if (sent == -1 && errno == EPIPE && !sigpipe_was_pending) {
+               struct timespec timeout = { 0, 0 };
+               int ret;
+
+               do {
+                       ret = sigtimedwait(&sigpipe_set, NULL,
+                               &timeout);
+               } while (ret == -1 && errno == EINTR);
+       }
+       if (!sigpipe_was_pending) {
+               if (pthread_sigmask(SIG_SETMASK, &old_set, NULL)) {
+                       return -1;
+               }
+       }
+       /* Restore send() errno */
+       errno = saved_err;
+
+       return sent;
+}
+#endif
+
+
+#endif /* _BABELTRACE_COMPAT_SOCKET_H */
diff --git a/src/compat/stdio.h b/src/compat/stdio.h
new file mode 100644 (file)
index 0000000..906e695
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef _BABELTRACE_COMPAT_STDIO_H
+#define _BABELTRACE_COMPAT_STDIO_H
+
+/*
+ * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "common/assert.h"
+
+#define BT_GETLINE_MINBUFLEN   64
+
+static inline
+char * _bt_getline_bufalloc(char **lineptr, size_t *n, size_t linelen)
+{
+       size_t buflen = *n;
+       char *buf = *lineptr;
+
+       if (buflen >= linelen && buf != NULL) {
+               return buf;
+       }
+       if (buf == NULL) {
+               buflen = BT_GETLINE_MINBUFLEN;
+       } else {
+               buflen = buflen << 1;
+               if (buflen < BT_GETLINE_MINBUFLEN) {
+                       buflen = BT_GETLINE_MINBUFLEN;
+               }
+       }
+       /* Check below not strictly needed, extra safety. */
+       if (buflen < linelen) {
+               buflen = linelen;
+       }
+       buf = realloc(buf, buflen);
+       if (!buf) {
+               errno = ENOMEM;
+               return NULL;
+       }
+       *n = buflen;
+       *lineptr = buf;
+       return buf;
+}
+
+/*
+ * Returns line length (including possible final \n, excluding final
+ * \0). On end of file, returns -1 with nonzero feof(stream) and errno
+ * set to 0. On error, returns -1 with errno set.
+ *
+ * This interface is similar to the getline(3) man page part of the
+ * Linux man-pages project, release 3.74. One major difference from the
+ * Open Group POSIX specification is that this implementation does not
+ * necessarily set the ferror() flag on error (because it is internal to
+ * libc).
+ */
+static inline
+ssize_t bt_getline(char **lineptr, size_t *n, FILE *stream)
+{
+       size_t linelen = 0;
+       char *buf;
+       int found_eof = 0;
+
+       if (lineptr == NULL || n == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+       for (;;) {
+               char c;
+               int ret;
+
+               ret = fgetc(stream);
+               if (ret == EOF) {
+                       if (ferror(stream)) {
+                               /* ferror() is set, errno set by fgetc(). */
+                               return -1;
+                       }
+                       BT_ASSERT(feof(stream));
+                       found_eof = 1;
+                       break;
+               }
+               c = (char) ret;
+               if (linelen == SSIZE_MAX) {
+                       errno = EOVERFLOW;
+                       return -1;
+               }
+               buf = _bt_getline_bufalloc(lineptr, n, ++linelen);
+               if (!buf) {
+                       return -1;
+               }
+               buf[linelen - 1] = c;
+               if (c == '\n') {
+                       break;
+               }
+       }
+       if (!linelen && found_eof) {
+               /* feof() is set. */
+               errno = 0;
+               return -1;
+       }
+       buf = _bt_getline_bufalloc(lineptr, n, ++linelen);
+       if (!buf) {
+               return -1;
+       }
+       buf[linelen - 1] = '\0';
+       return linelen - 1;     /* Count don't include final \0. */
+}
+
+#endif /* _BABELTRACE_COMPAT_STDIO_H */
diff --git a/src/compat/stdlib.h b/src/compat/stdlib.h
new file mode 100644 (file)
index 0000000..bd2a2c9
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _BABELTRACE_COMPAT_STDLIB_H
+#define _BABELTRACE_COMPAT_STDLIB_H
+
+/*
+ * Copyright (C) 2015 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This compat wrapper can be removed and replaced by g_mkdtemp() when we bump
+ * the requirement on glib to version 2.30.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <glib.h>
+
+#ifdef HAVE_MKDTEMP
+
+static inline
+char *bt_mkdtemp(char *template)
+{
+       return mkdtemp(template);
+}
+
+#elif GLIB_CHECK_VERSION(2,30,0)
+
+#include <glib/gstdio.h>
+static inline
+char *bt_mkdtemp(char *template)
+{
+       return g_mkdtemp(template);
+}
+
+#else
+
+static inline
+char *bt_mkdtemp(char *template)
+{
+       char *ret;
+
+       ret = mktemp(template);
+       if (!ret) {
+               goto end;
+       }
+
+       if(mkdir(template, 0700)) {
+               ret = NULL;
+               goto end;
+       }
+
+       ret = template;
+end:
+       return ret;
+}
+
+#endif
+
+#endif /* _BABELTRACE_COMPAT_STDLIB_H */
diff --git a/src/compat/string.h b/src/compat/string.h
new file mode 100644 (file)
index 0000000..c3325a3
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef _BABELTRACE_COMPAT_STRING_H
+#define _BABELTRACE_COMPAT_STRING_H
+
+/*
+ * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_STRNLEN
+static inline
+size_t bt_strnlen(const char *str, size_t max)
+{
+       return strnlen(str, max);
+}
+#else
+static inline
+size_t bt_strnlen(const char *str, size_t max)
+{
+       size_t ret;
+       const char *end;
+
+       end = memchr(str, 0, max);
+
+       if (end) {
+               ret = (size_t) (end - str);
+       } else {
+               ret = max;
+       }
+
+       return ret;
+}
+#endif /* HAVE_STRNLEN */
+
+#ifdef HAVE_STRNDUP
+static inline
+char *bt_strndup(const char *s, size_t n)
+{
+       return strndup(s, n);
+}
+#else
+static inline
+char *bt_strndup(const char *s, size_t n)
+{
+       char *ret;
+       size_t navail;
+
+       if (!s) {
+               ret = NULL;
+               goto end;
+       }
+
+       /* min() */
+       navail = strlen(s) + 1;
+       if ((n + 1) < navail) {
+               navail = n + 1;
+       }
+
+       ret = malloc(navail);
+       if (!ret) {
+               goto end;
+       }
+
+       memcpy(ret, s, navail);
+       ret[navail - 1] = '\0';
+end:
+       return ret;
+}
+#endif /* HAVE_STRNDUP */
+
+#endif /* _BABELTRACE_COMPAT_STRING_H */
diff --git a/src/compat/time.h b/src/compat/time.h
new file mode 100644 (file)
index 0000000..f5c09a9
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef _BABELTRACE_INCLUDE_COMPAT_TIME_H
+#define _BABELTRACE_INCLUDE_COMPAT_TIME_H
+
+/*
+ * Copyright (C) 2013 JP Ikaheimonen <jp_ikaheimonen@mentor.com>
+ *               2016 Michael Jeanson <mjeanson@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include <time.h>
+#include <stdlib.h>
+
+#ifdef __MINGW32__
+
+#include <string.h>
+
+/*
+ * The Windows version of the time functions use one common tm structure per
+ * thread which makes them thread-safe. Implement the POSIX _r variants by
+ * copying this to a user supplied struct.
+ */
+
+static inline
+struct tm *bt_gmtime_r(const time_t *timep, struct tm *result)
+{
+       struct tm *local_res;
+
+       if (!result) {
+               goto error;
+       }
+
+       local_res = gmtime(timep);
+       if (!local_res) {
+               result = NULL;
+               goto error;
+       }
+
+       memcpy(result, local_res, sizeof(struct tm));
+
+error:
+       return result;
+}
+
+static inline
+struct tm *bt_localtime_r(const time_t *timep, struct tm *result)
+{
+       struct tm *local_res;
+
+       if (!result) {
+               goto error;
+       }
+
+       local_res = localtime(timep);
+       if (!local_res) {
+               result = NULL;
+               goto error;
+       }
+
+       memcpy(result, local_res, sizeof(struct tm));
+
+error:
+       return result;
+}
+
+#else /* __MINGW32__ */
+
+static inline
+struct tm *bt_gmtime_r(const time_t *timep, struct tm *result)
+{
+       return gmtime_r(timep, result);
+}
+
+static inline
+struct tm *bt_localtime_r(const time_t *timep, struct tm *result)
+{
+       return localtime_r(timep, result);
+}
+
+#endif /* __MINGW32__ */
+#endif /* _BABELTRACE_INCLUDE_COMPAT_TIME_H */
diff --git a/src/compat/unistd.h b/src/compat/unistd.h
new file mode 100644 (file)
index 0000000..502e87a
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef _BABELTRACE_COMPAT_UNISTD_H
+#define _BABELTRACE_COMPAT_UNISTD_H
+
+/*
+ * (C) Copyright 2016 - Michael Jeanson <mjeanson@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include <unistd.h>
+
+#ifdef __MINGW32__
+#include <windows.h>
+#include <errno.h>
+
+#define _SC_PAGESIZE 30
+
+static inline
+long bt_sysconf(int name)
+{
+       SYSTEM_INFO si;
+
+       switch(name) {
+       case _SC_PAGESIZE:
+               GetNativeSystemInfo(&si);
+               return si.dwPageSize;
+       default:
+               errno = EINVAL;
+               return -1;
+       }
+}
+
+#else
+
+static inline
+long bt_sysconf(int name)
+{
+       return sysconf(name);
+}
+
+#endif
+#endif /* _BABELTRACE_COMPAT_UNISTD_H */
diff --git a/src/compat/utc.h b/src/compat/utc.h
new file mode 100644 (file)
index 0000000..3660e08
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef _BABELTRACE_UTC_H
+#define _BABELTRACE_UTC_H
+
+/*
+ * Copyright (C) 2011-2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <time.h>
+
+/* If set, use GNU or BSD timegm(3) */
+#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE)
+
+static inline
+time_t bt_timegm(struct tm *tm)
+{
+       return timegm(tm);
+}
+
+#elif defined(__MINGW32__)
+
+static inline
+time_t bt_timegm(struct tm *tm)
+{
+       return _mkgmtime(tm);
+}
+
+#else
+
+#include <errno.h>
+
+/*
+ * This is a simple implementation of timegm() it just turns the "struct tm" into
+ * a GMT time_t. It does not normalize any of the fields of the "struct tm", nor
+ * does it set tm_wday or tm_yday.
+ */
+
+static inline
+int bt_leapyear(int year)
+{
+    return ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0));
+}
+
+static inline
+time_t bt_timegm(struct tm *tm)
+{
+       int year, month, total_days;
+
+       int monthlen[2][12] = {
+               /* Days per month for a regular year */
+               { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+               /* Days per month for a leap year */
+               { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+       };
+
+       if ((tm->tm_mon >= 12) ||
+                       (tm->tm_mday >= 32) ||
+                       (tm->tm_hour >= 24) ||
+                       (tm->tm_min >= 60) ||
+                       (tm->tm_sec >= 61)) {
+               errno = EOVERFLOW;
+               return (time_t) -1;
+       }
+
+       /* Add 365 days for each year since 1970 */
+       total_days = 365 * (tm->tm_year - 70);
+
+       /* Add one day for each leap year since 1970 */
+       for (year = 70; year < tm->tm_year; year++) {
+               if (bt_leapyear(1900 + year)) {
+                       total_days++;
+               }
+       }
+
+       /* Add days for each remaining month */
+       for (month = 0; month < tm->tm_mon; month++) {
+               total_days += monthlen[bt_leapyear(1900 + year)][month];
+       }
+
+       /* Add remaining days */
+       total_days += tm->tm_mday - 1;
+
+       return ((((total_days * 24) + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec);
+}
+
+#endif
+
+#endif /* _BABELTRACE_UTC_H */
diff --git a/src/compat/uuid.c b/src/compat/uuid.c
new file mode 100644 (file)
index 0000000..0b050e3
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * compat/compat_uuid.h
+ *
+ * Copyright (C) 2013   Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COMPAT-UUID"
+#include "logging.h"
+
+#ifdef __APPLE__
+/*
+ * On macOS, we need a dummy symbol so that the linker won't
+ * complain of an empty table of contents.
+ */
+BT_HIDDEN
+int bt_uuid_dummy_symbol;
+#endif /* __APPLE__ */
+
+#ifdef __MINGW32__
+
+#include <rpc.h>
+#include <stdlib.h>
+#include "compat/uuid.h"
+
+/* MinGW does not provide byteswap - implement our own version. */
+static
+void swap(unsigned char *ptr, unsigned int i, unsigned int j)
+{
+       unsigned char tmp;
+
+       tmp = ptr[i];
+       ptr[i] = ptr[j];
+       ptr[j] = tmp;
+}
+
+static
+void fix_uuid_endian(unsigned char * ptr)
+{
+       swap(ptr, 0, 3);
+       swap(ptr, 1, 2);
+       swap(ptr, 4, 5);
+       swap(ptr, 6, 7);
+}
+
+int bt_uuid_generate(unsigned char *uuid_out)
+{
+       RPC_STATUS status;
+
+       status = UuidCreate((UUID *) uuid_out);
+       if (status == RPC_S_OK)
+               return 0;
+       else
+               return -1;
+}
+
+int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out)
+{
+       RPC_STATUS status;
+       unsigned char *alloc_str;
+       int ret;
+       unsigned char copy_of_uuid_in[BABELTRACE_UUID_LEN];
+
+       /* make a modifyable copy of uuid_in */
+       memcpy(copy_of_uuid_in, uuid_in, BABELTRACE_UUID_LEN);
+
+       fix_uuid_endian(copy_of_uuid_in);
+       status = UuidToString((UUID *) copy_of_uuid_in, &alloc_str);
+
+       if (status == RPC_S_OK) {
+               strncpy(str_out, (char *) alloc_str, BABELTRACE_UUID_STR_LEN);
+               str_out[BABELTRACE_UUID_STR_LEN - 1] = '\0';
+               ret = 0;
+       } else {
+               ret = -1;
+       }
+       RpcStringFree(&alloc_str);
+       return ret;
+}
+
+int bt_uuid_parse(const char *str_in, unsigned char *uuid_out)
+{
+       RPC_STATUS status;
+
+       status = UuidFromString((unsigned char *) str_in,
+                       (UUID *) uuid_out);
+       fix_uuid_endian(uuid_out);
+
+       if (status == RPC_S_OK)
+               return 0;
+       else
+               return -1;
+}
+
+int bt_uuid_compare(const unsigned char *uuid_a,
+               const unsigned char *uuid_b)
+{
+       RPC_STATUS status;
+
+       return !UuidCompare((UUID *) uuid_a, (UUID *) uuid_b, &status) ? 0 : -1;
+}
+
+#endif
diff --git a/src/compat/uuid.h b/src/compat/uuid.h
new file mode 100644 (file)
index 0000000..2c2e929
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef _BABELTRACE_COMPAT_UUID_H
+#define _BABELTRACE_COMPAT_UUID_H
+
+/*
+ * Copyright (C) 2011   Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Includes final \0. */
+#define BABELTRACE_UUID_STR_LEN                37
+#define BABELTRACE_UUID_LEN            16
+
+#ifdef BABELTRACE_HAVE_LIBUUID
+#include <uuid/uuid.h>
+
+static inline
+int bt_uuid_generate(unsigned char *uuid_out)
+{
+       uuid_generate(uuid_out);
+       return 0;
+}
+
+/* Sun's libuuid lacks const qualifiers */
+#if defined(__sun__)
+static inline
+int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out)
+{
+       uuid_unparse((unsigned char *) uuid_in, str_out);
+       return 0;
+}
+
+static inline
+int bt_uuid_parse(const char *str_in, unsigned char *uuid_out)
+{
+       return uuid_parse((char *) str_in, uuid_out);
+}
+
+static inline
+int bt_uuid_compare(const unsigned char *uuid_a,
+               const unsigned char *uuid_b)
+{
+       return uuid_compare((unsigned char *) uuid_a,
+               (unsigned char *) uuid_b);
+}
+#else
+static inline
+int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out)
+{
+       uuid_unparse(uuid_in, str_out);
+       return 0;
+}
+
+static inline
+int bt_uuid_parse(const char *str_in, unsigned char *uuid_out)
+{
+       return uuid_parse(str_in, uuid_out);
+}
+
+static inline
+int bt_uuid_compare(const unsigned char *uuid_a,
+               const unsigned char *uuid_b)
+{
+       return uuid_compare(uuid_a, uuid_b);
+}
+#endif
+
+#elif defined(BABELTRACE_HAVE_LIBC_UUID)
+#include <uuid.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+static inline
+int bt_uuid_generate(unsigned char *uuid_out)
+{
+       uint32_t status;
+
+       uuid_create((uuid_t *) uuid_out, &status);
+       if (status == uuid_s_ok)
+               return 0;
+       else
+               return -1;
+}
+
+static inline
+int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out)
+{
+       uint32_t status;
+       char *alloc_str;
+       int ret;
+
+       uuid_to_string((uuid_t *) uuid_in, &alloc_str, &status);
+       if (status == uuid_s_ok) {
+               strcpy(str_out, alloc_str);
+               ret = 0;
+       } else {
+               ret = -1;
+       }
+       free(alloc_str);
+       return ret;
+}
+
+static inline
+int bt_uuid_parse(const char *str_in, unsigned char *uuid_out)
+{
+       uint32_t status;
+
+       uuid_from_string(str_in, (uuid_t *) uuid_out, &status);
+       if (status == uuid_s_ok)
+               return 0;
+       else
+               return -1;
+}
+
+static inline
+int bt_uuid_compare(const unsigned char *uuid_a,
+               const unsigned char *uuid_b)
+{
+       uint32_t status;
+
+       uuid_compare((uuid_t *) uuid_a, (uuid_t *) uuid_b, &status);
+       if (status == uuid_s_ok)
+               return 0;
+       else
+               return -1;
+}
+
+#elif defined(__MINGW32__)
+
+int bt_uuid_generate(unsigned char *uuid_out);
+int bt_uuid_unparse(const unsigned char *uuid_in, char *str_out);
+int bt_uuid_parse(const char *str_in, unsigned char *uuid_out);
+int bt_uuid_compare(const unsigned char *uuid_a,
+               const unsigned char *uuid_b);
+
+#else
+#error "Babeltrace needs to have a UUID generator configured."
+#endif
+
+#endif /* _BABELTRACE_COMPAT_UUID_H */
diff --git a/src/ctf-writer/Makefile.am b/src/ctf-writer/Makefile.am
new file mode 100644 (file)
index 0000000..be8d1e1
--- /dev/null
@@ -0,0 +1,58 @@
+lib_LTLIBRARIES = libbabeltrace2-ctf-writer.la
+
+libbabeltrace2_ctf_writer_la_SOURCES = \
+       assert-pre.h \
+       attributes.c \
+       attributes.h \
+       clock.c \
+       clock-class.c \
+       clock-class.h \
+       clock.h \
+       event.c \
+       event-class.c \
+       event-class.h \
+       event.h \
+       field-path.c \
+       field-path.h \
+       fields.c \
+       fields.h \
+       field-types.c \
+       field-types.h \
+       field-wrapper.c \
+       field-wrapper.h \
+       functor.c \
+       functor.h \
+       logging.c \
+       logging.h \
+       object.c \
+       object.h \
+       object-pool.c \
+       object-pool.h \
+       resolve.c \
+       resolve.h \
+       stream.c \
+       stream-class.c \
+       stream-class.h \
+       stream.h \
+       trace.c \
+       trace.h \
+       utils.c \
+       utils.h \
+       validation.c \
+       validation.h \
+       values.c \
+       values.h \
+       visitor.c \
+       visitor.h \
+       writer.c \
+       writer.h
+
+libbabeltrace2_ctf_writer_la_LDFLAGS = $(LT_NO_UNDEFINED) \
+                       -version-info $(BABELTRACE_LIBRARY_VERSION)
+
+libbabeltrace2_ctf_writer_la_LIBADD = \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/ctfser/libbabeltrace2-ctfser.la \
+       $(top_builddir)/src/compat/libcompat.la \
+       $(UUID_LIBS)
diff --git a/src/ctf-writer/assert-pre.h b/src/ctf-writer/assert-pre.h
new file mode 100644 (file)
index 0000000..8f66d51
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * The macros in this header use macros defined in
+ * <logging/log.h>. We don't want this header to
+ * automatically include <logging/log.h> because you
+ * need to manually define BT_LOG_TAG before including
+ * <logging/log.h> and it is unexpected that you
+ * also need to define it before including this header.
+ *
+ * This is a reminder that in order to use
+ * <ctf-writer/assert-pre.h>, you also need to use logging
+ * explicitly.
+ */
+
+#ifndef BABELTRACE_LOGGING_INTERNAL_H
+# error Include <logging/log.h> before this header.
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include "common/babeltrace.h"
+
+#ifdef BT_DEV_MODE
+/*
+ * Asserts that the library precondition _cond is satisfied.
+ *
+ * If _cond is false, log a fatal statement using _fmt and the optional
+ * arguments using BT_LOGF(), and abort.
+ *
+ * To assert that a postcondition is satisfied or that some internal
+ * object/context/value is in the expected state, use BT_ASSERT().
+ */
+# define BT_CTF_ASSERT_PRE(_cond, _fmt, ...)                           \
+       do {                                                            \
+               if (!(_cond)) {                                         \
+                       BT_LOGF_STR("Library precondition not satisfied; error is:"); \
+                       BT_LOGF((_fmt), ##__VA_ARGS__);         \
+                       BT_LOGF_STR("Aborting...");                     \
+                       abort();                                        \
+               }                                                       \
+       } while (0)
+
+/*
+ * Marks a function as being only used within a BT_CTF_ASSERT_PRE() context.
+ */
+# define BT_CTF_ASSERT_PRE_FUNC
+
+/*
+ * Prints the details of an unsatisfied precondition without immediately
+ * aborting. You should use this within a function which checks
+ * preconditions, but which is called from a BT_CTF_ASSERT_PRE() context, so
+ * that the function can still return its result for BT_CTF_ASSERT_PRE() to
+ * evaluate it.
+ *
+ * Example:
+ *
+ *     BT_CTF_ASSERT_PRE_FUNC
+ *     static inline bool check_complex_precond(...)
+ *     {
+ *         ...
+ *
+ *         if (...) {
+ *             BT_CTF_ASSERT_PRE_MSG("Invalid object: ...", ...);
+ *             return false;
+ *         }
+ *
+ *         ...
+ *     }
+ *
+ *     ...
+ *
+ *     BT_CTF_ASSERT_PRE(check_complex_precond(...),
+ *                   "Precondition is not satisfied: ...", ...);
+ */
+# define BT_CTF_ASSERT_PRE_MSG BT_LOGF
+#else
+# define BT_CTF_ASSERT_PRE(_cond, _fmt, ...)   ((void) sizeof((void) (_cond), 0))
+# define BT_CTF_ASSERT_PRE_FUNC        BT_UNUSED
+# define BT_CTF_ASSERT_PRE_MSG(_fmt, ...)
+#endif /* BT_DEV_MODE */
+
+/*
+ * Developer mode: asserts that a given variable is not NULL.
+ */
+#define BT_CTF_ASSERT_PRE_NON_NULL(_obj, _obj_name)                            \
+       BT_CTF_ASSERT_PRE((_obj) != NULL, "%s is NULL: ", _obj_name)
+
+/*
+ * Developer mode: asserts that a given object is NOT frozen. This macro
+ * checks the `frozen` field of _obj.
+ */
+#define BT_CTF_ASSERT_PRE_HOT(_obj, _obj_name, _fmt, ...)                      \
+       BT_CTF_ASSERT_PRE(!(_obj)->frozen, "%s is frozen" _fmt, _obj_name,      \
+               ##__VA_ARGS__)
+
+/*
+ * Developer mode: asserts that a given index is less than a given size.
+ */
+#define BT_CTF_ASSERT_PRE_VALID_INDEX(_index, _length)                 \
+       BT_CTF_ASSERT_PRE((_index) < (_length),                         \
+               "Index is out of bounds: index=%" PRIu64 ", "           \
+               "count=%" PRIu64, (uint64_t) (_index), (uint64_t) (_length))
+
+#endif /* BABELTRACE_CTF_WRITER_ASSERT_PRE_INTERNAL_H */
diff --git a/src/ctf-writer/attributes.c b/src/ctf-writer/attributes.c
new file mode 100644 (file)
index 0000000..e79dc58
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * attributes.c
+ *
+ * Babeltrace CTF writer - Attributes
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-ATTRS"
+#include "logging.h"
+
+#include "common/assert.h"
+#include "common/babeltrace.h"
+#include "compat/string.h"
+#include <babeltrace2/ctf-writer/object.h>
+#include <inttypes.h>
+
+#include "values.h"
+
+#define BT_CTF_ATTR_NAME_INDEX         0
+#define BT_CTF_ATTR_VALUE_INDEX                1
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_create(void)
+{
+       struct bt_ctf_private_value *attr_obj;
+
+       /*
+        * Attributes: array value object of array value objects, each one
+        * containing two entries: a string value object (attributes
+        * field name), and a value object (attributes field value).
+        *
+        * Example (JSON representation):
+        *
+        *     [
+        *         ["hostname", "eeppdesk"],
+        *         ["sysname", "Linux"],
+        *         ["tracer_major", 2],
+        *         ["tracer_minor", 5]
+        *     ]
+        */
+       BT_LOGD_STR("Creating attributes object.");
+       attr_obj = bt_ctf_private_value_array_create();
+       if (!attr_obj) {
+               BT_LOGE_STR("Failed to create array value.");
+       } else {
+               BT_LOGD("Created attributes object: addr=%p",
+                       attr_obj);
+       }
+
+       return attr_obj;
+}
+
+BT_HIDDEN
+void bt_ctf_attributes_destroy(struct bt_ctf_private_value *attr_obj)
+{
+       BT_LOGD("Destroying attributes object: addr=%p", attr_obj);
+       bt_ctf_object_put_ref(attr_obj);
+}
+
+BT_HIDDEN
+int64_t bt_ctf_attributes_get_count(struct bt_ctf_private_value *attr_obj)
+{
+       return bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
+}
+
+BT_HIDDEN
+const char *bt_ctf_attributes_get_field_name(struct bt_ctf_private_value *attr_obj,
+               uint64_t index)
+{
+       const char *ret = NULL;
+       struct bt_ctf_private_value *attr_field_obj = NULL;
+       struct bt_ctf_private_value *attr_field_name_obj = NULL;
+
+       if (!attr_obj) {
+               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
+               goto end;
+       }
+
+       if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) {
+               BT_LOGW("Invalid parameter: index is out of bounds: "
+                       "index=%" PRIu64 ", count=%" PRId64,
+                       index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)));
+               goto end;
+       }
+
+       attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index(
+               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_ctf_private_value_array_borrow_element_by_index(
+                       attr_field_obj, BT_CTF_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_CTF_ATTR_NAME_INDEX);
+               goto end;
+       }
+
+       ret = bt_ctf_value_string_get(
+               bt_ctf_private_value_as_value(attr_field_name_obj));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value(struct bt_ctf_private_value *attr_obj,
+               uint64_t index)
+{
+       struct bt_ctf_private_value *value_obj = NULL;
+       struct bt_ctf_private_value *attr_field_obj = NULL;
+
+       if (!attr_obj) {
+               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
+               goto end;
+       }
+
+       if (index >= bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj))) {
+               BT_LOGW("Invalid parameter: index is out of bounds: "
+                       "index=%" PRIu64 ", count=%" PRId64,
+                       index, bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj)));
+               goto end;
+       }
+
+       attr_field_obj = bt_ctf_private_value_array_borrow_element_by_index(
+               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_ctf_private_value_array_borrow_element_by_index(attr_field_obj,
+               BT_CTF_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_CTF_ATTR_VALUE_INDEX);
+       }
+
+end:
+       return value_obj;
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_by_name(
+               struct bt_ctf_private_value *attr_obj, const char *name)
+{
+       uint64_t i;
+       int64_t attr_size;
+       struct bt_ctf_private_value *value_obj = NULL;
+       struct bt_ctf_private_value *attr_field_name_obj = NULL;
+
+       attr_size = bt_ctf_value_array_get_size(bt_ctf_private_value_as_value(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) {
+               const char *field_name;
+
+               value_obj = bt_ctf_private_value_array_borrow_element_by_index(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_ctf_private_value_array_borrow_element_by_index(value_obj,
+                       BT_CTF_ATTR_NAME_INDEX);
+               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) BT_CTF_ATTR_NAME_INDEX);
+                       goto error;
+               }
+
+               field_name = bt_ctf_value_string_get(
+                       bt_ctf_private_value_as_value(attr_field_name_obj));
+
+               if (!strcmp(field_name, name)) {
+                       break;
+               }
+
+               value_obj = NULL;
+       }
+
+       return value_obj;
+
+error:
+       value_obj = NULL;
+       return value_obj;
+}
+
+BT_HIDDEN
+int bt_ctf_attributes_set_field_value(struct bt_ctf_private_value *attr_obj,
+               const char *name, struct bt_ctf_private_value *value_obj)
+{
+       int ret = 0;
+       struct bt_ctf_private_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_ctf_attributes_borrow_field_by_name(attr_obj, name);
+       if (attr_field_obj) {
+               ret = bt_ctf_private_value_array_set_element_by_index(
+                       attr_field_obj, BT_CTF_ATTR_VALUE_INDEX,
+                       bt_ctf_private_value_as_value(value_obj));
+               attr_field_obj = NULL;
+               goto end;
+       }
+
+       attr_field_obj = bt_ctf_private_value_array_create();
+       if (!attr_field_obj) {
+               BT_LOGE_STR("Failed to create empty array value.");
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_private_value_array_append_string_element(attr_field_obj, name);
+       ret |= bt_ctf_private_value_array_append_element(attr_field_obj,
+               bt_ctf_private_value_as_value(value_obj));
+       if (ret) {
+               BT_LOGE("Cannot append elements to array value: addr=%p",
+                       attr_field_obj);
+               goto end;
+       }
+
+       ret = bt_ctf_private_value_array_append_element(attr_obj,
+               bt_ctf_private_value_as_value(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_ctf_object_put_ref(attr_field_obj);
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value_by_name(
+               struct bt_ctf_private_value *attr_obj, const char *name)
+{
+       struct bt_ctf_private_value *value_obj = NULL;
+       struct bt_ctf_private_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_ctf_attributes_borrow_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_ctf_private_value_array_borrow_element_by_index(attr_field_obj,
+               BT_CTF_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_CTF_ATTR_VALUE_INDEX);
+       }
+
+end:
+       return value_obj;
+}
+
+BT_HIDDEN
+int bt_ctf_attributes_freeze(struct bt_ctf_private_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_ctf_value_array_get_size(bt_ctf_private_value_as_value(attr_obj));
+       BT_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_ctf_private_value *obj = NULL;
+
+               obj = bt_ctf_attributes_borrow_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_ctf_value_freeze(bt_ctf_private_value_as_value(obj));
+       }
+
+end:
+       return ret;
+}
diff --git a/src/ctf-writer/attributes.h b/src/ctf-writer/attributes.h
new file mode 100644 (file)
index 0000000..a990653
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef BABELTRACE_CTF_WRITER_ATTRIBUTES_H
+#define BABELTRACE_CTF_WRITER_ATTRIBUTES_H
+
+/*
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include "common/babeltrace.h"
+
+#include "values.h"
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_create(void);
+
+BT_HIDDEN
+void bt_ctf_attributes_destroy(struct bt_ctf_private_value *attr_obj);
+
+BT_HIDDEN
+int64_t bt_ctf_attributes_get_count(struct bt_ctf_private_value *attr_obj);
+
+BT_HIDDEN
+const char *bt_ctf_attributes_get_field_name(struct bt_ctf_private_value *attr_obj,
+               uint64_t index);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value(struct bt_ctf_private_value *attr_obj,
+               uint64_t index);
+
+BT_HIDDEN
+int bt_ctf_attributes_set_field_value(struct bt_ctf_private_value *attr_obj,
+               const char *name, struct bt_ctf_private_value *value_obj);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_attributes_borrow_field_value_by_name(
+               struct bt_ctf_private_value *attr_obj, const char *name);
+
+BT_HIDDEN
+int bt_ctf_attributes_freeze(struct bt_ctf_private_value *attr_obj);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_CTF_WRITER_ATTRIBUTES_H */
diff --git a/src/ctf-writer/clock-class.c b/src/ctf-writer/clock-class.c
new file mode 100644 (file)
index 0000000..258d4a6
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ * clock-class.c
+ *
+ * Babeltrace CTF writer - Clock class
+ *
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-CLOCK-CLASS"
+#include "logging.h"
+
+#include "compat/uuid.h"
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include "compat/compiler.h"
+#include <babeltrace2/types.h>
+#include "compat/string.h"
+#include <inttypes.h>
+#include "common/assert.h"
+
+#include "assert-pre.h"
+#include "clock-class.h"
+#include "object.h"
+
+static
+void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class)
+{
+       return clock_class && clock_class->name;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class,
+               const char *name)
+{
+       int ret = 0;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (clock_class->frozen) {
+               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_identifier_is_valid(name)) {
+               BT_LOGW("Clock class's name is not a valid CTF identifier: "
+                       "addr=%p, name=\"%s\"",
+                       clock_class, name);
+               ret = -1;
+               goto end;
+       }
+
+       if (clock_class->name) {
+               g_string_assign(clock_class->name, name);
+       } else {
+               clock_class->name = g_string_new(name);
+               if (!clock_class->name) {
+                       BT_LOGE_STR("Failed to allocate a GString.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       BT_LOGV("Set clock class's name: addr=%p, name=\"%s\"",
+               clock_class, name);
+
+end:
+       return ret;
+}
+
+static
+bool validate_freq(struct bt_ctf_clock_class *clock_class,
+               const char *name, uint64_t freq)
+{
+       bool is_valid = true;
+
+       if (freq == -1ULL || freq == 0) {
+               BT_LOGW("Invalid parameter: frequency is invalid: "
+                       "addr=%p, name=\"%s\", freq=%" PRIu64,
+                       clock_class, name, freq);
+               is_valid = false;
+               goto end;
+       }
+
+end:
+       return is_valid;
+}
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name,
+               uint64_t freq)
+{
+       int ret;
+       struct bt_ctf_clock_class *clock_class = NULL;
+
+       BT_LOGD("Creating default clock class object: name=\"%s\"",
+               name);
+
+       if (!validate_freq(NULL, name, freq)) {
+               /* validate_freq() logs errors */
+               goto error;
+       }
+
+       clock_class = g_new0(struct bt_ctf_clock_class, 1);
+       if (!clock_class) {
+               BT_LOGE_STR("Failed to allocate one clock class.");
+               goto error;
+       }
+
+       clock_class->precision = 1;
+       clock_class->frequency = freq;
+       bt_ctf_object_init_shared(&clock_class->base, bt_ctf_clock_class_destroy);
+
+       if (name) {
+               ret = bt_ctf_clock_class_set_name(clock_class, name);
+               if (ret) {
+                       /* bt_ctf_clock_class_set_name() logs errors */
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Created clock class object: addr=%p, name=\"%s\"",
+               clock_class, name);
+       return clock_class;
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(clock_class);
+       return clock_class;
+}
+
+BT_HIDDEN
+const char *bt_ctf_clock_class_get_name(struct bt_ctf_clock_class *clock_class)
+{
+       const char *ret = NULL;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               goto end;
+       }
+
+       if (clock_class->name) {
+               ret = clock_class->name->str;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+const char *bt_ctf_clock_class_get_description(
+               struct bt_ctf_clock_class *clock_class)
+{
+       const char *ret = NULL;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               goto end;
+       }
+
+       if (clock_class->description) {
+               ret = clock_class->description->str;
+       }
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_description(struct bt_ctf_clock_class *clock_class,
+               const char *desc)
+{
+       int ret = 0;
+
+       if (!clock_class || !desc) {
+               BT_LOGW("Invalid parameter: clock class or description is NULL: "
+                       "clock-class-addr=%p, name=\"%s\", desc-addr=%p",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class),
+                       desc);
+               ret = -1;
+               goto end;
+       }
+
+       if (clock_class->frozen) {
+               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       clock_class->description = g_string_new(desc);
+       ret = clock_class->description ? 0 : -1;
+       BT_LOGV("Set clock class's description: addr=%p, "
+               "name=\"%s\", desc=\"%s\"",
+               clock_class, bt_ctf_clock_class_get_name(clock_class), desc);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+uint64_t bt_ctf_clock_class_get_frequency(
+               struct bt_ctf_clock_class *clock_class)
+{
+       uint64_t ret = -1ULL;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               goto end;
+       }
+
+       ret = clock_class->frequency;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_frequency(struct bt_ctf_clock_class *clock_class,
+               uint64_t freq)
+{
+       int ret = 0;
+
+       if (!clock_class) {
+               BT_LOGW("Invalid parameter: clock class is NULL or frequency is invalid: "
+                       "addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (!validate_freq(clock_class, bt_ctf_clock_class_get_name(clock_class),
+                       freq)) {
+               /* validate_freq() logs errors */
+               goto end;
+       }
+
+       if (clock_class->frozen) {
+               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       clock_class->frequency = freq;
+       BT_LOGV("Set clock class's frequency: addr=%p, name=\"%s\", freq=%" PRIu64,
+               clock_class, bt_ctf_clock_class_get_name(clock_class), freq);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+uint64_t bt_ctf_clock_class_get_precision(struct bt_ctf_clock_class *clock_class)
+{
+       uint64_t ret = -1ULL;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               goto end;
+       }
+
+       ret = clock_class->precision;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_precision(struct bt_ctf_clock_class *clock_class,
+               uint64_t precision)
+{
+       int ret = 0;
+
+       if (!clock_class || precision == -1ULL) {
+               BT_LOGW("Invalid parameter: clock class is NULL or precision is invalid: "
+                       "addr=%p, name=\"%s\", precision=%" PRIu64,
+                       clock_class, bt_ctf_clock_class_get_name(clock_class),
+                       precision);
+               ret = -1;
+               goto end;
+       }
+
+       if (clock_class->frozen) {
+               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       clock_class->precision = precision;
+       BT_LOGV("Set clock class's precision: addr=%p, name=\"%s\", precision=%" PRIu64,
+               clock_class, bt_ctf_clock_class_get_name(clock_class),
+               precision);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_get_offset_s(struct bt_ctf_clock_class *clock_class,
+               int64_t *offset_s)
+{
+       int ret = 0;
+
+       if (!clock_class || !offset_s) {
+               BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: "
+                       "clock-class-addr=%p, name=\"%s\", offset-addr=%p",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class),
+                       offset_s);
+               ret = -1;
+               goto end;
+       }
+
+       *offset_s = clock_class->offset_s;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_offset_s(struct bt_ctf_clock_class *clock_class,
+               int64_t offset_s)
+{
+       int ret = 0;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (clock_class->frozen) {
+               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       clock_class->offset_s = offset_s;
+       BT_LOGV("Set clock class's offset (seconds): "
+               "addr=%p, name=\"%s\", offset-s=%" PRId64,
+               clock_class, bt_ctf_clock_class_get_name(clock_class),
+               offset_s);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_get_offset_cycles(struct bt_ctf_clock_class *clock_class,
+               int64_t *offset)
+{
+       int ret = 0;
+
+       if (!clock_class || !offset) {
+               BT_LOGW("Invalid parameter: clock class or offset pointer is NULL: "
+                       "clock-class-addr=%p, name=\"%s\", offset-addr=%p",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class),
+                       offset);
+               ret = -1;
+               goto end;
+       }
+
+       *offset = clock_class->offset;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_offset_cycles(struct bt_ctf_clock_class *clock_class,
+               int64_t offset)
+{
+       int ret = 0;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (clock_class->frozen) {
+               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       clock_class->offset = offset;
+       BT_LOGV("Set clock class's offset (cycles): addr=%p, name=\"%s\", offset-cycles=%" PRId64,
+               clock_class, bt_ctf_clock_class_get_name(clock_class), offset);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_clock_class_is_absolute(struct bt_ctf_clock_class *clock_class)
+{
+       int ret = -1;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               goto end;
+       }
+
+       ret = clock_class->absolute;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_is_absolute(struct bt_ctf_clock_class *clock_class,
+               bt_bool is_absolute)
+{
+       int ret = 0;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (clock_class->frozen) {
+               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       clock_class->absolute = !!is_absolute;
+       BT_LOGV("Set clock class's absolute flag: addr=%p, name=\"%s\", is-absolute=%d",
+               clock_class, bt_ctf_clock_class_get_name(clock_class),
+               is_absolute);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+const unsigned char *bt_ctf_clock_class_get_uuid(
+               struct bt_ctf_clock_class *clock_class)
+{
+       const unsigned char *ret;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               ret = NULL;
+               goto end;
+       }
+
+       if (!clock_class->uuid_set) {
+               BT_LOGV("Clock class's UUID is not set: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = NULL;
+               goto end;
+       }
+
+       ret = clock_class->uuid;
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class,
+               const unsigned char *uuid)
+{
+       int ret = 0;
+
+       if (!clock_class || !uuid) {
+               BT_LOGW("Invalid parameter: clock class or UUID is NULL: "
+                       "clock-class-addr=%p, name=\"%s\", uuid-addr=%p",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class),
+                       uuid);
+               ret = -1;
+               goto end;
+       }
+
+       if (clock_class->frozen) {
+               BT_LOGW("Invalid parameter: clock class is frozen: addr=%p, name=\"%s\"",
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       memcpy(clock_class->uuid, uuid, BABELTRACE_UUID_LEN);
+       clock_class->uuid_set = 1;
+       BT_LOGV("Set clock class's UUID: addr=%p, name=\"%s\", "
+               "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+               clock_class, bt_ctf_clock_class_get_name(clock_class),
+               (unsigned int) uuid[0],
+               (unsigned int) uuid[1],
+               (unsigned int) uuid[2],
+               (unsigned int) uuid[3],
+               (unsigned int) uuid[4],
+               (unsigned int) uuid[5],
+               (unsigned int) uuid[6],
+               (unsigned int) uuid[7],
+               (unsigned int) uuid[8],
+               (unsigned int) uuid[9],
+               (unsigned int) uuid[10],
+               (unsigned int) uuid[11],
+               (unsigned int) uuid[12],
+               (unsigned int) uuid[13],
+               (unsigned int) uuid[14],
+               (unsigned int) uuid[15]);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class)
+{
+       if (!clock_class || clock_class->frozen) {
+               return;
+       }
+
+       BT_LOGD("Freezing clock class: addr=%p, name=\"%s\"",
+               clock_class, bt_ctf_clock_class_get_name(clock_class));
+       clock_class->frozen = 1;
+}
+
+static
+void bt_ctf_clock_class_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_clock_class *clock_class;
+
+       clock_class = container_of(obj, struct bt_ctf_clock_class, base);
+       BT_LOGD("Destroying clock class: addr=%p, name=\"%s\"",
+               obj, bt_ctf_clock_class_get_name(clock_class));
+
+       if (clock_class->name) {
+               g_string_free(clock_class->name, TRUE);
+       }
+
+       if (clock_class->description) {
+               g_string_free(clock_class->description, TRUE);
+       }
+
+       g_free(clock_class);
+}
+
+BT_HIDDEN
+int bt_ctf_clock_class_compare(struct bt_ctf_clock_class *clock_class_a,
+               struct bt_ctf_clock_class *clock_class_b)
+{
+       int ret = 1;
+       BT_ASSERT(clock_class_a);
+       BT_ASSERT(clock_class_b);
+
+       /* Name */
+       if (strcmp(clock_class_a->name->str, clock_class_b->name->str) != 0) {
+               BT_LOGV("Clock classes differ: different names: "
+                       "cc-a-name=\"%s\", cc-b-name=\"%s\"",
+                       clock_class_a->name->str,
+                       clock_class_b->name->str);
+               goto end;
+       }
+
+       /* Description */
+       if (clock_class_a->description) {
+               if (!clock_class_b->description) {
+                       BT_LOGV_STR("Clock classes differ: clock class A has a "
+                               "description, but clock class B does not.");
+                       goto end;
+               }
+
+               if (strcmp(clock_class_a->name->str, clock_class_b->name->str)
+                               != 0) {
+                       BT_LOGV("Clock classes differ: different descriptions: "
+                               "cc-a-descr=\"%s\", cc-b-descr=\"%s\"",
+                               clock_class_a->description->str,
+                               clock_class_b->description->str);
+                       goto end;
+               }
+       } else {
+               if (clock_class_b->description) {
+                       BT_LOGV_STR("Clock classes differ: clock class A has "
+                               "no description, but clock class B has one.");
+                       goto end;
+               }
+       }
+
+       /* Frequency */
+       if (clock_class_a->frequency != clock_class_b->frequency) {
+               BT_LOGV("Clock classes differ: different frequencies: "
+                       "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64,
+                       clock_class_a->frequency,
+                       clock_class_b->frequency);
+               goto end;
+       }
+
+       /* Precision */
+       if (clock_class_a->precision != clock_class_b->precision) {
+               BT_LOGV("Clock classes differ: different precisions: "
+                       "cc-a-freq=%" PRIu64 ", cc-b-freq=%" PRIu64,
+                       clock_class_a->precision,
+                       clock_class_b->precision);
+               goto end;
+       }
+
+       /* Offset (seconds) */
+       if (clock_class_a->offset_s != clock_class_b->offset_s) {
+               BT_LOGV("Clock classes differ: different offsets (seconds): "
+                       "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64,
+                       clock_class_a->offset_s,
+                       clock_class_b->offset_s);
+               goto end;
+       }
+
+       /* Offset (cycles) */
+       if (clock_class_a->offset != clock_class_b->offset) {
+               BT_LOGV("Clock classes differ: different offsets (cycles): "
+                       "cc-a-offset-s=%" PRId64 ", cc-b-offset-s=%" PRId64,
+                       clock_class_a->offset,
+                       clock_class_b->offset);
+               goto end;
+       }
+
+       /* UUIDs */
+       if (clock_class_a->uuid_set) {
+               if (!clock_class_b->uuid_set) {
+                       BT_LOGV_STR("Clock classes differ: clock class A has a "
+                               "UUID, but clock class B does not.");
+                       goto end;
+               }
+
+               if (memcmp(clock_class_a->uuid, clock_class_b->uuid,
+                               BABELTRACE_UUID_LEN) != 0) {
+                       BT_LOGV("Clock classes differ: different UUIDs: "
+                               "cc-a-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", "
+                               "cc-b-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+                               (unsigned int) clock_class_a->uuid[0],
+                               (unsigned int) clock_class_a->uuid[1],
+                               (unsigned int) clock_class_a->uuid[2],
+                               (unsigned int) clock_class_a->uuid[3],
+                               (unsigned int) clock_class_a->uuid[4],
+                               (unsigned int) clock_class_a->uuid[5],
+                               (unsigned int) clock_class_a->uuid[6],
+                               (unsigned int) clock_class_a->uuid[7],
+                               (unsigned int) clock_class_a->uuid[8],
+                               (unsigned int) clock_class_a->uuid[9],
+                               (unsigned int) clock_class_a->uuid[10],
+                               (unsigned int) clock_class_a->uuid[11],
+                               (unsigned int) clock_class_a->uuid[12],
+                               (unsigned int) clock_class_a->uuid[13],
+                               (unsigned int) clock_class_a->uuid[14],
+                               (unsigned int) clock_class_a->uuid[15],
+                               (unsigned int) clock_class_b->uuid[0],
+                               (unsigned int) clock_class_b->uuid[1],
+                               (unsigned int) clock_class_b->uuid[2],
+                               (unsigned int) clock_class_b->uuid[3],
+                               (unsigned int) clock_class_b->uuid[4],
+                               (unsigned int) clock_class_b->uuid[5],
+                               (unsigned int) clock_class_b->uuid[6],
+                               (unsigned int) clock_class_b->uuid[7],
+                               (unsigned int) clock_class_b->uuid[8],
+                               (unsigned int) clock_class_b->uuid[9],
+                               (unsigned int) clock_class_b->uuid[10],
+                               (unsigned int) clock_class_b->uuid[11],
+                               (unsigned int) clock_class_b->uuid[12],
+                               (unsigned int) clock_class_b->uuid[13],
+                               (unsigned int) clock_class_b->uuid[14],
+                               (unsigned int) clock_class_b->uuid[15]);
+                       goto end;
+               }
+       } else {
+               if (clock_class_b->uuid_set) {
+                       BT_LOGV_STR("Clock classes differ: clock class A has "
+                               "no UUID, but clock class B has one.");
+                       goto end;
+               }
+       }
+
+       /* Absolute */
+       if (!!clock_class_a->absolute != !!clock_class_b->absolute) {
+               BT_LOGV("Clock classes differ: one is absolute, the other "
+                       "is not: cc-a-is-absolute=%d, cc-b-is-absolute=%d",
+                       !!clock_class_a->absolute,
+                       !!clock_class_b->absolute);
+               goto end;
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
diff --git a/src/ctf-writer/clock-class.h b/src/ctf-writer/clock-class.h
new file mode 100644 (file)
index 0000000..d317508
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef BABELTRACE_CTF_WRITER_CLOCK_CLASS_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_CLOCK_CLASS_INTERNAL_H
+
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "lib/object-pool.h"
+#include "compat/uuid.h"
+#include <babeltrace2/types.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <glib.h>
+
+#include "object.h"
+
+struct bt_ctf_clock_class {
+       struct bt_ctf_object base;
+       GString *name;
+       GString *description;
+       uint64_t frequency;
+       uint64_t precision;
+       int64_t offset_s;       /* Offset in seconds */
+       int64_t offset;         /* Offset in ticks */
+       unsigned char uuid[BABELTRACE_UUID_LEN];
+       int uuid_set;
+       int absolute;
+
+       /*
+        * A clock's properties can't be modified once it is added to a stream
+        * class.
+        */
+       int frozen;
+};
+
+BT_HIDDEN
+void bt_ctf_clock_class_freeze(struct bt_ctf_clock_class *clock_class);
+
+BT_HIDDEN
+bt_bool bt_ctf_clock_class_is_valid(struct bt_ctf_clock_class *clock_class);
+
+BT_HIDDEN
+int bt_ctf_clock_class_compare(struct bt_ctf_clock_class *clock_class_a,
+               struct bt_ctf_clock_class *clock_class_b);
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_clock_class_create(const char *name,
+               uint64_t freq);
+BT_HIDDEN
+const char *bt_ctf_clock_class_get_name(
+               struct bt_ctf_clock_class *clock_class);
+BT_HIDDEN
+int bt_ctf_clock_class_set_name(struct bt_ctf_clock_class *clock_class,
+               const char *name);
+BT_HIDDEN
+const char *bt_ctf_clock_class_get_description(
+               struct bt_ctf_clock_class *clock_class);
+BT_HIDDEN
+int bt_ctf_clock_class_set_description(
+               struct bt_ctf_clock_class *clock_class,
+               const char *desc);
+BT_HIDDEN
+uint64_t bt_ctf_clock_class_get_frequency(
+               struct bt_ctf_clock_class *clock_class);
+BT_HIDDEN
+int bt_ctf_clock_class_set_frequency(
+               struct bt_ctf_clock_class *clock_class, uint64_t freq);
+BT_HIDDEN
+uint64_t bt_ctf_clock_class_get_precision(
+               struct bt_ctf_clock_class *clock_class);
+BT_HIDDEN
+int bt_ctf_clock_class_set_precision(
+               struct bt_ctf_clock_class *clock_class, uint64_t precision);
+BT_HIDDEN
+int bt_ctf_clock_class_get_offset_s(
+               struct bt_ctf_clock_class *clock_class, int64_t *seconds);
+BT_HIDDEN
+int bt_ctf_clock_class_set_offset_s(
+               struct bt_ctf_clock_class *clock_class, int64_t seconds);
+BT_HIDDEN
+int bt_ctf_clock_class_get_offset_cycles(
+               struct bt_ctf_clock_class *clock_class, int64_t *cycles);
+BT_HIDDEN
+int bt_ctf_clock_class_set_offset_cycles(
+               struct bt_ctf_clock_class *clock_class, int64_t cycles);
+BT_HIDDEN
+bt_bool bt_ctf_clock_class_is_absolute(
+               struct bt_ctf_clock_class *clock_class);
+BT_HIDDEN
+int bt_ctf_clock_class_set_is_absolute(
+               struct bt_ctf_clock_class *clock_class, bt_bool is_absolute);
+BT_HIDDEN
+const unsigned char *bt_ctf_clock_class_get_uuid(
+               struct bt_ctf_clock_class *clock_class);
+BT_HIDDEN
+int bt_ctf_clock_class_set_uuid(struct bt_ctf_clock_class *clock_class,
+               const unsigned char *uuid);
+
+#endif /* BABELTRACE_CTF_WRITER_CLOCK_CLASS_INTERNAL_H */
diff --git a/src/ctf-writer/clock.c b/src/ctf-writer/clock.c
new file mode 100644 (file)
index 0000000..cb55926
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * clock.c
+ *
+ * Babeltrace CTF writer - Clock
+ *
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-CLOCK"
+#include "logging.h"
+
+#include "common/assert.h"
+#include "compat/uuid.h"
+#include "compat/compiler.h"
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <inttypes.h>
+
+#include "clock-class.h"
+#include "clock.h"
+#include "object.h"
+#include "writer.h"
+
+static
+void bt_ctf_clock_destroy(struct bt_ctf_object *obj);
+
+struct bt_ctf_clock *bt_ctf_clock_create(const char *name)
+{
+       int ret;
+       struct bt_ctf_clock *clock = NULL;
+       unsigned char cc_uuid[BABELTRACE_UUID_LEN];
+
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       clock = g_new0(struct bt_ctf_clock, 1);
+       if (!clock) {
+               goto error;
+       }
+
+       bt_ctf_object_init_shared(&clock->base, bt_ctf_clock_destroy);
+       clock->value = 0;
+
+       /* Pre-2.0.0 backward compatibility: default frequency is 1 GHz */
+       clock->clock_class = (void *) bt_ctf_clock_class_create(name, 1000000000);
+       if (!clock->clock_class) {
+               goto error;
+       }
+
+       /* Automatically set clock class's UUID. */
+       ret = bt_uuid_generate(cc_uuid);
+       if (ret) {
+               goto error;
+       }
+
+       ret = bt_ctf_clock_class_set_uuid(clock->clock_class, cc_uuid);
+       BT_ASSERT(ret == 0);
+       return clock;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(clock);
+       return clock;
+}
+
+const char *bt_ctf_clock_get_name(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_name(clock->clock_class);
+}
+
+const char *bt_ctf_clock_get_description(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_description(clock->clock_class);
+}
+
+int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, const char *desc)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_description(clock->clock_class,
+               desc);
+}
+
+uint64_t bt_ctf_clock_get_frequency(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_frequency(clock->clock_class);
+}
+
+int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, uint64_t freq)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_frequency(clock->clock_class,
+               freq);
+}
+
+uint64_t bt_ctf_clock_get_precision(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_precision(clock->clock_class);
+}
+
+int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, uint64_t precision)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_precision(clock->clock_class,
+               precision);
+}
+
+int bt_ctf_clock_get_offset_s(struct bt_ctf_clock *clock, int64_t *offset_s)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_offset_s(clock->clock_class,
+               offset_s);
+}
+
+int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, int64_t offset_s)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_offset_s(clock->clock_class,
+               offset_s);
+}
+
+int bt_ctf_clock_get_offset(struct bt_ctf_clock *clock, int64_t *offset)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_offset_cycles(clock->clock_class,
+               offset);
+}
+
+int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, int64_t offset)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_offset_cycles(clock->clock_class,
+               offset);
+}
+
+int bt_ctf_clock_get_is_absolute(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_is_absolute(clock->clock_class);
+}
+
+int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, int is_absolute)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_is_absolute(clock->clock_class,
+               is_absolute);
+}
+
+const unsigned char *bt_ctf_clock_get_uuid(struct bt_ctf_clock *clock)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_get_uuid(clock->clock_class);
+}
+
+int bt_ctf_clock_set_uuid(struct bt_ctf_clock *clock, const unsigned char *uuid)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       return bt_ctf_clock_class_set_uuid(clock->clock_class, uuid);
+}
+
+int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, int64_t time)
+{
+       int64_t value;
+       struct bt_ctf_clock_class *cc;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       cc = clock->clock_class;
+
+       /* Common case where cycles are actually nanoseconds */
+       if (cc->frequency == 1000000000) {
+               value = time;
+       } else {
+               value = (uint64_t) (((double) time *
+                       (double) cc->frequency) / 1e9);
+       }
+
+       BT_CTF_ASSERT_PRE(clock->value <= value,
+               "CTF writer clock value must be updated monotonically: "
+               "prev-value=%" PRId64 ", new-value=%" PRId64,
+               clock->value, value);
+       clock->value = value;
+       return 0;
+}
+
+BT_HIDDEN
+int bt_ctf_clock_get_value(struct bt_ctf_clock *clock, uint64_t *value)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(clock, "CTF writer clock");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       *value = clock->value;
+       return 0;
+}
+
+static
+void bt_ctf_clock_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_clock *clock;
+
+       clock = container_of(obj, struct bt_ctf_clock, base);
+       bt_ctf_object_put_ref(clock->clock_class);
+       g_free(clock);
+}
+
+BT_HIDDEN
+void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class,
+               struct metadata_context *context)
+{
+       unsigned char *uuid;
+
+       BT_LOGD("Serializing clock class's metadata: clock-class-addr=%p, "
+               "name=\"%s\", metadata-context-addr=%p", clock_class,
+               bt_ctf_clock_class_get_name(clock_class),
+               context);
+
+       if (!clock_class || !context) {
+               BT_LOGW("Invalid parameter: clock class or metadata context is NULL: "
+                       "clock-class-addr=%p, name=\"%s\", metadata-context-addr=%p",
+                       clock_class,
+                       bt_ctf_clock_class_get_name(clock_class),
+                       context);
+               return;
+       }
+
+       uuid = clock_class->uuid;
+       g_string_append(context->string, "clock {\n");
+       g_string_append_printf(context->string, "\tname = %s;\n",
+               clock_class->name->str);
+
+       if (clock_class->uuid_set) {
+               g_string_append_printf(context->string,
+                       "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
+                       uuid[0], uuid[1], uuid[2], uuid[3],
+                       uuid[4], uuid[5], uuid[6], uuid[7],
+                       uuid[8], uuid[9], uuid[10], uuid[11],
+                       uuid[12], uuid[13], uuid[14], uuid[15]);
+       }
+
+       if (clock_class->description) {
+               g_string_append_printf(context->string, "\tdescription = \"%s\";\n",
+                       clock_class->description->str);
+       }
+
+       g_string_append_printf(context->string, "\tfreq = %" PRIu64 ";\n",
+               clock_class->frequency);
+       g_string_append_printf(context->string, "\tprecision = %" PRIu64 ";\n",
+               clock_class->precision);
+       g_string_append_printf(context->string, "\toffset_s = %" PRIu64 ";\n",
+               clock_class->offset_s);
+       g_string_append_printf(context->string, "\toffset = %" PRIu64 ";\n",
+               clock_class->offset);
+       g_string_append_printf(context->string, "\tabsolute = %s;\n",
+               clock_class->absolute ? "true" : "false");
+       g_string_append(context->string, "};\n\n");
+}
diff --git a/src/ctf-writer/clock.h b/src/ctf-writer/clock.h
new file mode 100644 (file)
index 0000000..f510d73
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H
+
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/ctf-writer/clock.h>
+#include "common/babeltrace.h"
+#include <glib.h>
+#include "compat/uuid.h"
+
+#include "clock-class.h"
+#include "object.h"
+#include "trace.h"
+
+struct bt_ctf_clock {
+       struct bt_ctf_object base;
+       struct bt_ctf_clock_class *clock_class;
+       uint64_t value;         /* Current clock value */
+};
+
+struct metadata_context;
+
+BT_HIDDEN
+int bt_ctf_clock_get_value(struct bt_ctf_clock *clock, uint64_t *value);
+
+BT_HIDDEN
+void bt_ctf_clock_class_serialize(struct bt_ctf_clock_class *clock_class,
+               struct metadata_context *context);
+
+#endif /* BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H */
diff --git a/src/ctf-writer/event-class.c b/src/ctf-writer/event-class.c
new file mode 100644 (file)
index 0000000..419707e
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-EVENT-CLASS"
+#include "logging.h"
+
+#include <glib.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/types.h>
+
+#include "common/assert.h"
+#include "compat/compiler.h"
+#include "compat/endian.h"
+
+#include "assert-pre.h"
+#include "attributes.h"
+#include "event-class.h"
+#include "event.h"
+#include "fields.h"
+#include "field-types.h"
+#include "stream-class.h"
+#include "trace.h"
+#include "utils.h"
+#include "validation.h"
+#include "values.h"
+#include "writer.h"
+
+BT_HIDDEN
+void bt_ctf_event_class_common_finalize(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_event_class_common *event_class;
+
+       event_class = container_of(obj, struct bt_ctf_event_class_common, base);
+       BT_LOGD("Finalizing common event class: addr=%p, name=\"%s\", id=%" PRId64,
+               event_class, bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+
+       if (event_class->name) {
+               g_string_free(event_class->name, TRUE);
+       }
+
+       if (event_class->emf_uri) {
+               g_string_free(event_class->emf_uri, TRUE);
+       }
+
+       BT_LOGD_STR("Putting context field type.");
+       bt_ctf_object_put_ref(event_class->context_field_type);
+       BT_LOGD_STR("Putting payload field type.");
+       bt_ctf_object_put_ref(event_class->payload_field_type);
+}
+
+BT_HIDDEN
+int bt_ctf_event_class_common_initialize(struct bt_ctf_event_class_common *event_class,
+               const char *name, bt_ctf_object_release_func release_func,
+               bt_ctf_field_type_structure_create_func ft_struct_create_func)
+{
+       int ret = 0;
+
+       BT_LOGD("Initializing common event class object: name=\"%s\"",
+               name);
+       bt_ctf_object_init_shared_with_parent(&event_class->base, release_func);
+       event_class->payload_field_type = ft_struct_create_func();
+       if (!event_class->payload_field_type) {
+               BT_LOGE_STR("Cannot create event class's initial payload field type object.");
+               goto error;
+       }
+
+       event_class->id = -1;
+       event_class->name = g_string_new(name);
+       if (!event_class->name) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       event_class->emf_uri = g_string_new(NULL);
+       if (!event_class->emf_uri) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       event_class->log_level = BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED;
+       BT_LOGD("Initialized common event class object: addr=%p, name=\"%s\"",
+               event_class, bt_ctf_event_class_common_get_name(event_class));
+       return ret;
+
+error:
+       ret = -1;
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_event_class_common_freeze(struct bt_ctf_event_class_common *event_class)
+{
+       BT_ASSERT(event_class);
+
+       if (event_class->frozen) {
+               return;
+       }
+
+       BT_LOGD("Freezing event class: addr=%p, name=\"%s\", id=%" PRId64,
+               event_class, bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+       event_class->frozen = 1;
+       BT_LOGD_STR("Freezing event class's context field type.");
+       bt_ctf_field_type_common_freeze(event_class->context_field_type);
+       BT_LOGD_STR("Freezing event class's payload field type.");
+       bt_ctf_field_type_common_freeze(event_class->payload_field_type);
+}
+
+BT_HIDDEN
+int bt_ctf_event_class_common_validate_single_clock_class(
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_clock_class **expected_clock_class)
+{
+       int ret = 0;
+
+       BT_ASSERT(event_class);
+       BT_ASSERT(expected_clock_class);
+       ret = bt_ctf_field_type_common_validate_single_clock_class(
+               event_class->context_field_type,
+               expected_clock_class);
+       if (ret) {
+               BT_LOGW("Event class's context field type "
+                       "is not recursively mapped to the "
+                       "expected clock class: "
+                       "event-class-addr=%p, "
+                       "event-class-name=\"%s\", "
+                       "event-class-id=%" PRId64 ", "
+                       "ft-addr=%p",
+                       event_class,
+                       bt_ctf_event_class_common_get_name(event_class),
+                       event_class->id,
+                       event_class->context_field_type);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_validate_single_clock_class(
+               event_class->payload_field_type,
+               expected_clock_class);
+       if (ret) {
+               BT_LOGW("Event class's payload field type "
+                       "is not recursively mapped to the "
+                       "expected clock class: "
+                       "event-class-addr=%p, "
+                       "event-class-name=\"%s\", "
+                       "event-class-id=%" PRId64 ", "
+                       "ft-addr=%p",
+                       event_class,
+                       bt_ctf_event_class_common_get_name(event_class),
+                       event_class->id,
+                       event_class->payload_field_type);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+void bt_ctf_event_class_destroy(struct bt_ctf_object *obj)
+{
+       bt_ctf_event_class_common_finalize(obj);
+       g_free(obj);
+}
+
+struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name)
+{
+       struct bt_ctf_event_class *ctf_event_class = NULL;
+       int ret;
+
+       if (!name) {
+               BT_LOGW_STR("Invalid parameter: name is NULL.");
+               goto error;
+       }
+
+       BT_LOGD("Creating event class object: name=\"%s\"",
+               name);
+       ctf_event_class = g_new0(struct bt_ctf_event_class, 1);
+       if (!ctf_event_class) {
+               BT_LOGE_STR("Failed to allocate one event class.");
+               goto error;
+       }
+
+       ret = bt_ctf_event_class_common_initialize(BT_CTF_TO_COMMON(ctf_event_class),
+               name, bt_ctf_event_class_destroy,
+               (bt_ctf_field_type_structure_create_func)
+                       bt_ctf_field_type_structure_create);
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       bt_ctf_object_put_ref(ctf_event_class);
+
+end:
+       return ctf_event_class;
+}
+
+const char *bt_ctf_event_class_get_name(struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_event_class_common_get_name(BT_CTF_TO_COMMON(event_class));
+}
+
+int64_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_event_class_common_get_id(BT_CTF_TO_COMMON(event_class));
+}
+
+int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class,
+               uint64_t id)
+{
+       return bt_ctf_event_class_common_set_id(BT_CTF_TO_COMMON(event_class), id);
+}
+
+enum bt_ctf_event_class_log_level bt_ctf_event_class_get_log_level(
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_event_class_common_get_log_level(BT_CTF_TO_COMMON(event_class));
+}
+
+int bt_ctf_event_class_set_log_level(struct bt_ctf_event_class *event_class,
+               enum bt_ctf_event_class_log_level log_level)
+{
+       return bt_ctf_event_class_common_set_log_level(BT_CTF_TO_COMMON(event_class),
+               log_level);
+}
+
+const char *bt_ctf_event_class_get_emf_uri(
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_event_class_common_get_emf_uri(BT_CTF_TO_COMMON(event_class));
+}
+
+int bt_ctf_event_class_set_emf_uri(struct bt_ctf_event_class *event_class,
+               const char *emf_uri)
+{
+       return bt_ctf_event_class_common_set_emf_uri(BT_CTF_TO_COMMON(event_class),
+               emf_uri);
+}
+
+struct bt_ctf_stream_class *bt_ctf_event_class_get_stream_class(
+               struct bt_ctf_event_class *event_class)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_stream_class(
+               BT_CTF_TO_COMMON(event_class)));
+}
+
+struct bt_ctf_field_type *bt_ctf_event_class_get_payload_field_type(
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_payload_field_type(
+               BT_CTF_TO_COMMON(event_class)));
+}
+
+int bt_ctf_event_class_set_payload_field_type(
+               struct bt_ctf_event_class *event_class,
+               struct bt_ctf_field_type *field_type)
+{
+       return bt_ctf_event_class_common_set_payload_field_type(
+               BT_CTF_TO_COMMON(event_class), (void *) field_type);
+}
+
+struct bt_ctf_field_type *bt_ctf_event_class_get_context_field_type(
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_class_common_borrow_context_field_type(
+               BT_CTF_TO_COMMON(event_class)));
+}
+
+int bt_ctf_event_class_set_context_field_type(
+               struct bt_ctf_event_class *event_class,
+               struct bt_ctf_field_type *field_type)
+{
+       return bt_ctf_event_class_common_set_context_field_type(
+               BT_CTF_TO_COMMON(event_class), (void *) field_type);
+}
+
+int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class,
+               struct bt_ctf_field_type *type,
+               const char *name)
+{
+       int ret = 0;
+
+       if (!event_class || !type) {
+               BT_LOGW("Invalid parameter: event class or field type is NULL: "
+                       "event-class-addr=%p, field-type-addr=%p",
+                       event_class, type);
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_identifier_is_valid(name)) {
+               BT_LOGW("Invalid parameter: event class's payload field type's field name is not a valid CTF identifier: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", field-name=\"%s\"",
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class),
+                       name);
+               ret = -1;
+               goto end;
+       }
+
+       if (event_class->common.frozen) {
+               BT_LOGW("Invalid parameter: event class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (!event_class->common.payload_field_type) {
+               BT_LOGW("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));
+               ret = -1;
+               goto end;
+       }
+
+       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
+               event_class->common.payload_field_type) ==
+               BT_CTF_FIELD_TYPE_ID_STRUCT);
+       ret = bt_ctf_field_type_structure_add_field(
+               (void *) event_class->common.payload_field_type,
+               (void *) type, name);
+       BT_LOGV("Added field to event class's payload field type: "
+               "event-class-addr=%p, event-class-name=\"%s\", "
+               "event-class-id=%" PRId64 ", field-name=\"%s\", ft-addr=%p",
+               event_class, bt_ctf_event_class_get_name(event_class),
+               bt_ctf_event_class_get_id(event_class), name, type);
+end:
+       return ret;
+}
+
+int64_t bt_ctf_event_class_get_payload_type_field_count(
+               struct bt_ctf_event_class *event_class)
+{
+       int64_t ret;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = (int64_t) -1;
+               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));
+               ret = (int64_t) -1;
+               goto end;
+       }
+
+       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
+               event_class->common.payload_field_type) ==
+                       BT_CTF_FIELD_TYPE_ID_STRUCT);
+       ret = bt_ctf_field_type_common_structure_get_field_count(
+               event_class->common.payload_field_type);
+end:
+       return ret;
+}
+
+int bt_ctf_event_class_get_payload_type_field_by_index(
+               struct bt_ctf_event_class *event_class,
+               const char **field_name, struct bt_ctf_field_type **field_type,
+               uint64_t index)
+{
+       int ret;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!event_class->common.payload_field_type) {
+               BT_LOGV("Event class has no payload field type: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", index=%" PRIu64,
+                       event_class, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class), index);
+               ret = -1;
+               goto end;
+       }
+
+       BT_ASSERT(bt_ctf_field_type_common_get_type_id(
+               event_class->common.payload_field_type) ==
+                       BT_CTF_FIELD_TYPE_ID_STRUCT);
+       ret = bt_ctf_field_type_structure_get_field_by_index(
+               (void *) event_class->common.payload_field_type,
+               field_name, (void *) field_type, index);
+
+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_ctf_event_class_serialize(struct bt_ctf_event_class *event_class,
+               struct metadata_context *context)
+{
+       int ret = 0;
+       struct bt_ctf_value *attr_value = NULL;
+
+       BT_ASSERT(event_class);
+       BT_ASSERT(context);
+       BT_LOGD("Serializing event class's metadata: "
+               "event-class-addr=%p, event-class-name=\"%s\", "
+               "event-class-id=%" PRId64 ", metadata-context-addr=%p",
+               event_class, bt_ctf_event_class_get_name(event_class),
+               bt_ctf_event_class_get_id(event_class), context);
+       context->current_indentation_level = 1;
+       g_string_assign(context->field_name, "");
+       g_string_append(context->string, "event {\n");
+
+       /* Serialize attributes */
+       g_string_append_printf(context->string, "\tname = \"%s\";\n",
+               event_class->common.name->str);
+       BT_ASSERT(event_class->common.id >= 0);
+       g_string_append_printf(context->string, "\tid = %" PRId64 ";\n",
+               event_class->common.id);
+       g_string_append_printf(context->string, "\tstream_id = %" PRId64 ";\n",
+               bt_ctf_stream_class_common_get_id(
+                       bt_ctf_event_class_common_borrow_stream_class(
+                               BT_CTF_TO_COMMON(event_class))));
+
+       if (event_class->common.log_level !=
+                       BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED) {
+               g_string_append_printf(context->string, "\tloglevel = %d;\n",
+                       (int) event_class->common.log_level);
+       }
+
+       if (event_class->common.emf_uri->len > 0) {
+               g_string_append_printf(context->string, "\tmodel.emf.uri = \"%s\";\n",
+                       event_class->common.emf_uri->str);
+       }
+
+       /* Serialize context field type */
+       if (event_class->common.context_field_type) {
+               g_string_append(context->string, "\tcontext := ");
+               BT_LOGD_STR("Serializing event class's context field type metadata.");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) event_class->common.context_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event class's context field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";\n");
+       }
+
+       /* Serialize payload field type */
+       if (event_class->common.payload_field_type) {
+               g_string_append(context->string, "\tfields := ");
+               BT_LOGD_STR("Serializing event class's payload field type metadata.");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) event_class->common.payload_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event class's payload field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";\n");
+       }
+
+       g_string_append(context->string, "};\n\n");
+
+end:
+       context->current_indentation_level = 0;
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(attr_value);
+       return ret;
+}
+
+struct bt_ctf_field_type *bt_ctf_event_class_get_field_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(event_class->common.payload_field_type->id ==
+               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 = bt_ctf_object_get_ref(
+               bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+                       event_class->common.payload_field_type, name));
+
+end:
+       return field_type;
+}
diff --git a/src/ctf-writer/event-class.h b/src/ctf-writer/event-class.h
new file mode 100644 (file)
index 0000000..c5ebb85
--- /dev/null
@@ -0,0 +1,396 @@
+#ifndef BABELTRACE_CTF_WRITER_EVENT_CLASS_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_EVENT_CLASS_INTERNAL_H
+
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/assert.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/fields.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/stream.h>
+#include <glib.h>
+
+#include "object.h"
+#include "trace.h"
+#include "values.h"
+
+struct bt_ctf_event_class_common {
+       struct bt_ctf_object base;
+       struct bt_ctf_field_type_common *context_field_type;
+       struct bt_ctf_field_type_common *payload_field_type;
+       int frozen;
+
+       /*
+        * This flag indicates if the event class is valid. A valid
+        * event class is _always_ frozen. However, an event class
+        * may be frozen, but not valid yet. This is okay, as long as
+        * no events are created out of this event class.
+        */
+       int valid;
+
+       /* Attributes */
+       GString *name;
+       int64_t id;
+       int log_level;
+       GString *emf_uri;
+};
+
+BT_HIDDEN
+void bt_ctf_event_class_common_freeze(struct bt_ctf_event_class_common *event_class);
+
+BT_HIDDEN
+void bt_ctf_event_class_common_set_native_byte_order(
+               struct bt_ctf_event_class_common *event_class, int byte_order);
+
+static inline
+struct bt_ctf_stream_class_common *bt_ctf_event_class_common_borrow_stream_class(
+               struct bt_ctf_event_class_common *event_class)
+{
+       BT_ASSERT(event_class);
+       return (void *) bt_ctf_object_borrow_parent(&event_class->base);
+}
+
+typedef struct bt_ctf_field_type_common *(*bt_ctf_field_type_structure_create_func)();
+
+BT_HIDDEN
+int bt_ctf_event_class_common_initialize(struct bt_ctf_event_class_common *event_class,
+               const char *name, bt_ctf_object_release_func release_func,
+               bt_ctf_field_type_structure_create_func ft_struct_create_func);
+
+BT_HIDDEN
+void bt_ctf_event_class_common_finalize(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+int bt_ctf_event_class_common_validate_single_clock_class(
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_clock_class **expected_clock_class);
+
+static inline
+const char *bt_ctf_event_class_common_get_name(
+               struct bt_ctf_event_class_common *event_class)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT(event_class->name);
+       return event_class->name->str;
+}
+
+static inline
+int64_t bt_ctf_event_class_common_get_id(
+               struct bt_ctf_event_class_common *event_class)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->id;
+}
+
+static inline
+int bt_ctf_event_class_common_set_id(
+               struct bt_ctf_event_class_common *event_class, uint64_t id_param)
+{
+       int ret = 0;
+       int64_t id = (int64_t) id_param;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (event_class->frozen) {
+               BT_LOGW("Invalid parameter: event class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class,
+                       bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (id < 0) {
+               BT_LOGW("Invalid parameter: invalid event class's ID: "
+                       "addr=%p, name=\"%s\", id=%" PRIu64,
+                       event_class,
+                       bt_ctf_event_class_common_get_name(event_class),
+                       id_param);
+               ret = -1;
+               goto end;
+       }
+
+       event_class->id = id;
+       BT_LOGV("Set event class's ID: "
+               "addr=%p, name=\"%s\", id=%" PRId64,
+               event_class, bt_ctf_event_class_common_get_name(event_class), id);
+
+end:
+       return ret;
+}
+
+static inline
+int bt_ctf_event_class_common_get_log_level(
+               struct bt_ctf_event_class_common *event_class)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->log_level;
+}
+
+static inline
+int bt_ctf_event_class_common_set_log_level(
+               struct bt_ctf_event_class_common *event_class, int log_level)
+{
+       int ret = 0;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (event_class->frozen) {
+               BT_LOGW("Invalid parameter: event class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class,
+                       bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class));
+               ret = -1;
+               goto end;
+       }
+
+       switch (log_level) {
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_ALERT:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_CRITICAL:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_ERROR:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_WARNING:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_NOTICE:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_INFO:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG:
+               break;
+       default:
+               BT_LOGW("Invalid parameter: unknown event class log level: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", log-level=%d",
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class), log_level);
+               ret = -1;
+               goto end;
+       }
+
+       event_class->log_level = log_level;
+       BT_LOGV("Set event class's log level: "
+               "addr=%p, name=\"%s\", id=%" PRId64 ", log-level=%s",
+               event_class, bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class),
+               bt_ctf_event_class_log_level_string(log_level));
+
+end:
+       return ret;
+}
+
+static inline
+const char *bt_ctf_event_class_common_get_emf_uri(
+               struct bt_ctf_event_class_common *event_class)
+{
+       const char *emf_uri = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+
+       if (event_class->emf_uri->len > 0) {
+               emf_uri = event_class->emf_uri->str;
+       }
+
+       return emf_uri;
+}
+
+static inline
+int bt_ctf_event_class_common_set_emf_uri(
+               struct bt_ctf_event_class_common *event_class,
+               const char *emf_uri)
+{
+       int ret = 0;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (emf_uri && strlen(emf_uri) == 0) {
+               BT_LOGW_STR("Invalid parameter: EMF URI is empty.");
+               ret = -1;
+               goto end;
+       }
+
+       if (event_class->frozen) {
+               BT_LOGW("Invalid parameter: event class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (emf_uri) {
+               g_string_assign(event_class->emf_uri, emf_uri);
+               BT_LOGV("Set event class's EMF URI: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", emf-uri=\"%s\"",
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class), emf_uri);
+       } else {
+               g_string_assign(event_class->emf_uri, "");
+               BT_LOGV("Reset event class's EMF URI: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class));
+       }
+
+end:
+       return ret;
+}
+
+static inline
+struct bt_ctf_field_type_common *bt_ctf_event_class_common_borrow_context_field_type(
+               struct bt_ctf_event_class_common *event_class)
+{
+       struct bt_ctf_field_type_common *context_ft = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+
+       if (!event_class->context_field_type) {
+               BT_LOGV("Event class has no context field type: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class));
+               goto end;
+       }
+
+       context_ft = event_class->context_field_type;
+
+end:
+       return context_ft;
+}
+
+static inline
+int bt_ctf_event_class_common_set_context_field_type(
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_field_type_common *context_ft)
+{
+       int ret = 0;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (event_class->frozen) {
+               BT_LOGW("Invalid parameter: event class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (context_ft && bt_ctf_field_type_common_get_type_id(context_ft) !=
+                       BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               BT_LOGW("Invalid parameter: event class's context field type must be a structure: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
+                       "context-ft-id=%s",
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class),
+                       bt_ctf_field_type_id_string(
+                               bt_ctf_field_type_common_get_type_id(context_ft)));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(event_class->context_field_type);
+       event_class->context_field_type = context_ft;
+       bt_ctf_object_get_ref(event_class->context_field_type);
+       BT_LOGV("Set event class's context field type: "
+               "event-class-addr=%p, event-class-name=\"%s\", "
+               "event-class-id=%" PRId64 ", context-ft-addr=%p",
+               event_class, bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class), context_ft);
+
+end:
+       return ret;
+}
+
+static inline
+struct bt_ctf_field_type_common *bt_ctf_event_class_common_borrow_payload_field_type(
+               struct bt_ctf_event_class_common *event_class)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->payload_field_type;
+}
+
+static inline
+int bt_ctf_event_class_common_set_payload_field_type(
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_field_type_common *payload_ft)
+{
+       int ret = 0;
+
+       if (!event_class) {
+               BT_LOGW_STR("Invalid parameter: event class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (payload_ft && bt_ctf_field_type_common_get_type_id(payload_ft) !=
+                       BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               BT_LOGW("Invalid parameter: event class's payload field type must be a structure: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
+                       "payload-ft-addr=%p, payload-ft-id=%s",
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class), payload_ft,
+                       bt_ctf_field_type_id_string(
+                               bt_ctf_field_type_common_get_type_id(payload_ft)));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(event_class->payload_field_type);
+       event_class->payload_field_type = payload_ft;
+       bt_ctf_object_get_ref(event_class->payload_field_type);
+       BT_LOGV("Set event class's payload field type: "
+               "event-class-addr=%p, event-class-name=\"%s\", "
+               "event-class-id=%" PRId64 ", payload-ft-addr=%p",
+               event_class, bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class), payload_ft);
+end:
+       return ret;
+}
+
+#endif /* BABELTRACE_CTF_WRITER_EVENT_CLASS_INTERNAL_H */
diff --git a/src/ctf-writer/event.c b/src/ctf-writer/event.c
new file mode 100644 (file)
index 0000000..e1bc85e
--- /dev/null
@@ -0,0 +1,903 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-EVENT"
+#include "logging.h"
+
+#include <inttypes.h>
+
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/fields.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/trace.h>
+#include <babeltrace2/ctf-writer/utils.h>
+
+#include "common/assert.h"
+#include "compat/compiler.h"
+
+#include "assert-pre.h"
+#include "attributes.h"
+#include "clock-class.h"
+#include "clock.h"
+#include "event-class.h"
+#include "event.h"
+#include "fields.h"
+#include "field-types.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "trace.h"
+#include "validation.h"
+
+static
+int bt_ctf_event_common_validate_types_for_create(
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_validation_output *validation_output,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
+{
+       int ret;
+       enum bt_ctf_validation_flag validation_flags =
+               BT_CTF_VALIDATION_FLAG_STREAM |
+               BT_CTF_VALIDATION_FLAG_EVENT;
+       struct bt_ctf_trace_common *trace = NULL;
+       struct bt_ctf_stream_class_common *stream_class = NULL;
+       struct bt_ctf_field_type_common *packet_header_type = NULL;
+       struct bt_ctf_field_type_common *packet_context_type = NULL;
+       struct bt_ctf_field_type_common *event_header_type = NULL;
+       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
+       struct bt_ctf_field_type_common *event_context_type = NULL;
+       struct bt_ctf_field_type_common *event_payload_type = NULL;
+       int trace_valid = 0;
+       struct bt_ctf_private_value *environment = NULL;
+
+       stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
+       BT_ASSERT(stream_class);
+       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
+       if (trace) {
+               BT_LOGD_STR("Event class is part of a trace.");
+               packet_header_type =
+                       bt_ctf_trace_common_borrow_packet_header_field_type(trace);
+               trace_valid = trace->valid;
+               BT_ASSERT(trace_valid);
+               environment = trace->environment;
+       }
+
+       packet_context_type =
+               bt_ctf_stream_class_common_borrow_packet_context_field_type(
+                       stream_class);
+       event_header_type =
+               bt_ctf_stream_class_common_borrow_event_header_field_type(
+                       stream_class);
+       stream_event_ctx_type =
+               bt_ctf_stream_class_common_borrow_event_context_field_type(
+                       stream_class);
+       event_context_type =
+               bt_ctf_event_class_common_borrow_context_field_type(event_class);
+       event_payload_type =
+               bt_ctf_event_class_common_borrow_payload_field_type(event_class);
+       ret = bt_ctf_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, copy_field_type_func);
+       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;
+       }
+
+       goto end;
+
+error:
+       bt_ctf_validation_output_put_types(validation_output);
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_event_common_create_fields(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_validation_output *validation_output,
+               create_field_func create_field_func,
+               release_field_func release_field_func,
+               create_header_field_func create_header_field_func,
+               release_header_field_func release_header_field_func,
+               struct bt_ctf_field_wrapper **header_field,
+               struct bt_ctf_field_common **stream_event_context_field,
+               struct bt_ctf_field_common **context_field,
+               struct bt_ctf_field_common **payload_field)
+{
+       int ret = 0;
+
+       if (validation_output->event_header_type) {
+               BT_LOGD("Creating initial event header field: ft-addr=%p",
+                       validation_output->event_header_type);
+               *header_field =
+                       create_header_field_func(stream_class,
+                               validation_output->event_header_type);
+               if (!*header_field) {
+                       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_field = create_field_func(
+                       validation_output->stream_event_ctx_type);
+               if (!*stream_event_context_field) {
+                       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);
+               *context_field = create_field_func(
+                       validation_output->event_context_type);
+               if (!*context_field) {
+                       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);
+               *payload_field = create_field_func(
+                       validation_output->event_payload_type);
+               if (!*payload_field) {
+                       BT_LOGE_STR("Cannot create initial event payload field object.");
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       if (*header_field) {
+               release_header_field_func(*header_field, stream_class);
+       }
+
+       if (*stream_event_context_field) {
+               release_field_func(*stream_event_context_field);
+       }
+
+       if (*context_field) {
+               release_field_func(*context_field);
+       }
+
+       if (*payload_field) {
+               release_field_func(*payload_field);
+       }
+
+       ret = -1;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int _bt_ctf_event_common_validate(struct bt_ctf_event_common *event)
+{
+       int ret = 0;
+       struct bt_ctf_stream_class_common *stream_class;
+
+       BT_ASSERT(event);
+       if (event->header_field) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       event->header_field->field);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid event's header field: "
+                               "event-addr=%p, field-addr=%p",
+                               event, event->header_field->field);
+                       goto end;
+               }
+       }
+
+       stream_class = bt_ctf_event_class_common_borrow_stream_class(event->class);
+
+       /*
+        * We should not have been able to create the event without associating
+        * the event class to a stream class.
+        */
+       BT_ASSERT(stream_class);
+
+       if (stream_class->event_context_field_type) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       event->stream_event_context_field);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid event's stream event context field: "
+                               "event-addr=%p, field-addr=%p",
+                               event, event->stream_event_context_field);
+                       goto end;
+               }
+       }
+
+       if (event->class->context_field_type) {
+               ret = bt_ctf_field_common_validate_recursive(event->context_field);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid event's payload field: "
+                               "event-addr=%p, field-addr=%p",
+                               event, event->context_field);
+                       goto end;
+               }
+       }
+
+       ret = bt_ctf_field_common_validate_recursive(event->payload_field);
+       if (ret) {
+               BT_CTF_ASSERT_PRE_MSG("Invalid event's payload field: "
+                       "event-addr=%p, field-addr=%p",
+                       event, event->payload_field);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event,
+               bool is_frozen)
+{
+       BT_ASSERT(event);
+       BT_LOGD("Freezing event: addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               event, bt_ctf_event_class_common_get_name(event->class),
+               bt_ctf_event_class_common_get_id(event->class));
+
+       if (event->header_field) {
+               BT_LOGD_STR("Freezing event's header field.");
+               bt_ctf_field_common_set_is_frozen_recursive(
+                       event->header_field->field, is_frozen);
+       }
+
+       if (event->stream_event_context_field) {
+               BT_LOGD_STR("Freezing event's stream event context field.");
+               bt_ctf_field_common_set_is_frozen_recursive(
+                       event->stream_event_context_field, is_frozen);
+       }
+
+       if (event->context_field) {
+               BT_LOGD_STR("Freezing event's context field.");
+               bt_ctf_field_common_set_is_frozen_recursive(event->context_field,
+                       is_frozen);
+       }
+
+       if (event->payload_field) {
+               BT_LOGD_STR("Freezing event's payload field.");
+               bt_ctf_field_common_set_is_frozen_recursive(event->payload_field,
+                       is_frozen);
+       }
+
+       event->frozen = is_frozen;
+}
+
+BT_HIDDEN
+int bt_ctf_event_common_initialize(struct bt_ctf_event_common *event,
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_clock_class *init_expected_clock_class,
+               bool is_shared_with_parent, bt_ctf_object_release_func release_func,
+               bt_ctf_validation_flag_copy_field_type_func field_type_copy_func,
+               bool must_be_in_trace,
+               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
+                       struct bt_ctf_field_type_common *packet_context_field_type,
+                       struct bt_ctf_field_type_common *event_header_field_type),
+               create_field_func create_field_func,
+               release_field_func release_field_func,
+               create_header_field_func create_header_field_func,
+               release_header_field_func release_header_field_func)
+{
+       int ret;
+       struct bt_ctf_trace_common *trace = NULL;
+       struct bt_ctf_stream_class_common *stream_class = NULL;
+       struct bt_ctf_field_wrapper *event_header = NULL;
+       struct bt_ctf_field_common *stream_event_context = NULL;
+       struct bt_ctf_field_common *event_context = NULL;
+       struct bt_ctf_field_common *event_payload = NULL;
+       struct bt_ctf_validation_output validation_output = { 0 };
+       struct bt_ctf_clock_class *expected_clock_class =
+               init_expected_clock_class ? bt_ctf_object_get_ref(init_expected_clock_class) :
+               NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_LOGD("Initializing common event object: event-class-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               event_class, bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+
+       stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
+       BT_CTF_ASSERT_PRE(stream_class,
+               "Event class is not part of a stream class: event-class-addr=%p",
+               event_class);
+
+       /* The event class was frozen when added to its stream class */
+       BT_ASSERT(event_class->frozen);
+       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
+
+       if (must_be_in_trace) {
+               BT_CTF_ASSERT_PRE(trace,
+                       "Event class's stream class is not part of a trace: "
+                       "ec-addr=%p, sc-addr=%p", event_class, stream_class);
+       }
+
+       /*
+        * This must be called before anything that can fail because on
+        * failure, the caller releases the reference to `event` to
+        * destroy it.
+        */
+       if (is_shared_with_parent) {
+               bt_ctf_object_init_shared_with_parent(&event->base, release_func);
+       } else {
+               bt_ctf_object_init_unique(&event->base);
+       }
+
+       if (!stream_class->frozen) {
+               /*
+                * Because this function freezes the stream class,
+                * validate that this stream class contains at most a
+                * single clock class so that we set its expected clock
+                * class for future checks.
+                */
+               ret = bt_ctf_stream_class_common_validate_single_clock_class(
+                       stream_class, &expected_clock_class);
+               if (ret) {
+                       BT_LOGW("Event class's stream class or one of its event "
+                               "classes contains a field type which is not "
+                               "recursively mapped to the expected "
+                               "clock class: "
+                               "stream-class-addr=%p, "
+                               "stream-class-id=%" PRId64 ", "
+                               "stream-class-name=\"%s\", "
+                               "expected-clock-class-addr=%p, "
+                               "expected-clock-class-name=\"%s\"",
+                               stream_class,
+                               bt_ctf_stream_class_common_get_id(stream_class),
+                               bt_ctf_stream_class_common_get_name(stream_class),
+                               expected_clock_class,
+                               expected_clock_class ?
+                                       bt_ctf_clock_class_get_name(expected_clock_class) :
+                                       NULL);
+                       goto error;
+               }
+       }
+
+       /* Validate the trace, the stream class, and the event class */
+       ret = bt_ctf_event_common_validate_types_for_create(
+               event_class, &validation_output, field_type_copy_func);
+       if (ret) {
+               /* bt_ctf_event_common_validate_types_for_create() logs errors */
+               goto error;
+       }
+
+       if (map_clock_classes_func) {
+               /*
+                * Safe to automatically map selected fields to the
+                * stream's clock's class here because the stream class
+                * is about to be frozen.
+                */
+               if (map_clock_classes_func(stream_class,
+                               validation_output.packet_context_type,
+                               validation_output.event_header_type)) {
+                       BT_LOGW_STR("Cannot automatically map selected stream class's "
+                               "field types to stream class's clock's class.");
+                       goto error;
+               }
+       }
+
+       /*
+        * 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->class = bt_ctf_object_get_ref(event_class);
+
+       ret = bt_ctf_event_common_create_fields(stream_class,
+               &validation_output,
+               create_field_func, release_field_func,
+               create_header_field_func, release_header_field_func,
+               &event_header, &stream_event_context, &event_context,
+               &event_payload);
+       if (ret) {
+               /* bt_ctf_event_common_create_fields() logs errors */
+               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_ctf_validation_replace_types(trace, stream_class, event_class,
+               &validation_output,
+               BT_CTF_VALIDATION_FLAG_STREAM | BT_CTF_VALIDATION_FLAG_EVENT);
+       event->header_field = event_header;
+       event_header = NULL;
+       event->stream_event_context_field = stream_event_context;
+       stream_event_context = NULL;
+       event->context_field = event_context;
+       event_context = NULL;
+       event->payload_field = event_payload;
+       event_payload = NULL;
+
+       /*
+        * Put what was not moved in bt_ctf_validation_replace_types().
+        */
+       bt_ctf_validation_output_put_types(&validation_output);
+
+       /*
+        * Freeze the stream class since the event header must not be changed
+        * anymore.
+        */
+       bt_ctf_stream_class_common_freeze(stream_class);
+
+       /*
+        * It is safe to set the stream class's unique clock class
+        * now because the stream class is frozen.
+        */
+       if (expected_clock_class) {
+               BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_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_LOGD("Initialized event object: addr=%p, event-class-name=\"%s\", "
+               "event-class-id=%" PRId64,
+               event, bt_ctf_event_class_common_get_name(event->class),
+               bt_ctf_event_class_common_get_id(event->class));
+       goto end;
+
+error:
+       bt_ctf_validation_output_put_types(&validation_output);
+       bt_ctf_object_put_ref(expected_clock_class);
+
+       if (event_header) {
+               release_header_field_func(event_header, stream_class);
+       }
+
+       if (stream_event_context) {
+               release_field_func(stream_event_context);
+       }
+
+       if (event_context) {
+               release_field_func(event_context);
+       }
+
+       if (event_payload) {
+               release_field_func(event_payload);
+       }
+
+       ret = -1;
+
+end:
+       return ret;
+}
+
+int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type)
+{
+       int ret = bt_ctf_stream_class_map_clock_class(
+               BT_CTF_FROM_COMMON(stream_class),
+               BT_CTF_FROM_COMMON(packet_context_type),
+               BT_CTF_FROM_COMMON(event_header_type));
+
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
+       }
+
+       return ret;
+}
+
+static
+void destroy_event_header_field(struct bt_ctf_field_wrapper *field_wrapper)
+{
+       BT_ASSERT(field_wrapper);
+       bt_ctf_object_put_ref(field_wrapper->field);
+       bt_ctf_field_wrapper_destroy(field_wrapper);
+}
+
+static
+struct bt_ctf_field_wrapper *create_event_header_field(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_wrapper *field_wrapper = NULL;
+       struct bt_ctf_field *field = bt_ctf_field_create((void *) ft);
+
+       if (!field) {
+               goto error;
+       }
+
+       field_wrapper = bt_ctf_field_wrapper_new(NULL);
+       if (!field_wrapper) {
+               goto error;
+       }
+
+       field_wrapper->field = (void *) field;
+       field = NULL;
+       goto end;
+
+error:
+       bt_ctf_object_put_ref(field);
+
+       if (field_wrapper) {
+               destroy_event_header_field(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return field_wrapper;
+}
+
+static
+void release_event_header_field(struct bt_ctf_field_wrapper *field_wrapper,
+               struct bt_ctf_event_common *event_common)
+{
+       BT_ASSERT(field_wrapper);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_wrapper->field);
+       bt_ctf_field_wrapper_destroy(field_wrapper);
+}
+
+static
+void bt_ctf_event_destroy(struct bt_ctf_object *obj)
+{
+       bt_ctf_event_common_finalize(obj, (void *) bt_ctf_object_put_ref,
+               (void *) release_event_header_field);
+       g_free(obj);
+}
+
+struct bt_ctf_event *bt_ctf_event_create(struct bt_ctf_event_class *event_class)
+{
+       int ret;
+       struct bt_ctf_event *event = NULL;
+       struct bt_ctf_clock_class *expected_clock_class = NULL;
+
+       event = g_new0(struct bt_ctf_event, 1);
+       if (!event) {
+               BT_LOGE_STR("Failed to allocate one CTF writer event.");
+               goto error;
+       }
+
+       if (event_class) {
+               struct bt_ctf_stream_class *stream_class =
+                       BT_CTF_FROM_COMMON(bt_ctf_event_class_common_borrow_stream_class(
+                               BT_CTF_TO_COMMON(event_class)));
+
+               if (stream_class && stream_class->clock) {
+                       expected_clock_class = stream_class->clock->clock_class;
+               }
+       }
+
+       ret = bt_ctf_event_common_initialize(BT_CTF_TO_COMMON(event),
+               BT_CTF_TO_COMMON(event_class), expected_clock_class,
+               true, bt_ctf_event_destroy,
+               (bt_ctf_validation_flag_copy_field_type_func)
+                       bt_ctf_field_type_copy,
+               false, map_clock_classes_func,
+               (create_field_func) bt_ctf_field_create,
+               (release_field_func) bt_ctf_object_put_ref,
+               (create_header_field_func) create_event_header_field,
+               (release_header_field_func) destroy_event_header_field);
+       if (ret) {
+               /* bt_ctf_event_common_initialize() logs errors */
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(event);
+
+end:
+       return event;
+}
+
+struct bt_ctf_event_class *bt_ctf_event_get_class(struct bt_ctf_event *event)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event)));
+}
+
+BT_HIDDEN
+struct bt_ctf_stream *bt_ctf_event_borrow_stream(struct bt_ctf_event *event)
+{
+       BT_ASSERT(event);
+       return (struct bt_ctf_stream *)
+               bt_ctf_object_borrow_parent(&BT_CTF_TO_COMMON(event)->base);
+}
+
+struct bt_ctf_stream *bt_ctf_event_get_stream(struct bt_ctf_event *event)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       return bt_ctf_object_get_ref(bt_ctf_event_borrow_stream(event));
+}
+
+int bt_ctf_event_set_payload(struct bt_ctf_event *event, const char *name,
+               struct bt_ctf_field *field)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Payload field");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+       return bt_ctf_field_structure_set_field_by_name(
+               (void *) event->common.payload_field, name, field);
+}
+
+struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event,
+               const char *name)
+{
+       struct bt_ctf_field *field = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+
+       if (name) {
+               field = bt_ctf_field_structure_get_field_by_name(
+                       BT_CTF_FROM_COMMON(event->common.payload_field), name);
+       } else {
+               field = BT_CTF_FROM_COMMON(event->common.payload_field);
+               bt_ctf_object_get_ref(field);
+       }
+
+       return field;
+}
+
+struct bt_ctf_field *bt_ctf_event_get_payload_field(
+               struct bt_ctf_event *event)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_payload(BT_CTF_TO_COMMON(event)));
+}
+
+struct bt_ctf_field *bt_ctf_event_get_header(struct bt_ctf_event *event)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_header(BT_CTF_TO_COMMON(event)));
+}
+
+struct bt_ctf_field *bt_ctf_event_get_context(struct bt_ctf_event *event)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_context(BT_CTF_TO_COMMON(event)));
+}
+
+struct bt_ctf_field *bt_ctf_event_get_stream_event_context(
+               struct bt_ctf_event *event)
+{
+       return bt_ctf_object_get_ref(bt_ctf_event_common_borrow_stream_event_context(
+               BT_CTF_TO_COMMON(event)));
+}
+
+BT_HIDDEN
+int bt_ctf_event_serialize(struct bt_ctf_event *event,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int ret = 0;
+
+       BT_ASSERT(event);
+       BT_ASSERT(ctfser);
+
+       BT_LOGV_STR("Serializing event's context field.");
+       if (event->common.context_field) {
+               ret = bt_ctf_field_serialize_recursive(
+                       (void *) event->common.context_field, ctfser,
+                       native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event's context field: "
+                               "event-addr=%p, event-class-name=\"%s\", "
+                               "event-class-id=%" PRId64,
+                               event,
+                               bt_ctf_event_class_common_get_name(event->common.class),
+                               bt_ctf_event_class_common_get_id(event->common.class));
+                       goto end;
+               }
+       }
+
+       BT_LOGV_STR("Serializing event's payload field.");
+       if (event->common.payload_field) {
+               ret = bt_ctf_field_serialize_recursive(
+                       (void *) event->common.payload_field, ctfser,
+                       native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event's payload field: "
+                               "event-addr=%p, event-class-name=\"%s\", "
+                               "event-class-id=%" PRId64,
+                               event,
+                               bt_ctf_event_class_common_get_name(event->common.class),
+                               bt_ctf_event_class_common_get_id(event->common.class));
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void _bt_ctf_event_freeze(struct bt_ctf_event *event)
+{
+       _bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
+}
+
+int bt_ctf_event_set_header(struct bt_ctf_event *event,
+               struct bt_ctf_field *header)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+
+       /*
+        * Ensure the provided header's type matches the one registered to the
+        * stream class.
+        */
+       if (header) {
+               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+                       ((struct bt_ctf_field_common *) header)->type,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type) == 0,
+                       "Header field's type is different from the "
+                       "expected field type: event-addr=%p, ft-addr=%p, "
+                       "expected-ft-addr=%p",
+                       event, ((struct bt_ctf_field_common *) header)->type,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
+       } else {
+               BT_CTF_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type,
+                       "Setting no event header field, "
+                       "but event header field type is not NULL: "
+                       "event-addr=%p, header-ft-addr=%p",
+                       event,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_header_field_type);
+       }
+
+       bt_ctf_object_put_ref(event->common.header_field->field);
+       event->common.header_field->field = bt_ctf_object_get_ref(header);
+       BT_LOGV("Set event's header field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "header-field-addr=%p",
+               event, bt_ctf_event_class_common_get_name(event->common.class),
+               bt_ctf_event_class_common_get_id(event->common.class), header);
+       return 0;
+}
+
+int bt_ctf_event_common_set_payload(struct bt_ctf_event *event,
+               struct bt_ctf_field *payload)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+
+       if (payload) {
+               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+                       ((struct bt_ctf_field_common *) payload)->type,
+                       event->common.class->payload_field_type) == 0,
+                       "Payload field's type is different from the "
+                       "expected field type: event-addr=%p, ft-addr=%p, "
+                       "expected-ft-addr=%p",
+                       event,
+                       ((struct bt_ctf_field_common *) payload)->type,
+                       event->common.class->payload_field_type);
+       } else {
+               BT_CTF_ASSERT_PRE(!event->common.class->payload_field_type,
+                       "Setting no event payload field, "
+                       "but event payload field type is not NULL: "
+                       "event-addr=%p, payload-ft-addr=%p",
+                       event, event->common.class->payload_field_type);
+       }
+
+       bt_ctf_object_put_ref(event->common.payload_field);
+       event->common.payload_field = bt_ctf_object_get_ref(payload);
+       BT_LOGV("Set event's payload field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "payload-field-addr=%p",
+               event, bt_ctf_event_class_common_get_name(event->common.class),
+               bt_ctf_event_class_common_get_id(event->common.class), payload);
+       return 0;
+}
+
+int bt_ctf_event_set_context(struct bt_ctf_event *event,
+               struct bt_ctf_field *context)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+
+       if (context) {
+               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+                       ((struct bt_ctf_field_common *) context)->type,
+                       event->common.class->context_field_type) == 0,
+                       "Context field's type is different from the "
+                       "expected field type: event-addr=%p, ft-addr=%p, "
+                       "expected-ft-addr=%p",
+                       event, ((struct bt_ctf_field_common *) context)->type,
+                       event->common.class->context_field_type);
+       } else {
+               BT_CTF_ASSERT_PRE(!event->common.class->context_field_type,
+                       "Setting no event context field, "
+                       "but event context field type is not NULL: "
+                       "event-addr=%p, context-ft-addr=%p",
+                       event, event->common.class->context_field_type);
+       }
+
+       bt_ctf_object_put_ref(event->common.context_field);
+       event->common.context_field = bt_ctf_object_get_ref(context);
+       BT_LOGV("Set event's context field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "context-field-addr=%p",
+               event, bt_ctf_event_class_common_get_name(event->common.class),
+               bt_ctf_event_class_common_get_id(event->common.class), context);
+       return 0;
+}
+
+int bt_ctf_event_set_stream_event_context(struct bt_ctf_event *event,
+               struct bt_ctf_field *stream_event_context)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(BT_CTF_TO_COMMON(event), "Event");
+
+       if (stream_event_context) {
+               BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+                       ((struct bt_ctf_field_common *) stream_event_context)->type,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type) == 0,
+                       "Stream event context field's type is different from the "
+                       "expected field type: event-addr=%p, ft-addr=%p, "
+                       "expected-ft-addr=%p",
+                       event,
+                       ((struct bt_ctf_field_common *) stream_event_context)->type,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
+       } else {
+               BT_CTF_ASSERT_PRE(!bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type,
+                       "Setting no stream event context field, "
+                       "but stream event context field type is not NULL: "
+                       "event-addr=%p, context-ft-addr=%p",
+                       event,
+                       bt_ctf_event_class_common_borrow_stream_class(event->common.class)->event_context_field_type);
+       }
+
+       bt_ctf_object_put_ref(event->common.stream_event_context_field);
+       event->common.stream_event_context_field = bt_ctf_object_get_ref(stream_event_context);
+       BT_LOGV("Set event's stream event context field: event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "stream-event-context-field-addr=%p",
+               event, bt_ctf_event_class_common_get_name(event->common.class),
+               bt_ctf_event_class_common_get_id(event->common.class),
+               stream_event_context);
+       return 0;
+}
diff --git a/src/ctf-writer/event.h b/src/ctf-writer/event.h
new file mode 100644 (file)
index 0000000..1a8138a
--- /dev/null
@@ -0,0 +1,270 @@
+#ifndef BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H
+
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include "common/assert.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/fields.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/stream.h>
+#include "ctfser/ctfser.h"
+
+#include "assert-pre.h"
+#include "event-class.h"
+#include "event.h"
+#include "fields.h"
+#include "field-wrapper.h"
+#include "object.h"
+#include "stream.h"
+#include "validation.h"
+#include "values.h"
+
+struct bt_ctf_stream_class;
+struct bt_ctf_stream_pos;
+struct metadata_context;
+
+struct bt_ctf_event_common {
+       struct bt_ctf_object base;
+       struct bt_ctf_event_class_common *class;
+       struct bt_ctf_field_wrapper *header_field;
+       struct bt_ctf_field_common *stream_event_context_field;
+       struct bt_ctf_field_common *context_field;
+       struct bt_ctf_field_common *payload_field;
+       int frozen;
+};
+
+BT_HIDDEN
+int _bt_ctf_event_common_validate(struct bt_ctf_event_common *event);
+
+BT_HIDDEN
+void _bt_ctf_event_common_set_is_frozen(struct bt_ctf_event_common *event,
+               bool is_frozen);
+
+#ifdef BT_DEV_MODE
+# define bt_ctf_event_common_validate  _bt_ctf_event_common_validate
+# define bt_ctf_event_common_set_is_frozen     _bt_ctf_event_common_set_is_frozen
+#else
+# define bt_ctf_event_common_validate(_event)                  0
+# define bt_ctf_event_common_set_is_frozen(_event, _is_frozen)
+#endif
+
+#define BT_CTF_ASSERT_PRE_EVENT_COMMON_HOT(_event, _name)                      \
+       BT_CTF_ASSERT_PRE_HOT((_event), (_name), ": event-addr=%p", (_event))
+
+static inline
+struct bt_ctf_event_class_common *bt_ctf_event_common_borrow_class(
+               struct bt_ctf_event_common *event)
+{
+       BT_ASSERT(event);
+       return event->class;
+}
+
+typedef void *(*create_field_func)(void *);
+typedef void (*release_field_func)(void *);
+typedef void *(*create_header_field_func)(void *, void *);
+typedef void (*release_header_field_func)(void *, void *);
+
+BT_HIDDEN
+int bt_ctf_event_common_initialize(struct bt_ctf_event_common *event,
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_clock_class *init_expected_clock_class,
+               bool is_shared_with_parent, bt_ctf_object_release_func release_func,
+               bt_ctf_validation_flag_copy_field_type_func field_type_copy_func,
+               bool must_be_in_trace,
+               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
+                       struct bt_ctf_field_type_common *packet_context_field_type,
+                       struct bt_ctf_field_type_common *event_header_field_type),
+               create_field_func create_field_func,
+               release_field_func release_field_func,
+               create_header_field_func create_header_field_func,
+               release_header_field_func release_header_field_func);
+
+static inline
+struct bt_ctf_field_common *bt_ctf_event_common_borrow_payload(
+               struct bt_ctf_event_common *event)
+{
+       struct bt_ctf_field_common *payload = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+
+       if (!event->payload_field) {
+               BT_LOGV("Event has no current payload field: addr=%p, "
+                       "event-class-name=\"%s\", event-class-id=%" PRId64,
+                       event, bt_ctf_event_class_common_get_name(event->class),
+                       bt_ctf_event_class_common_get_id(event->class));
+               goto end;
+       }
+
+       payload = event->payload_field;
+
+end:
+       return payload;
+}
+
+static inline
+struct bt_ctf_field_common *bt_ctf_event_common_borrow_header(
+               struct bt_ctf_event_common *event)
+{
+       struct bt_ctf_field_common *header = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+
+       if (!event->header_field) {
+               BT_LOGV("Event has no current header field: addr=%p, "
+                       "event-class-name=\"%s\", event-class-id=%" PRId64,
+                       event, bt_ctf_event_class_common_get_name(event->class),
+                       bt_ctf_event_class_common_get_id(event->class));
+               goto end;
+       }
+
+       header = event->header_field->field;
+
+end:
+       return header;
+}
+
+static inline
+struct bt_ctf_field_common *bt_ctf_event_common_borrow_context(
+               struct bt_ctf_event_common *event)
+{
+       struct bt_ctf_field_common *context = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+
+       if (!event->context_field) {
+               BT_LOGV("Event has no current context field: addr=%p, "
+                       "event-class-name=\"%s\", event-class-id=%" PRId64,
+                       event, bt_ctf_event_class_common_get_name(event->class),
+                       bt_ctf_event_class_common_get_id(event->class));
+               goto end;
+       }
+
+       context = event->context_field;
+
+end:
+       return context;
+}
+
+static inline
+struct bt_ctf_field_common *bt_ctf_event_common_borrow_stream_event_context(
+               struct bt_ctf_event_common *event)
+{
+       struct bt_ctf_field_common *stream_event_context = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(event, "Event");
+
+       if (!event->stream_event_context_field) {
+               BT_LOGV("Event has no current stream event context field: addr=%p, "
+                       "event-class-name=\"%s\", event-class-id=%" PRId64,
+                       event, bt_ctf_event_class_common_get_name(event->class),
+                       bt_ctf_event_class_common_get_id(event->class));
+               goto end;
+       }
+
+       stream_event_context = event->stream_event_context_field;
+
+end:
+       return stream_event_context;
+}
+
+static inline
+void bt_ctf_event_common_finalize(struct bt_ctf_object *obj,
+               void (*field_release_func)(void *),
+               void (*header_field_release_func)(void *, struct bt_ctf_event_common *))
+{
+       struct bt_ctf_event_common *event = (void *) obj;
+
+       BT_LOGD("Destroying event: addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               event,
+               event->class ? bt_ctf_event_class_common_get_name(event->class) : NULL,
+               event->class ? bt_ctf_event_class_common_get_id(event->class) : INT64_C(-1));
+
+       if (event->header_field) {
+               BT_LOGD_STR("Releasing event's header field.");
+               header_field_release_func(event->header_field, event);
+       }
+
+       if (event->stream_event_context_field) {
+               BT_LOGD_STR("Releasing event's stream event context field.");
+               field_release_func(event->stream_event_context_field);
+       }
+
+       if (event->context_field) {
+               BT_LOGD_STR("Releasing event's context field.");
+               field_release_func(event->context_field);
+       }
+
+       if (event->payload_field) {
+               BT_LOGD_STR("Releasing event's payload field.");
+               field_release_func(event->payload_field);
+       }
+
+       /*
+        * Leave this after calling header_field_release_func() because
+        * this function receives the event object and could need its
+        * class to perform some cleanup.
+        */
+       if (!event->base.parent) {
+               /*
+                * Event was keeping a reference to its class since it shared no
+                * common ancestor with it to guarantee they would both have the
+                * same lifetime.
+                */
+               bt_ctf_object_put_ref(event->class);
+       }
+}
+
+struct bt_ctf_event {
+       struct bt_ctf_event_common common;
+};
+
+struct bt_ctf_event_class {
+       struct bt_ctf_event_class_common common;
+};
+
+BT_HIDDEN
+int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class,
+               struct metadata_context *context);
+
+BT_HIDDEN
+int bt_ctf_event_serialize(struct bt_ctf_event *event,
+               struct bt_ctfser *pos,
+               enum bt_ctf_byte_order native_byte_order);
+
+static inline
+struct bt_ctf_stream_class *bt_ctf_event_class_borrow_stream_class(
+               struct bt_ctf_event_class *event_class)
+{
+       return BT_CTF_FROM_COMMON(bt_ctf_event_class_common_borrow_stream_class(
+               BT_CTF_TO_COMMON(event_class)));
+}
+
+#endif /* BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H */
diff --git a/src/ctf-writer/field-path.c b/src/ctf-writer/field-path.c
new file mode 100644 (file)
index 0000000..dbd817a
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * field-path.c
+ *
+ * Babeltrace CTF writer - Field path
+ *
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-FIELD-PATH"
+#include "logging.h"
+
+#include <glib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <babeltrace2/ctf-writer/field-types.h>
+
+#include "common/assert.h"
+
+#include "field-path.h"
+#include "field-types.h"
+
+static
+void field_path_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_path *field_path = (struct bt_ctf_field_path *) obj;
+
+       BT_LOGD("Destroying field path: addr=%p", obj);
+
+       if (!field_path) {
+               return;
+       }
+
+       if (field_path->indexes) {
+               g_array_free(field_path->indexes, TRUE);
+       }
+       g_free(field_path);
+}
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_path_create(void)
+{
+       struct bt_ctf_field_path *field_path = NULL;
+
+       BT_LOGD_STR("Creating empty field path object.");
+
+       field_path = g_new0(struct bt_ctf_field_path, 1);
+       if (!field_path) {
+               BT_LOGE_STR("Failed to allocate one field path.");
+               goto error;
+       }
+
+       bt_ctf_object_init_shared(&field_path->base, field_path_destroy);
+       field_path->root = BT_CTF_SCOPE_UNKNOWN;
+       field_path->indexes = g_array_new(TRUE, FALSE, sizeof(int));
+       if (!field_path->indexes) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
+       }
+
+       BT_LOGD("Created empty field path object: addr=%p", field_path);
+       return field_path;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path);
+       return NULL;
+}
+
+BT_HIDDEN
+void bt_ctf_field_path_clear(struct bt_ctf_field_path *field_path)
+{
+       if (field_path->indexes->len > 0) {
+               g_array_remove_range(field_path->indexes, 0,
+                       field_path->indexes->len);
+       }
+}
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_path_copy(
+               struct bt_ctf_field_path *path)
+{
+       struct bt_ctf_field_path *new_path;
+
+       BT_ASSERT(path);
+       BT_LOGD("Copying field path: addr=%p, index-count=%u",
+               path, path->indexes->len);
+       new_path = bt_ctf_field_path_create();
+       if (!new_path) {
+               BT_LOGE_STR("Cannot create empty field path.");
+               goto end;
+       }
+
+       new_path->root = path->root;
+       g_array_insert_vals(new_path->indexes, 0,
+               path->indexes->data, path->indexes->len);
+       BT_LOGD("Copied field path: original-addr=%p, copy-addr=%p",
+               path, new_path);
+end:
+       return new_path;
+}
+
+enum bt_ctf_scope bt_ctf_field_path_get_root_scope(
+               const struct bt_ctf_field_path *field_path)
+{
+       enum bt_ctf_scope scope = BT_CTF_SCOPE_UNKNOWN;
+
+       if (!field_path) {
+               BT_LOGW_STR("Invalid parameter: field path is NULL.");
+               goto end;
+       }
+
+       scope = field_path->root;
+
+end:
+       return scope;
+}
+
+int64_t bt_ctf_field_path_get_index_count(
+               const struct bt_ctf_field_path *field_path)
+{
+       int64_t count = (int64_t) -1;
+
+       if (!field_path) {
+               BT_LOGW_STR("Invalid parameter: field path is NULL.");
+               goto end;
+       }
+
+       count = (int64_t) field_path->indexes->len;
+
+end:
+       return count;
+}
+
+int bt_ctf_field_path_get_index(const struct bt_ctf_field_path *field_path,
+               uint64_t index)
+{
+       int ret = INT_MIN;
+
+       if (!field_path) {
+               BT_LOGW_STR("Invalid parameter: field path is NULL.");
+               goto end;
+       }
+
+       if (index >= field_path->indexes->len) {
+               BT_LOGW("Invalid parameter: index is out of bounds: "
+                       "addr=%p, index=%" PRIu64 ", count=%u",
+                       field_path, index, field_path->indexes->len);
+               goto end;
+       }
+
+       ret = g_array_index(field_path->indexes, int, index);
+
+end:
+       return ret;
+}
diff --git a/src/ctf-writer/field-path.h b/src/ctf-writer/field-path.h
new file mode 100644 (file)
index 0000000..cf9edd3
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef BABELTRACE_CTF_WRITER_FIELD_PATH_INTERNAL
+#define BABELTRACE_CTF_WRITER_FIELD_PATH_INTERNAL
+
+/*
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include "common/common.h"
+#include "common/assert.h"
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <glib.h>
+
+#include "object.h"
+
+struct bt_ctf_field_path {
+       struct bt_ctf_object base;
+       enum bt_ctf_scope root;
+
+       /*
+        * Array of integers (int) indicating the index in either
+        * structures, variants, arrays, or sequences that make up
+        * the path to a field type. -1 means the "current element
+        * of an array or sequence type".
+        */
+       GArray *indexes;
+};
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_path_create(void);
+
+BT_HIDDEN
+void bt_ctf_field_path_clear(struct bt_ctf_field_path *field_path);
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_path_copy(
+               struct bt_ctf_field_path *path);
+
+BT_HIDDEN enum bt_ctf_scope bt_ctf_field_path_get_root_scope(
+               const struct bt_ctf_field_path *field_path);
+
+BT_HIDDEN int64_t bt_ctf_field_path_get_index_count(
+               const struct bt_ctf_field_path *field_path);
+
+BT_HIDDEN int bt_ctf_field_path_get_index(
+               const struct bt_ctf_field_path *field_path, uint64_t index);
+
+#endif /* BABELTRACE_CTF_WRITER_FIELD_PATH_INTERNAL */
diff --git a/src/ctf-writer/field-types.c b/src/ctf-writer/field-types.c
new file mode 100644 (file)
index 0000000..644270a
--- /dev/null
@@ -0,0 +1,5567 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-FIELD-TYPES"
+#include "logging.h"
+
+#include <float.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <babeltrace2/ctf-writer/fields.h>
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/utils.h>
+
+#include "common/assert.h"
+#include "compat/compiler.h"
+#include "compat/endian.h"
+
+#include "assert-pre.h"
+#include "clock-class.h"
+#include "clock.h"
+#include "field-path.h"
+#include "fields.h"
+#include "field-types.h"
+#include "object.h"
+#include "utils.h"
+
+static
+void destroy_enumeration_mapping(struct bt_ctf_enumeration_mapping *mapping)
+{
+       g_free(mapping);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_initialize(struct bt_ctf_field_type_common *ft,
+               bool init_bo, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       BT_ASSERT(ft && (ft->id > BT_CTF_FIELD_TYPE_ID_UNKNOWN) &&
+               (ft->id < BT_CTF_FIELD_TYPE_ID_NR));
+
+       bt_ctf_object_init_shared(&ft->base, release_func);
+       ft->methods = methods;
+
+       if (init_bo) {
+               int ret;
+               const enum bt_ctf_byte_order bo = BT_CTF_BYTE_ORDER_NATIVE;
+
+               BT_LOGD("Setting initial field type's byte order: bo=%s",
+                       bt_ctf_byte_order_string(bo));
+               ret = bt_ctf_field_type_common_set_byte_order(ft, bo);
+               BT_ASSERT(ret == 0);
+       }
+
+       ft->alignment = 1;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_initialize(
+               struct bt_ctf_field_type_common *ft,
+               unsigned int size, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(size > 0);
+       BT_LOGD("Initializing common integer field type object: size=%u",
+               size);
+       ft->id = BT_CTF_FIELD_TYPE_ID_INTEGER;
+       int_ft->size = size;
+       int_ft->base = BT_CTF_INTEGER_BASE_DECIMAL;
+       int_ft->encoding = BT_CTF_STRING_ENCODING_NONE;
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       BT_LOGD("Initialized common integer field type object: addr=%p, size=%u",
+               ft, size);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_LOGD_STR("Initializing common floating point number field type object.");
+       ft->id = BT_CTF_FIELD_TYPE_ID_FLOAT;
+       flt_ft->exp_dig = sizeof(float) * CHAR_BIT - FLT_MANT_DIG;
+       flt_ft->mant_dig = FLT_MANT_DIG;
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       BT_LOGD("Initialized common floating point number field type object: addr=%p, "
+               "exp-size=%u, mant-size=%u", ft, flt_ft->exp_dig,
+               flt_ft->mant_dig);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *container_ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(container_ft);
+       BT_LOGD("Initializing common enumeration field type object: int-ft-addr=%p",
+               container_ft);
+       ft->id = BT_CTF_FIELD_TYPE_ID_ENUM;
+       enum_ft->container_ft = bt_ctf_object_get_ref(container_ft);
+       enum_ft->entries = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) destroy_enumeration_mapping);
+       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
+       BT_LOGD("Initialized common enumeration field type object: addr=%p, "
+               "int-ft-addr=%p, int-ft-size=%u", ft, container_ft,
+               bt_ctf_field_type_common_integer_get_size(container_ft));
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_string_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_LOGD_STR("Initializing common string field type object.");
+       ft->id = BT_CTF_FIELD_TYPE_ID_STRING;
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       string_ft->encoding = BT_CTF_STRING_ENCODING_UTF8;
+       ft->alignment = CHAR_BIT;
+       BT_LOGD("Initialized common string field type object: addr=%p", ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_LOGD_STR("Initializing common structure field type object.");
+       ft->id = BT_CTF_FIELD_TYPE_ID_STRUCT;
+       struct_ft->fields = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_ctf_field_type_common_structure_field));
+       struct_ft->field_name_to_index = g_hash_table_new(NULL, NULL);
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       BT_LOGD("Initialized common structure field type object: addr=%p", ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft,
+               unsigned int length, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(element_ft);
+       BT_LOGD("Initializing common array field type object: element-ft-addr=%p, "
+               "length=%u", element_ft, length);
+       ft->id = BT_CTF_FIELD_TYPE_ID_ARRAY;
+       array_ft->element_ft = bt_ctf_object_get_ref(element_ft);
+       array_ft->length = length;
+       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
+       BT_LOGD("Initialized common array field type object: addr=%p, "
+               "element-ft-addr=%p, length=%u", ft, element_ft, length);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft,
+               const char *length_field_name,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(element_ft);
+       BT_ASSERT(length_field_name);
+       BT_ASSERT(bt_ctf_identifier_is_valid(length_field_name));
+       BT_LOGD("Initializing common sequence field type object: element-ft-addr=%p, "
+               "length-field-name=\"%s\"", element_ft, length_field_name);
+       ft->id = BT_CTF_FIELD_TYPE_ID_SEQUENCE;
+       seq_ft->element_ft = bt_ctf_object_get_ref(element_ft);
+       seq_ft->length_field_name = g_string_new(length_field_name);
+       bt_ctf_field_type_common_initialize(ft, false, release_func, methods);
+       BT_LOGD("Initialized common sequence field type object: addr=%p, "
+               "element-ft-addr=%p, length-field-name=\"%s\"",
+               ft, element_ft, length_field_name);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *tag_ft,
+               const char *tag_name,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(!tag_name || bt_ctf_identifier_is_valid(tag_name));
+       BT_LOGD("Initializing common variant field type object: "
+               "tag-ft-addr=%p, tag-field-name=\"%s\"",
+               tag_ft, tag_name);
+       ft->id = BT_CTF_FIELD_TYPE_ID_VARIANT;
+       var_ft->tag_name = g_string_new(tag_name);
+       var_ft->choice_name_to_index = g_hash_table_new(NULL, NULL);
+       var_ft->choices = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_ctf_field_type_common_variant_choice));
+
+       if (tag_ft) {
+               var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft);
+       }
+
+       bt_ctf_field_type_common_initialize(ft, true, release_func, methods);
+       /* A variant's alignment is undefined */
+       ft->alignment = 0;
+       BT_LOGD("Initialized common variant field type object: addr=%p, "
+               "tag-ft-addr=%p, tag-field-name=\"%s\"",
+               ft, tag_ft, tag_name);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_integer *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying integer field type object: addr=%p", ft);
+       BT_LOGD_STR("Putting mapped clock class.");
+       bt_ctf_object_put_ref(ft->mapped_clock_class);
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_floating_point *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying floating point number field type object: addr=%p", ft);
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_enumeration *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying enumeration field type object: addr=%p", ft);
+       g_ptr_array_free(ft->entries, TRUE);
+       BT_LOGD_STR("Putting container field type.");
+       bt_ctf_object_put_ref(ft->container_ft);
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_string_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_string *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying string field type object: addr=%p", ft);
+       g_free(ft);
+}
+
+static
+void bt_ctf_field_type_common_structure_field_finalize(
+               struct bt_ctf_field_type_common_structure_field *field)
+{
+       if (!field) {
+               return;
+       }
+
+       BT_LOGD("Finalizing structure field type's field: "
+               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
+               field, field->type, g_quark_to_string(field->name));
+       BT_LOGD_STR("Putting field type.");
+       bt_ctf_object_put_ref(field->type);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_structure *ft = (void *) obj;
+       uint64_t i;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying structure field type object: addr=%p", ft);
+
+       if (ft->fields) {
+               for (i = 0; i < ft->fields->len; i++) {
+                       bt_ctf_field_type_common_structure_field_finalize(
+                               BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                                       ft, i));
+               }
+
+               g_array_free(ft->fields, TRUE);
+       }
+
+       if (ft->field_name_to_index) {
+               g_hash_table_destroy(ft->field_name_to_index);
+       }
+
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_array *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying array field type object: addr=%p", ft);
+       BT_LOGD_STR("Putting element field type.");
+       bt_ctf_object_put_ref(ft->element_ft);
+       g_free(ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_sequence *ft = (void *) obj;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying sequence field type object: addr=%p", ft);
+       BT_LOGD_STR("Putting element field type.");
+       bt_ctf_object_put_ref(ft->element_ft);
+       g_string_free(ft->length_field_name, TRUE);
+       BT_LOGD_STR("Putting length field path.");
+       bt_ctf_object_put_ref(ft->length_field_path);
+       g_free(ft);
+}
+
+static
+void bt_ctf_field_type_common_variant_choice_finalize(
+               struct bt_ctf_field_type_common_variant_choice *choice)
+{
+       if (!choice) {
+               return;
+       }
+
+       BT_LOGD("Finalizing variant field type's choice: "
+               "addr=%p, field-ft-addr=%p, field-name=\"%s\"",
+               choice, choice->type, g_quark_to_string(choice->name));
+       BT_LOGD_STR("Putting field type.");
+       bt_ctf_object_put_ref(choice->type);
+
+       if (choice->ranges) {
+               g_array_free(choice->ranges, TRUE);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_destroy_recursive(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_common_variant *ft = (void *) obj;
+       uint64_t i;
+
+       if (!ft) {
+               return;
+       }
+
+       BT_LOGD("Destroying variant field type object: addr=%p", ft);
+
+       if (ft->choices) {
+               for (i = 0; i < ft->choices->len; i++) {
+                       bt_ctf_field_type_common_variant_choice_finalize(
+                               BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                                       ft, i));
+               }
+
+               g_array_free(ft->choices, TRUE);
+       }
+
+       if (ft->choice_name_to_index) {
+               g_hash_table_destroy(ft->choice_name_to_index);
+       }
+
+       if (ft->tag_name) {
+               g_string_free(ft->tag_name, TRUE);
+       }
+
+       BT_LOGD_STR("Putting tag field type.");
+       bt_ctf_object_put_ref(ft->tag_ft);
+       BT_LOGD_STR("Putting tag field path.");
+       bt_ctf_object_put_ref(ft->tag_field_path);
+       g_free(ft);
+}
+
+struct range_overlap_query {
+       union {
+               uint64_t _unsigned;
+               int64_t _signed;
+       } range_start;
+
+       union {
+               uint64_t _unsigned;
+               int64_t _signed;
+       } range_end;
+       int overlaps;
+       GQuark mapping_name;
+};
+
+static
+void check_ranges_overlap(gpointer element, gpointer query)
+{
+       struct bt_ctf_enumeration_mapping *mapping = element;
+       struct range_overlap_query *overlap_query = query;
+
+       if (mapping->range_start._signed <= overlap_query->range_end._signed
+                       && overlap_query->range_start._signed <=
+                       mapping->range_end._signed) {
+               overlap_query->overlaps = 1;
+               overlap_query->mapping_name = mapping->string;
+       }
+
+       overlap_query->overlaps |=
+               mapping->string == overlap_query->mapping_name;
+
+       if (overlap_query->overlaps) {
+               BT_LOGV("Overlapping enumeration field type mappings: "
+                       "mapping-name=\"%s\", "
+                       "mapping-a-range-start=%" PRId64 ", "
+                       "mapping-a-range-end=%" PRId64 ", "
+                       "mapping-b-range-start=%" PRId64 ", "
+                       "mapping-b-range-end=%" PRId64,
+                       g_quark_to_string(mapping->string),
+                       mapping->range_start._signed,
+                       mapping->range_end._signed,
+                       overlap_query->range_start._signed,
+                       overlap_query->range_end._signed);
+       }
+}
+
+static
+void check_ranges_overlap_unsigned(gpointer element, gpointer query)
+{
+       struct bt_ctf_enumeration_mapping *mapping = element;
+       struct range_overlap_query *overlap_query = query;
+
+       if (mapping->range_start._unsigned <= overlap_query->range_end._unsigned
+                       && overlap_query->range_start._unsigned <=
+                       mapping->range_end._unsigned) {
+               overlap_query->overlaps = 1;
+               overlap_query->mapping_name = mapping->string;
+       }
+
+       overlap_query->overlaps |=
+               mapping->string == overlap_query->mapping_name;
+
+       if (overlap_query->overlaps) {
+               BT_LOGW("Overlapping enumeration field type mappings: "
+                       "mapping-name=\"%s\", "
+                       "mapping-a-range-start=%" PRIu64 ", "
+                       "mapping-a-range-end=%" PRIu64 ", "
+                       "mapping-b-range-start=%" PRIu64 ", "
+                       "mapping-b-range-end=%" PRIu64,
+                       g_quark_to_string(mapping->string),
+                       mapping->range_start._unsigned,
+                       mapping->range_end._unsigned,
+                       overlap_query->range_start._unsigned,
+                       overlap_query->range_end._unsigned);
+       }
+}
+
+static
+gint compare_enumeration_mappings_signed(struct bt_ctf_enumeration_mapping **a,
+               struct bt_ctf_enumeration_mapping **b)
+{
+       return ((*a)->range_start._signed < (*b)->range_start._signed) ? -1 : 1;
+}
+
+static
+gint compare_enumeration_mappings_unsigned(struct bt_ctf_enumeration_mapping **a,
+               struct bt_ctf_enumeration_mapping **b)
+{
+       return ((*a)->range_start._unsigned < (*b)->range_start._unsigned) ? -1 : 1;
+}
+
+static
+int add_structure_variant_member(GArray *members,
+               GHashTable *field_name_to_index,
+               struct bt_ctf_field_type_common *field_type, const char *field_name,
+               bool is_variant)
+{
+       int ret = 0;
+       GQuark name_quark = g_quark_from_string(field_name);
+       struct bt_ctf_field_type_common **member_ft;
+       GQuark *member_name;
+
+       /* Make sure structure does not contain a field of the same name */
+       if (g_hash_table_lookup_extended(field_name_to_index,
+                       GUINT_TO_POINTER(name_quark), NULL, NULL)) {
+               BT_LOGW("Structure or variant field type already contains a field type with this name: "
+                       "field-name=\"%s\"", field_name);
+               ret = -1;
+               goto end;
+       }
+
+       g_array_set_size(members, members->len + 1);
+
+       if (is_variant) {
+               struct bt_ctf_field_type_common_variant_choice *choice =
+                       &g_array_index(members,
+                               struct bt_ctf_field_type_common_variant_choice,
+                               members->len - 1);
+
+               member_ft = &choice->type;
+               member_name = &choice->name;
+               BT_ASSERT(!choice->ranges);
+               choice->ranges = g_array_new(FALSE, TRUE,
+                       sizeof(struct bt_ctf_field_type_common_variant_choice_range));
+               BT_ASSERT(choice->ranges);
+       } else {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       &g_array_index(members,
+                               struct bt_ctf_field_type_common_structure_field,
+                               members->len - 1);
+
+               member_ft = &field->type;
+               member_name = &field->name;
+       }
+
+       *member_name = name_quark;
+       *member_ft = bt_ctf_object_get_ref(field_type);
+       g_hash_table_insert(field_name_to_index,
+               GUINT_TO_POINTER(name_quark),
+               GUINT_TO_POINTER(members->len - 1));
+       BT_LOGV("Added structure/variant field type member: member-ft-addr=%p, "
+               "member-name=\"%s\"", field_type, field_name);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_validate(struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (int_ft->mapped_clock_class && int_ft->is_signed) {
+               BT_LOGW("Invalid integer field type: cannot be signed and have a mapped clock class: "
+                       "ft-addr=%p, clock-class-addr=%p, clock-class-name=\"%s\"",
+                       ft, int_ft->mapped_clock_class,
+                       bt_ctf_clock_class_get_name(int_ft->mapped_clock_class));
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+void bt_ctf_field_type_enum_iter_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter =
+               container_of(obj,
+                       struct bt_ctf_field_type_enumeration_mapping_iterator,
+                       base);
+
+       BT_LOGD("Destroying enumeration field type mapping iterator: addr=%p",
+               obj);
+       BT_LOGD_STR("Putting parent enumeration field type.");
+       bt_ctf_object_put_ref(iter->enumeration_ft);
+       g_free(iter);
+}
+
+static
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_find_mappings_type(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_field_type_enumeration_mapping_iterator_type iterator_type)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM,
+               "Field type");
+       iter = g_new0(struct bt_ctf_field_type_enumeration_mapping_iterator, 1);
+       if (!iter) {
+               BT_LOGE_STR("Failed to allocate one enumeration field type mapping.");
+               goto end;
+       }
+
+       bt_ctf_object_init_shared(&iter->base, bt_ctf_field_type_enum_iter_destroy);
+       iter->enumeration_ft = bt_ctf_object_get_ref(ft);
+       iter->index = -1;
+       iter->type = iterator_type;
+
+end:
+       return iter;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_find_mappings_by_name(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
+
+       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
+                       ft, CTF_ITERATOR_BY_NAME);
+       if (!iter) {
+               BT_LOGW("Cannot create enumeration field type mapping iterator: "
+                       "ft-addr=%p, mapping-name=\"%s\"", ft, name);
+               goto error;
+       }
+
+       iter->u.name_quark = g_quark_try_string(name);
+       if (!iter->u.name_quark) {
+               /*
+                * No results are possible, set the iterator's position at the
+                * end.
+                */
+               iter->index = iter->enumeration_ft->entries->len;
+       }
+
+       return iter;
+
+error:
+       bt_ctf_object_put_ref(iter);
+       return NULL;
+}
+
+static
+struct bt_ctf_enumeration_mapping *bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+               struct bt_ctf_field_type_common *ft, uint64_t index)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_enumeration_mapping *mapping = NULL;
+
+       if (index >= enum_ft->entries->len) {
+               BT_LOGW("Invalid parameter: index is out of bounds: "
+                       "addr=%p, index=%" PRIu64 ", count=%u",
+                       ft, index, enum_ft->entries->len);
+               goto end;
+       }
+
+       mapping = g_ptr_array_index(enum_ft->entries, index);
+
+end:
+       return mapping;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_enumeration_mapping_iterator_next(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = iter->enumeration_ft;
+       int i, ret = 0, len;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
+       len = enum_ft->entries->len;
+       for (i = iter->index + 1; i < len; i++) {
+               struct bt_ctf_enumeration_mapping *mapping =
+                       bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+                               BT_CTF_TO_COMMON(enum_ft), i);
+
+               switch (iter->type) {
+               case CTF_ITERATOR_BY_NAME:
+                       if (mapping->string == iter->u.name_quark) {
+                               iter->index = i;
+                               goto end;
+                       }
+                       break;
+               case CTF_ITERATOR_BY_SIGNED_VALUE:
+               {
+                       int64_t value = iter->u.signed_value;
+
+                       if (value >= mapping->range_start._signed &&
+                                       value <= mapping->range_end._signed) {
+                               iter->index = i;
+                               goto end;
+                       }
+                       break;
+               }
+               case CTF_ITERATOR_BY_UNSIGNED_VALUE:
+               {
+                       uint64_t value = iter->u.unsigned_value;
+
+                       if (value >= mapping->range_start._unsigned &&
+                                       value <= mapping->range_end._unsigned) {
+                               iter->index = i;
+                               goto end;
+                       }
+                       break;
+               }
+               default:
+                       BT_LOGF("Invalid enumeration field type mapping iterator type: "
+                               "type=%d", iter->type);
+                       abort();
+               }
+       }
+
+       ret = -1;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_signed_find_mappings_by_value(
+               struct bt_ctf_field_type_common *ft, int64_t value)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
+
+       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
+                       ft, CTF_ITERATOR_BY_SIGNED_VALUE);
+       if (!iter) {
+               BT_LOGW("Cannot create enumeration field type mapping iterator: "
+                       "ft-addr=%p, value=%" PRId64, ft, value);
+               goto error;
+       }
+
+       if (bt_ctf_field_type_common_integer_is_signed(
+                       BT_CTF_TO_COMMON(iter->enumeration_ft->container_ft)) != 1) {
+               BT_LOGW("Invalid parameter: enumeration field type is unsigned: "
+                       "enum-ft-addr=%p, int-ft-addr=%p",
+                       ft, iter->enumeration_ft->container_ft);
+               goto error;
+       }
+
+       iter->u.signed_value = value;
+       return iter;
+
+error:
+       bt_ctf_object_put_ref(iter);
+       return NULL;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_unsigned_find_mappings_by_value(
+               struct bt_ctf_field_type_common *ft, uint64_t value)
+{
+       struct bt_ctf_field_type_enumeration_mapping_iterator *iter;
+
+       iter = bt_ctf_field_type_common_enumeration_find_mappings_type(
+                       ft, CTF_ITERATOR_BY_UNSIGNED_VALUE);
+       if (!iter) {
+               BT_LOGW("Cannot create enumeration field type mapping iterator: "
+                       "ft-addr=%p, value=%" PRIu64, ft, value);
+               goto error;
+       }
+
+       if (bt_ctf_field_type_common_integer_is_signed(
+                       BT_CTF_TO_COMMON(iter->enumeration_ft->container_ft)) != 0) {
+               BT_LOGW("Invalid parameter: enumeration field type is signed: "
+                       "enum-ft-addr=%p, int-ft-addr=%p",
+                       ft, iter->enumeration_ft->container_ft);
+               goto error;
+       }
+
+       iter->u.unsigned_value = value;
+       return iter;
+
+error:
+       bt_ctf_object_put_ref(iter);
+       return NULL;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_enumeration_mapping_iterator_signed_get(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter,
+               const char **mapping_name, int64_t *range_begin,
+               int64_t *range_end)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
+       BT_CTF_ASSERT_PRE(iter->index != -1,
+               "Invalid enumeration field type mapping iterator access: "
+               "addr=%p, position=-1", iter);
+       return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
+                       (void *) iter->enumeration_ft, iter->index,
+                       mapping_name, range_begin, range_end);
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get(
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter,
+               const char **mapping_name, uint64_t *range_begin,
+               uint64_t *range_end)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(iter, "Enumeration field type mapping iterator");
+       BT_CTF_ASSERT_PRE(iter->index != -1,
+               "Invalid enumeration field type mapping iterator access: "
+               "addr=%p, position=-1", iter);
+       return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
+                       (void *) iter->enumeration_ft, iter->index,
+                       mapping_name, range_begin, range_end);
+}
+
+/*
+ * Note: This algorithm is O(n^2) vs number of enumeration mappings.
+ * Only used when freezing an enumeration.
+ */
+static
+void bt_ctf_field_type_common_enumeration_set_range_overlap(
+               struct bt_ctf_field_type_common_enumeration *ft)
+{
+       int64_t i, j, len;
+       int is_signed;
+
+       BT_LOGV("Setting enumeration field type's overlap flag: addr=%p",
+               ft);
+       len = ft->entries->len;
+       is_signed = bt_ctf_field_type_common_integer_is_signed(
+               BT_CTF_TO_COMMON(ft->container_ft));
+
+       for (i = 0; i < len; i++) {
+               for (j = i + 1; j < len; j++) {
+                       struct bt_ctf_enumeration_mapping *mapping[2];
+
+                       mapping[0] = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+                               BT_CTF_TO_COMMON(ft), i);
+                       mapping[1] = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+                               BT_CTF_TO_COMMON(ft), j);
+                       if (is_signed) {
+                               if (mapping[0]->range_start._signed
+                                                       <= mapping[1]->range_end._signed
+                                               && mapping[0]->range_end._signed
+                                                       >= mapping[1]->range_start._signed) {
+                                       ft->has_overlapping_ranges = BT_TRUE;
+                                       goto end;
+                               }
+                       } else {
+                               if (mapping[0]->range_start._unsigned
+                                                       <= mapping[1]->range_end._unsigned
+                                               && mapping[0]->range_end._unsigned
+                                                       >= mapping[1]->range_start._unsigned) {
+                                       ft->has_overlapping_ranges = BT_TRUE;
+                                       goto end;
+                               }
+                       }
+               }
+       }
+
+end:
+       if (ft->has_overlapping_ranges) {
+               BT_LOGV_STR("Enumeration field type has overlapping ranges.");
+       } else {
+               BT_LOGV_STR("Enumeration field type has no overlapping ranges.");
+       }
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       ret = bt_ctf_field_type_common_integer_validate(
+                       BT_CTF_TO_COMMON(enum_ft->container_ft));
+       if (ret) {
+               BT_LOGW("Invalid enumeration field type: container type is invalid: "
+                       "enum-ft-addr=%p, int-ft-addr=%p",
+                       ft, enum_ft->container_ft);
+               goto end;
+       }
+
+       /* Ensure enum has entries */
+       if (enum_ft->entries->len == 0) {
+               BT_LOGW("Invalid enumeration field type: no entries: "
+                       "addr=%p", ft);
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       /* Length field name should be set at this point */
+       if (seq_ft->length_field_name->len == 0) {
+               BT_LOGW("Invalid sequence field type: no length field name: "
+                       "addr=%p", ft);
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_validate(seq_ft->element_ft);
+       if (ret) {
+               BT_LOGW("Invalid sequence field type: invalid element field type: "
+                       "seq-ft-addr=%p, element-ft-add=%p",
+                       ft, seq_ft->element_ft);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       ret = bt_ctf_field_type_common_validate(array_ft->element_ft);
+       if (ret) {
+               BT_LOGW("Invalid array field type: invalid element field type: "
+                       "array-ft-addr=%p, element-ft-add=%p",
+                       ft, array_ft->element_ft);
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common *child_ft = NULL;
+       int64_t field_count =
+               bt_ctf_field_type_common_structure_get_field_count(ft);
+       int64_t i;
+
+       BT_ASSERT(field_count >= 0);
+
+       for (i = 0; i < field_count; ++i) {
+               const char *field_name;
+
+               ret = bt_ctf_field_type_common_structure_borrow_field_by_index(ft,
+                       &field_name, &child_ft, i);
+               BT_ASSERT(ret == 0);
+               ret = bt_ctf_field_type_common_validate(child_ft);
+               if (ret) {
+                       BT_LOGW("Invalid structure field type: "
+                               "a contained field type is invalid: "
+                               "struct-ft-addr=%p, field-ft-addr=%p, "
+                               "field-name=\"%s\", field-index=%" PRId64,
+                               ft, child_ft, field_name, i);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_bool bt_ctf_field_type_common_enumeration_has_overlapping_ranges(
+               struct bt_ctf_field_type_common_enumeration *enum_ft)
+{
+       if (!enum_ft->common.frozen) {
+               bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft);
+       }
+
+       return enum_ft->has_overlapping_ranges;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_validate_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+       int64_t field_count;
+       struct bt_ctf_field_type_common *child_ft = NULL;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       int64_t i;
+
+       if (var_ft->tag_name->len == 0) {
+               BT_LOGW("Invalid variant field type: no tag field name: "
+                       "addr=%p", ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (!var_ft->tag_ft) {
+               BT_LOGW("Invalid variant field type: no tag field type: "
+                       "addr=%p, tag-field-name=\"%s\"", var_ft,
+                       var_ft->tag_name->str);
+               ret = -1;
+               goto end;
+       }
+
+       if (bt_ctf_field_type_common_enumeration_has_overlapping_ranges(var_ft->tag_ft)) {
+               BT_LOGW("Invalid variant field type: enumeration tag field type has overlapping ranges: "
+                       "variant-ft-addr=%p, tag-field-name=\"%s\", "
+                       "enum-ft-addr=%p", ft, var_ft->tag_name->str,
+                       var_ft->tag_ft);
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * It is valid to have a variant field type which does not have
+        * the fields corresponding to each label in the associated
+        * enumeration.
+        *
+        * It is also valid to have variant field type fields which
+        * cannot be selected because the variant field type tag has no
+        * mapping named as such. This scenario, while not ideal, cannot
+        * cause any error.
+        *
+        * If a non-existing field happens to be selected by an
+        * enumeration while reading a variant field, an error will be
+        * generated at that point (while reading the stream).
+        */
+       field_count = bt_ctf_field_type_common_variant_get_field_count(ft);
+       if (field_count < 0) {
+               BT_LOGW("Invalid variant field type: no fields: "
+                       "addr=%p, tag-field-name=\"%s\"",
+                       ft, var_ft->tag_name->str);
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < field_count; ++i) {
+               const char *field_name;
+
+               ret = bt_ctf_field_type_common_variant_borrow_field_by_index(ft,
+                       &field_name, &child_ft, i);
+               BT_ASSERT(ret == 0);
+               ret = bt_ctf_field_type_common_validate(child_ft);
+               if (ret) {
+                       BT_LOGW("Invalid variant field type: "
+                               "a contained field type is invalid: "
+                               "variant-ft-addr=%p, tag-field-name=\"%s\", "
+                               "field-ft-addr=%p, field-name=\"%s\", "
+                               "field-index=%" PRId64,
+                               ft, var_ft->tag_name->str, child_ft,
+                               field_name, i);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * This function validates a given field type without considering
+ * where this field type is located. It only validates the properties
+ * of the given field type and the properties of its children if
+ * applicable.
+ */
+BT_HIDDEN
+int bt_ctf_field_type_common_validate(struct bt_ctf_field_type_common *ft)
+{
+       int ret = 0;
+
+       BT_ASSERT(ft);
+
+       if (ft->valid) {
+               /* Already marked as valid */
+               goto end;
+       }
+
+       if (ft->methods->validate) {
+               ret = ft->methods->validate(ft);
+       }
+
+       if (ret == 0 && ft->frozen) {
+               /* Field type is valid */
+               BT_LOGV("Marking field type as valid: addr=%p", ft);
+               ft->valid = 1;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_get_size(struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return (int) int_ft->size;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_type_common_integer_is_signed(struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return int_ft->is_signed;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_is_signed(struct bt_ctf_field_type_common *ft,
+               bt_bool is_signed)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       int_ft->is_signed = !!is_signed;
+       BT_LOGV("Set integer field type's signedness: addr=%p, is-signed=%d",
+               ft, is_signed);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_size(struct bt_ctf_field_type_common *ft,
+               unsigned int size)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (size == 0 || size > 64) {
+               BT_LOGW("Invalid parameter: size must be between 1 and 64: "
+                       "addr=%p, size=%u", ft, size);
+               ret = -1;
+               goto end;
+       }
+
+       int_ft->size = size;
+       BT_LOGV("Set integer field type's size: addr=%p, size=%u",
+               ft, size);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_integer_base bt_ctf_field_type_common_integer_get_base(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return int_ft->base;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_base(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_integer_base base)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       switch (base) {
+       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
+       case BT_CTF_INTEGER_BASE_BINARY:
+       case BT_CTF_INTEGER_BASE_OCTAL:
+       case BT_CTF_INTEGER_BASE_DECIMAL:
+       case BT_CTF_INTEGER_BASE_HEXADECIMAL:
+       {
+               int_ft->base = base;
+               break;
+       }
+       default:
+               BT_LOGW("Invalid parameter: unknown integer field type base: "
+                       "addr=%p, base=%d", ft, base);
+               ret = -1;
+       }
+
+       BT_LOGV("Set integer field type's base: addr=%p, base=%s",
+               ft, bt_ctf_integer_base_string(base));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_string_encoding bt_ctf_field_type_common_integer_get_encoding(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return int_ft->encoding;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_encoding(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_string_encoding encoding)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (encoding != BT_CTF_STRING_ENCODING_UTF8 &&
+                       encoding != BT_CTF_STRING_ENCODING_ASCII &&
+                       encoding != BT_CTF_STRING_ENCODING_NONE) {
+               BT_LOGW("Invalid parameter: unknown string encoding: "
+                       "addr=%p, encoding=%d", ft, encoding);
+               ret = -1;
+               goto end;
+       }
+
+       int_ft->encoding = encoding;
+       BT_LOGV("Set integer field type's encoding: addr=%p, encoding=%s",
+               ft, bt_ctf_string_encoding_string(encoding));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_INTEGER,
+               "Field type");
+       return int_ft->mapped_clock_class;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_clock_class *clock_class)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+       int ret = 0;
+
+       if (!clock_class) {
+               BT_LOGW_STR("Invalid parameter: clock class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: field type is not an integer field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               goto end;
+       }
+
+       if (!bt_ctf_clock_class_is_valid(clock_class)) {
+               BT_LOGW("Invalid parameter: clock class is invalid: ft-addr=%p"
+                       "clock-class-addr=%p, clock-class-name=\"%s\"",
+                       ft, clock_class,
+                       bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(int_ft->mapped_clock_class);
+       int_ft->mapped_clock_class = bt_ctf_object_get_ref(clock_class);
+       BT_LOGV("Set integer field type's mapped clock class: ft-addr=%p, "
+               "clock-class-addr=%p, clock-class-name=\"%s\"",
+               ft, clock_class, bt_ctf_clock_class_get_name(clock_class));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_mapped_clock_class(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_clock_class *clock_class)
+{
+       int ret = 0;
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
+               ft, clock_class);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
+               struct bt_ctf_field_type_common *ft, uint64_t index,
+               const char **mapping_name, int64_t *range_begin,
+               int64_t *range_end)
+{
+       int ret = 0;
+       struct bt_ctf_enumeration_mapping *mapping;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
+       mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(ft,
+               index);
+       if (!mapping) {
+               /* bt_ctf_field_type_common_enumeration_get_mapping_by_index() logs errors */
+               ret = -1;
+               goto end;
+       }
+
+       if (mapping_name) {
+               *mapping_name = g_quark_to_string(mapping->string);
+               BT_ASSERT(*mapping_name);
+       }
+
+       if (range_begin) {
+               *range_begin = mapping->range_start._signed;
+       }
+
+       if (range_end) {
+               *range_end = mapping->range_end._signed;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
+               struct bt_ctf_field_type_common *ft, uint64_t index,
+               const char **mapping_name, uint64_t *range_begin,
+               uint64_t *range_end)
+{
+       int ret = 0;
+       struct bt_ctf_enumeration_mapping *mapping;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
+       mapping = bt_ctf_field_type_common_enumeration_get_mapping_by_index(
+               ft, index);
+       if (!mapping) {
+               /* bt_ctf_field_type_common_enumeration_get_mapping_by_index() reports any error */
+               ret = -1;
+               goto end;
+       }
+
+       if (mapping_name) {
+               *mapping_name = g_quark_to_string(mapping->string);
+               BT_ASSERT(*mapping_name);
+       }
+
+       if (range_begin) {
+               *range_begin = mapping->range_start._unsigned;
+       }
+
+       if (range_end) {
+               *range_end = mapping->range_end._unsigned;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_enumeration_borrow_container_field_type(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
+       return BT_CTF_TO_COMMON(enum_ft->container_ft);
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_signed_add_mapping(
+               struct bt_ctf_field_type_common *ft, const char *string,
+               int64_t range_start, int64_t range_end)
+{
+       int ret = 0;
+       GQuark mapping_name;
+       struct bt_ctf_enumeration_mapping *mapping;
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+       char *escaped_string;
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!string) {
+               BT_LOGW_STR("Invalid parameter: string is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) {
+               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (range_end < range_start) {
+               BT_LOGW("Invalid parameter: range's end is lesser than range's start: "
+                       "addr=%p, range-start=%" PRId64 ", range-end=%" PRId64,
+                       ft, range_start, range_end);
+               ret = -1;
+               goto end;
+       }
+
+       if (strlen(string) == 0) {
+               BT_LOGW("Invalid parameter: mapping name is an empty string: "
+                       "enum-ft-addr=%p, mapping-name-addr=%p", ft,
+                       string);
+               ret = -1;
+               goto end;
+       }
+
+       escaped_string = g_strescape(string, NULL);
+       if (!escaped_string) {
+               BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, "
+                       "mapping-name-addr=%p, mapping-name=\"%s\"",
+                       ft, string, string);
+               ret = -1;
+               goto end;
+       }
+
+       mapping = g_new(struct bt_ctf_enumeration_mapping, 1);
+       if (!mapping) {
+               BT_LOGE_STR("Failed to allocate one enumeration mapping.");
+               ret = -1;
+               goto error_free;
+       }
+       mapping_name = g_quark_from_string(escaped_string);
+       *mapping = (struct bt_ctf_enumeration_mapping) {
+               .range_start._signed = range_start,
+               .range_end._signed = range_end,
+               .string =  mapping_name,
+       };
+       g_ptr_array_add(enum_ft->entries, mapping);
+       g_ptr_array_sort(enum_ft->entries,
+               (GCompareFunc) compare_enumeration_mappings_signed);
+       BT_LOGV("Added mapping to signed enumeration field type: addr=%p, "
+               "name=\"%s\", range-start=%" PRId64 ", "
+               "range-end=%" PRId64,
+               ft, string, range_start, range_end);
+
+error_free:
+       free(escaped_string);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
+               struct bt_ctf_field_type_common *ft, const char *string,
+               uint64_t range_start, uint64_t range_end)
+{
+       int ret = 0;
+       GQuark mapping_name;
+       struct bt_ctf_enumeration_mapping *mapping;
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+       char *escaped_string;
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!string) {
+               BT_LOGW_STR("Invalid parameter: string is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) {
+               BT_LOGW("Invalid parameter: field type is not an enumeration field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (range_end < range_start) {
+               BT_LOGW("Invalid parameter: range's end is lesser than range's start: "
+                       "addr=%p, range-start=%" PRIu64 ", range-end=%" PRIu64,
+                       ft, range_start, range_end);
+               ret = -1;
+               goto end;
+       }
+
+       if (strlen(string) == 0) {
+               BT_LOGW("Invalid parameter: mapping name is an empty string: "
+                       "enum-ft-addr=%p, mapping-name-addr=%p", ft,
+                       string);
+               ret = -1;
+               goto end;
+       }
+
+       escaped_string = g_strescape(string, NULL);
+       if (!escaped_string) {
+               BT_LOGE("Cannot escape mapping name: enum-ft-addr=%p, "
+                       "mapping-name-addr=%p, mapping-name=\"%s\"",
+                       ft, string, string);
+               ret = -1;
+               goto end;
+       }
+
+       mapping = g_new(struct bt_ctf_enumeration_mapping, 1);
+       if (!mapping) {
+               BT_LOGE_STR("Failed to allocate one enumeration mapping.");
+               ret = -1;
+               goto error_free;
+       }
+       mapping_name = g_quark_from_string(escaped_string);
+       *mapping = (struct bt_ctf_enumeration_mapping) {
+               .range_start._unsigned = range_start,
+               .range_end._unsigned = range_end,
+               .string = mapping_name,
+       };
+       g_ptr_array_add(enum_ft->entries, mapping);
+       g_ptr_array_sort(enum_ft->entries,
+               (GCompareFunc) compare_enumeration_mappings_unsigned);
+       BT_LOGV("Added mapping to unsigned enumeration field type: addr=%p, "
+               "name=\"%s\", range-start=%" PRIu64 ", "
+               "range-end=%" PRIu64,
+               ft, string, range_start, range_end);
+
+error_free:
+       free(escaped_string);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_enumeration_get_mapping_count(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ENUM, "Field type");
+       return (int64_t) enum_ft->entries->len;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_get_exponent_digits(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT,
+               "Field type");
+       return (int) flt_ft->exp_dig;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_set_exponent_digits(
+               struct bt_ctf_field_type_common *ft,
+               unsigned int exponent_digits)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_FLOAT) {
+               BT_LOGW("Invalid parameter: field type is not a floating point number field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if ((exponent_digits != sizeof(float) * CHAR_BIT - FLT_MANT_DIG) &&
+               (exponent_digits != sizeof(double) * CHAR_BIT - DBL_MANT_DIG) &&
+               (exponent_digits !=
+                       sizeof(long double) * CHAR_BIT - LDBL_MANT_DIG)) {
+               BT_LOGW("Invalid parameter: invalid exponent size: "
+                       "addr=%p, exp-size=%u", ft, exponent_digits);
+               ret = -1;
+               goto end;
+       }
+
+       flt_ft->exp_dig = exponent_digits;
+       BT_LOGV("Set floating point number field type's exponent size: addr=%p, "
+               "exp-size=%u", ft, exponent_digits);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_get_mantissa_digits(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_FLOAT,
+               "Field type");
+       return (int) flt_ft->mant_dig;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_set_mantissa_digits(
+               struct bt_ctf_field_type_common *ft, unsigned int mantissa_digits)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_FLOAT) {
+               BT_LOGW("Invalid parameter: field type is not a floating point number field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if ((mantissa_digits != FLT_MANT_DIG) &&
+               (mantissa_digits != DBL_MANT_DIG) &&
+               (mantissa_digits != LDBL_MANT_DIG)) {
+               BT_LOGW("Invalid parameter: invalid mantissa size: "
+                       "addr=%p, mant-size=%u", ft, mantissa_digits);
+               ret = -1;
+               goto end;
+       }
+
+       flt_ft->mant_dig = mantissa_digits;
+       BT_LOGV("Set floating point number field type's mantissa size: addr=%p, "
+               "mant-size=%u", ft, mantissa_digits);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_replace_field(
+               struct bt_ctf_field_type_common *ft,
+               const char *field_name,
+               struct bt_ctf_field_type_common *field_type)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+       GQuark name_quark;
+       uint64_t i;
+
+       BT_ASSERT(ft);
+       BT_ASSERT(field_name);
+       BT_ASSERT(field_type);
+       BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_STRUCT);
+       name_quark = g_quark_from_string(field_name);
+
+       for (i = 0; i < struct_ft->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i);
+
+               if (field->name == name_quark) {
+                       bt_ctf_object_put_ref(field->type);
+                       field->type = bt_ctf_object_get_ref(field_type);
+               }
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_add_field(struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *field_type,
+               const char *field_name)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       /*
+        * TODO: check that `field_type` does not contain `type`,
+        *       recursively.
+        */
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!field_name) {
+               BT_LOGW_STR("Invalid parameter: field name is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               BT_LOGW("Invalid parameter: field type is not a structure field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (ft == field_type) {
+               BT_LOGW("Invalid parameter: structure field type and field type to add are the same: "
+                       "addr=%p", ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (add_structure_variant_member(struct_ft->fields,
+                       struct_ft->field_name_to_index, field_type, field_name,
+                       false)) {
+               BT_LOGW("Cannot add field to structure field type: "
+                       "struct-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"",
+                       ft, field_type, field_name);
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Added structure field type field: struct-ft-addr=%p, "
+               "field-ft-addr=%p, field-name=\"%s\"", ft,
+               field_type, field_name);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_structure_get_field_count(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
+               "Field type");
+       return (int64_t) struct_ft->fields->len;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_borrow_field_by_index(
+               struct bt_ctf_field_type_common *ft,
+               const char **field_name,
+               struct bt_ctf_field_type_common **field_type, uint64_t index)
+{
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common_structure_field *field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
+               "Field type");
+       BT_CTF_ASSERT_PRE(index < struct_ft->fields->len,
+               "Index is out of bounds: index=%" PRIu64 ", "
+               "count=%u, ft-addr=%p",
+               index, struct_ft->fields->len, ft);
+       field = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(struct_ft, index);
+
+       if (field_type) {
+               *field_type = field->type;
+       }
+
+       if (field_name) {
+               *field_name = g_quark_to_string(field->name);
+               BT_ASSERT(*field_name);
+       }
+
+       return 0;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       size_t index;
+       GQuark name_quark;
+       struct bt_ctf_field_type_common_structure_field *field;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
+               "Field type");
+       name_quark = g_quark_try_string(name);
+       if (!name_quark) {
+               BT_LOGV("No such structure field type field name: "
+                       "ft-addr=%p, field-name=\"%s\"",
+                       ft, name);
+               goto end;
+       }
+
+       if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index,
+                       GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) {
+               BT_LOGV("No such structure field type field name: "
+                       "ft-addr=%p, field-name=\"%s\"",
+                       ft, name);
+               goto end;
+       }
+
+       field = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, index);
+       field_type = field->type;
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_tag_field_type(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common *tag_ft = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+
+       if (!var_ft->tag_ft) {
+               BT_LOGV("Variant field type has no tag field type: "
+                       "addr=%p", ft);
+               goto end;
+       }
+
+       tag_ft = BT_CTF_TO_COMMON(var_ft->tag_ft);
+
+end:
+       return tag_ft;
+}
+
+BT_HIDDEN
+const char *bt_ctf_field_type_common_variant_get_tag_name(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       const char *tag_name = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+
+       if (var_ft->tag_name->len == 0) {
+               BT_LOGV("Variant field type has no tag field name: "
+                       "addr=%p", ft);
+               goto end;
+       }
+
+       tag_name = var_ft->tag_name->str;
+
+end:
+       return tag_name;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_set_tag_name(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
+               BT_LOGW("Invalid parameter: field type is not a variant field type: "
+                       "addr=%p, ft-id=%s", ft, bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_identifier_is_valid(name)) {
+               BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: "
+                       "variant-ft-addr=%p, tag-field-name=\"%s\"",
+                       ft, name);
+               ret = -1;
+               goto end;
+       }
+
+       g_string_assign(var_ft->tag_name, name);
+       BT_LOGV("Set variant field type's tag field name: addr=%p, "
+               "tag-field-name=\"%s\"", ft, name);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_add_field(struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *field_type,
+               const char *field_name)
+{
+       size_t i;
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       GQuark field_name_quark = g_quark_from_string(field_name);
+
+       /*
+        * TODO: check that `field_type` does not contain `type`,
+        *       recursively.
+        */
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
+               BT_LOGW("Invalid parameter: field type is not a variant field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (ft == field_type) {
+               BT_LOGW("Invalid parameter: variant field type and field type to add are the same: "
+                       "addr=%p", ft);
+               ret = -1;
+               goto end;
+       }
+
+       /* The user has explicitly provided a tag; validate against it. */
+       if (var_ft->tag_ft) {
+               int name_found = 0;
+
+               /* Make sure this name is present in the enum tag */
+               for (i = 0; i < var_ft->tag_ft->entries->len; i++) {
+                       struct bt_ctf_enumeration_mapping *mapping =
+                               g_ptr_array_index(var_ft->tag_ft->entries, i);
+
+                       if (mapping->string == field_name_quark) {
+                               name_found = 1;
+                               break;
+                       }
+               }
+
+               if (!name_found) {
+                       /* Validation failed */
+                       BT_LOGW("Invalid parameter: field name does not name a tag field type's mapping: "
+                               "variant-ft-addr=%p, tag-ft-addr=%p, "
+                               "tag-field-name=\"%s\""
+                               "field-ft-addr=%p, field-name=\"%s\"",
+                               ft, var_ft->tag_ft, var_ft->tag_name->str,
+                               field_type, field_name);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       if (add_structure_variant_member(var_ft->choices,
+                       var_ft->choice_name_to_index, field_type,
+                       field_name, true)) {
+               BT_LOGW("Cannot add field to variant field type: "
+                       "variant-ft-addr=%p, field-ft-addr=%p, field-name=\"%s\"",
+                       ft, field_type, field_name);
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Added variant field type field: variant-ft-addr=%p, "
+               "field-ft-addr=%p, field-name=\"%s\"", ft,
+               field_type, field_name);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_by_name(
+               struct bt_ctf_field_type_common *ft,
+               const char *field_name)
+{
+       size_t index;
+       GQuark name_quark;
+       struct bt_ctf_field_type_common_variant_choice *choice;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(field_name, "Name");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       name_quark = g_quark_try_string(field_name);
+       if (!name_quark) {
+               BT_LOGV("No such variant field type field name: "
+                       "ft-addr=%p, field-name=\"%s\"",
+                       ft, field_name);
+               goto end;
+       }
+
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
+                       GUINT_TO_POINTER(name_quark), NULL, (gpointer *) &index)) {
+               BT_LOGV("No such variant field type field name: "
+                       "ft-addr=%p, field-name=\"%s\"",
+                       ft, field_name);
+               goto end;
+       }
+
+       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index);
+       field_type = choice->type;
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_variant_get_field_count(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Variant field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       return (int64_t) var_ft->choices->len;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_borrow_field_by_index(
+               struct bt_ctf_field_type_common *ft,
+               const char **field_name,
+               struct bt_ctf_field_type_common **field_type, uint64_t index)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common_variant_choice *choice;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       BT_CTF_ASSERT_PRE(index < var_ft->choices->len,
+               "Index is out of bounds: index=%" PRIu64 ", "
+               "count=%u, ft-addr=%p",
+               index, var_ft->choices->len, ft);
+       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, index);
+
+       if (field_type) {
+               *field_type = choice->type;
+       }
+
+       if (field_name) {
+               *field_name = g_quark_to_string(choice->name);
+               BT_ASSERT(*field_name);
+       }
+
+       return 0;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_variant_find_choice_index(
+               struct bt_ctf_field_type_common *ft, uint64_t uval,
+               bool is_signed)
+{
+       int64_t ret;
+       uint64_t i;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_ASSERT(ft);
+       BT_ASSERT(ft->id == BT_CTF_FIELD_TYPE_ID_VARIANT);
+
+       if (bt_ctf_field_type_common_variant_update_choices(ft)) {
+               ret = INT64_C(-1);
+               goto end;
+       }
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               uint64_t range_i;
+               struct bt_ctf_field_type_common_variant_choice *choice =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft, i);
+
+               for (range_i = 0; range_i < choice->ranges->len; range_i++) {
+                       struct bt_ctf_field_type_common_variant_choice_range *range =
+                               &g_array_index(
+                                       choice->ranges,
+                                       struct bt_ctf_field_type_common_variant_choice_range,
+                                       range_i);
+
+                       if (is_signed) {
+                               int64_t tag_ival = (int64_t) uval;
+
+                               if (tag_ival >= range->lower.i &&
+                                               tag_ival <= range->upper.i) {
+                                       goto found;
+                               }
+                       } else {
+                               if (uval >= range->lower.u &&
+                                               uval <= range->upper.u) {
+                                       goto found;
+                               }
+                       }
+               }
+       }
+
+       /* Range not found */
+       ret = INT64_C(-1);
+       goto end;
+
+found:
+       ret = (int64_t) i;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_array_borrow_element_field_type(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY,
+               "Field type");
+       BT_ASSERT(array_ft && array_ft->element_ft);
+       return array_ft->element_ft;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_set_element_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: array field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!element_ft) {
+               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_ARRAY) {
+               BT_LOGW("Invalid parameter: field type is not an array field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (array_ft->element_ft) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(array_ft->element_ft);
+       }
+
+       array_ft->element_ft = bt_ctf_object_get_ref(element_ft);
+       BT_LOGV("Set array field type's element field type: array-ft-addr=%p, "
+               "element-ft-addr=%p", ft, element_ft);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_array_get_length(struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_ARRAY,
+               "Field type");
+       return (int64_t) array_ft->length;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *bt_ctf_field_type_common_sequence_borrow_element_field_type(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+               "Field type");
+       return seq_ft->element_ft;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_set_element_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: sequence field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!element_ft) {
+               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
+               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (seq_ft->element_ft) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(seq_ft->element_ft);
+       }
+
+       seq_ft->element_ft = element_ft;
+       bt_ctf_object_get_ref(seq_ft->element_ft);
+       BT_LOGV("Set sequence field type's element field type: sequence-ft-addr=%p, "
+               "element-ft-addr=%p", ft, element_ft);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+const char *bt_ctf_field_type_common_sequence_get_length_field_name(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+               "Field type");
+       return seq_ft->length_field_name ?
+               seq_ft->length_field_name->str : NULL;
+}
+
+BT_HIDDEN
+enum bt_ctf_string_encoding bt_ctf_field_type_common_string_get_encoding(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRING,
+               "Field type");
+       return string_ft->encoding;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_string_set_encoding(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_string_encoding encoding)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_string *string_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_STRING) {
+               BT_LOGW("Invalid parameter: field type is not a string field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       if (encoding != BT_CTF_STRING_ENCODING_UTF8 &&
+                       encoding != BT_CTF_STRING_ENCODING_ASCII) {
+               BT_LOGW("Invalid parameter: unknown string encoding: "
+                       "addr=%p, encoding=%d", ft, encoding);
+               ret = -1;
+               goto end;
+       }
+
+       string_ft->encoding = encoding;
+       BT_LOGV("Set string field type's encoding: addr=%p, encoding=%s",
+               ft, bt_ctf_string_encoding_string(encoding));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_get_alignment(struct bt_ctf_field_type_common *ft)
+{
+       int ret;
+       enum bt_ctf_field_type_id type_id;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+
+       if (ft->frozen) {
+               ret = (int) ft->alignment;
+               goto end;
+       }
+
+       type_id = bt_ctf_field_type_common_get_type_id(ft);
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct bt_ctf_field_type_common *element_ft =
+                       bt_ctf_field_type_common_sequence_borrow_element_field_type(ft);
+
+               BT_ASSERT(element_ft);
+               ret = bt_ctf_field_type_common_get_alignment(element_ft);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       {
+               struct bt_ctf_field_type_common *element_ft =
+                       bt_ctf_field_type_common_array_borrow_element_field_type(ft);
+
+               BT_ASSERT(element_ft);
+               ret = bt_ctf_field_type_common_get_alignment(element_ft);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               int64_t i, element_count;
+
+               element_count = bt_ctf_field_type_common_structure_get_field_count(
+                       ft);
+               BT_ASSERT(element_count >= 0);
+
+               for (i = 0; i < element_count; i++) {
+                       struct bt_ctf_field_type_common *field = NULL;
+                       int field_alignment;
+
+                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               ft, NULL, &field, i);
+                       BT_ASSERT(ret == 0);
+                       BT_ASSERT(field);
+                       field_alignment = bt_ctf_field_type_common_get_alignment(
+                               field);
+                       if (field_alignment < 0) {
+                               ret = field_alignment;
+                               goto end;
+                       }
+
+                       ft->alignment = MAX(field_alignment, ft->alignment);
+               }
+               ret = (int) ft->alignment;
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_UNKNOWN:
+               BT_LOGW("Invalid parameter: unknown field type ID: "
+                       "addr=%p, ft-id=%d", ft, type_id);
+               ret = -1;
+               break;
+       default:
+               ret = (int) ft->alignment;
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static inline
+int is_power_of_two(unsigned int value)
+{
+       return ((value & (value - 1)) == 0) && value > 0;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_set_alignment(struct bt_ctf_field_type_common *ft,
+               unsigned int alignment)
+{
+       int ret = 0;
+       enum bt_ctf_field_type_id type_id;
+
+       /* Alignment must be a power of two */
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (!is_power_of_two(alignment)) {
+               BT_LOGW("Invalid parameter: alignment is not a power of two: "
+                       "addr=%p, align=%u", ft, alignment);
+               ret = -1;
+               goto end;
+       }
+
+       type_id = bt_ctf_field_type_common_get_type_id(ft);
+       if (type_id == BT_CTF_FIELD_TYPE_ID_UNKNOWN) {
+               BT_LOGW("Invalid parameter: unknown field type ID: "
+                       "addr=%p, ft-id=%d", ft, type_id);
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id == BT_CTF_FIELD_TYPE_ID_STRING && alignment != CHAR_BIT) {
+               BT_LOGW("Invalid parameter: alignment must be %u for a string field type: "
+                       "addr=%p, align=%u", CHAR_BIT, ft, alignment);
+               ret = -1;
+               goto end;
+       }
+
+       if (type_id == BT_CTF_FIELD_TYPE_ID_VARIANT ||
+                       type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE ||
+                       type_id == BT_CTF_FIELD_TYPE_ID_ARRAY) {
+               /* Setting an alignment on these types makes no sense */
+               BT_LOGW("Invalid parameter: cannot set the alignment of this field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       ft->alignment = alignment;
+       ret = 0;
+       BT_LOGV("Set field type's alignment: addr=%p, align=%u",
+               ft, alignment);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_byte_order bt_ctf_field_type_common_get_byte_order(
+               struct bt_ctf_field_type_common *ft)
+{
+       enum bt_ctf_byte_order ret = BT_CTF_BYTE_ORDER_UNKNOWN;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_INTEGER:
+       {
+               struct bt_ctf_field_type_common_integer *integer =
+                       BT_CTF_FROM_COMMON(ft);
+
+               ret = integer->user_byte_order;
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ENUM:
+       {
+               struct bt_ctf_field_type_common_enumeration *enum_ft =
+                       BT_CTF_FROM_COMMON(ft);
+
+               ret = bt_ctf_field_type_common_get_byte_order(
+                       BT_CTF_TO_COMMON(enum_ft->container_ft));
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_FLOAT:
+       {
+               struct bt_ctf_field_type_common_floating_point *floating_point =
+                       BT_CTF_FROM_COMMON(ft);
+               ret = floating_point->user_byte_order;
+               break;
+       }
+       default:
+               BT_LOGW("Invalid parameter: cannot get the byte order of this field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               goto end;
+       }
+
+       BT_ASSERT(ret == BT_CTF_BYTE_ORDER_NATIVE ||
+               ret == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
+               ret == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
+               ret == BT_CTF_BYTE_ORDER_NETWORK);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_set_byte_order(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       int ret = 0;
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->frozen) {
+               BT_LOGW("Invalid parameter: field type is frozen: addr=%p",
+                       ft);
+               ret = -1;
+               goto end;
+       }
+
+       if (byte_order != BT_CTF_BYTE_ORDER_NATIVE &&
+                       byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
+                       byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
+                       byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
+               BT_LOGW("Invalid parameter: invalid byte order: "
+                       "addr=%p, bo=%s", ft,
+                       bt_ctf_byte_order_string(byte_order));
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->methods->set_byte_order) {
+               ft->methods->set_byte_order(ft, byte_order);
+       }
+
+       BT_LOGV("Set field type's byte order: addr=%p, bo=%s",
+               ft, bt_ctf_byte_order_string(byte_order));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_field_type_id bt_ctf_field_type_common_get_type_id(
+               struct bt_ctf_field_type_common *ft)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       return ft->id;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_freeze(struct bt_ctf_field_type_common *ft)
+{
+       if (!ft || ft->frozen) {
+               return;
+       }
+
+       BT_ASSERT(ft->methods->freeze);
+       ft->methods->freeze(ft);
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_signed(
+               struct bt_ctf_field_type_common_variant *var_ft,
+               int64_t tag_value)
+{
+       struct bt_ctf_field_type_common *field_type = NULL;
+       GQuark field_name_quark;
+       gpointer index;
+       struct bt_ctf_field_type_common_variant_choice *choice;
+       struct range_overlap_query query = {
+               .range_start._signed = tag_value,
+               .range_end._signed = tag_value,
+               .mapping_name = 0,
+               .overlaps = 0,
+       };
+
+       g_ptr_array_foreach(var_ft->tag_ft->entries, check_ranges_overlap,
+               &query);
+       if (!query.overlaps) {
+               goto end;
+       }
+
+       field_name_quark = query.mapping_name;
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
+                       GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
+               goto end;
+       }
+
+       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
+               (size_t) index);
+       field_type = choice->type;
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_unsigned(
+               struct bt_ctf_field_type_common_variant *var_ft,
+               uint64_t tag_value)
+{
+       struct bt_ctf_field_type_common *field_type = NULL;
+       GQuark field_name_quark;
+       gpointer index;
+       struct bt_ctf_field_type_common_variant_choice *choice;
+       struct range_overlap_query query = {
+               .range_start._unsigned = tag_value,
+               .range_end._unsigned = tag_value,
+               .mapping_name = 0,
+               .overlaps = 0,
+       };
+
+       g_ptr_array_foreach(var_ft->tag_ft->entries,
+               check_ranges_overlap_unsigned, &query);
+       if (!query.overlaps) {
+               goto end;
+       }
+
+       field_name_quark = query.mapping_name;
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
+               GUINT_TO_POINTER(field_name_quark), NULL, &index)) {
+               goto end;
+       }
+
+       choice = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft,
+               (size_t) index);
+       field_type = choice->type;
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *bt_ctf_field_type_common_copy(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common *ft_copy = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_ASSERT(ft->methods->copy);
+       ft_copy = ft->methods->copy(ft);
+       if (!ft_copy) {
+               BT_LOGE_STR("Cannot copy field type.");
+               goto end;
+       }
+
+       ft_copy->alignment = ft->alignment;
+
+end:
+       return ft_copy;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_get_field_name_index(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       int ret;
+       size_t index;
+       GQuark name_quark;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_STRUCT,
+               "Field type");
+
+       name_quark = g_quark_try_string(name);
+       if (!name_quark) {
+               BT_LOGV("No such structure field type field name: "
+                       "ft-addr=%p, field-name=\"%s\"",
+                       ft, name);
+               ret = -1;
+               goto end;
+       }
+
+       if (!g_hash_table_lookup_extended(struct_ft->field_name_to_index,
+                       GUINT_TO_POINTER(name_quark),
+                       NULL, (gpointer *) &index)) {
+               BT_LOGV("No such structure field type field name: "
+                       "ft-addr=%p, field-name=\"%s\"",
+                       ft, name);
+               ret = -1;
+               goto end;
+       }
+
+       ret = (int) index;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_get_field_name_index(
+               struct bt_ctf_field_type_common *ft, const char *name)
+{
+       int ret;
+       size_t index;
+       GQuark name_quark;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       name_quark = g_quark_try_string(name);
+       if (!name_quark) {
+               BT_LOGV("No such variant field type field name: "
+                       "ft-addr=%p, field-name=\"%s\"",
+                       ft, name);
+               ret = -1;
+               goto end;
+       }
+
+       if (!g_hash_table_lookup_extended(var_ft->choice_name_to_index,
+                       GUINT_TO_POINTER(name_quark),
+                       NULL, (gpointer *) &index)) {
+               BT_LOGV("No such variant field type field name: "
+                       "ft-addr=%p, field-name=\"%s\"",
+                       ft, name);
+               ret = -1;
+               goto end;
+       }
+
+       ret = (int) index;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_set_length_field_path(
+               struct bt_ctf_field_type_common *ft, struct bt_ctf_field_path *path)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
+               BT_LOGW("Invalid parameter: field type is not a sequence field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_get_ref(path);
+       BT_CTF_OBJECT_MOVE_REF(seq_ft->length_field_path, path);
+       BT_LOGV("Set sequence field type's length field path: ft-addr=%p, "
+               "field-path-addr=%p", ft, path);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_set_tag_field_path(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_path *path)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft->id != BT_CTF_FIELD_TYPE_ID_VARIANT) {
+               BT_LOGW("Invalid parameter: field type is not a variant field type: "
+                       "addr=%p, ft-id=%s", ft,
+                       bt_ctf_field_type_id_string(ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_get_ref(path);
+       BT_CTF_OBJECT_MOVE_REF(var_ft->tag_field_path, path);
+       BT_LOGV("Set variant field type's tag field path: ft-addr=%p, "
+               "field-path-addr=%p", ft, path);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_set_tag_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *tag_ft)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       if (!ft) {
+               BT_LOGW_STR("Invalid parameter: variant field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!tag_ft) {
+               BT_LOGW_STR("Invalid parameter: tag field type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (tag_ft->id != BT_CTF_FIELD_TYPE_ID_ENUM) {
+               BT_LOGW("Invalid parameter: tag field type is not an enumeration field type: "
+                       "addr=%p, ft-id=%s", tag_ft,
+                       bt_ctf_field_type_id_string(tag_ft->id));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(var_ft->tag_ft);
+       var_ft->tag_ft = bt_ctf_object_get_ref(tag_ft);
+       BT_LOGV("Set variant field type's tag field type: variant-ft-addr=%p, "
+               "tag-ft-addr=%p", ft, tag_ft);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_generic_freeze(struct bt_ctf_field_type_common *ft)
+{
+       ft->frozen = 1;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_LOGD("Freezing enumeration field type object: addr=%p", ft);
+       bt_ctf_field_type_common_enumeration_set_range_overlap(enum_ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+       BT_LOGD("Freezing enumeration field type object's container field type: int-ft-addr=%p",
+               enum_ft->container_ft);
+       bt_ctf_field_type_common_freeze(BT_CTF_TO_COMMON(enum_ft->container_ft));
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+       uint64_t i;
+
+       /* Cache the alignment */
+       BT_LOGD("Freezing structure field type object: addr=%p", ft);
+       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+
+       for (i = 0; i < struct_ft->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(ft, i);
+
+               BT_LOGD("Freezing structure field type field: "
+                       "ft-addr=%p, name=\"%s\"",
+                       field->type, g_quark_to_string(field->name));
+               bt_ctf_field_type_common_freeze(field->type);
+       }
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_update_choices(struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       uint64_t i;
+       int ret = 0;
+       bool is_signed;
+
+       if (ft->frozen && var_ft->choices_up_to_date) {
+               goto end;
+       }
+
+       BT_ASSERT(var_ft->tag_ft);
+       is_signed = !!var_ft->tag_ft->container_ft->is_signed;
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_ctf_field_type_common_variant_choice *choice =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i);
+               const char *choice_name = g_quark_to_string(choice->name);
+               struct bt_ctf_field_type_enumeration_mapping_iterator *iter =
+                       bt_ctf_field_type_common_enumeration_find_mappings_by_name(
+                               BT_CTF_TO_COMMON(var_ft->tag_ft), choice_name);
+
+               if (!iter) {
+                       ret = -1;
+                       goto end;
+               }
+
+               BT_ASSERT(choice->ranges);
+               g_array_set_size(choice->ranges, 0);
+
+               while (bt_ctf_field_type_enumeration_mapping_iterator_next(iter) == 0) {
+                       struct bt_ctf_field_type_common_variant_choice_range range;
+
+                       if (is_signed) {
+                               ret = bt_ctf_field_type_enumeration_mapping_iterator_signed_get(
+                                       iter, NULL,
+                                       &range.lower.i, &range.upper.i);
+                       } else {
+                               ret = bt_ctf_field_type_enumeration_mapping_iterator_unsigned_get(
+                                       iter, NULL,
+                                       &range.lower.u, &range.upper.u);
+                       }
+
+                       BT_ASSERT(ret == 0);
+                       g_array_append_val(choice->ranges, range);
+               }
+
+               bt_ctf_object_put_ref(iter);
+       }
+
+       var_ft->choices_up_to_date = true;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+       uint64_t i;
+
+       BT_LOGD("Freezing variant field type object: addr=%p", ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_ctf_field_type_common_variant_choice *choice =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(ft, i);
+
+               BT_LOGD("Freezing variant field type member: "
+                       "ft-addr=%p, name=\"%s\"",
+                       choice->type, g_quark_to_string(choice->name));
+               bt_ctf_field_type_common_freeze(choice->type);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       /* Cache the alignment */
+       BT_LOGD("Freezing array field type object: addr=%p", ft);
+       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+       BT_LOGD("Freezing array field type object's element field type: element-ft-addr=%p",
+               array_ft->element_ft);
+       bt_ctf_field_type_common_freeze(array_ft->element_ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_freeze_recursive(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       /* Cache the alignment */
+       BT_LOGD("Freezing sequence field type object: addr=%p", ft);
+       ft->alignment = bt_ctf_field_type_common_get_alignment(ft);
+       bt_ctf_field_type_common_generic_freeze(ft);
+       BT_LOGD("Freezing sequence field type object's element field type: element-ft-addr=%p",
+               seq_ft->element_ft);
+       bt_ctf_field_type_common_freeze(seq_ft->element_ft);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_set_byte_order(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = BT_CTF_FROM_COMMON(ft);
+
+       int_ft->user_byte_order = byte_order;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = BT_CTF_FROM_COMMON(ft);
+
+       bt_ctf_field_type_common_set_byte_order(BT_CTF_TO_COMMON(enum_ft->container_ft),
+               byte_order);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_set_byte_order(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+
+       flt_ft->user_byte_order = byte_order;
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       int i;
+       struct bt_ctf_field_type_common_structure *struct_ft = BT_CTF_FROM_COMMON(ft);
+
+       for (i = 0; i < struct_ft->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               struct_ft, i);
+               struct bt_ctf_field_type_common *field_type = field->type;
+
+               bt_ctf_field_type_common_set_byte_order(field_type, byte_order);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       int i;
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_ctf_field_type_common_variant_choice *choice =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft, i);
+               struct bt_ctf_field_type_common *field_type = choice->type;
+
+               bt_ctf_field_type_common_set_byte_order(field_type, byte_order);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_array *array_ft = BT_CTF_FROM_COMMON(ft);
+
+       bt_ctf_field_type_common_set_byte_order(array_ft->element_ft, byte_order);
+}
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       bt_ctf_field_type_common_set_byte_order(seq_ft->element_ft, byte_order);
+}
+
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       struct bt_ctf_field_type_common_integer *int_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_integer *int_ft_b = BT_CTF_FROM_COMMON(ft_b);
+
+       /* Length */
+       if (int_ft_a->size != int_ft_b->size) {
+               BT_LOGV("Integer field types differ: different sizes: "
+                       "ft-a-size=%u, ft-b-size=%u",
+                       int_ft_a->size, int_ft_b->size);
+               goto end;
+       }
+
+       /* Byte order */
+       if (int_ft_a->user_byte_order != int_ft_b->user_byte_order) {
+               BT_LOGV("Integer field types differ: different byte orders: "
+                       "ft-a-bo=%s, ft-b-bo=%s",
+                       bt_ctf_byte_order_string(int_ft_a->user_byte_order),
+                       bt_ctf_byte_order_string(int_ft_b->user_byte_order));
+               goto end;
+       }
+
+       /* Signedness */
+       if (int_ft_a->is_signed != int_ft_b->is_signed) {
+               BT_LOGV("Integer field types differ: different signedness: "
+                       "ft-a-is-signed=%d, ft-b-is-signed=%d",
+                       int_ft_a->is_signed,
+                       int_ft_b->is_signed);
+               goto end;
+       }
+
+       /* Base */
+       if (int_ft_a->base != int_ft_b->base) {
+               BT_LOGV("Integer field types differ: different bases: "
+                       "ft-a-base=%s, ft-b-base=%s",
+                       bt_ctf_integer_base_string(int_ft_a->base),
+                       bt_ctf_integer_base_string(int_ft_b->base));
+               goto end;
+       }
+
+       /* Encoding */
+       if (int_ft_a->encoding != int_ft_b->encoding) {
+               BT_LOGV("Integer field types differ: different encodings: "
+                       "ft-a-encoding=%s, ft-b-encoding=%s",
+                       bt_ctf_string_encoding_string(int_ft_a->encoding),
+                       bt_ctf_string_encoding_string(int_ft_b->encoding));
+               goto end;
+       }
+
+       /* Mapped clock class */
+       if (int_ft_a->mapped_clock_class) {
+               if (!int_ft_b->mapped_clock_class) {
+                       BT_LOGV_STR("Integer field types differ: field type A "
+                               "has a mapped clock class, but field type B "
+                               "does not.");
+                       goto end;
+               }
+
+               if (bt_ctf_clock_class_compare(int_ft_a->mapped_clock_class,
+                               int_ft_b->mapped_clock_class) != 0) {
+                       BT_LOGV_STR("Integer field types differ: different "
+                               "mapped clock classes.");
+               }
+       } else {
+               if (int_ft_b->mapped_clock_class) {
+                       BT_LOGV_STR("Integer field types differ: field type A "
+                               "has no description, but field type B has one.");
+                       goto end;
+               }
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_compare(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       struct bt_ctf_field_type_common_floating_point *flt_ft_a =
+               BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_floating_point *flt_ft_b =
+               BT_CTF_FROM_COMMON(ft_b);
+
+       /* Byte order */
+       if (flt_ft_a->user_byte_order != flt_ft_b->user_byte_order) {
+               BT_LOGV("Floating point number field types differ: different byte orders: "
+                       "ft-a-bo=%s, ft-b-bo=%s",
+                       bt_ctf_byte_order_string(flt_ft_a->user_byte_order),
+                       bt_ctf_byte_order_string(flt_ft_b->user_byte_order));
+               goto end;
+       }
+
+       /* Exponent length */
+       if (flt_ft_a->exp_dig != flt_ft_b->exp_dig) {
+               BT_LOGV("Floating point number field types differ: different exponent sizes: "
+                       "ft-a-exp-size=%u, ft-b-exp-size=%u",
+                       flt_ft_a->exp_dig, flt_ft_b->exp_dig);
+               goto end;
+       }
+
+       /* Mantissa length */
+       if (flt_ft_a->mant_dig != flt_ft_b->mant_dig) {
+               BT_LOGV("Floating point number field types differ: different mantissa sizes: "
+                       "ft-a-mant-size=%u, ft-b-mant-size=%u",
+                       flt_ft_a->mant_dig, flt_ft_b->mant_dig);
+               goto end;
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static
+int compare_enumeration_mappings(struct bt_ctf_enumeration_mapping *mapping_a,
+               struct bt_ctf_enumeration_mapping *mapping_b)
+{
+       int ret = 1;
+
+       /* Label */
+       if (mapping_a->string != mapping_b->string) {
+               BT_LOGV("Enumeration field type mappings differ: different names: "
+                       "mapping-a-name=\"%s\", mapping-b-name=\"%s\"",
+                       g_quark_to_string(mapping_a->string),
+                       g_quark_to_string(mapping_b->string));
+               goto end;
+       }
+
+       /* Range start */
+       if (mapping_a->range_start._unsigned !=
+                       mapping_b->range_start._unsigned) {
+               BT_LOGV("Enumeration field type mappings differ: different starts of range: "
+                       "mapping-a-range-start-unsigned=%" PRIu64 ", "
+                       "mapping-b-range-start-unsigned=%" PRIu64,
+                       mapping_a->range_start._unsigned,
+                       mapping_b->range_start._unsigned);
+               goto end;
+       }
+
+       /* Range end */
+       if (mapping_a->range_end._unsigned !=
+                       mapping_b->range_end._unsigned) {
+               BT_LOGV("Enumeration field type mappings differ: different ends of range: "
+                       "mapping-a-range-end-unsigned=%" PRIu64 ", "
+                       "mapping-b-range-end-unsigned=%" PRIu64,
+                       mapping_a->range_end._unsigned,
+                       mapping_b->range_end._unsigned);
+               goto end;
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       int i;
+       struct bt_ctf_field_type_common_enumeration *enum_ft_a =
+               BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_enumeration *enum_ft_b =
+               BT_CTF_FROM_COMMON(ft_b);
+
+       /* Container field type */
+       ret = bt_ctf_field_type_common_compare(
+               BT_CTF_TO_COMMON(enum_ft_a->container_ft),
+               BT_CTF_TO_COMMON(enum_ft_b->container_ft));
+       if (ret) {
+               BT_LOGV("Enumeration field types differ: different container field types: "
+                       "ft-a-container-ft-addr=%p, ft-b-container-ft-addr=%p",
+                       enum_ft_a->container_ft, enum_ft_b->container_ft);
+               goto end;
+       }
+
+       ret = 1;
+
+       /* Entries */
+       if (enum_ft_a->entries->len != enum_ft_b->entries->len) {
+               goto end;
+       }
+
+       for (i = 0; i < enum_ft_a->entries->len; ++i) {
+               struct bt_ctf_enumeration_mapping *mapping_a =
+                       g_ptr_array_index(enum_ft_a->entries, i);
+               struct bt_ctf_enumeration_mapping *mapping_b =
+                       g_ptr_array_index(enum_ft_b->entries, i);
+
+               if (compare_enumeration_mappings(mapping_a, mapping_b)) {
+                       BT_LOGV("Enumeration field types differ: different mappings: "
+                               "ft-a-mapping-addr=%p, ft-b-mapping-addr=%p, "
+                               "ft-a-mapping-name=\"%s\", ft-b-mapping-name=\"%s\"",
+                               mapping_a, mapping_b,
+                               g_quark_to_string(mapping_a->string),
+                               g_quark_to_string(mapping_b->string));
+                       goto end;
+               }
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_string_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       struct bt_ctf_field_type_common_string *string_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_string *string_ft_b = BT_CTF_FROM_COMMON(ft_b);
+
+       /* Encoding */
+       if (string_ft_a->encoding != string_ft_b->encoding) {
+               BT_LOGV("String field types differ: different encodings: "
+                       "ft-a-encoding=%s, ft-b-encoding=%s",
+                       bt_ctf_string_encoding_string(string_ft_a->encoding),
+                       bt_ctf_string_encoding_string(string_ft_b->encoding));
+               goto end;
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static
+int compare_structure_variant_members(
+               struct bt_ctf_field_type_common *member_a_ft,
+               struct bt_ctf_field_type_common *member_b_ft,
+               GQuark member_a_name, GQuark member_b_name)
+{
+       int ret = 1;
+
+       /* Label */
+       if (member_a_name != member_b_name) {
+               BT_LOGV("Structure/variant field type fields differ: different names: "
+                       "field-a-name=%s, field-b-name=%s",
+                       g_quark_to_string(member_a_name),
+                       g_quark_to_string(member_b_name));
+               goto end;
+       }
+
+       /* Type */
+       ret = bt_ctf_field_type_common_compare(member_a_ft, member_b_ft);
+       if (ret == 1) {
+               BT_LOGV("Structure/variant field type fields differ: different field types: "
+                       "field-name=\"%s\", field-a-ft-addr=%p, field-b-ft-addr=%p",
+                       g_quark_to_string(member_a_name),
+                       member_a_ft, member_b_ft);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       int i;
+       struct bt_ctf_field_type_common_structure *struct_ft_a =
+               BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_structure *struct_ft_b =
+               BT_CTF_FROM_COMMON(ft_b);
+
+       /* Alignment */
+       if (bt_ctf_field_type_common_get_alignment(ft_a) !=
+                       bt_ctf_field_type_common_get_alignment(ft_b)) {
+               BT_LOGV("Structure field types differ: different alignments: "
+                       "ft-a-align=%u, ft-b-align=%u",
+                       bt_ctf_field_type_common_get_alignment(ft_a),
+                       bt_ctf_field_type_common_get_alignment(ft_b));
+               goto end;
+       }
+
+       /* Fields */
+       if (struct_ft_a->fields->len != struct_ft_b->fields->len) {
+               BT_LOGV("Structure field types differ: different field counts: "
+                       "ft-a-field-count=%u, ft-b-field-count=%u",
+                       struct_ft_a->fields->len, struct_ft_b->fields->len);
+               goto end;
+       }
+
+       for (i = 0; i < struct_ft_a->fields->len; ++i) {
+               struct bt_ctf_field_type_common_structure_field *field_a =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               struct_ft_a, i);
+               struct bt_ctf_field_type_common_structure_field *field_b =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               struct_ft_b, i);
+
+               ret = compare_structure_variant_members(field_a->type,
+                       field_b->type, field_a->name, field_b->name);
+               if (ret) {
+                       /* compare_structure_variant_members() logs what differs */
+                       BT_LOGV_STR("Structure field types differ: different fields.");
+                       goto end;
+               }
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       int i;
+       struct bt_ctf_field_type_common_variant *var_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_variant *var_ft_b = BT_CTF_FROM_COMMON(ft_b);
+
+       /* Tag name */
+       if (strcmp(var_ft_a->tag_name->str, var_ft_b->tag_name->str)) {
+               BT_LOGV("Variant field types differ: different tag field names: "
+                       "ft-a-tag-field-name=\"%s\", ft-b-tag-field-name=\"%s\"",
+                       var_ft_a->tag_name->str, var_ft_b->tag_name->str);
+               goto end;
+       }
+
+       /* Tag type */
+       ret = bt_ctf_field_type_common_compare(BT_CTF_TO_COMMON(var_ft_a->tag_ft),
+               BT_CTF_TO_COMMON(var_ft_b->tag_ft));
+       if (ret) {
+               BT_LOGV("Variant field types differ: different tag field types: "
+                       "ft-a-tag-ft-addr=%p, ft-b-tag-ft-addr=%p",
+                       var_ft_a->tag_ft, var_ft_b->tag_ft);
+               goto end;
+       }
+
+       ret = 1;
+
+       /* Fields */
+       if (var_ft_a->choices->len != var_ft_b->choices->len) {
+               BT_LOGV("Variant field types differ: different field counts: "
+                       "ft-a-field-count=%u, ft-b-field-count=%u",
+                       var_ft_a->choices->len, var_ft_b->choices->len);
+               goto end;
+       }
+
+       for (i = 0; i < var_ft_a->choices->len; ++i) {
+               struct bt_ctf_field_type_common_variant_choice *choice_a =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft_a, i);
+               struct bt_ctf_field_type_common_variant_choice *choice_b =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               var_ft_b, i);
+
+               ret = compare_structure_variant_members(choice_a->type,
+                       choice_b->type, choice_a->name, choice_b->name);
+               if (ret) {
+                       /* compare_structure_variant_members() logs what differs */
+                       BT_LOGV_STR("Variant field types differ: different fields.");
+                       goto end;
+               }
+       }
+
+       /* Equal */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+       struct bt_ctf_field_type_common_array *array_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_array *array_ft_b = BT_CTF_FROM_COMMON(ft_b);
+
+       /* Length */
+       if (array_ft_a->length != array_ft_b->length) {
+               BT_LOGV("Structure field types differ: different lengths: "
+                       "ft-a-length=%u, ft-b-length=%u",
+                       array_ft_a->length, array_ft_b->length);
+               goto end;
+       }
+
+       /* Element type */
+       ret = bt_ctf_field_type_common_compare(array_ft_a->element_ft,
+               array_ft_b->element_ft);
+       if (ret == 1) {
+               BT_LOGV("Array field types differ: different element field types: "
+                       "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p",
+                       array_ft_a->element_ft, array_ft_b->element_ft);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = -1;
+       struct bt_ctf_field_type_common_sequence *seq_ft_a = BT_CTF_FROM_COMMON(ft_a);
+       struct bt_ctf_field_type_common_sequence *seq_ft_b = BT_CTF_FROM_COMMON(ft_b);
+
+       /* Length name */
+       if (strcmp(seq_ft_a->length_field_name->str,
+                       seq_ft_b->length_field_name->str)) {
+               BT_LOGV("Sequence field types differ: different length field names: "
+                       "ft-a-length-field-name=\"%s\", "
+                       "ft-b-length-field-name=\"%s\"",
+                       seq_ft_a->length_field_name->str,
+                       seq_ft_b->length_field_name->str);
+               goto end;
+       }
+
+       /* Element type */
+       ret = bt_ctf_field_type_common_compare(seq_ft_a->element_ft,
+                       seq_ft_b->element_ft);
+       if (ret == 1) {
+               BT_LOGV("Sequence field types differ: different element field types: "
+                       "ft-a-element-ft-addr=%p, ft-b-element-ft-addr=%p",
+                       seq_ft_a->element_ft, seq_ft_b->element_ft);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b)
+{
+       int ret = 1;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft_a, "Field type A");
+       BT_CTF_ASSERT_PRE_NON_NULL(ft_b, "Field type B");
+
+       if (ft_a == ft_b) {
+               /* Same reference: equal (even if both are NULL) */
+               ret = 0;
+               goto end;
+       }
+
+       if (!ft_a) {
+               BT_LOGW_STR("Invalid parameter: field type A is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!ft_b) {
+               BT_LOGW_STR("Invalid parameter: field type B is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (ft_a->id != ft_b->id) {
+               /* Different type IDs */
+               BT_LOGV("Field types differ: different IDs: "
+                       "ft-a-addr=%p, ft-b-addr=%p, "
+                       "ft-a-id=%s, ft-b-id=%s",
+                       ft_a, ft_b,
+                       bt_ctf_field_type_id_string(ft_a->id),
+                       bt_ctf_field_type_id_string(ft_b->id));
+               goto end;
+       }
+
+       if (ft_a->id == BT_CTF_FIELD_TYPE_ID_UNKNOWN) {
+               /* Both have unknown type IDs */
+               BT_LOGW_STR("Invalid parameter: field type IDs are unknown.");
+               goto end;
+       }
+
+       BT_ASSERT(ft_a->methods->compare);
+       ret = ft_a->methods->compare(ft_a, ft_b);
+       if (ret == 1) {
+               BT_LOGV("Field types differ: ft-a-addr=%p, ft-b-addr=%p",
+                       ft_a, ft_b);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_get_field_count(struct bt_ctf_field_type_common *ft)
+{
+       int64_t field_count = -1;
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+               field_count =
+                       bt_ctf_field_type_common_structure_get_field_count(ft);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               field_count =
+                       bt_ctf_field_type_common_variant_get_field_count(ft);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               /*
+                * Array and sequence types always contain a single member
+                * (the element type).
+                */
+               field_count = 1;
+               break;
+       default:
+               break;
+       }
+
+       return field_count;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *bt_ctf_field_type_common_borrow_field_at_index(
+               struct bt_ctf_field_type_common *ft, int index)
+{
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               int ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                       ft, NULL, &field_type, index);
+               if (ret) {
+                       field_type = NULL;
+                       goto end;
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               int ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
+                       ft, NULL, &field_type, index);
+               if (ret) {
+                       field_type = NULL;
+                       goto end;
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+               field_type =
+                       bt_ctf_field_type_common_array_borrow_element_field_type(ft);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               field_type =
+                       bt_ctf_field_type_common_sequence_borrow_element_field_type(ft);
+               break;
+       default:
+               break;
+       }
+
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_get_field_index(struct bt_ctf_field_type_common *ft,
+               const char *name)
+{
+       int field_index = -1;
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+               field_index = bt_ctf_field_type_common_structure_get_field_name_index(
+                       ft, name);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               field_index = bt_ctf_field_type_common_variant_get_field_name_index(
+                       ft, name);
+               break;
+       default:
+               break;
+       }
+
+       return field_index;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_type_common_variant_borrow_tag_field_path(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       return var_ft->tag_field_path;
+}
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_type_common_sequence_borrow_length_field_path(
+               struct bt_ctf_field_type_common *ft)
+{
+       struct bt_ctf_field_type_common_sequence *seq_ft = BT_CTF_FROM_COMMON(ft);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+               "Field type");
+       return seq_ft->length_field_path;
+}
+
+BT_HIDDEN
+int bt_ctf_field_type_common_validate_single_clock_class(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_clock_class **expected_clock_class)
+{
+       int ret = 0;
+
+       if (!ft) {
+               goto end;
+       }
+
+       BT_ASSERT(expected_clock_class);
+
+       switch (ft->id) {
+       case BT_CTF_FIELD_TYPE_ID_INTEGER:
+       {
+               struct bt_ctf_clock_class *mapped_clock_class =
+                       bt_ctf_field_type_common_integer_borrow_mapped_clock_class(ft);
+
+               if (!mapped_clock_class) {
+                       goto end;
+               }
+
+               if (!*expected_clock_class) {
+                       /* Move reference to output parameter */
+                       *expected_clock_class = bt_ctf_object_get_ref(mapped_clock_class);
+                       mapped_clock_class = NULL;
+                       BT_LOGV("Setting expected clock class: "
+                               "expected-clock-class-addr=%p",
+                               *expected_clock_class);
+               } else {
+                       if (mapped_clock_class != *expected_clock_class) {
+                               BT_LOGW("Integer field type is not mapped to "
+                                       "the expected clock class: "
+                                       "mapped-clock-class-addr=%p, "
+                                       "mapped-clock-class-name=\"%s\", "
+                                       "expected-clock-class-addr=%p, "
+                                       "expected-clock-class-name=\"%s\"",
+                                       mapped_clock_class,
+                                       bt_ctf_clock_class_get_name(mapped_clock_class),
+                                       *expected_clock_class,
+                                       bt_ctf_clock_class_get_name(*expected_clock_class));
+                               bt_ctf_object_put_ref(mapped_clock_class);
+                               ret = -1;
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ENUM:
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               struct bt_ctf_field_type_common *sub_ft = NULL;
+
+               switch (ft->id) {
+               case BT_CTF_FIELD_TYPE_ID_ENUM:
+                       sub_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type(
+                               ft);
+                       break;
+               case BT_CTF_FIELD_TYPE_ID_ARRAY:
+                       sub_ft = bt_ctf_field_type_common_array_borrow_element_field_type(
+                               ft);
+                       break;
+               case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+                       sub_ft = bt_ctf_field_type_common_sequence_borrow_element_field_type(
+                               ft);
+                       break;
+               default:
+                       BT_LOGF("Unexpected field type ID: id=%d", ft->id);
+                       abort();
+               }
+
+               BT_ASSERT(sub_ft);
+               ret = bt_ctf_field_type_common_validate_single_clock_class(sub_ft,
+                       expected_clock_class);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               uint64_t i;
+               int64_t count = bt_ctf_field_type_common_structure_get_field_count(
+                       ft);
+
+               for (i = 0; i < count; i++) {
+                       const char *name;
+                       struct bt_ctf_field_type_common *member_type;
+
+                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               ft, &name, &member_type, i);
+                       BT_ASSERT(ret == 0);
+                       ret = bt_ctf_field_type_common_validate_single_clock_class(
+                               member_type, expected_clock_class);
+                       if (ret) {
+                               BT_LOGW("Structure field type's field's type "
+                                       "is not recursively mapped to the "
+                                       "expected clock class: "
+                                       "field-ft-addr=%p, field-name=\"%s\"",
+                                       member_type, name);
+                               goto end;
+                       }
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               uint64_t i;
+               int64_t count = bt_ctf_field_type_common_variant_get_field_count(
+                       ft);
+
+               for (i = 0; i < count; i++) {
+                       const char *name;
+                       struct bt_ctf_field_type_common *member_type;
+
+                       ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
+                               ft, &name, &member_type, i);
+                       BT_ASSERT(ret == 0);
+                       ret = bt_ctf_field_type_common_validate_single_clock_class(
+                               member_type, expected_clock_class);
+                       if (ret) {
+                               BT_LOGW("Variant field type's field's type "
+                                       "is not recursively mapped to the "
+                                       "expected clock class: "
+                                       "field-ft-addr=%p, field-name=\"%s\"",
+                                       member_type, name);
+                               goto end;
+                       }
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_integer_copy(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive(
+               struct bt_ctf_field_type *ft);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive(
+               struct bt_ctf_field_type *type);
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_string_copy(
+               struct bt_ctf_field_type *type);
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_integer_methods = {
+       .freeze = bt_ctf_field_type_common_generic_freeze,
+       .validate = bt_ctf_field_type_common_integer_validate,
+       .set_byte_order = bt_ctf_field_type_common_integer_set_byte_order,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_integer_copy,
+       .compare = bt_ctf_field_type_common_integer_compare,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_floating_point_methods = {
+       .freeze = bt_ctf_field_type_common_generic_freeze,
+       .validate = NULL,
+       .set_byte_order = bt_ctf_field_type_common_floating_point_set_byte_order,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_floating_point_copy,
+       .compare = bt_ctf_field_type_common_floating_point_compare,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_enumeration_methods = {
+       .freeze = bt_ctf_field_type_common_enumeration_freeze_recursive,
+       .validate = bt_ctf_field_type_common_enumeration_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_enumeration_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_enumeration_copy_recursive,
+       .compare = bt_ctf_field_type_common_enumeration_compare_recursive,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_string_methods = {
+       .freeze = bt_ctf_field_type_common_generic_freeze,
+       .validate = NULL,
+       .set_byte_order = NULL,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_string_copy,
+       .compare = bt_ctf_field_type_common_string_compare,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_array_methods = {
+       .freeze = bt_ctf_field_type_common_array_freeze_recursive,
+       .validate = bt_ctf_field_type_common_array_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_array_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_array_copy_recursive,
+       .compare = bt_ctf_field_type_common_array_compare_recursive,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_sequence_methods = {
+       .freeze = bt_ctf_field_type_common_sequence_freeze_recursive,
+       .validate = bt_ctf_field_type_common_sequence_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_sequence_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_sequence_copy_recursive,
+       .compare = bt_ctf_field_type_common_sequence_compare_recursive,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_structure_methods = {
+       .freeze = bt_ctf_field_type_common_structure_freeze_recursive,
+       .validate = bt_ctf_field_type_common_structure_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_structure_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_structure_copy_recursive,
+       .compare = bt_ctf_field_type_common_structure_compare_recursive,
+};
+
+static struct bt_ctf_field_type_common_methods bt_ctf_field_type_variant_methods = {
+       .freeze = bt_ctf_field_type_common_variant_freeze_recursive,
+       .validate = bt_ctf_field_type_common_variant_validate_recursive,
+       .set_byte_order = bt_ctf_field_type_common_variant_set_byte_order_recursive,
+       .copy = (bt_ctf_field_type_common_method_copy)
+               bt_ctf_field_type_variant_copy_recursive,
+       .compare = bt_ctf_field_type_common_variant_compare_recursive,
+};
+
+typedef int (*bt_ctf_field_type_serialize_func)(struct bt_ctf_field_type_common *,
+               struct metadata_context *);
+
+BT_HIDDEN
+int bt_ctf_field_type_serialize_recursive(struct bt_ctf_field_type *type,
+               struct metadata_context *context)
+{
+       int ret;
+       struct bt_ctf_field_type_common *type_common = (void *) type;
+       bt_ctf_field_type_serialize_func serialize_func;
+
+       BT_ASSERT(type);
+       BT_ASSERT(context);
+
+       /* Make sure field type is valid before serializing it */
+       ret = bt_ctf_field_type_common_validate((void *) type);
+       if (ret) {
+               BT_LOGW("Cannot serialize field type's metadata: field type is invalid: "
+                       "addr=%p", type);
+               goto end;
+       }
+
+       serialize_func = type_common->spec.writer.serialize_func;
+       ret = serialize_func((void *) type, context);
+
+end:
+       return ret;
+}
+
+static
+const char *get_encoding_string(enum bt_ctf_string_encoding encoding)
+{
+       const char *encoding_string;
+
+       switch (encoding) {
+       case BT_CTF_STRING_ENCODING_NONE:
+               encoding_string = "none";
+               break;
+       case BT_CTF_STRING_ENCODING_ASCII:
+               encoding_string = "ASCII";
+               break;
+       case BT_CTF_STRING_ENCODING_UTF8:
+               encoding_string = "UTF8";
+               break;
+       default:
+               encoding_string = "unknown";
+               break;
+       }
+
+       return encoding_string;
+}
+
+static
+const char *get_integer_base_string(enum bt_ctf_integer_base base)
+{
+       const char *base_string;
+
+       switch (base) {
+       case BT_CTF_INTEGER_BASE_DECIMAL:
+       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
+               base_string = "decimal";
+               break;
+       case BT_CTF_INTEGER_BASE_HEXADECIMAL:
+               base_string = "hexadecimal";
+               break;
+       case BT_CTF_INTEGER_BASE_OCTAL:
+               base_string = "octal";
+               break;
+       case BT_CTF_INTEGER_BASE_BINARY:
+               base_string = "binary";
+               break;
+       default:
+               base_string = "unknown";
+               break;
+       }
+
+       return base_string;
+}
+
+static
+void append_field_name(struct metadata_context *context,
+               const char *name)
+{
+       g_string_append_c(context->string, ' ');
+
+       if (!bt_ctf_identifier_is_valid(name) || *name == '_') {
+               g_string_append_c(context->string, '_');
+       }
+
+       g_string_append(context->string, name);
+}
+
+static
+int bt_ctf_field_type_integer_serialize(struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       struct bt_ctf_field_type_common_integer *integer = BT_CTF_FROM_COMMON(type);
+       int ret = 0;
+
+       BT_LOGD("Serializing CTF writer integer field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       g_string_append_printf(context->string,
+               "integer { size = %u; align = %u; signed = %s; encoding = %s; base = %s; byte_order = %s",
+               integer->size, type->alignment,
+               (integer->is_signed ? "true" : "false"),
+               get_encoding_string(integer->encoding),
+               get_integer_base_string(integer->base),
+               bt_ctf_get_byte_order_string(integer->user_byte_order));
+       if (integer->mapped_clock_class) {
+               const char *clock_name = bt_ctf_clock_class_get_name(
+                       integer->mapped_clock_class);
+
+               BT_ASSERT(clock_name);
+               g_string_append_printf(context->string,
+                       "; map = clock.%s.value", clock_name);
+       }
+
+       g_string_append(context->string, "; }");
+       return ret;
+}
+
+static
+int bt_ctf_field_type_enumeration_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       size_t entry;
+       int ret;
+       struct bt_ctf_field_type_common_enumeration *enumeration =
+               BT_CTF_FROM_COMMON(type);
+       struct bt_ctf_field_type_common *container_type;
+       int container_signed;
+
+       BT_LOGD("Serializing CTF writer enumeration field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       container_type =
+               bt_ctf_field_type_common_enumeration_borrow_container_field_type(type);
+       BT_ASSERT(container_type);
+       container_signed = bt_ctf_field_type_common_integer_is_signed(
+               container_type);
+       BT_ASSERT(container_signed >= 0);
+       g_string_append(context->string, "enum : ");
+       BT_LOGD_STR("Serializing CTF writer enumeration field type's container field type's metadata.");
+       ret = bt_ctf_field_type_serialize_recursive(
+               (void *) enumeration->container_ft, context);
+       if (ret) {
+               BT_LOGW("Cannot serialize CTF writer enumeration field type's container field type's metadata: "
+                       "container-ft-addr=%p", enumeration->container_ft);
+               goto end;
+       }
+
+       g_string_append(context->string, " { ");
+       for (entry = 0; entry < enumeration->entries->len; entry++) {
+               struct bt_ctf_enumeration_mapping *mapping =
+                       enumeration->entries->pdata[entry];
+               const char *label = g_quark_to_string(mapping->string);
+
+               g_string_append(context->string, "\"");
+
+               if (!bt_ctf_identifier_is_valid(label) || label[0] == '_') {
+                       g_string_append(context->string, "_");
+               }
+
+               g_string_append_printf(context->string, "%s\" = ", label);
+
+               if (container_signed) {
+                       if (mapping->range_start._signed ==
+                               mapping->range_end._signed) {
+                               g_string_append_printf(context->string,
+                                       "%" PRId64,
+                                       mapping->range_start._signed);
+                       } else {
+                               g_string_append_printf(context->string,
+                                       "%" PRId64 " ... %" PRId64,
+                                       mapping->range_start._signed,
+                                       mapping->range_end._signed);
+                       }
+               } else {
+                       if (mapping->range_start._unsigned ==
+                               mapping->range_end._unsigned) {
+                               g_string_append_printf(context->string,
+                                       "%" PRIu64,
+                                       mapping->range_start._unsigned);
+                       } else {
+                               g_string_append_printf(context->string,
+                                       "%" PRIu64 " ... %" PRIu64,
+                                       mapping->range_start._unsigned,
+                                       mapping->range_end._unsigned);
+                       }
+               }
+
+               g_string_append(context->string,
+                       ((entry != (enumeration->entries->len - 1)) ?
+                       ", " : " }"));
+       }
+
+       if (context->field_name->len) {
+               append_field_name(context,
+                       context->field_name->str);
+               g_string_assign(context->field_name, "");
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_type_floating_point_serialize(struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       struct bt_ctf_field_type_common_floating_point *floating_point =
+               BT_CTF_FROM_COMMON(type);
+
+       BT_LOGD("Serializing CTF writer floating point number field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       g_string_append_printf(context->string,
+               "floating_point { exp_dig = %u; mant_dig = %u; byte_order = %s; align = %u; }",
+               floating_point->exp_dig,
+               floating_point->mant_dig,
+               bt_ctf_get_byte_order_string(floating_point->user_byte_order),
+               type->alignment);
+       return 0;
+}
+
+static
+int bt_ctf_field_type_structure_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       size_t i;
+       unsigned int indent;
+       int ret = 0;
+       struct bt_ctf_field_type_common_structure *structure = BT_CTF_FROM_COMMON(type);
+       GString *structure_field_name = context->field_name;
+
+       BT_LOGD("Serializing CTF writer structure field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       context->field_name = g_string_new("");
+
+       context->current_indentation_level++;
+       g_string_append(context->string, "struct {\n");
+
+       for (i = 0; i < structure->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *field =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               structure, i);
+
+               BT_LOGD("Serializing CTF writer structure field type's field metadata: "
+                       "index=%zu, "
+                       "field-ft-addr=%p, field-name=\"%s\"",
+                       i, field, g_quark_to_string(field->name));
+
+               for (indent = 0; indent < context->current_indentation_level;
+                       indent++) {
+                       g_string_append_c(context->string, '\t');
+               }
+
+               g_string_assign(context->field_name,
+                       g_quark_to_string(field->name));
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) field->type, context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize CTF writer structure field type's field's metadata: "
+                               "index=%zu, "
+                               "field-ft-addr=%p, field-name=\"%s\"",
+                               i, field->type,
+                               g_quark_to_string(field->name));
+                       goto end;
+               }
+
+               if (context->field_name->len) {
+                       append_field_name(context,
+                               context->field_name->str);
+               }
+               g_string_append(context->string, ";\n");
+       }
+
+       context->current_indentation_level--;
+       for (indent = 0; indent < context->current_indentation_level;
+               indent++) {
+               g_string_append_c(context->string, '\t');
+       }
+
+       g_string_append_printf(context->string, "} align(%u)",
+                type->alignment);
+
+end:
+       g_string_free(context->field_name, TRUE);
+       context->field_name = structure_field_name;
+       return ret;
+}
+
+static
+int bt_ctf_field_type_variant_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       size_t i;
+       unsigned int indent;
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *variant = BT_CTF_FROM_COMMON(type);
+       GString *variant_field_name = context->field_name;
+
+       BT_LOGD("Serializing CTF writer variant field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       context->field_name = g_string_new("");
+       if (variant->tag_name->len > 0) {
+               g_string_append(context->string, "variant <");
+               append_field_name(context, variant->tag_name->str);
+               g_string_append(context->string, "> {\n");
+       } else {
+               g_string_append(context->string, "variant {\n");
+       }
+
+       context->current_indentation_level++;
+       for (i = 0; i < variant->choices->len; i++) {
+               struct bt_ctf_field_type_common_variant_choice *field =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               variant, i);
+
+               BT_LOGD("Serializing CTF writer variant field type's field metadata: "
+                       "index=%zu, "
+                       "field-ft-addr=%p, field-name=\"%s\"",
+                       i, field, g_quark_to_string(field->name));
+
+               g_string_assign(context->field_name,
+                       g_quark_to_string(field->name));
+               for (indent = 0; indent < context->current_indentation_level;
+                       indent++) {
+                       g_string_append_c(context->string, '\t');
+               }
+
+               g_string_assign(context->field_name,
+                       g_quark_to_string(field->name));
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) field->type, context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize CTF writer variant field type's field's metadata: "
+                               "index=%zu, "
+                               "field-ft-addr=%p, field-name=\"%s\"",
+                               i, field->type,
+                               g_quark_to_string(field->name));
+                       goto end;
+               }
+
+               if (context->field_name->len) {
+                       append_field_name(context,
+                               context->field_name->str);
+                       g_string_append_c(context->string, ';');
+               }
+
+               g_string_append_c(context->string, '\n');
+       }
+
+       context->current_indentation_level--;
+       for (indent = 0; indent < context->current_indentation_level;
+               indent++) {
+               g_string_append_c(context->string, '\t');
+       }
+
+       g_string_append(context->string, "}");
+
+end:
+       g_string_free(context->field_name, TRUE);
+       context->field_name = variant_field_name;
+       return ret;
+}
+
+static
+int bt_ctf_field_type_array_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_array *array = BT_CTF_FROM_COMMON(type);
+
+       BT_LOGD("Serializing CTF writer array field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       BT_LOGD_STR("Serializing CTF writer array field type's element field type's metadata.");
+       ret = bt_ctf_field_type_serialize_recursive(
+               (void *) array->element_ft, context);
+       if (ret) {
+               BT_LOGW("Cannot serialize CTF writer array field type's element field type's metadata: "
+                       "element-ft-addr=%p", array->element_ft);
+               goto end;
+       }
+
+       if (context->field_name->len) {
+               append_field_name(context,
+                       context->field_name->str);
+
+               g_string_append_printf(context->string, "[%u]", array->length);
+               g_string_assign(context->field_name, "");
+       } else {
+               g_string_append_printf(context->string, "[%u]", array->length);
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_type_sequence_serialize_recursive(
+               struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_sequence *sequence = BT_CTF_FROM_COMMON(type);
+
+       BT_LOGD("Serializing CTF writer sequence field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       BT_LOGD_STR("Serializing CTF writer sequence field type's element field type's metadata.");
+       ret = bt_ctf_field_type_serialize_recursive(
+               (void *) sequence->element_ft, context);
+       if (ret) {
+               BT_LOGW("Cannot serialize CTF writer sequence field type's element field type's metadata: "
+                       "element-ft-addr=%p", sequence->element_ft);
+               goto end;
+       }
+
+       if (context->field_name->len) {
+               append_field_name(context, context->field_name->str);
+               g_string_assign(context->field_name, "");
+       }
+       g_string_append(context->string, "[");
+       append_field_name(context, sequence->length_field_name->str);
+       g_string_append(context->string, "]");
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_type_string_serialize(struct bt_ctf_field_type_common *type,
+               struct metadata_context *context)
+{
+       struct bt_ctf_field_type_common_string *string = BT_CTF_FROM_COMMON(type);
+
+       BT_LOGD("Serializing CTF writer string field type's metadata: "
+               "ft-addr=%p, metadata-context-addr=%p", type, context);
+       g_string_append_printf(context->string,
+               "string { encoding = %s; }",
+               get_encoding_string(string->encoding));
+       return 0;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_integer_create(unsigned int size)
+{
+       struct bt_ctf_field_type_common_integer *integer = NULL;
+
+       BT_LOGD("Creating CTF writer integer field type object: size=%u", size);
+
+       if (size == 0 || size > 64) {
+               BT_LOGW("Invalid parameter: size must be between 1 and 64: "
+                       "size=%u", size);
+               goto error;
+       }
+
+       integer = g_new0(struct bt_ctf_field_type_common_integer, 1);
+       if (!integer) {
+               BT_LOGE_STR("Failed to allocate one integer field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_integer_initialize(BT_CTF_TO_COMMON(integer),
+               size, bt_ctf_field_type_common_integer_destroy,
+               &bt_ctf_field_type_integer_methods);
+       integer->common.spec.writer.serialize_func =
+               bt_ctf_field_type_integer_serialize;
+       BT_LOGD("Created CTF writer integer field type object: addr=%p, size=%u",
+               integer, size);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(integer);
+
+end:
+       return (void *) integer;
+}
+
+int bt_ctf_field_type_integer_get_size(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_integer_get_size((void *) ft);
+}
+
+bt_bool bt_ctf_field_type_integer_is_signed(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_integer_is_signed((void *) ft);
+}
+
+int bt_ctf_field_type_integer_set_is_signed(struct bt_ctf_field_type *ft,
+               bt_bool is_signed)
+{
+       return bt_ctf_field_type_common_integer_set_is_signed((void *) ft,
+               is_signed);
+}
+
+int bt_ctf_field_type_integer_set_size(struct bt_ctf_field_type *ft,
+               unsigned int size)
+{
+       return bt_ctf_field_type_common_integer_set_size((void *) ft, size);
+}
+
+enum bt_ctf_integer_base bt_ctf_field_type_integer_get_base(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_integer_get_base((void *) ft);
+}
+
+int bt_ctf_field_type_integer_set_base(struct bt_ctf_field_type *ft,
+               enum bt_ctf_integer_base base)
+{
+       return bt_ctf_field_type_common_integer_set_base((void *) ft,
+               (int) base);
+}
+
+enum bt_ctf_string_encoding bt_ctf_field_type_integer_get_encoding(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_integer_get_encoding((void *) ft);
+}
+
+int bt_ctf_field_type_integer_set_encoding(struct bt_ctf_field_type *ft,
+               enum bt_ctf_string_encoding encoding)
+{
+       return bt_ctf_field_type_common_integer_set_encoding((void *) ft,
+               (int) encoding);
+}
+
+struct bt_ctf_clock_class *bt_ctf_field_type_integer_get_mapped_clock_class(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
+               (void *) ft));
+}
+
+int bt_ctf_field_type_integer_set_mapped_clock_class(
+               struct bt_ctf_field_type *ft,
+               struct bt_ctf_clock_class *clock_class)
+{
+       return bt_ctf_field_type_common_integer_set_mapped_clock_class((void *) ft,
+               clock_class);
+}
+
+int bt_ctf_field_type_enumeration_signed_get_mapping_by_index(
+               struct bt_ctf_field_type *ft, uint64_t index,
+               const char **mapping_name, int64_t *range_begin,
+               int64_t *range_end)
+{
+       return bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
+               (void *) ft, index, mapping_name, range_begin, range_end);
+}
+
+int bt_ctf_field_type_enumeration_unsigned_get_mapping_by_index(
+               struct bt_ctf_field_type *ft, uint64_t index,
+               const char **mapping_name, uint64_t *range_begin,
+               uint64_t *range_end)
+{
+       return bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
+               (void *) ft, index, mapping_name, range_begin, range_end);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create(
+               struct bt_ctf_field_type *container_ft)
+{
+       struct bt_ctf_field_type_common_enumeration *enumeration = NULL;
+       struct bt_ctf_field_type_common *int_ft = (void *) container_ft;
+
+       BT_LOGD("Creating CTF writer enumeration field type object: int-ft-addr=%p",
+               container_ft);
+
+       if (!container_ft) {
+               BT_LOGW_STR("Invalid parameter: field type is NULL.");
+               goto error;
+       }
+
+       if (int_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               BT_LOGW("Invalid parameter: container field type is not an integer field type: "
+                       "container-ft-addr=%p, container-ft-id=%s",
+                       container_ft, bt_ctf_field_type_id_string(int_ft->id));
+               goto error;
+       }
+
+       enumeration = g_new0(struct bt_ctf_field_type_common_enumeration, 1);
+       if (!enumeration) {
+               BT_LOGE_STR("Failed to allocate one enumeration field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_enumeration_initialize(BT_CTF_TO_COMMON(enumeration),
+               int_ft, bt_ctf_field_type_common_enumeration_destroy_recursive,
+               &bt_ctf_field_type_enumeration_methods);
+       enumeration->common.spec.writer.serialize_func =
+               bt_ctf_field_type_enumeration_serialize_recursive;
+       BT_LOGD("Created CTF writer enumeration field type object: addr=%p, "
+               "int-ft-addr=%p, int-ft-size=%u",
+               enumeration, container_ft,
+               bt_ctf_field_type_integer_get_size(container_ft));
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration);
+
+end:
+       return (void *) enumeration;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_get_container_field_type(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_field_type_common_enumeration_borrow_container_field_type(
+                       (void *) ft));
+}
+
+int bt_ctf_field_type_enumeration_signed_add_mapping(
+               struct bt_ctf_field_type *ft, const char *string,
+               int64_t range_start, int64_t range_end)
+{
+       return bt_ctf_field_type_common_enumeration_signed_add_mapping(
+               (void *) ft, string, range_start, range_end);
+}
+
+int bt_ctf_field_type_enumeration_unsigned_add_mapping(
+               struct bt_ctf_field_type *ft, const char *string,
+               uint64_t range_start, uint64_t range_end)
+{
+       return bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
+               (void *) ft, string, range_start, range_end);
+}
+
+int64_t bt_ctf_field_type_enumeration_get_mapping_count(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_enumeration_get_mapping_count((void *) ft);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void)
+{
+       struct bt_ctf_field_type_common_floating_point *floating_point =
+               g_new0(struct bt_ctf_field_type_common_floating_point, 1);
+
+       BT_LOGD_STR("Creating CTF writer floating point number field type object.");
+
+       if (!floating_point) {
+               BT_LOGE_STR("Failed to allocate one floating point number field type.");
+               goto end;
+       }
+
+       bt_ctf_field_type_common_floating_point_initialize(
+               BT_CTF_TO_COMMON(floating_point),
+               bt_ctf_field_type_common_floating_point_destroy,
+               &bt_ctf_field_type_floating_point_methods);
+       floating_point->common.spec.writer.serialize_func =
+               bt_ctf_field_type_floating_point_serialize;
+       BT_LOGD("Created CTF writer floating point number field type object: addr=%p, "
+               "exp-size=%u, mant-size=%u", floating_point,
+               floating_point->exp_dig, floating_point->mant_dig);
+
+end:
+       return (void *) floating_point;
+}
+
+int bt_ctf_field_type_floating_point_get_exponent_digits(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_floating_point_get_exponent_digits(
+               (void *) ft);
+}
+
+int bt_ctf_field_type_floating_point_set_exponent_digits(
+               struct bt_ctf_field_type *ft, unsigned int exponent_digits)
+{
+       return bt_ctf_field_type_common_floating_point_set_exponent_digits(
+               (void *) ft, exponent_digits);
+}
+
+int bt_ctf_field_type_floating_point_get_mantissa_digits(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_floating_point_get_mantissa_digits(
+               (void *) ft);
+}
+
+int bt_ctf_field_type_floating_point_set_mantissa_digits(
+               struct bt_ctf_field_type *ft, unsigned int mantissa_digits)
+{
+       return bt_ctf_field_type_common_floating_point_set_mantissa_digits(
+               (void *) ft, mantissa_digits);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void)
+{
+       struct bt_ctf_field_type_common_structure *structure =
+               g_new0(struct bt_ctf_field_type_common_structure, 1);
+
+       BT_LOGD_STR("Creating CTF writer structure field type object.");
+
+       if (!structure) {
+               BT_LOGE_STR("Failed to allocate one structure field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_structure_initialize(BT_CTF_TO_COMMON(structure),
+               bt_ctf_field_type_common_structure_destroy_recursive,
+               &bt_ctf_field_type_structure_methods);
+       structure->common.spec.writer.serialize_func =
+               bt_ctf_field_type_structure_serialize_recursive;
+       BT_LOGD("Created CTF writer structure field type object: addr=%p",
+               structure);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(structure);
+
+end:
+       return (void *) structure;
+}
+
+int bt_ctf_field_type_structure_add_field(struct bt_ctf_field_type *ft,
+               struct bt_ctf_field_type *field_type,
+               const char *field_name)
+{
+       return bt_ctf_field_type_common_structure_add_field((void *) ft,
+               (void *) field_type, field_name);
+}
+
+int64_t bt_ctf_field_type_structure_get_field_count(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_structure_get_field_count((void *) ft);
+}
+
+int bt_ctf_field_type_structure_get_field_by_index(
+               struct bt_ctf_field_type *ft,
+               const char **field_name,
+               struct bt_ctf_field_type **field_type, uint64_t index)
+{
+       int ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+               (void *) ft, field_name, (void *) field_type, index);
+
+       if (ret == 0 && field_type) {
+               bt_ctf_object_get_ref(*field_type);
+       }
+
+       return ret;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_structure_get_field_type_by_name(
+               struct bt_ctf_field_type *ft, const char *name)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               (void *) ft, name));
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_variant_create(
+       struct bt_ctf_field_type *tag_ft, const char *tag_name)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = NULL;
+
+       BT_LOGD("Creating CTF writer variant field type object: "
+               "tag-ft-addr=%p, tag-field-name=\"%s\"",
+               tag_ft, tag_name);
+
+       if (tag_name && !bt_ctf_identifier_is_valid(tag_name)) {
+               BT_LOGW("Invalid parameter: tag field name is not a valid CTF identifier: "
+                       "tag-ft-addr=%p, tag-field-name=\"%s\"",
+                       tag_ft, tag_name);
+               goto error;
+       }
+
+       var_ft = g_new0(struct bt_ctf_field_type_common_variant, 1);
+       if (!var_ft) {
+               BT_LOGE_STR("Failed to allocate one variant field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_variant_initialize(BT_CTF_TO_COMMON(var_ft),
+               (void *) tag_ft, tag_name,
+               bt_ctf_field_type_common_variant_destroy_recursive,
+               &bt_ctf_field_type_variant_methods);
+       var_ft->common.spec.writer.serialize_func =
+               bt_ctf_field_type_variant_serialize_recursive;
+       BT_LOGD("Created CTF writer variant field type object: addr=%p, "
+               "tag-ft-addr=%p, tag-field-name=\"%s\"",
+               var_ft, tag_ft, tag_name);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(var_ft);
+
+end:
+       return (void *) var_ft;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_variant_get_tag_field_type(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_tag_field_type(
+               (void *) ft));
+}
+
+const char *bt_ctf_field_type_variant_get_tag_name(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_variant_get_tag_name((void *) ft);
+}
+
+int bt_ctf_field_type_variant_set_tag_name(
+               struct bt_ctf_field_type *ft, const char *name)
+{
+       return bt_ctf_field_type_common_variant_set_tag_name((void *) ft, name);
+}
+
+int bt_ctf_field_type_variant_add_field(struct bt_ctf_field_type *ft,
+               struct bt_ctf_field_type *field_type,
+               const char *field_name)
+{
+       return bt_ctf_field_type_common_variant_add_field((void *) ft,
+               (void *) field_type, field_name);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_by_name(
+               struct bt_ctf_field_type *ft,
+               const char *field_name)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_variant_borrow_field_type_by_name(
+               (void *) ft, field_name));
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type_from_tag(
+               struct bt_ctf_field_type *ft,
+               struct bt_ctf_field *tag_field)
+{
+       int ret;
+       int64_t choice_index;
+       struct bt_ctf_field *container;
+       struct bt_ctf_field_type_common_variant *var_ft = (void *) ft;
+       struct bt_ctf_field_type *ret_ft = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(ft, "Field type");
+       BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(ft, BT_CTF_FIELD_TYPE_ID_VARIANT,
+               "Field type");
+       BT_CTF_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_ctf_field_common *) tag_field,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((struct bt_ctf_field_common *) tag_field,
+               "Tag field");
+
+       container = bt_ctf_field_enumeration_borrow_container(tag_field);
+       BT_ASSERT(container);
+
+       if (var_ft->tag_ft->container_ft->is_signed) {
+               int64_t val;
+
+               ret = bt_ctf_field_integer_signed_get_value(container,
+                       &val);
+               BT_ASSERT(ret == 0);
+               choice_index = bt_ctf_field_type_common_variant_find_choice_index(
+                       (void *) ft, (uint64_t) val, true);
+       } else {
+               uint64_t val;
+
+               ret = bt_ctf_field_integer_unsigned_get_value(container,
+                       &val);
+               BT_ASSERT(ret == 0);
+               choice_index = bt_ctf_field_type_common_variant_find_choice_index(
+                       (void *) ft, val, false);
+       }
+
+       if (choice_index < 0) {
+               BT_LOGW("Cannot find variant field type's field: "
+                       "var-ft-addr=%p, tag-field-addr=%p", ft, tag_field);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_variant_get_field_by_index(ft, NULL,
+               &ret_ft, choice_index);
+       BT_ASSERT(ret == 0);
+
+end:
+       return ret_ft;
+}
+
+int64_t bt_ctf_field_type_variant_get_field_count(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_variant_get_field_count((void *) ft);
+}
+
+int bt_ctf_field_type_variant_get_field_by_index(struct bt_ctf_field_type *ft,
+               const char **field_name, struct bt_ctf_field_type **field_type,
+               uint64_t index)
+{
+       int ret = bt_ctf_field_type_common_variant_borrow_field_by_index(
+               (void *) ft, field_name, (void *) field_type, index);
+
+       if (ret == 0 && field_type) {
+               bt_ctf_object_get_ref(*field_type);
+       }
+
+       return ret;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_array_create(
+               struct bt_ctf_field_type *element_ft, unsigned int length)
+{
+       struct bt_ctf_field_type_common_array *array = NULL;
+
+       BT_LOGD("Creating CTF writer array field type object: element-ft-addr=%p, "
+               "length=%u", element_ft, length);
+
+       if (!element_ft) {
+               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
+               goto error;
+       }
+
+       if (length == 0) {
+               BT_LOGW_STR("Invalid parameter: length is zero.");
+               goto error;
+       }
+
+       array = g_new0(struct bt_ctf_field_type_common_array, 1);
+       if (!array) {
+               BT_LOGE_STR("Failed to allocate one array field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_array_initialize(BT_CTF_TO_COMMON(array),
+               (void *) element_ft, length,
+               bt_ctf_field_type_common_array_destroy_recursive,
+               &bt_ctf_field_type_array_methods);
+       array->common.spec.writer.serialize_func =
+               bt_ctf_field_type_array_serialize_recursive;
+       BT_LOGD("Created CTF writer array field type object: addr=%p, "
+               "element-ft-addr=%p, length=%u",
+               array, element_ft, length);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(array);
+
+end:
+       return (void *) array;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_field_type(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_array_borrow_element_field_type(
+               (void *) ft));
+}
+
+int64_t bt_ctf_field_type_array_get_length(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_array_get_length((void *) ft);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_create(
+               struct bt_ctf_field_type *element_ft,
+               const char *length_field_name)
+{
+       struct bt_ctf_field_type_common_sequence *sequence = NULL;
+
+       BT_LOGD("Creating CTF writer sequence field type object: element-ft-addr=%p, "
+               "length-field-name=\"%s\"", element_ft, length_field_name);
+
+       if (!element_ft) {
+               BT_LOGW_STR("Invalid parameter: element field type is NULL.");
+               goto error;
+       }
+
+       if (!bt_ctf_identifier_is_valid(length_field_name)) {
+               BT_LOGW("Invalid parameter: length field name is not a valid CTF identifier: "
+                       "length-field-name=\"%s\"", length_field_name);
+               goto error;
+       }
+
+       sequence = g_new0(struct bt_ctf_field_type_common_sequence, 1);
+       if (!sequence) {
+               BT_LOGE_STR("Failed to allocate one sequence field type.");
+               goto error;
+       }
+
+       bt_ctf_field_type_common_sequence_initialize(BT_CTF_TO_COMMON(sequence),
+               (void *) element_ft, length_field_name,
+               bt_ctf_field_type_common_sequence_destroy_recursive,
+               &bt_ctf_field_type_sequence_methods);
+       sequence->common.spec.writer.serialize_func =
+               bt_ctf_field_type_sequence_serialize_recursive;
+       BT_LOGD("Created CTF writer sequence field type object: addr=%p, "
+               "element-ft-addr=%p, length-field-name=\"%s\"",
+               sequence, element_ft, length_field_name);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(sequence);
+
+end:
+       return (void *) sequence;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_field_type(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_type_common_sequence_borrow_element_field_type(
+               (void *) ft));
+}
+
+const char *bt_ctf_field_type_sequence_get_length_field_name(
+               struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_sequence_get_length_field_name((void *) ft);
+}
+
+struct bt_ctf_field_type *bt_ctf_field_type_string_create(void)
+{
+       struct bt_ctf_field_type_common_string *string =
+               g_new0(struct bt_ctf_field_type_common_string, 1);
+
+       BT_LOGD_STR("Creating CTF writer string field type object.");
+
+       if (!string) {
+               BT_LOGE_STR("Failed to allocate one string field type.");
+               return NULL;
+       }
+
+       bt_ctf_field_type_common_string_initialize(BT_CTF_TO_COMMON(string),
+               bt_ctf_field_type_common_string_destroy,
+               &bt_ctf_field_type_string_methods);
+       string->common.spec.writer.serialize_func =
+               bt_ctf_field_type_string_serialize;
+       BT_LOGD("Created CTF writer string field type object: addr=%p", string);
+       return (void *) string;
+}
+
+enum bt_ctf_string_encoding bt_ctf_field_type_string_get_encoding(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_string_get_encoding((void *) ft);
+}
+
+int bt_ctf_field_type_string_set_encoding(struct bt_ctf_field_type *ft,
+               enum bt_ctf_string_encoding encoding)
+{
+       return bt_ctf_field_type_common_string_set_encoding((void *) ft,
+               (int) encoding);
+}
+
+int bt_ctf_field_type_get_alignment(struct bt_ctf_field_type *ft)
+{
+       return bt_ctf_field_type_common_get_alignment((void *) ft);
+}
+
+int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *ft,
+               unsigned int alignment)
+{
+       return bt_ctf_field_type_common_set_alignment((void *) ft, alignment);
+}
+
+enum bt_ctf_byte_order bt_ctf_field_type_get_byte_order(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_get_byte_order((void *) ft);
+}
+
+int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *ft,
+               enum bt_ctf_byte_order byte_order)
+{
+       return bt_ctf_field_type_common_set_byte_order((void *) ft,
+               (int) byte_order);
+}
+
+enum bt_ctf_field_type_id bt_ctf_field_type_get_type_id(
+               struct bt_ctf_field_type *ft)
+{
+       return (int) bt_ctf_field_type_common_get_type_id((void *) ft);
+}
+
+BT_HIDDEN
+struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *ft)
+{
+       return (void *) bt_ctf_field_type_common_copy((void *) ft);
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_integer_copy(
+               struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common_integer *int_ft = (void *) ft;
+       struct bt_ctf_field_type_common_integer *copy_ft;
+
+       BT_LOGD("Copying CTF writer integer field type's: addr=%p", ft);
+       copy_ft = (void *) bt_ctf_field_type_integer_create(int_ft->size);
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer integer field type.");
+               goto end;
+       }
+
+       copy_ft->mapped_clock_class = bt_ctf_object_get_ref(int_ft->mapped_clock_class);
+       copy_ft->user_byte_order = int_ft->user_byte_order;
+       copy_ft->is_signed = int_ft->is_signed;
+       copy_ft->size = int_ft->size;
+       copy_ft->base = int_ft->base;
+       copy_ft->encoding = int_ft->encoding;
+       BT_LOGD("Copied CTF writer integer field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       return (void *) copy_ft;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_enumeration_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       size_t i;
+       struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) ft;
+       struct bt_ctf_field_type_common_enumeration *copy_ft = NULL;
+       struct bt_ctf_field_type_common_enumeration *container_copy_ft;
+
+       BT_LOGD("Copying CTF writer enumeration field type's: addr=%p", ft);
+
+       /* Copy the source enumeration's container */
+       BT_LOGD_STR("Copying CTF writer enumeration field type's container field type.");
+       container_copy_ft = BT_CTF_FROM_COMMON(bt_ctf_field_type_common_copy(
+               BT_CTF_TO_COMMON(enum_ft->container_ft)));
+       if (!container_copy_ft) {
+               BT_LOGE_STR("Cannot copy CTF writer enumeration field type's container field type.");
+               goto end;
+       }
+
+       copy_ft = (void *) bt_ctf_field_type_enumeration_create(
+               (void *) container_copy_ft);
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer enumeration field type.");
+               goto end;
+       }
+
+       /* Copy all enumaration entries */
+       for (i = 0; i < enum_ft->entries->len; i++) {
+               struct bt_ctf_enumeration_mapping *mapping = g_ptr_array_index(
+                       enum_ft->entries, i);
+               struct bt_ctf_enumeration_mapping *copy_mapping = g_new0(
+                       struct bt_ctf_enumeration_mapping, 1);
+
+               if (!copy_mapping) {
+                       BT_LOGE_STR("Failed to allocate one enumeration mapping.");
+                       goto error;
+               }
+
+               *copy_mapping = *mapping;
+               g_ptr_array_add(copy_ft->entries, copy_mapping);
+       }
+
+       BT_LOGD("Copied CTF writer enumeration field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       bt_ctf_object_put_ref(container_copy_ft);
+       return (void *) copy_ft;
+
+error:
+       bt_ctf_object_put_ref(container_copy_ft);
+        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
+       return (void *) copy_ft;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_floating_point_copy(
+               struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common_floating_point *flt_ft = BT_CTF_FROM_COMMON(ft);
+       struct bt_ctf_field_type_common_floating_point *copy_ft;
+
+       BT_LOGD("Copying CTF writer floating point number field type's: addr=%p", ft);
+       copy_ft = (void *) bt_ctf_field_type_floating_point_create();
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer floating point number field type.");
+               goto end;
+       }
+
+       copy_ft->user_byte_order = flt_ft->user_byte_order;
+       copy_ft->exp_dig = flt_ft->exp_dig;
+       copy_ft->mant_dig = flt_ft->mant_dig;
+       BT_LOGD("Copied CTF writer floating point number field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       return (void *) copy_ft;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_structure_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       int64_t i;
+       GHashTableIter iter;
+       gpointer key, value;
+       struct bt_ctf_field_type_common_structure *struct_ft = (void *) ft;
+       struct bt_ctf_field_type_common_structure *copy_ft;
+
+       BT_LOGD("Copying CTF writer structure field type's: addr=%p", ft);
+       copy_ft = (void *) bt_ctf_field_type_structure_create();
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer structure field type.");
+               goto end;
+       }
+
+       /* Copy field_name_to_index */
+       g_hash_table_iter_init(&iter, struct_ft->field_name_to_index);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               g_hash_table_insert(copy_ft->field_name_to_index,
+                       key, value);
+       }
+
+       g_array_set_size(copy_ft->fields, struct_ft->fields->len);
+
+       for (i = 0; i < struct_ft->fields->len; i++) {
+               struct bt_ctf_field_type_common_structure_field *entry, *copy_entry;
+               struct bt_ctf_field_type_common *field_ft_copy;
+
+               entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                       struct_ft, i);
+               copy_entry = BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                       copy_ft, i);
+               BT_LOGD("Copying CTF writer structure field type's field: "
+                       "index=%" PRId64 ", "
+                       "field-ft-addr=%p, field-name=\"%s\"",
+                       i, entry, g_quark_to_string(entry->name));
+
+               field_ft_copy = (void *) bt_ctf_field_type_copy(
+                       (void *) entry->type);
+               if (!field_ft_copy) {
+                       BT_LOGE("Cannot copy CTF writer structure field type's field: "
+                               "index=%" PRId64 ", "
+                               "field-ft-addr=%p, field-name=\"%s\"",
+                               i, entry, g_quark_to_string(entry->name));
+                       goto error;
+               }
+
+               copy_entry->name = entry->name;
+               copy_entry->type = field_ft_copy;
+       }
+
+       BT_LOGD("Copied CTF writer structure field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       return (void *) copy_ft;
+
+error:
+        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
+       return NULL;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_variant_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       int64_t i;
+       GHashTableIter iter;
+       gpointer key, value;
+       struct bt_ctf_field_type_common *tag_ft_copy = NULL;
+       struct bt_ctf_field_type_common_variant *var_ft = (void *) ft;
+       struct bt_ctf_field_type_common_variant *copy_ft = NULL;
+
+       BT_LOGD("Copying CTF writer variant field type's: addr=%p", ft);
+       if (var_ft->tag_ft) {
+               BT_LOGD_STR("Copying CTF writer variant field type's tag field type.");
+               tag_ft_copy = bt_ctf_field_type_common_copy(
+                       BT_CTF_TO_COMMON(var_ft->tag_ft));
+               if (!tag_ft_copy) {
+                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field type.");
+                       goto end;
+               }
+       }
+
+       copy_ft = (void *) bt_ctf_field_type_variant_create(
+               (void *) tag_ft_copy,
+               var_ft->tag_name->len ? var_ft->tag_name->str : NULL);
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer variant field type.");
+               goto end;
+       }
+
+       /* Copy field_name_to_index */
+       g_hash_table_iter_init(&iter, var_ft->choice_name_to_index);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               g_hash_table_insert(copy_ft->choice_name_to_index,
+                       key, value);
+       }
+
+       g_array_set_size(copy_ft->choices, var_ft->choices->len);
+
+       for (i = 0; i < var_ft->choices->len; i++) {
+               struct bt_ctf_field_type_common_variant_choice *entry, *copy_entry;
+               struct bt_ctf_field_type_common *field_ft_copy;
+               uint64_t range_i;
+
+               entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(var_ft, i);
+               copy_entry = BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                       copy_ft, i);
+               BT_LOGD("Copying CTF writer variant field type's field: "
+                       "index=%" PRId64 ", "
+                       "field-ft-addr=%p, field-name=\"%s\"",
+                       i, entry, g_quark_to_string(entry->name));
+
+               field_ft_copy = (void *) bt_ctf_field_type_copy(
+                       (void *) entry->type);
+               if (!field_ft_copy) {
+                       BT_LOGE("Cannot copy CTF writer variant field type's field: "
+                               "index=%" PRId64 ", "
+                               "field-ft-addr=%p, field-name=\"%s\"",
+                               i, entry, g_quark_to_string(entry->name));
+                       g_free(copy_entry);
+                       goto error;
+               }
+
+               copy_entry->name = entry->name;
+               copy_entry->type = field_ft_copy;
+
+               /* Copy ranges */
+               copy_entry->ranges = g_array_new(FALSE, TRUE,
+                       sizeof(struct bt_ctf_field_type_common_variant_choice_range));
+               BT_ASSERT(copy_entry->ranges);
+               g_array_set_size(copy_entry->ranges, entry->ranges->len);
+
+               for (range_i = 0; range_i < entry->ranges->len; range_i++) {
+                       copy_entry->ranges[range_i] = entry->ranges[range_i];
+               }
+       }
+
+       if (var_ft->tag_field_path) {
+               BT_LOGD_STR("Copying CTF writer variant field type's tag field path.");
+               copy_ft->tag_field_path = bt_ctf_field_path_copy(
+                       var_ft->tag_field_path);
+               if (!copy_ft->tag_field_path) {
+                       BT_LOGE_STR("Cannot copy CTF writer variant field type's tag field path.");
+                       goto error;
+               }
+       }
+
+       copy_ft->choices_up_to_date = var_ft->choices_up_to_date;
+       BT_LOGD("Copied CTF writer variant field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       bt_ctf_object_put_ref(tag_ft_copy);
+       return (void *) copy_ft;
+
+error:
+       bt_ctf_object_put_ref(tag_ft_copy);
+        BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
+       return NULL;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_array_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common *container_ft_copy = NULL;
+       struct bt_ctf_field_type_common_array *array_ft = (void *) ft;
+       struct bt_ctf_field_type_common_array *copy_ft = NULL;
+
+       BT_LOGD("Copying CTF writer array field type's: addr=%p", ft);
+       BT_LOGD_STR("Copying CTF writer array field type's element field type.");
+       container_ft_copy = bt_ctf_field_type_common_copy(array_ft->element_ft);
+       if (!container_ft_copy) {
+               BT_LOGE_STR("Cannot copy CTF writer array field type's element field type.");
+               goto end;
+       }
+
+       copy_ft = (void *) bt_ctf_field_type_array_create(
+               (void *) container_ft_copy, array_ft->length);
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer array field type.");
+               goto end;
+       }
+
+       BT_LOGD("Copied CTF writer array field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       bt_ctf_object_put_ref(container_ft_copy);
+       return (void *) copy_ft;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_sequence_copy_recursive(
+               struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common *container_ft_copy = NULL;
+       struct bt_ctf_field_type_common_sequence *seq_ft = (void *) ft;
+       struct bt_ctf_field_type_common_sequence *copy_ft = NULL;
+
+       BT_LOGD("Copying CTF writer sequence field type's: addr=%p", ft);
+       BT_LOGD_STR("Copying CTF writer sequence field type's element field type.");
+       container_ft_copy = bt_ctf_field_type_common_copy(seq_ft->element_ft);
+       if (!container_ft_copy) {
+               BT_LOGE_STR("Cannot copy CTF writer sequence field type's element field type.");
+               goto end;
+       }
+
+       copy_ft = (void *) bt_ctf_field_type_sequence_create(
+               (void *) container_ft_copy,
+               seq_ft->length_field_name->len ?
+                       seq_ft->length_field_name->str : NULL);
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer sequence field type.");
+               goto end;
+       }
+
+       if (seq_ft->length_field_path) {
+               BT_LOGD_STR("Copying CTF writer sequence field type's length field path.");
+               copy_ft->length_field_path = bt_ctf_field_path_copy(
+                       seq_ft->length_field_path);
+               if (!copy_ft->length_field_path) {
+                       BT_LOGE_STR("Cannot copy CTF writer sequence field type's length field path.");
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Copied CTF writer sequence field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       bt_ctf_object_put_ref(container_ft_copy);
+       return (void *) copy_ft;
+error:
+       bt_ctf_object_put_ref(container_ft_copy);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_ft);
+       return NULL;
+}
+
+static
+struct bt_ctf_field_type *bt_ctf_field_type_string_copy(struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_type_common_string *string_ft = (void *) ft;
+       struct bt_ctf_field_type_common_string *copy_ft = NULL;
+
+       BT_LOGD("Copying CTF writer string field type's: addr=%p", ft);
+       copy_ft = (void *) bt_ctf_field_type_string_create();
+       if (!copy_ft) {
+               BT_LOGE_STR("Cannot create CTF writer string field type.");
+               goto end;
+       }
+
+       copy_ft->encoding = string_ft->encoding;
+       BT_LOGD("Copied CTF writer string field type: original-ft-addr=%p, copy-ft-addr=%p",
+               ft, copy_ft);
+
+end:
+       return (void *) copy_ft;
+}
diff --git a/src/ctf-writer/field-types.h b/src/ctf-writer/field-types.h
new file mode 100644 (file)
index 0000000..e1f75fd
--- /dev/null
@@ -0,0 +1,792 @@
+#ifndef BABELTRACE_CTF_WRITER_FIELD_TYPES_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_FIELD_TYPES_INTERNAL_H
+
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/types.h>
+
+#include "common/babeltrace.h"
+
+#include "assert-pre.h"
+#include "clock-class.h"
+#include "object.h"
+#include "writer.h"
+
+#define BT_CTF_ASSERT_PRE_CTF_FT_COMMON_HAS_ID(_ft, _type_id, _name)   \
+       BT_CTF_ASSERT_PRE(((struct bt_ctf_field_type_common *) (_ft))->id == (_type_id), \
+               _name " has the wrong type ID: expected-type-id=%s, "   \
+               "ft-addr=%p", bt_ctf_field_type_id_string(_type_id), (_ft))
+
+#define BT_CTF_ASSERT_PRE_CTF_FT_HOT(_ft, _name)                               \
+       BT_CTF_ASSERT_PRE_HOT((_ft), (_name), ": ft-addr=%p", (_ft))
+
+#define BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(_ft, _index) \
+       (&g_array_index(((struct bt_ctf_field_type_common_structure *) (_ft))->fields, \
+               struct bt_ctf_field_type_common_structure_field, (_index)))
+
+#define BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(_ft, _index)  \
+       (&g_array_index(((struct bt_ctf_field_type_common_variant *) (_ft))->choices, \
+               struct bt_ctf_field_type_common_variant_choice, (_index)))
+
+struct bt_ctf_field_common;
+struct bt_ctf_field_type_common;
+
+typedef void (*bt_ctf_field_type_common_method_freeze)(
+               struct bt_ctf_field_type_common *);
+typedef int (*bt_ctf_field_type_common_method_validate)(
+               struct bt_ctf_field_type_common *);
+typedef void (*bt_ctf_field_type_common_method_set_byte_order)(
+               struct bt_ctf_field_type_common *, enum bt_ctf_byte_order);
+typedef struct bt_ctf_field_type_common *(*bt_ctf_field_type_common_method_copy)(
+               struct bt_ctf_field_type_common *);
+typedef int (*bt_ctf_field_type_common_method_compare)(
+               struct bt_ctf_field_type_common *,
+               struct bt_ctf_field_type_common *);
+
+struct bt_ctf_field_type_common_methods {
+       bt_ctf_field_type_common_method_freeze freeze;
+       bt_ctf_field_type_common_method_validate validate;
+       bt_ctf_field_type_common_method_set_byte_order set_byte_order;
+       bt_ctf_field_type_common_method_copy copy;
+       bt_ctf_field_type_common_method_compare compare;
+};
+
+struct bt_ctf_field_type_common {
+       struct bt_ctf_object base;
+       enum bt_ctf_field_type_id id;
+       unsigned int alignment;
+
+       /* Virtual table */
+       struct bt_ctf_field_type_common_methods *methods;
+
+       /*
+        * A type can't be modified once it is added to an event or after a
+        * a field has been instanciated from it.
+        */
+       int frozen;
+
+       /*
+        * This flag indicates if the field type is valid. A valid
+        * field type is _always_ frozen. All the nested field types of
+        * a valid field type are also valid (and thus frozen).
+        */
+       int valid;
+
+       /*
+        * Specialized data for either CTF IR or CTF writer APIs.
+        * Having this here ensures that:
+        *
+        * * The type-specific common data is always found at the same
+        *   offset when the common API has a `struct
+        *   bt_ctf_field_type_common *` so that you can cast it to `struct
+        *   bt_ctf_field_type_common_integer *` for example and access the
+        *   common integer field type fields.
+        *
+        * * The specific CTF IR and CTF writer APIs can access their
+        *   specific field type fields in this union at an offset known
+        *   at build time. This avoids a pointer to specific data so
+        *   that all the fields, common or specific, of a CTF IR
+        *   integer field type or of a CTF writer integer field type,
+        *   for example, are contained within the same contiguous block
+        *   of memory.
+        */
+       union {
+               struct {
+               } ir;
+               struct {
+                       void *serialize_func;
+               } writer;
+       } spec;
+};
+
+struct bt_ctf_field_type_common_integer {
+       struct bt_ctf_field_type_common common;
+
+       /* Owned by this */
+       struct bt_ctf_clock_class *mapped_clock_class;
+
+       enum bt_ctf_byte_order user_byte_order;
+       bt_bool is_signed;
+       unsigned int size;
+       enum bt_ctf_integer_base base;
+       enum bt_ctf_string_encoding encoding;
+};
+
+struct bt_ctf_enumeration_mapping {
+       union {
+               uint64_t _unsigned;
+               int64_t _signed;
+       } range_start;
+       union {
+               uint64_t _unsigned;
+               int64_t _signed;
+       } range_end;
+       GQuark string;
+};
+
+struct bt_ctf_field_type_common_enumeration {
+       struct bt_ctf_field_type_common common;
+
+       /* Owned by this */
+       struct bt_ctf_field_type_common_integer *container_ft;
+
+       /* Array of `struct bt_ctf_enumeration_mapping *`, owned by this */
+       GPtrArray *entries;
+
+       /* Only set during validation */
+       bt_bool has_overlapping_ranges;
+};
+
+enum bt_ctf_field_type_enumeration_mapping_iterator_type {
+       CTF_ITERATOR_BY_NAME,
+       CTF_ITERATOR_BY_SIGNED_VALUE,
+       CTF_ITERATOR_BY_UNSIGNED_VALUE,
+};
+
+struct bt_ctf_field_type_enumeration_mapping_iterator {
+       struct bt_ctf_object base;
+
+       /* Owned by this */
+       struct bt_ctf_field_type_common_enumeration *enumeration_ft;
+
+       enum bt_ctf_field_type_enumeration_mapping_iterator_type type;
+       int index;
+       union {
+               GQuark name_quark;
+               int64_t signed_value;
+               uint64_t unsigned_value;
+       } u;
+};
+
+struct bt_ctf_field_type_common_floating_point {
+       struct bt_ctf_field_type_common common;
+       enum bt_ctf_byte_order user_byte_order;
+       unsigned int exp_dig;
+       unsigned int mant_dig;
+};
+
+struct bt_ctf_field_type_common_structure_field {
+       GQuark name;
+
+       /* Owned by this */
+       struct bt_ctf_field_type_common *type;
+};
+
+struct bt_ctf_field_type_common_structure {
+       struct bt_ctf_field_type_common common;
+       GHashTable *field_name_to_index;
+
+       /*
+        * Array of `struct bt_ctf_field_type_common_structure_field`,
+        * owned by this
+        */
+       GArray *fields;
+};
+
+struct bt_ctf_field_type_common_variant_choice_range {
+       union {
+               int64_t i;
+               uint64_t u;
+       } lower;
+       union {
+               int64_t i;
+               uint64_t u;
+       } upper;
+};
+
+struct bt_ctf_field_type_common_variant_choice {
+       GQuark name;
+
+       /* Owned by this */
+       struct bt_ctf_field_type_common *type;
+
+       /* Array of `struct bt_ctf_field_type_common_variant_choice_range` */
+       GArray *ranges;
+};
+
+struct bt_ctf_field_type_common_variant {
+       struct bt_ctf_field_type_common common;
+       GString *tag_name;
+       bool choices_up_to_date;
+
+       /* Owned by this */
+       struct bt_ctf_field_type_common_enumeration *tag_ft;
+
+       /* Owned by this */
+       struct bt_ctf_field_path *tag_field_path;
+
+       GHashTable *choice_name_to_index;
+
+       /*
+        * Array of `struct bt_ctf_field_type_common_variant_choice`,
+        * owned by this */
+       GArray *choices;
+};
+
+struct bt_ctf_field_type_common_array {
+       struct bt_ctf_field_type_common common;
+
+       /* Owned by this */
+       struct bt_ctf_field_type_common *element_ft;
+
+       unsigned int length;
+};
+
+struct bt_ctf_field_type_common_sequence {
+       struct bt_ctf_field_type_common common;
+
+       /* Owned by this */
+       struct bt_ctf_field_type_common *element_ft;
+
+       GString *length_field_name;
+
+       /* Owned by this */
+       struct bt_ctf_field_path *length_field_path;
+};
+
+struct bt_ctf_field_type_common_string {
+       struct bt_ctf_field_type_common common;
+       enum bt_ctf_string_encoding encoding;
+};
+
+typedef struct bt_ctf_field_common *(* bt_ctf_field_common_create_func)(
+               struct bt_ctf_field_type_common *);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_initialize(struct bt_ctf_field_type_common *ft,
+               bool init_bo, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_initialize(
+               struct bt_ctf_field_type_common *ft,
+               unsigned int size, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *container_ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_string_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_initialize(
+               struct bt_ctf_field_type_common *ft,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft,
+               unsigned int length, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft,
+               const char *length_field_name,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_initialize(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *tag_ft,
+               const char *tag_name,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_type_common_methods *methods);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_destroy(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_destroy(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_destroy_recursive(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_string_destroy(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_destroy_recursive(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_destroy_recursive(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_destroy_recursive(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_destroy_recursive(struct bt_ctf_object *obj);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_validate(struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_validate_recursive(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_validate_recursive(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_validate_recursive(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_validate_recursive(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_validate_recursive(
+               struct bt_ctf_field_type_common *type);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_validate(struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_get_size(struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+bt_bool bt_ctf_field_type_common_integer_is_signed(struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_is_signed(struct bt_ctf_field_type_common *ft,
+               bt_bool is_signed);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_size(struct bt_ctf_field_type_common *ft,
+               unsigned int size);
+
+BT_HIDDEN
+enum bt_ctf_integer_base bt_ctf_field_type_common_integer_get_base(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_base(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_integer_base base);
+
+BT_HIDDEN
+enum bt_ctf_string_encoding bt_ctf_field_type_common_integer_get_encoding(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_encoding(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_string_encoding encoding);
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_clock_class *clock_class);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_set_mapped_clock_class(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_clock_class *clock_class);
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_find_mappings_by_name(
+               struct bt_ctf_field_type_common *ft, const char *name);
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_signed_find_mappings_by_value(
+               struct bt_ctf_field_type_common *ft, int64_t value);
+
+BT_HIDDEN
+struct bt_ctf_field_type_enumeration_mapping_iterator *
+bt_ctf_field_type_common_enumeration_unsigned_find_mappings_by_value(
+               struct bt_ctf_field_type_common *ft, uint64_t value);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_signed_get_mapping_by_index(
+               struct bt_ctf_field_type_common *ft, uint64_t index,
+               const char **mapping_name, int64_t *range_begin,
+               int64_t *range_end);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_unsigned_get_mapping_by_index(
+               struct bt_ctf_field_type_common *ft, uint64_t index,
+               const char **mapping_name, uint64_t *range_begin,
+               uint64_t *range_end);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_enumeration_borrow_container_field_type(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_signed_add_mapping(
+               struct bt_ctf_field_type_common *ft, const char *string,
+               int64_t range_start, int64_t range_end);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_unsigned_add_mapping(
+               struct bt_ctf_field_type_common *ft, const char *string,
+               uint64_t range_start, uint64_t range_end);
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_enumeration_get_mapping_count(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_get_exponent_digits(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_set_exponent_digits(
+               struct bt_ctf_field_type_common *ft,
+               unsigned int exponent_digits);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_get_mantissa_digits(
+               struct bt_ctf_field_type_common *type);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_set_mantissa_digits(
+               struct bt_ctf_field_type_common *ft, unsigned int mantissa_digits);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_replace_field(
+               struct bt_ctf_field_type_common *ft,
+               const char *field_name,
+               struct bt_ctf_field_type_common *field_type);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_add_field(struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *field_type,
+               const char *field_name);
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_structure_get_field_count(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_borrow_field_by_index(
+               struct bt_ctf_field_type_common *ft,
+               const char **field_name,
+               struct bt_ctf_field_type_common **field_type, uint64_t index);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               struct bt_ctf_field_type_common *ft, const char *name);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_tag_field_type(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+const char *bt_ctf_field_type_common_variant_get_tag_name(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_set_tag_name(
+               struct bt_ctf_field_type_common *ft, const char *name);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_add_field(struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *field_type,
+               const char *field_name);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_update_choices(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_by_name(
+               struct bt_ctf_field_type_common *ft,
+               const char *field_name);
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_variant_get_field_count(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_borrow_field_by_index(
+               struct bt_ctf_field_type_common *ft,
+               const char **field_name,
+               struct bt_ctf_field_type_common **field_type, uint64_t index);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_array_borrow_element_field_type(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_set_element_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft);
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_array_get_length(struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_sequence_borrow_element_field_type(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_set_element_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *element_ft);
+
+BT_HIDDEN
+const char *bt_ctf_field_type_common_sequence_get_length_field_name(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+enum bt_ctf_string_encoding bt_ctf_field_type_common_string_get_encoding(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_string_set_encoding(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_string_encoding encoding);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_get_alignment(struct bt_ctf_field_type_common *type);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_set_alignment(struct bt_ctf_field_type_common *ft,
+               unsigned int alignment);
+
+BT_HIDDEN
+enum bt_ctf_byte_order bt_ctf_field_type_common_get_byte_order(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_set_byte_order(struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+enum bt_ctf_field_type_id bt_ctf_field_type_common_get_type_id(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_freeze(struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_signed(
+               struct bt_ctf_field_type_common_variant *var_ft,
+               int64_t tag_value);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *
+bt_ctf_field_type_common_variant_borrow_field_type_unsigned(
+               struct bt_ctf_field_type_common_variant *var_ft,
+               uint64_t tag_value);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *bt_ctf_field_type_common_copy(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_get_field_name_index(
+               struct bt_ctf_field_type_common *ft, const char *name);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_get_field_name_index(
+               struct bt_ctf_field_type_common *ft, const char *name);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_set_length_field_path(
+               struct bt_ctf_field_type_common *ft, struct bt_ctf_field_path *path);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_set_tag_field_path(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_path *path);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_set_tag_field_type(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_field_type_common *tag_ft);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_generic_freeze(struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_freeze_recursive(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_freeze_recursive(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_freeze_recursive(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_freeze_recursive(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_freeze_recursive(
+               struct bt_ctf_field_type_common *type);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_integer_set_byte_order(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_enumeration_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_floating_point_set_byte_order(
+               struct bt_ctf_field_type_common *ft, enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_structure_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_variant_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_array_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+void bt_ctf_field_type_common_sequence_set_byte_order_recursive(
+               struct bt_ctf_field_type_common *ft,
+               enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_integer_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_floating_point_compare(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_enumeration_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_string_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_structure_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_variant_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_array_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_sequence_compare_recursive(
+               struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_compare(struct bt_ctf_field_type_common *ft_a,
+               struct bt_ctf_field_type_common *ft_b);
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_get_field_count(struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+struct bt_ctf_field_type_common *bt_ctf_field_type_common_borrow_field_at_index(
+               struct bt_ctf_field_type_common *ft, int index);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_get_field_index(struct bt_ctf_field_type_common *ft,
+               const char *name);
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_type_common_variant_borrow_tag_field_path(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+struct bt_ctf_field_path *bt_ctf_field_type_common_sequence_borrow_length_field_path(
+               struct bt_ctf_field_type_common *ft);
+
+BT_HIDDEN
+int bt_ctf_field_type_common_validate_single_clock_class(
+               struct bt_ctf_field_type_common *ft,
+               struct bt_ctf_clock_class **expected_clock_class);
+
+BT_HIDDEN
+int64_t bt_ctf_field_type_common_variant_find_choice_index(
+               struct bt_ctf_field_type_common *ft, uint64_t uval,
+               bool is_signed);
+
+BT_HIDDEN
+int bt_ctf_field_type_serialize_recursive(struct bt_ctf_field_type *type,
+               struct metadata_context *context);
+
+BT_HIDDEN
+struct bt_ctf_field_type *bt_ctf_field_type_copy(struct bt_ctf_field_type *ft);
+
+#endif /* BABELTRACE_CTF_WRITER_FIELD_TYPES_INTERNAL_H */
diff --git a/src/ctf-writer/field-wrapper.c b/src/ctf-writer/field-wrapper.c
new file mode 100644 (file)
index 0000000..eecd330
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-FIELD-WRAPPER"
+#include "logging.h"
+
+#include <glib.h>
+
+#include "lib/object-pool.h"
+
+#include "fields.h"
+#include "field-wrapper.h"
+#include "object.h"
+
+BT_HIDDEN
+struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_new(void *data)
+{
+       struct bt_ctf_field_wrapper *field_wrapper =
+               g_new0(struct bt_ctf_field_wrapper, 1);
+
+       BT_LOGD_STR("Creating empty field wrapper object.");
+
+       if (!field_wrapper) {
+               BT_LOGE("Failed to allocate one field wrapper.");
+               goto end;
+       }
+
+       bt_ctf_object_init_unique(&field_wrapper->base);
+       BT_LOGD("Created empty field wrapper object: addr=%p",
+               field_wrapper);
+
+end:
+       return field_wrapper;
+}
+
+BT_HIDDEN
+void bt_ctf_field_wrapper_destroy(struct bt_ctf_field_wrapper *field_wrapper)
+{
+       BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper);
+       BT_ASSERT(!field_wrapper->field);
+       BT_LOGD_STR("Putting stream class.");
+       g_free(field_wrapper);
+}
+
+BT_HIDDEN
+struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_create(
+               struct bt_ctf_object_pool *pool, struct bt_ctf_field_type *ft)
+{
+       struct bt_ctf_field_wrapper *field_wrapper = NULL;
+
+       BT_ASSERT(pool);
+       BT_ASSERT(ft);
+       field_wrapper = bt_ctf_object_pool_create_object(pool);
+       if (!field_wrapper) {
+               BT_LOGE("Cannot allocate one field wrapper");
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_ctf_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return field_wrapper;
+}
diff --git a/src/ctf-writer/field-wrapper.h b/src/ctf-writer/field-wrapper.h
new file mode 100644 (file)
index 0000000..55aee6c
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef BABELTRACE_CTF_WRITER_FIELD_WRAPPER_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_FIELD_WRAPPER_INTERNAL_H
+
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+
+#include "fields.h"
+#include "object.h"
+#include "object-pool.h"
+
+struct bt_ctf_field_wrapper {
+       struct bt_ctf_object base;
+
+       /* Owned by this */
+       struct bt_ctf_field_common *field;
+};
+
+BT_HIDDEN
+struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_new(void *data);
+
+BT_HIDDEN
+void bt_ctf_field_wrapper_destroy(struct bt_ctf_field_wrapper *field);
+
+BT_HIDDEN
+struct bt_ctf_field_wrapper *bt_ctf_field_wrapper_create(
+               struct bt_ctf_object_pool *pool, struct bt_ctf_field_type *ft);
+
+#endif /* BABELTRACE_CTF_WRITER_FIELD_WRAPPER_INTERNAL_H */
diff --git a/src/ctf-writer/fields.c b/src/ctf-writer/fields.c
new file mode 100644 (file)
index 0000000..832f8f2
--- /dev/null
@@ -0,0 +1,1862 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-FIELDS"
+#include "logging.h"
+
+#include <float.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <babeltrace2/ctf-writer/object.h>
+
+#include "common/align.h"
+#include "common/assert.h"
+#include "compat/compiler.h"
+#include "compat/endian.h"
+#include "compat/fcntl.h"
+#include "ctfser/ctfser.h"
+
+#include "assert-pre.h"
+#include "fields.h"
+#include "field-types.h"
+#include "object.h"
+
+#define BT_CTF_ASSERT_PRE_CTF_FIELD_IS_INT_OR_ENUM(_field, _name)              \
+       BT_CTF_ASSERT_PRE((_field)->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER || \
+               (_field)->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,        \
+               _name " is not an integer or an enumeration field: "    \
+               "field-addr=%p", (_field))
+
+BT_HIDDEN
+struct bt_ctf_field_common *bt_ctf_field_common_copy(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common *copy = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT(field_type_common_has_known_id(field->type));
+       BT_ASSERT(field->methods->copy);
+       copy = field->methods->copy(field);
+       if (!copy) {
+               BT_LOGW("Cannot create field: ft-addr=%p", field->type);
+               goto end;
+       }
+
+       bt_ctf_field_common_set(copy, field->payload_set);
+
+end:
+       return copy;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_structure_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_structure *structure_type =
+               BT_CTF_FROM_COMMON(type);
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+       size_t i;
+
+       BT_LOGD("Initializing common structure field object: ft-addr=%p", type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       structure->fields = g_ptr_array_new_with_free_func(field_release_func);
+       g_ptr_array_set_size(structure->fields, structure_type->fields->len);
+
+       /* Create all fields contained in the structure field. */
+       for (i = 0; i < structure_type->fields->len; i++) {
+               struct bt_ctf_field_common *field;
+               struct bt_ctf_field_type_common_structure_field *struct_field =
+                       BT_CTF_FIELD_TYPE_COMMON_STRUCTURE_FIELD_AT_INDEX(
+                               structure_type, i);
+               field = field_create_func(struct_field->type);
+               if (!field) {
+                       BT_LOGE("Failed to create structure field's member: name=\"%s\", index=%zu",
+                               g_quark_to_string(struct_field->name), i);
+                       ret = -1;
+                       goto end;
+               }
+
+               g_ptr_array_index(structure->fields, i) = field;
+       }
+
+       BT_LOGD("Initialized common structure field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_variant_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func)
+{
+       int ret = 0;
+       struct bt_ctf_field_type_common_variant *variant_type =
+               BT_CTF_FROM_COMMON(type);
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+       size_t i;
+
+       BT_LOGD("Initializing common variant field object: ft-addr=%p", type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       ret = bt_ctf_field_type_common_variant_update_choices(type);
+       if (ret) {
+               BT_LOGE("Cannot update common variant field type choices: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       variant->fields = g_ptr_array_new_with_free_func(field_release_func);
+       g_ptr_array_set_size(variant->fields, variant_type->choices->len);
+
+       /* Create all fields contained in the variant field. */
+       for (i = 0; i < variant_type->choices->len; i++) {
+               struct bt_ctf_field_common *field;
+               struct bt_ctf_field_type_common_variant_choice *var_choice =
+                       BT_CTF_FIELD_TYPE_COMMON_VARIANT_CHOICE_AT_INDEX(
+                               variant_type, i);
+
+               field = field_create_func(var_choice->type);
+               if (!field) {
+                       BT_LOGE("Failed to create variant field's member: name=\"%s\", index=%zu",
+                               g_quark_to_string(var_choice->name), i);
+                       ret = -1;
+                       goto end;
+               }
+
+               g_ptr_array_index(variant->fields, i) = field;
+       }
+
+       BT_LOGD("Initialized common variant field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_string_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods)
+{
+       int ret = 0;
+       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Initializing common string field object: ft-addr=%p", type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       string->buf = g_array_sized_new(FALSE, FALSE, sizeof(char), 1);
+       if (!string->buf) {
+               ret = -1;
+               goto end;
+       }
+
+       g_array_index(string->buf, char, 0) = '\0';
+       BT_LOGD("Initialized common string field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_array_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_destroy_func)
+{
+       struct bt_ctf_field_type_common_array *array_type = BT_CTF_FROM_COMMON(type);
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+       unsigned int array_length;
+       int ret = 0;
+       uint64_t i;
+
+       BT_LOGD("Initializing common array field object: ft-addr=%p", type);
+       BT_ASSERT(type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       array_length = array_type->length;
+       array->elements = g_ptr_array_sized_new(array_length);
+       if (!array->elements) {
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_set_free_func(array->elements, field_destroy_func);
+       g_ptr_array_set_size(array->elements, array_length);
+
+       for (i = 0; i < array_length; i++) {
+               array->elements->pdata[i] = field_create_func(
+                       array_type->element_ft);
+               if (!array->elements->pdata[i]) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       BT_LOGD("Initialized common array field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_sequence_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               GDestroyNotify field_destroy_func)
+{
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+       int ret = 0;
+
+       BT_LOGD("Initializing common sequence field object: ft-addr=%p", type);
+       BT_ASSERT(type);
+       bt_ctf_field_common_initialize(field, type, is_shared,
+               release_func, methods);
+       sequence->elements = g_ptr_array_new();
+       if (!sequence->elements) {
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_set_free_func(sequence->elements, field_destroy_func);
+       BT_LOGD("Initialized common sequence field object: addr=%p, ft-addr=%p",
+               field, type);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_generic_validate(struct bt_ctf_field_common *field)
+{
+       return (field && field->payload_set) ? 0 : -1;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_structure_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < structure->fields->len; i++) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       (void *) structure->fields->pdata[i]);
+
+               if (ret) {
+                       int this_ret;
+                       const char *name;
+
+                       this_ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               field->type, &name, NULL, i);
+                       BT_ASSERT(this_ret == 0);
+                       BT_CTF_ASSERT_PRE_MSG("Invalid structure field's field: "
+                               "struct-field-addr=%p, field-name=\"%s\", "
+                               "index=%" PRId64 ", field-addr=%p",
+                               field, name, i, structure->fields->pdata[i]);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_variant_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int ret = 0;
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       if (!variant->current_field) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_common_validate_recursive(variant->current_field);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_array_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < array->elements->len; i++) {
+               ret = bt_ctf_field_common_validate_recursive((void *) array->elements->pdata[i]);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid array field's element field: "
+                               "array-field-addr=%p, %" PRId64 ", "
+                               "elem-field-addr=%p",
+                               field, i, array->elements->pdata[i]);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_common_sequence_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < sequence->elements->len; i++) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       (void *) sequence->elements->pdata[i]);
+               if (ret) {
+                       BT_CTF_ASSERT_PRE_MSG("Invalid sequence field's element field: "
+                               "seq-field-addr=%p, %" PRId64 ", "
+                               "elem-field-addr=%p",
+                               field, i, sequence->elements->pdata[i]);
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_generic_reset(struct bt_ctf_field_common *field)
+{
+       BT_ASSERT(field);
+       field->payload_set = false;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_structure_reset_recursive(struct bt_ctf_field_common *field)
+{
+       int64_t i;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < structure->fields->len; i++) {
+               struct bt_ctf_field_common *member = structure->fields->pdata[i];
+
+               if (!member) {
+                       /*
+                        * Structure members are lazily initialized;
+                        * skip if this member has not been allocated
+                        * yet.
+                        */
+                       continue;
+               }
+
+               bt_ctf_field_common_reset_recursive(member);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_variant_reset_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       variant->current_field = NULL;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_array_reset_recursive(struct bt_ctf_field_common *field)
+{
+       size_t i;
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < array->elements->len; i++) {
+               struct bt_ctf_field_common *member = array->elements->pdata[i];
+
+               if (!member) {
+                       /*
+                        * Array elements are lazily initialized; skip
+                        * if this member has not been allocated yet.
+                        */
+                       continue;
+               }
+
+               bt_ctf_field_common_reset_recursive(member);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_sequence_reset_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+       uint64_t i;
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < sequence->elements->len; i++) {
+               if (sequence->elements->pdata[i]) {
+                       bt_ctf_field_common_reset_recursive(
+                               sequence->elements->pdata[i]);
+               }
+       }
+
+       sequence->length = 0;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_generic_set_is_frozen(struct bt_ctf_field_common *field,
+               bool is_frozen)
+{
+       field->frozen = is_frozen;
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_structure_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       uint64_t i;
+       struct bt_ctf_field_common_structure *structure_field =
+               BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Freezing structure field object: addr=%p", field);
+
+       for (i = 0; i < structure_field->fields->len; i++) {
+               struct bt_ctf_field_common *struct_field =
+                       g_ptr_array_index(structure_field->fields, i);
+
+               BT_LOGD("Freezing structure field's field: field-addr=%p, index=%" PRId64,
+                       struct_field, i);
+               bt_ctf_field_common_set_is_frozen_recursive(struct_field,
+                       is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_variant_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       uint64_t i;
+       struct bt_ctf_field_common_variant *variant_field = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Freezing variant field object: addr=%p", field);
+
+       for (i = 0; i < variant_field->fields->len; i++) {
+               struct bt_ctf_field_common *var_field =
+                       g_ptr_array_index(variant_field->fields, i);
+
+               BT_LOGD("Freezing variant field's field: field-addr=%p, index=%" PRId64,
+                       var_field, i);
+               bt_ctf_field_common_set_is_frozen_recursive(var_field, is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_array_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       int64_t i;
+       struct bt_ctf_field_common_array *array_field = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Freezing array field object: addr=%p", field);
+
+       for (i = 0; i < array_field->elements->len; i++) {
+               struct bt_ctf_field_common *elem_field =
+                       g_ptr_array_index(array_field->elements, i);
+
+               BT_LOGD("Freezing array field object's element field: "
+                       "element-field-addr=%p, index=%" PRId64,
+                       elem_field, i);
+               bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void bt_ctf_field_common_sequence_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       int64_t i;
+       struct bt_ctf_field_common_sequence *sequence_field =
+               BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Freezing sequence field object: addr=%p", field);
+
+       for (i = 0; i < sequence_field->length; i++) {
+               struct bt_ctf_field_common *elem_field =
+                       g_ptr_array_index(sequence_field->elements, i);
+
+               BT_LOGD("Freezing sequence field object's element field: "
+                       "element-field-addr=%p, index=%" PRId64,
+                       elem_field, i);
+               bt_ctf_field_common_set_is_frozen_recursive(elem_field, is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void _bt_ctf_field_common_set_is_frozen_recursive(struct bt_ctf_field_common *field,
+               bool is_frozen)
+{
+       if (!field) {
+               goto end;
+       }
+
+       BT_LOGD("Setting field object's frozen state: addr=%p, is-frozen=%d",
+               field, is_frozen);
+       BT_ASSERT(field_type_common_has_known_id(field->type));
+       BT_ASSERT(field->methods->set_is_frozen);
+       field->methods->set_is_frozen(field, is_frozen);
+
+end:
+       return;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_generic_is_set(struct bt_ctf_field_common *field)
+{
+       return field && field->payload_set;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_structure_is_set_recursive(
+               struct bt_ctf_field_common *field)
+{
+       bt_bool is_set = BT_FALSE;
+       size_t i;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < structure->fields->len; i++) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       structure->fields->pdata[i]);
+               if (!is_set) {
+                       goto end;
+               }
+       }
+
+end:
+       return is_set;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_variant_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+       bt_bool is_set = BT_FALSE;
+
+       BT_ASSERT(field);
+
+       if (variant->current_field) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       variant->current_field);
+       }
+
+       return is_set;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_array_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       size_t i;
+       bt_bool is_set = BT_FALSE;
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < array->elements->len; i++) {
+               is_set = bt_ctf_field_common_is_set_recursive(array->elements->pdata[i]);
+               if (!is_set) {
+                       goto end;
+               }
+       }
+
+end:
+       return is_set;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_sequence_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       size_t i;
+       bt_bool is_set = BT_FALSE;
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+
+       if (!sequence->elements) {
+               goto end;
+       }
+
+       for (i = 0; i < sequence->elements->len; i++) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       sequence->elements->pdata[i]);
+               if (!is_set) {
+                       goto end;
+               }
+       }
+
+end:
+       return is_set;
+}
+
+static struct bt_ctf_field_common_methods bt_ctf_field_integer_methods = {
+       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
+       .validate = bt_ctf_field_common_generic_validate,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_generic_is_set,
+       .reset = bt_ctf_field_common_generic_reset,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_floating_point_methods = {
+       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
+       .validate = bt_ctf_field_common_generic_validate,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_generic_is_set,
+       .reset = bt_ctf_field_common_generic_reset,
+};
+
+static
+void bt_ctf_field_enumeration_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen);
+
+static
+int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field);
+
+static
+bt_bool bt_ctf_field_enumeration_is_set_recursive(
+               struct bt_ctf_field_common *field);
+
+static
+void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field);
+
+static struct bt_ctf_field_common_methods bt_ctf_field_enumeration_methods = {
+       .set_is_frozen = bt_ctf_field_enumeration_set_is_frozen_recursive,
+       .validate = bt_ctf_field_enumeration_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_enumeration_is_set_recursive,
+       .reset = bt_ctf_field_enumeration_reset_recursive,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_string_methods = {
+       .set_is_frozen = bt_ctf_field_common_generic_set_is_frozen,
+       .validate = bt_ctf_field_common_generic_validate,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_generic_is_set,
+       .reset = bt_ctf_field_common_generic_reset,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_structure_methods = {
+       .set_is_frozen = bt_ctf_field_common_structure_set_is_frozen_recursive,
+       .validate = bt_ctf_field_common_structure_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_structure_is_set_recursive,
+       .reset = bt_ctf_field_common_structure_reset_recursive,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_sequence_methods = {
+       .set_is_frozen = bt_ctf_field_common_sequence_set_is_frozen_recursive,
+       .validate = bt_ctf_field_common_sequence_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_sequence_is_set_recursive,
+       .reset = bt_ctf_field_common_sequence_reset_recursive,
+};
+
+static struct bt_ctf_field_common_methods bt_ctf_field_array_methods = {
+       .set_is_frozen = bt_ctf_field_common_array_set_is_frozen_recursive,
+       .validate = bt_ctf_field_common_array_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_common_array_is_set_recursive,
+       .reset = bt_ctf_field_common_array_reset_recursive,
+};
+
+static
+void bt_ctf_field_variant_set_is_frozen_recursive(struct bt_ctf_field_common *field,
+               bool is_frozen);
+
+static
+int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field);
+
+static
+bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field);
+
+static
+void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field);
+
+static struct bt_ctf_field_common_methods bt_ctf_field_variant_methods = {
+       .set_is_frozen = bt_ctf_field_variant_set_is_frozen_recursive,
+       .validate = bt_ctf_field_variant_validate_recursive,
+       .copy = NULL,
+       .is_set = bt_ctf_field_variant_is_set_recursive,
+       .reset = bt_ctf_field_variant_reset_recursive,
+};
+
+static
+struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_enumeration_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_floating_point_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_structure_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *);
+
+static
+struct bt_ctf_field *(* const field_create_funcs[])(struct bt_ctf_field_type *) = {
+       [BT_CTF_FIELD_TYPE_ID_INTEGER] =        bt_ctf_field_integer_create,
+       [BT_CTF_FIELD_TYPE_ID_ENUM] =           bt_ctf_field_enumeration_create,
+       [BT_CTF_FIELD_TYPE_ID_FLOAT] =          bt_ctf_field_floating_point_create,
+       [BT_CTF_FIELD_TYPE_ID_STRUCT] =         bt_ctf_field_structure_create,
+       [BT_CTF_FIELD_TYPE_ID_VARIANT] =        bt_ctf_field_variant_create,
+       [BT_CTF_FIELD_TYPE_ID_ARRAY] =          bt_ctf_field_array_create,
+       [BT_CTF_FIELD_TYPE_ID_SEQUENCE] =       bt_ctf_field_sequence_create,
+       [BT_CTF_FIELD_TYPE_ID_STRING] =         bt_ctf_field_string_create,
+};
+
+typedef int (*bt_ctf_field_serialize_recursive_func)(
+               struct bt_ctf_field_common *, struct bt_ctfser *,
+               enum bt_ctf_byte_order);
+
+static
+void bt_ctf_field_integer_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer integer field object: addr=%p", field);
+       bt_ctf_field_common_integer_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_floating_point_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer floating point field object: addr=%p",
+               field);
+       bt_ctf_field_common_floating_point_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_enumeration_destroy_recursive(struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_enumeration *enumeration = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Destroying CTF writer enumeration field object: addr=%p",
+               field);
+       BT_LOGD_STR("Putting container field.");
+       bt_ctf_object_put_ref(enumeration->container);
+       bt_ctf_field_common_finalize((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_structure_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer structure field object: addr=%p", field);
+       bt_ctf_field_common_structure_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_variant_destroy_recursive(struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGD("Destroying CTF writer variant field object: addr=%p", field);
+       BT_LOGD_STR("Putting tag field.");
+       bt_ctf_object_put_ref(variant->tag);
+       bt_ctf_field_common_variant_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_array_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer array field object: addr=%p", field);
+       bt_ctf_field_common_array_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_sequence_destroy_recursive(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer sequence field object: addr=%p", field);
+       bt_ctf_field_common_sequence_finalize_recursive((void *) field);
+       g_free(field);
+}
+
+static
+void bt_ctf_field_string_destroy(struct bt_ctf_field *field)
+{
+       BT_LOGD("Destroying CTF writer string field object: addr=%p", field);
+       bt_ctf_field_common_string_finalize((void *) field);
+       g_free(field);
+}
+
+BT_HIDDEN
+int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       struct bt_ctf_field_common *field_common = (void *) field;
+       bt_ctf_field_serialize_recursive_func serialize_func;
+
+       BT_ASSERT(ctfser);
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT(field_common->spec.writer.serialize_func);
+       serialize_func = field_common->spec.writer.serialize_func;
+       return serialize_func(field_common, ctfser,
+               native_byte_order);
+}
+
+static
+int bt_ctf_field_integer_serialize(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int ret;
+       struct bt_ctf_field_type_common_integer *int_type =
+               BT_CTF_FROM_COMMON(field->type);
+       struct bt_ctf_field_common_integer *int_field =
+               BT_CTF_FROM_COMMON(field);
+       enum bt_ctf_byte_order byte_order;
+
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Integer field");
+       BT_LOGV("Serializing CTF writer integer field: addr=%p, native-bo=%s",
+               field,
+               bt_ctf_byte_order_string(native_byte_order));
+       byte_order = int_type->user_byte_order;
+       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
+               byte_order = native_byte_order;
+       }
+
+       if (int_type->is_signed) {
+               ret = bt_ctfser_write_signed_int(ctfser,
+                       int_field->payload.signd, int_type->common.alignment,
+                       int_type->size,
+                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN);
+       } else {
+               ret = bt_ctfser_write_unsigned_int(ctfser,
+                       int_field->payload.unsignd, int_type->common.alignment,
+                       int_type->size,
+                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN);
+       }
+
+       if (unlikely(ret)) {
+               BT_LOGE("Cannot serialize integer field: ret=%d", ret);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_enumeration_serialize_recursive(
+               struct bt_ctf_field_common *field, struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       BT_LOGV("Serializing enumeration field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+       BT_LOGV_STR("Serializing enumeration field's payload field.");
+       return bt_ctf_field_serialize_recursive(
+               (void *) enumeration->container, ctfser, native_byte_order);
+}
+
+static
+int bt_ctf_field_floating_point_serialize(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int ret = -1;
+       struct bt_ctf_field_type_common_floating_point *flt_type =
+               BT_CTF_FROM_COMMON(field->type);
+       struct bt_ctf_field_common_floating_point *flt_field = BT_CTF_FROM_COMMON(field);
+       enum bt_ctf_byte_order byte_order;
+
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
+       BT_LOGV("Serializing floating point number field: "
+               "addr=%p, native-bo=%s", field,
+               bt_ctf_byte_order_string(native_byte_order));
+
+       byte_order = flt_type->user_byte_order;
+       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
+               byte_order = native_byte_order;
+       }
+
+       if (flt_type->mant_dig == FLT_MANT_DIG) {
+               ret = bt_ctfser_write_float32(ctfser, flt_field->payload,
+                       flt_type->common.alignment,
+                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN);
+       } else if (flt_type->mant_dig == DBL_MANT_DIG) {
+               ret = bt_ctfser_write_float64(ctfser, flt_field->payload,
+                       flt_type->common.alignment,
+                       byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN);
+       } else {
+               abort();
+       }
+
+       if (unlikely(ret)) {
+               BT_LOGE("Cannot serialize floating point number field: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_structure_serialize_recursive(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int64_t i;
+       int ret;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGV("Serializing structure field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+       ret = bt_ctfser_align_offset_in_current_packet(ctfser,
+               field->type->alignment);
+       if (unlikely(ret)) {
+               BT_LOGE("Cannot align offset before serializing structure field: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       for (i = 0; i < structure->fields->len; i++) {
+               struct bt_ctf_field_common *member = g_ptr_array_index(
+                       structure->fields, i);
+               const char *field_name = NULL;
+
+               BT_LOGV("Serializing structure field's field: ser-offset=%" PRIu64 ", "
+                       "field-addr=%p, index=%" PRIu64,
+                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+                       member, i);
+
+               if (unlikely(!member)) {
+                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               field->type, &field_name, NULL, i);
+                       BT_ASSERT(ret == 0);
+                       BT_LOGW("Cannot serialize structure field's field: field is not set: "
+                               "struct-field-addr=%p, "
+                               "field-name=\"%s\", index=%" PRId64,
+                               field, field_name, i);
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = bt_ctf_field_serialize_recursive((void *) member, ctfser,
+                       native_byte_order);
+               if (unlikely(ret)) {
+                       ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                               field->type, &field_name, NULL, i);
+                       BT_ASSERT(ret == 0);
+                       BT_LOGW("Cannot serialize structure field's field: "
+                               "struct-field-addr=%p, field-addr=%p, "
+                               "field-name=\"%s\", index=%" PRId64,
+                               field->type, member, field_name, i);
+                       break;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_variant_serialize_recursive(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGV("Serializing variant field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+       BT_LOGV_STR("Serializing variant field's payload field.");
+       return bt_ctf_field_serialize_recursive(
+               (void *) variant->current_field, ctfser, native_byte_order);
+}
+
+static
+int bt_ctf_field_array_serialize_recursive(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGV("Serializing array field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+
+       for (i = 0; i < array->elements->len; i++) {
+               struct bt_ctf_field_common *elem_field =
+                       g_ptr_array_index(array->elements, i);
+
+               BT_LOGV("Serializing array field's element field: "
+                       "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
+                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+                       elem_field, i);
+               ret = bt_ctf_field_serialize_recursive(
+                       (void *) elem_field, ctfser, native_byte_order);
+               if (unlikely(ret)) {
+                       BT_LOGW("Cannot serialize array field's element field: "
+                               "array-field-addr=%p, field-addr=%p, "
+                               "index=%" PRId64, field, elem_field, i);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_sequence_serialize_recursive(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int64_t i;
+       int ret = 0;
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_LOGV("Serializing sequence field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string(native_byte_order));
+
+       for (i = 0; i < sequence->elements->len; i++) {
+               struct bt_ctf_field_common *elem_field =
+                       g_ptr_array_index(sequence->elements, i);
+
+               BT_LOGV("Serializing sequence field's element field: "
+                       "ser-offset=%" PRIu64 ", field-addr=%p, index=%" PRId64,
+                       bt_ctfser_get_offset_in_current_packet_bits(ctfser),
+                       elem_field, i);
+               ret = bt_ctf_field_serialize_recursive(
+                       (void *) elem_field, ctfser, native_byte_order);
+               if (unlikely(ret)) {
+                       BT_LOGW("Cannot serialize sequence field's element field: "
+                               "sequence-field-addr=%p, field-addr=%p, "
+                               "index=%" PRId64, field, elem_field, i);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int bt_ctf_field_string_serialize(struct bt_ctf_field_common *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order)
+{
+       int ret;
+       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
+       BT_LOGV("Serializing string field: addr=%p, native-bo=%s",
+               field, bt_ctf_byte_order_string((int) native_byte_order));
+       ret = bt_ctfser_write_string(ctfser, (const char *) string->buf->data);
+       if (unlikely(ret)) {
+               BT_LOGE("Cannot serialize string field: ret=%d", ret);
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+struct bt_ctf_field *bt_ctf_field_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field *field = NULL;
+       enum bt_ctf_field_type_id type_id;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(type, "Field type");
+       BT_ASSERT(field_type_common_has_known_id((void *) type));
+       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_validate((void *) type) == 0,
+               "Field type is invalid: ft-addr=%p", type);
+       type_id = bt_ctf_field_type_get_type_id(type);
+       field = field_create_funcs[type_id](type);
+       if (!field) {
+               goto end;
+       }
+
+       bt_ctf_field_type_common_freeze((void *) type);
+
+end:
+       return field;
+}
+
+struct bt_ctf_field_type *bt_ctf_field_get_type(struct bt_ctf_field *field)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_common_borrow_type((void *) field));
+}
+
+enum bt_ctf_field_type_id bt_ctf_field_get_type_id(struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_common *field_common = (void *) field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
+       return (int) field_common->type->id;
+}
+
+int bt_ctf_field_sequence_set_length(struct bt_ctf_field *field,
+               struct bt_ctf_field *length_field)
+{
+       int ret;
+       struct bt_ctf_field_common *common_length_field = (void *) length_field;
+       uint64_t length;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(length_field, "Length field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) length_field, "Length field");
+       BT_CTF_ASSERT_PRE(common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_INTEGER ||
+                       common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM,
+               "Length field must be an integer or enumeration field: field-addr=%p",
+               length_field);
+
+       if (common_length_field->type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
+               struct bt_ctf_field_enumeration *enumeration = (void *)
+                       length_field;
+
+               length_field = (void *) enumeration->container;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_get_value(length_field, &length);
+       BT_ASSERT(ret == 0);
+       return bt_ctf_field_common_sequence_set_length((void *) field,
+               length, (bt_ctf_field_common_create_func) bt_ctf_field_create);
+}
+
+struct bt_ctf_field *bt_ctf_field_structure_get_field_by_index(
+               struct bt_ctf_field *field, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_index(
+               (void *) field, index));
+}
+
+struct bt_ctf_field *bt_ctf_field_structure_get_field_by_name(
+               struct bt_ctf_field *field, const char *name)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_common_structure_borrow_field_by_name(
+               (void *) field, name));
+}
+
+struct bt_ctf_field *bt_ctf_field_array_get_field(
+               struct bt_ctf_field *field, uint64_t index)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_field_common_array_borrow_field((void *) field, index));
+}
+
+struct bt_ctf_field *bt_ctf_field_sequence_get_field(
+               struct bt_ctf_field *field, uint64_t index)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_field_common_sequence_borrow_field((void *) field, index));
+}
+
+struct bt_ctf_field *bt_ctf_field_variant_get_field(struct bt_ctf_field *field,
+               struct bt_ctf_field *tag_field)
+{
+       struct bt_ctf_field_variant *variant_field = (void *) field;
+       struct bt_ctf_field_enumeration *enum_field = (void *) tag_field;
+       struct bt_ctf_field_type_common_variant *variant_ft;
+       struct bt_ctf_field_type_common_enumeration *tag_ft;
+       struct bt_ctf_field *current_field = NULL;
+       bt_bool is_signed;
+       uint64_t tag_uval;
+       int ret;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Variant field");
+       BT_CTF_ASSERT_PRE_NON_NULL(tag_field, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET((void *) tag_field, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_ctf_field_common *) tag_field,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Tag field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(
+               (struct bt_ctf_field_common *) field,
+               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_CTF_ASSERT_PRE(
+               bt_ctf_field_common_validate_recursive((void *) tag_field) == 0,
+               "Tag field is invalid: field-addr=%p", tag_field);
+       variant_ft = BT_CTF_FROM_COMMON(variant_field->common.common.type);
+       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_compare(
+               BT_CTF_TO_COMMON(variant_ft->tag_ft), enum_field->common.type) == 0,
+               "Unexpected tag field's type: expected-ft-addr=%p, "
+               "tag-ft-addr=%p", variant_ft->tag_ft,
+               enum_field->common.type);
+       tag_ft = BT_CTF_FROM_COMMON(enum_field->common.type);
+       is_signed = tag_ft->container_ft->is_signed;
+
+       if (is_signed) {
+               int64_t tag_ival;
+
+               ret = bt_ctf_field_integer_signed_get_value(
+                       (void *) enum_field->container, &tag_ival);
+               tag_uval = (uint64_t) tag_ival;
+       } else {
+               ret = bt_ctf_field_integer_unsigned_get_value(
+                       (void *) enum_field->container, &tag_uval);
+       }
+
+       BT_ASSERT(ret == 0);
+       ret = bt_ctf_field_common_variant_set_tag((void *) field, tag_uval,
+               is_signed);
+       if (ret) {
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(variant_field->tag);
+       variant_field->tag = bt_ctf_object_get_ref(tag_field);
+       current_field = bt_ctf_field_variant_get_current_field(field);
+       BT_ASSERT(current_field);
+
+end:
+       return current_field;
+}
+
+struct bt_ctf_field *bt_ctf_field_variant_get_current_field(
+               struct bt_ctf_field *variant_field)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_common_variant_borrow_current_field(
+               (void *) variant_field));
+}
+
+BT_HIDDEN
+struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container(
+               struct bt_ctf_field *field)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Enumeration field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID((struct bt_ctf_field_common *) field,
+               BT_CTF_FIELD_TYPE_ID_ENUM, "Field");
+       BT_ASSERT(enumeration->container);
+       return (void *) enumeration->container;
+}
+
+struct bt_ctf_field *bt_ctf_field_enumeration_get_container(
+               struct bt_ctf_field *field)
+{
+       return bt_ctf_object_get_ref(bt_ctf_field_enumeration_borrow_container(field));
+}
+
+int bt_ctf_field_integer_signed_get_value(struct bt_ctf_field *field,
+               int64_t *value)
+{
+       struct bt_ctf_field_common_integer *integer = (void *) field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
+               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
+       BT_CTF_ASSERT_PRE(bt_ctf_field_type_common_integer_is_signed(
+               integer->common.type),
+               "Field's type is unsigned: field-addr=%p", field);
+       *value = integer->payload.signd;
+       return 0;
+}
+
+int bt_ctf_field_integer_signed_set_value(struct bt_ctf_field *field,
+               int64_t value)
+{
+       int ret = 0;
+       struct bt_ctf_field_common_integer *integer = (void *) field;
+       struct bt_ctf_field_type_common_integer *integer_type;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
+               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
+       integer_type = BT_CTF_FROM_COMMON(integer->common.type);
+       BT_CTF_ASSERT_PRE(
+               bt_ctf_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is unsigned: field-addr=%p", field);
+       BT_CTF_ASSERT_PRE(value_is_in_range_signed(integer_type->size, value),
+               "Value is out of bounds: value=%" PRId64 ", field-addr=%p",
+               value, field);
+       integer->payload.signd = value;
+       bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true);
+       return ret;
+}
+
+int bt_ctf_field_integer_unsigned_get_value(struct bt_ctf_field *field,
+               uint64_t *value)
+{
+       struct bt_ctf_field_common_integer *integer = (void *) field;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(BT_CTF_TO_COMMON(integer), "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
+               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
+       BT_CTF_ASSERT_PRE(
+               !bt_ctf_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is signed: field-addr=%p", field);
+       *value = integer->payload.unsignd;
+       return 0;
+}
+
+int bt_ctf_field_integer_unsigned_set_value(struct bt_ctf_field *field,
+               uint64_t value)
+{
+       struct bt_ctf_field_common_integer *integer = (void *) field;
+       struct bt_ctf_field_type_common_integer *integer_type;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(BT_CTF_TO_COMMON(integer), "Integer field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(BT_CTF_TO_COMMON(integer),
+               BT_CTF_FIELD_TYPE_ID_INTEGER, "Field");
+       integer_type = BT_CTF_FROM_COMMON(integer->common.type);
+       BT_CTF_ASSERT_PRE(
+               !bt_ctf_field_type_common_integer_is_signed(integer->common.type),
+               "Field's type is signed: field-addr=%p", field);
+       BT_CTF_ASSERT_PRE(value_is_in_range_unsigned(integer_type->size, value),
+               "Value is out of bounds: value=%" PRIu64 ", field-addr=%p",
+               value, field);
+       integer->payload.unsignd = value;
+       bt_ctf_field_common_set(BT_CTF_TO_COMMON(integer), true);
+       return 0;
+}
+
+int bt_ctf_field_floating_point_get_value(struct bt_ctf_field *field,
+               double *value)
+{
+       return bt_ctf_field_common_floating_point_get_value((void *) field, value);
+}
+
+int bt_ctf_field_floating_point_set_value(struct bt_ctf_field *field,
+               double value)
+{
+       return bt_ctf_field_common_floating_point_set_value((void *) field, value);
+}
+
+const char *bt_ctf_field_string_get_value(struct bt_ctf_field *field)
+{
+       return bt_ctf_field_common_string_get_value((void *) field);
+}
+
+int bt_ctf_field_string_set_value(struct bt_ctf_field *field, const char *value)
+{
+       return bt_ctf_field_common_string_set_value((void *) field, value);
+}
+
+int bt_ctf_field_string_append(struct bt_ctf_field *field, const char *value)
+{
+       return bt_ctf_field_common_string_append((void *) field, value);
+}
+
+int bt_ctf_field_string_append_len(struct bt_ctf_field *field,
+               const char *value, unsigned int length)
+{
+       return bt_ctf_field_common_string_append_len((void *) field, value, length);
+}
+
+struct bt_ctf_field *bt_ctf_field_copy(struct bt_ctf_field *field)
+{
+       return (void *) bt_ctf_field_common_copy((void *) field);
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_integer_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_integer *integer =
+               g_new0(struct bt_ctf_field_common_integer, 1);
+
+       BT_LOGD("Creating CTF writer integer field object: ft-addr=%p", type);
+
+       if (integer) {
+               bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(integer), (void *) type,
+                       true,
+                       (bt_ctf_object_release_func) bt_ctf_field_integer_destroy,
+                       &bt_ctf_field_integer_methods);
+               integer->common.spec.writer.serialize_func =
+                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_integer_serialize;
+               BT_LOGD("Created CTF writer integer field object: addr=%p, ft-addr=%p",
+                       integer, type);
+       } else {
+               BT_LOGE_STR("Failed to allocate one integer field.");
+       }
+
+       return (void *) integer;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_enumeration_create(
+               struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_type_common_enumeration *enum_ft = (void *) type;
+       struct bt_ctf_field_enumeration *enumeration = g_new0(
+               struct bt_ctf_field_enumeration, 1);
+
+       BT_LOGD("Creating CTF writer enumeration field object: ft-addr=%p", type);
+
+       if (!enumeration) {
+               BT_LOGE_STR("Failed to allocate one enumeration field.");
+               goto end;
+       }
+
+       bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(enumeration),
+               (void *) type,
+               true, (bt_ctf_object_release_func)
+                       bt_ctf_field_enumeration_destroy_recursive,
+               &bt_ctf_field_enumeration_methods);
+       enumeration->container = (void *) bt_ctf_field_create(
+               BT_CTF_FROM_COMMON(enum_ft->container_ft));
+       if (!enumeration->container) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(enumeration);
+               goto end;
+       }
+
+       enumeration->common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func)
+                       bt_ctf_field_enumeration_serialize_recursive;
+       BT_LOGD("Created CTF writer enumeration field object: addr=%p, ft-addr=%p",
+               enumeration, type);
+
+end:
+       return (void *) enumeration;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_floating_point_create(
+               struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_floating_point *floating_point;
+
+       BT_LOGD("Creating CTF writer floating point number field object: ft-addr=%p", type);
+       floating_point = g_new0(struct bt_ctf_field_common_floating_point, 1);
+
+       if (floating_point) {
+               bt_ctf_field_common_initialize(BT_CTF_TO_COMMON(floating_point),
+                       (void *) type,
+                       true, (bt_ctf_object_release_func)
+                               bt_ctf_field_floating_point_destroy,
+                       &bt_ctf_field_floating_point_methods);
+               floating_point->common.spec.writer.serialize_func =
+                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_floating_point_serialize;
+               BT_LOGD("Created CTF writer floating point number field object: addr=%p, ft-addr=%p",
+                       floating_point, type);
+       } else {
+               BT_LOGE_STR("Failed to allocate one floating point number field.");
+       }
+
+       return (void *) floating_point;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_structure_create(
+               struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_structure *structure = g_new0(
+               struct bt_ctf_field_common_structure, 1);
+       int iret;
+
+       BT_LOGD("Creating CTF writer structure field object: ft-addr=%p", type);
+
+       if (!structure) {
+               BT_LOGE_STR("Failed to allocate one structure field.");
+               goto end;
+       }
+
+       iret = bt_ctf_field_common_structure_initialize(BT_CTF_TO_COMMON(structure),
+               (void *) type,
+               true, (bt_ctf_object_release_func)
+                       bt_ctf_field_structure_destroy_recursive,
+               &bt_ctf_field_structure_methods,
+               (bt_ctf_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       structure->common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_structure_serialize_recursive;
+       if (iret) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(structure);
+               goto end;
+       }
+
+       BT_LOGD("Created CTF writer structure field object: addr=%p, ft-addr=%p",
+               structure, type);
+
+end:
+       return (void *) structure;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_variant_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_type_common_variant *var_ft = (void *) type;
+       struct bt_ctf_field_variant *variant = g_new0(
+               struct bt_ctf_field_variant, 1);
+
+       BT_LOGD("Creating CTF writer variant field object: ft-addr=%p", type);
+
+       if (!variant) {
+               BT_LOGE_STR("Failed to allocate one variant field.");
+               goto end;
+       }
+
+       bt_ctf_field_common_variant_initialize(BT_CTF_TO_COMMON(BT_CTF_TO_COMMON(variant)),
+               (void *) type,
+               true, (bt_ctf_object_release_func)
+                       bt_ctf_field_variant_destroy_recursive,
+               &bt_ctf_field_variant_methods,
+               (bt_ctf_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       variant->tag = (void *) bt_ctf_field_create(
+               BT_CTF_FROM_COMMON(var_ft->tag_ft));
+       variant->common.common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_variant_serialize_recursive;
+       BT_LOGD("Created CTF writer variant field object: addr=%p, ft-addr=%p",
+               variant, type);
+
+end:
+       return (void *) variant;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_array_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_array *array =
+               g_new0(struct bt_ctf_field_common_array, 1);
+       int ret;
+
+       BT_LOGD("Creating CTF writer array field object: ft-addr=%p", type);
+       BT_ASSERT(type);
+
+       if (!array) {
+               BT_LOGE_STR("Failed to allocate one array field.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_common_array_initialize(BT_CTF_TO_COMMON(array),
+               (void *) type,
+               true, (bt_ctf_object_release_func)
+                       bt_ctf_field_array_destroy_recursive,
+               &bt_ctf_field_array_methods,
+               (bt_ctf_field_common_create_func) bt_ctf_field_create,
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       array->common.spec.writer.serialize_func =
+               (bt_ctf_field_serialize_recursive_func) bt_ctf_field_array_serialize_recursive;
+       if (ret) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(array);
+               goto end;
+       }
+
+       BT_LOGD("Created CTF writer array field object: addr=%p, ft-addr=%p",
+               array, type);
+
+end:
+       return (void *) array;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_sequence_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_sequence *sequence = g_new0(
+               struct bt_ctf_field_common_sequence, 1);
+
+       BT_LOGD("Creating CTF writer sequence field object: ft-addr=%p", type);
+
+       if (sequence) {
+               bt_ctf_field_common_sequence_initialize(BT_CTF_TO_COMMON(sequence),
+                       (void *) type,
+                       true, (bt_ctf_object_release_func)
+                               bt_ctf_field_sequence_destroy_recursive,
+                       &bt_ctf_field_sequence_methods,
+                       (GDestroyNotify) bt_ctf_object_put_ref);
+               sequence->common.spec.writer.serialize_func =
+                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_sequence_serialize_recursive;
+               BT_LOGD("Created CTF writer sequence field object: addr=%p, ft-addr=%p",
+                       sequence, type);
+       } else {
+               BT_LOGE_STR("Failed to allocate one sequence field.");
+       }
+
+       return (void *) sequence;
+}
+
+static
+struct bt_ctf_field *bt_ctf_field_string_create(struct bt_ctf_field_type *type)
+{
+       struct bt_ctf_field_common_string *string = g_new0(
+               struct bt_ctf_field_common_string, 1);
+
+       BT_LOGD("Creating CTF writer string field object: ft-addr=%p", type);
+
+       if (string) {
+               bt_ctf_field_common_string_initialize(BT_CTF_TO_COMMON(string),
+                       (void *) type,
+                       true, (bt_ctf_object_release_func)
+                               bt_ctf_field_string_destroy,
+                       &bt_ctf_field_string_methods);
+               string->common.spec.writer.serialize_func =
+                       (bt_ctf_field_serialize_recursive_func) bt_ctf_field_string_serialize;
+               BT_LOGD("Created CTF writer string field object: addr=%p, ft-addr=%p",
+                       string, type);
+       } else {
+               BT_LOGE_STR("Failed to allocate one string field.");
+       }
+
+       return (void *) string;
+}
+
+static
+void bt_ctf_field_enumeration_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               bt_ctf_field_common_set_is_frozen_recursive(
+                       (void *) enumeration->container, is_frozen);
+       }
+
+       bt_ctf_field_common_generic_set_is_frozen((void *) field, is_frozen);
+}
+
+static
+int bt_ctf_field_enumeration_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int ret = -1;
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       (void *) enumeration->container);
+       }
+
+       return ret;
+}
+
+static
+bt_bool bt_ctf_field_enumeration_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       bt_bool is_set = BT_FALSE;
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       (void *) enumeration->container);
+       }
+
+       return is_set;
+}
+
+static
+void bt_ctf_field_enumeration_reset_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_enumeration *enumeration = (void *) field;
+
+       if (enumeration->container) {
+               bt_ctf_field_common_reset_recursive(
+                       (void *) enumeration->container);
+       }
+
+       bt_ctf_field_common_generic_reset((void *) field);
+}
+
+static
+void bt_ctf_field_variant_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen)
+{
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               bt_ctf_field_common_set_is_frozen_recursive(
+                       (void *) variant->tag, is_frozen);
+       }
+
+       bt_ctf_field_common_variant_set_is_frozen_recursive((void *) field,
+               is_frozen);
+}
+
+static
+int bt_ctf_field_variant_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int ret;
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               ret = bt_ctf_field_common_validate_recursive(
+                       (void *) variant->tag);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = bt_ctf_field_common_variant_validate_recursive((void *) field);
+
+end:
+       return ret;
+}
+
+static
+bt_bool bt_ctf_field_variant_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       bt_bool is_set;
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               is_set = bt_ctf_field_common_is_set_recursive(
+                       (void *) variant->tag);
+               if (is_set) {
+                       goto end;
+               }
+       }
+
+       is_set = bt_ctf_field_common_variant_is_set_recursive((void *) field);
+
+end:
+       return is_set;
+}
+
+static
+void bt_ctf_field_variant_reset_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_variant *variant = (void *) field;
+
+       if (variant->tag) {
+               bt_ctf_field_common_reset_recursive(
+                       (void *) variant->tag);
+       }
+
+       bt_ctf_field_common_variant_reset_recursive((void *) field);
+}
+
+BT_CTF_ASSERT_PRE_FUNC
+static inline bool field_to_set_has_expected_type(
+               struct bt_ctf_field_common *struct_field,
+               const char *name, struct bt_ctf_field_common *value)
+{
+       bool ret = true;
+       struct bt_ctf_field_type_common *expected_field_type = NULL;
+
+       expected_field_type =
+               bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+                       struct_field->type, name);
+
+       if (bt_ctf_field_type_common_compare(expected_field_type, value->type)) {
+               BT_CTF_ASSERT_PRE_MSG("Value field's type is different from the expected field type: "
+                       "value-ft-addr=%p, expected-ft-addr=%p", value->type,
+                       expected_field_type);
+               ret = false;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
+               const char *name, struct bt_ctf_field *value)
+{
+       int ret = 0;
+       GQuark field_quark;
+       struct bt_ctf_field_common *common_field = (void *) field;
+       struct bt_ctf_field_common_structure *structure =
+               BT_CTF_FROM_COMMON(common_field);
+       struct bt_ctf_field_common *common_value = (void *) value;
+       size_t index;
+       GHashTable *field_name_to_index;
+       struct bt_ctf_field_type_common_structure *structure_ft;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Parent field");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Field name");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(common_field,
+               BT_CTF_FIELD_TYPE_ID_STRUCT, "Parent field");
+       BT_CTF_ASSERT_PRE(field_to_set_has_expected_type(common_field,
+               name, common_value),
+               "Value field's type is different from the expected field type.");
+       field_quark = g_quark_from_string(name);
+       structure_ft = BT_CTF_FROM_COMMON(common_field->type);
+       field_name_to_index = structure_ft->field_name_to_index;
+       if (!g_hash_table_lookup_extended(field_name_to_index,
+                       GUINT_TO_POINTER(field_quark), NULL,
+                       (gpointer *) &index)) {
+               BT_LOGV("Invalid parameter: no such field in structure field's type: "
+                       "struct-field-addr=%p, struct-ft-addr=%p, "
+                       "field-ft-addr=%p, name=\"%s\"",
+                       field, common_field->type, common_value->type, name);
+               ret = -1;
+               goto end;
+       }
+       bt_ctf_object_get_ref(value);
+       BT_CTF_OBJECT_MOVE_REF(structure->fields->pdata[index], value);
+
+end:
+       return ret;
+}
diff --git a/src/ctf-writer/fields.h b/src/ctf-writer/fields.h
new file mode 100644 (file)
index 0000000..b1525e4
--- /dev/null
@@ -0,0 +1,852 @@
+#ifndef BABELTRACE_CTF_WRITER_FIELDS_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_FIELDS_INTERNAL_H
+
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include <glib.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <babeltrace2/ctf-writer/fields.h>
+#include <babeltrace2/types.h>
+
+#include "common/babeltrace.h"
+#include "common/common.h"
+#include "ctfser/ctfser.h"
+
+#include "assert-pre.h"
+#include "field-types.h"
+#include "object.h"
+#include "utils.h"
+
+#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(_field, _type_id, _name) \
+       BT_CTF_ASSERT_PRE((_field)->type->id == ((int) (_type_id)),             \
+               _name " has the wrong type ID: expected-type-id=%s, "   \
+               "field-addr=%p",                                        \
+               bt_ctf_field_type_id_string((int) (_type_id)), (_field))
+
+#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(_field, _name)               \
+       BT_CTF_ASSERT_PRE(bt_ctf_field_common_is_set_recursive(_field), \
+               _name " is not set: field-addr=%p", (_field))
+
+#define BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(_field, _name)          \
+       BT_CTF_ASSERT_PRE_HOT((_field), (_name), ": field-addr=%p", (_field))
+
+struct bt_ctf_field_common;
+
+typedef void (*bt_ctf_field_common_method_set_is_frozen)(struct bt_ctf_field_common *,
+               bool);
+typedef int (*bt_ctf_field_common_method_validate)(struct bt_ctf_field_common *);
+typedef struct bt_ctf_field_common *(*bt_ctf_field_common_method_copy)(
+               struct bt_ctf_field_common *);
+typedef bt_bool (*bt_ctf_field_common_method_is_set)(struct bt_ctf_field_common *);
+typedef void (*bt_ctf_field_common_method_reset)(struct bt_ctf_field_common *);
+
+struct bt_ctf_field_common_methods {
+       bt_ctf_field_common_method_set_is_frozen set_is_frozen;
+       bt_ctf_field_common_method_validate validate;
+       bt_ctf_field_common_method_copy copy;
+       bt_ctf_field_common_method_is_set is_set;
+       bt_ctf_field_common_method_reset reset;
+};
+
+struct bt_ctf_field_common {
+       struct bt_ctf_object base;
+       struct bt_ctf_field_type_common *type;
+       struct bt_ctf_field_common_methods *methods;
+       bool payload_set;
+       bool frozen;
+
+       /*
+        * Specialized data for either CTF IR or CTF writer APIs.
+        * See comment in `field-types.h` for more details.
+        */
+       union {
+               struct {
+               } ir;
+               struct {
+                       void *serialize_func;
+               } writer;
+       } spec;
+};
+
+struct bt_ctf_field_common_integer {
+       struct bt_ctf_field_common common;
+       union {
+               int64_t signd;
+               uint64_t unsignd;
+       } payload;
+};
+
+struct bt_ctf_field_common_floating_point {
+       struct bt_ctf_field_common common;
+       double payload;
+};
+
+struct bt_ctf_field_common_structure {
+       struct bt_ctf_field_common common;
+
+       /* Array of `struct bt_ctf_field_common *`, owned by this */
+       GPtrArray *fields;
+};
+
+struct bt_ctf_field_common_variant {
+       struct bt_ctf_field_common common;
+
+       union {
+               uint64_t u;
+               int64_t i;
+       } tag_value;
+
+       /* Weak: belongs to `choices` below */
+       struct bt_ctf_field_common *current_field;
+
+       /* Array of `struct bt_ctf_field_common *`, owned by this */
+       GPtrArray *fields;
+};
+
+struct bt_ctf_field_common_array {
+       struct bt_ctf_field_common common;
+
+       /* Array of `struct bt_ctf_field_common *`, owned by this */
+       GPtrArray *elements;
+};
+
+struct bt_ctf_field_common_sequence {
+       struct bt_ctf_field_common common;
+
+       /*
+        * This is the true sequence field's length: its value can be
+        * less than `elements->len` below because we never shrink the
+        * array of elements to avoid reallocation.
+        */
+       uint64_t length;
+
+       /* Array of `struct bt_ctf_field_common *`, owned by this */
+       GPtrArray *elements;
+};
+
+struct bt_ctf_field_common_string {
+       struct bt_ctf_field_common common;
+       GArray *buf;
+       size_t size;
+};
+
+BT_HIDDEN
+struct bt_ctf_field_common *bt_ctf_field_common_copy(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+int bt_ctf_field_common_structure_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func);
+
+BT_HIDDEN
+int bt_ctf_field_common_array_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_destroy_func);
+
+BT_HIDDEN
+int bt_ctf_field_common_sequence_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               GDestroyNotify field_destroy_func);
+
+BT_HIDDEN
+int bt_ctf_field_common_variant_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods,
+               bt_ctf_field_common_create_func field_create_func,
+               GDestroyNotify field_release_func);
+
+BT_HIDDEN
+int bt_ctf_field_common_string_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *type,
+               bool is_shared, bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods);
+
+BT_HIDDEN
+int bt_ctf_field_common_generic_validate(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+int bt_ctf_field_common_structure_validate_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+int bt_ctf_field_common_variant_validate_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+int bt_ctf_field_common_array_validate_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+int bt_ctf_field_common_sequence_validate_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+void bt_ctf_field_common_generic_reset(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+void bt_ctf_field_common_structure_reset_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+void bt_ctf_field_common_variant_reset_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+void bt_ctf_field_common_array_reset_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+void bt_ctf_field_common_sequence_reset_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+void bt_ctf_field_common_generic_set_is_frozen(struct bt_ctf_field_common *field,
+               bool is_frozen);
+
+BT_HIDDEN
+void bt_ctf_field_common_structure_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen);
+
+BT_HIDDEN
+void bt_ctf_field_common_variant_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen);
+
+BT_HIDDEN
+void bt_ctf_field_common_array_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen);
+
+BT_HIDDEN
+void bt_ctf_field_common_sequence_set_is_frozen_recursive(
+               struct bt_ctf_field_common *field, bool is_frozen);
+
+BT_HIDDEN
+void _bt_ctf_field_common_set_is_frozen_recursive(struct bt_ctf_field_common *field,
+               bool is_frozen);
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_generic_is_set(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_structure_is_set_recursive(
+               struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_variant_is_set_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_array_is_set_recursive(struct bt_ctf_field_common *field);
+
+BT_HIDDEN
+bt_bool bt_ctf_field_common_sequence_is_set_recursive(struct bt_ctf_field_common *field);
+
+#ifdef BT_DEV_MODE
+# define bt_ctf_field_common_validate_recursive                _bt_ctf_field_common_validate_recursive
+# define bt_ctf_field_common_set_is_frozen_recursive   _bt_ctf_field_common_set_is_frozen_recursive
+# define bt_ctf_field_common_is_set_recursive          _bt_ctf_field_common_is_set_recursive
+# define bt_ctf_field_common_reset_recursive           _bt_ctf_field_common_reset_recursive
+# define bt_ctf_field_common_set                               _bt_ctf_field_common_set
+#else
+# define bt_ctf_field_common_validate_recursive(_field)        (-1)
+# define bt_ctf_field_common_set_is_frozen_recursive(_field, _is_frozen)
+# define bt_ctf_field_common_is_set_recursive(_field)  (BT_FALSE)
+# define bt_ctf_field_common_reset_recursive(_field)
+# define bt_ctf_field_common_set(_field, _val)
+#endif
+
+BT_ASSERT_FUNC
+static inline bool field_type_common_has_known_id(
+               struct bt_ctf_field_type_common *ft)
+{
+       return (int) ft->id > BT_CTF_FIELD_TYPE_ID_UNKNOWN ||
+               (int) ft->id < BT_CTF_FIELD_TYPE_ID_NR;
+}
+
+static inline
+int _bt_ctf_field_common_validate_recursive(struct bt_ctf_field_common *field)
+{
+       int ret = 0;
+
+       if (!field) {
+               BT_CTF_ASSERT_PRE_MSG("%s", "Invalid field: field is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_ASSERT(field_type_common_has_known_id(field->type));
+
+       if (field->methods->validate) {
+               ret = field->methods->validate(field);
+       }
+
+end:
+       return ret;
+}
+
+static inline
+void _bt_ctf_field_common_reset_recursive(struct bt_ctf_field_common *field)
+{
+       BT_ASSERT(field);
+       BT_ASSERT(field->methods->reset);
+       field->methods->reset(field);
+}
+
+static inline
+void _bt_ctf_field_common_set(struct bt_ctf_field_common *field, bool value)
+{
+       BT_ASSERT(field);
+       field->payload_set = value;
+}
+
+static inline
+bt_bool _bt_ctf_field_common_is_set_recursive(struct bt_ctf_field_common *field)
+{
+       bt_bool is_set = BT_FALSE;
+
+       if (!field) {
+               goto end;
+       }
+
+       BT_ASSERT(field_type_common_has_known_id(field->type));
+       BT_ASSERT(field->methods->is_set);
+       is_set = field->methods->is_set(field);
+
+end:
+       return is_set;
+}
+
+static inline
+void bt_ctf_field_common_initialize(struct bt_ctf_field_common *field,
+               struct bt_ctf_field_type_common *ft, bool is_shared,
+               bt_ctf_object_release_func release_func,
+               struct bt_ctf_field_common_methods *methods)
+{
+       BT_ASSERT(field);
+       BT_ASSERT(ft);
+       bt_ctf_object_init(&field->base, is_shared, release_func);
+       field->methods = methods;
+       field->type = (void *) bt_ctf_object_get_ref(ft);
+}
+
+static inline
+struct bt_ctf_field_type_common *bt_ctf_field_common_borrow_type(
+               struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_type_common *ret = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Field");
+       ret = field->type;
+       return ret;
+}
+
+static inline
+int64_t bt_ctf_field_common_sequence_get_length(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+               "Field");
+       return (int64_t) sequence->length;
+}
+
+static inline
+int bt_ctf_field_common_sequence_set_length(struct bt_ctf_field_common *field,
+               uint64_t length, bt_ctf_field_common_create_func field_create_func)
+{
+       int ret = 0;
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
+       BT_CTF_ASSERT_PRE(((int64_t) length) >= 0,
+               "Invalid sequence length (too large): length=%" PRId64,
+               length);
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Sequence field");
+
+       if (unlikely(length > sequence->elements->len)) {
+               /* Make more room */
+               struct bt_ctf_field_type_common_sequence *sequence_ft;
+               uint64_t cur_len = sequence->elements->len;
+               uint64_t i;
+
+               g_ptr_array_set_size(sequence->elements, length);
+               sequence_ft = BT_CTF_FROM_COMMON(sequence->common.type);
+
+               for (i = cur_len; i < sequence->elements->len; i++) {
+                       struct bt_ctf_field_common *elem_field =
+                               field_create_func(sequence_ft->element_ft);
+
+                       if (!elem_field) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       BT_ASSERT(!sequence->elements->pdata[i]);
+                       sequence->elements->pdata[i] = elem_field;
+               }
+       }
+
+       sequence->length = length;
+
+end:
+       return ret;
+}
+
+static inline
+struct bt_ctf_field_common *bt_ctf_field_common_structure_borrow_field_by_name(
+               struct bt_ctf_field_common *field, const char *name)
+{
+       struct bt_ctf_field_common *ret = NULL;
+       GQuark field_quark;
+       struct bt_ctf_field_type_common_structure *structure_ft;
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+       size_t index;
+       GHashTable *field_name_to_index;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Structure field");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Field name");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_CTF_FIELD_TYPE_ID_STRUCT, "Field");
+       structure_ft = BT_CTF_FROM_COMMON(field->type);
+       field_name_to_index = structure_ft->field_name_to_index;
+       field_quark = g_quark_from_string(name);
+       if (!g_hash_table_lookup_extended(field_name_to_index,
+                       GUINT_TO_POINTER(field_quark),
+                       NULL, (gpointer *) &index)) {
+               BT_LOGV("Invalid parameter: no such field in structure field's type: "
+                       "struct-field-addr=%p, struct-ft-addr=%p, name=\"%s\"",
+                       field, field->type, name);
+               goto error;
+       }
+
+       ret = structure->fields->pdata[index];
+       BT_ASSERT(ret);
+
+error:
+       return ret;
+}
+
+static inline
+struct bt_ctf_field_common *bt_ctf_field_common_structure_borrow_field_by_index(
+               struct bt_ctf_field_common *field, uint64_t index)
+{
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Structure field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_CTF_FIELD_TYPE_ID_STRUCT, "Field");
+       BT_CTF_ASSERT_PRE(index < structure->fields->len,
+               "Index is out of bound: struct-field-addr=%p, "
+               "index=%" PRIu64 ", count=%u", field, index,
+               structure->fields->len);
+       return structure->fields->pdata[index];
+}
+
+static inline
+struct bt_ctf_field_common *bt_ctf_field_common_array_borrow_field(
+               struct bt_ctf_field_common *field, uint64_t index)
+{
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Array field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_ARRAY,
+               "Field");
+       BT_CTF_ASSERT_PRE(index < array->elements->len,
+               "Index is out of bound: array-field-addr=%p, "
+               "index=%" PRIu64 ", count=%u", field,
+               index, array->elements->len);
+       return array->elements->pdata[(size_t) index];
+}
+
+static inline
+struct bt_ctf_field_common *bt_ctf_field_common_sequence_borrow_field(
+               struct bt_ctf_field_common *field, uint64_t index)
+{
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Sequence field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field, BT_CTF_FIELD_TYPE_ID_SEQUENCE,
+               "Field");
+       BT_CTF_ASSERT_PRE(index < sequence->length,
+               "Index is out of bound: seq-field-addr=%p, "
+               "index=%" PRIu64 ", count=%u", field, index,
+               sequence->elements->len);
+       return sequence->elements->pdata[(size_t) index];
+}
+
+static inline
+int bt_ctf_field_common_variant_set_tag(struct bt_ctf_field_common *variant_field,
+               uint64_t tag_uval, bool is_signed)
+{
+       int ret = 0;
+       int64_t choice_index;
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
+
+       /* Find matching index in variant field's type */
+       choice_index = bt_ctf_field_type_common_variant_find_choice_index(
+               variant_field->type, tag_uval, is_signed);
+       if (choice_index < 0) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Select corresponding field */
+       BT_ASSERT(choice_index < variant->fields->len);
+       variant->current_field = variant->fields->pdata[choice_index];
+       variant->tag_value.u = tag_uval;
+
+end:
+       return ret;
+}
+
+static inline
+struct bt_ctf_field_common *bt_ctf_field_common_variant_borrow_current_field(
+               struct bt_ctf_field_common *variant_field)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_CTF_ASSERT_PRE(variant->current_field,
+               "Variant field has no current field: field-addr=%p", variant_field);
+       return variant->current_field;
+}
+
+static inline
+int bt_ctf_field_common_variant_get_tag_signed(struct bt_ctf_field_common *variant_field,
+       int64_t *tag)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_CTF_ASSERT_PRE(variant->current_field,
+               "Variant field has no current field: field-addr=%p", variant_field);
+       *tag = variant->tag_value.i;
+       return 0;
+}
+
+static inline
+int bt_ctf_field_common_variant_get_tag_unsigned(struct bt_ctf_field_common *variant_field,
+       uint64_t *tag)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(variant_field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(variant_field, "Variant field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(variant_field,
+               BT_CTF_FIELD_TYPE_ID_VARIANT, "Field");
+       BT_CTF_ASSERT_PRE(variant->current_field,
+               "Variant field has no current field: field-addr=%p", variant_field);
+       *tag = variant->tag_value.u;
+       return 0;
+}
+
+static inline
+int bt_ctf_field_common_floating_point_get_value(struct bt_ctf_field_common *field,
+               double *value)
+{
+       struct bt_ctf_field_common_floating_point *floating_point =
+               BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Floating point number field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "Floating point number field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_CTF_FIELD_TYPE_ID_FLOAT, "Field");
+       *value = floating_point->payload;
+       return 0;
+}
+
+static inline
+int bt_ctf_field_common_floating_point_set_value(struct bt_ctf_field_common *field,
+               double value)
+{
+       struct bt_ctf_field_common_floating_point *floating_point =
+               BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "Floating point number field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "Floating point number field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_CTF_FIELD_TYPE_ID_FLOAT, "Field");
+       floating_point->payload = value;
+       bt_ctf_field_common_set(field, true);
+       return 0;
+}
+
+static inline
+const char *bt_ctf_field_common_string_get_value(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_IS_SET(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_CTF_FIELD_TYPE_ID_STRING, "Field");
+       return (const char *) string->buf->data;
+}
+
+static inline
+int bt_ctf_field_common_string_clear(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_string *string_field = BT_CTF_FROM_COMMON(field);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_CTF_FIELD_TYPE_ID_STRING, "Field");
+       string_field->size = 0;
+       bt_ctf_field_common_set(field, true);
+       return 0;
+}
+
+static inline
+int bt_ctf_field_common_string_append_len(struct bt_ctf_field_common *field,
+               const char *value, unsigned int length)
+{
+       struct bt_ctf_field_common_string *string_field = BT_CTF_FROM_COMMON(field);
+       char *data;
+       size_t new_size;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_CTF_FIELD_TYPE_ID_STRING, "Field");
+
+       /* Make sure no null bytes are appended */
+       BT_CTF_ASSERT_PRE(memchr(value, '\0', length) == NULL,
+               "String value to append contains a null character: "
+               "partial-value=\"%.32s\", length=%u", value, length);
+
+       new_size = string_field->size + length;
+
+       if (unlikely(new_size + 1 > string_field->buf->len)) {
+               g_array_set_size(string_field->buf, new_size + 1);
+       }
+
+       data = string_field->buf->data;
+       memcpy(data + string_field->size, value, length);
+       ((char *) string_field->buf->data)[new_size] = '\0';
+       string_field->size = new_size;
+       bt_ctf_field_common_set(field, true);
+       return 0;
+}
+
+static inline
+int bt_ctf_field_common_string_append(struct bt_ctf_field_common *field,
+               const char *value)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       return bt_ctf_field_common_string_append_len(field, value,
+               strlen(value));
+}
+
+static inline
+int bt_ctf_field_common_string_set_value(struct bt_ctf_field_common *field,
+               const char *value)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(field, "String field");
+       BT_CTF_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HOT(field, "String field");
+       BT_CTF_ASSERT_PRE_CTF_FIELD_COMMON_HAS_TYPE_ID(field,
+               BT_CTF_FIELD_TYPE_ID_STRING, "Field");
+       bt_ctf_field_common_string_clear(field);
+       return bt_ctf_field_common_string_append_len(field,
+               value, strlen(value));
+}
+
+static inline
+void bt_ctf_field_common_finalize(struct bt_ctf_field_common *field)
+{
+       BT_ASSERT(field);
+       BT_LOGD_STR("Putting field's type.");
+       bt_ctf_object_put_ref(field->type);
+}
+
+static inline
+void bt_ctf_field_common_integer_finalize(struct bt_ctf_field_common *field)
+{
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common integer field object: addr=%p", field);
+       bt_ctf_field_common_finalize(field);
+}
+
+static inline
+void bt_ctf_field_common_floating_point_finalize(struct bt_ctf_field_common *field)
+{
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common floating point number field object: addr=%p", field);
+       bt_ctf_field_common_finalize(field);
+}
+
+static inline
+void bt_ctf_field_common_structure_finalize_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_structure *structure = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common structure field object: addr=%p", field);
+       bt_ctf_field_common_finalize(field);
+
+       if (structure->fields) {
+               g_ptr_array_free(structure->fields, TRUE);
+       }
+}
+
+static inline
+void bt_ctf_field_common_variant_finalize_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_variant *variant = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common variant field object: addr=%p", field);
+       bt_ctf_field_common_finalize(field);
+
+       if (variant->fields) {
+               g_ptr_array_free(variant->fields, TRUE);
+       }
+}
+
+static inline
+void bt_ctf_field_common_array_finalize_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_array *array = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common array field object: addr=%p", field);
+       bt_ctf_field_common_finalize(field);
+
+       if (array->elements) {
+               g_ptr_array_free(array->elements, TRUE);
+       }
+}
+
+static inline
+void bt_ctf_field_common_sequence_finalize_recursive(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_sequence *sequence = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common sequence field object: addr=%p", field);
+       bt_ctf_field_common_finalize(field);
+
+       if (sequence->elements) {
+               g_ptr_array_free(sequence->elements, TRUE);
+       }
+}
+
+static inline
+void bt_ctf_field_common_string_finalize(struct bt_ctf_field_common *field)
+{
+       struct bt_ctf_field_common_string *string = BT_CTF_FROM_COMMON(field);
+
+       BT_ASSERT(field);
+       BT_LOGD("Finalizing common string field object: addr=%p", field);
+       bt_ctf_field_common_finalize(field);
+
+       if (string->buf) {
+               g_array_free(string->buf, TRUE);
+       }
+}
+
+BT_CTF_ASSERT_PRE_FUNC
+static inline bool value_is_in_range_signed(unsigned int size, int64_t value)
+{
+       bool ret = true;
+       int64_t min_value, max_value;
+
+       min_value = -(1ULL << (size - 1));
+       max_value = (1ULL << (size - 1)) - 1;
+       if (value < min_value || value > max_value) {
+               BT_LOGF("Value is out of bounds: value=%" PRId64 ", "
+                       "min-value=%" PRId64 ", max-value=%" PRId64,
+                       value, min_value, max_value);
+               ret = false;
+       }
+
+       return ret;
+}
+
+BT_CTF_ASSERT_PRE_FUNC
+static inline bool value_is_in_range_unsigned(unsigned int size, uint64_t value)
+{
+       bool ret = true;
+       int64_t max_value;
+
+       max_value = (size == 64) ? UINT64_MAX : ((uint64_t) 1 << size) - 1;
+       if (value > max_value) {
+               BT_LOGF("Value is out of bounds: value=%" PRIu64 ", "
+                       "max-value=%" PRIu64,
+                       value, max_value);
+               ret = false;
+       }
+
+       return ret;
+}
+
+struct bt_ctf_field_enumeration {
+       struct bt_ctf_field_common common;
+       struct bt_ctf_field_common_integer *container;
+};
+
+struct bt_ctf_field_variant {
+       struct bt_ctf_field_common_variant common;
+       struct bt_ctf_field_enumeration *tag;
+};
+
+BT_HIDDEN
+int bt_ctf_field_serialize_recursive(struct bt_ctf_field *field,
+               struct bt_ctfser *ctfser,
+               enum bt_ctf_byte_order native_byte_order);
+
+BT_HIDDEN
+int bt_ctf_field_structure_set_field_by_name(struct bt_ctf_field *field,
+               const char *name, struct bt_ctf_field *value);
+
+BT_HIDDEN
+struct bt_ctf_field *bt_ctf_field_enumeration_borrow_container(
+               struct bt_ctf_field *field);
+
+static inline
+bt_bool bt_ctf_field_is_set_recursive(struct bt_ctf_field *field)
+{
+       return bt_ctf_field_common_is_set_recursive((void *) field);
+}
+
+#endif /* BABELTRACE_CTF_WRITER_FIELDS_INTERNAL_H */
diff --git a/src/ctf-writer/functor.c b/src/ctf-writer/functor.c
new file mode 100644 (file)
index 0000000..0b1ecc8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * functor.c
+ *
+ * Babeltrace CTF Writer
+ *
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+
+#include "functor.h"
+#include "utils.h"
+
+BT_HIDDEN
+void value_exists(gpointer element, gpointer search_query)
+{
+       if (element == ((struct bt_ctf_search_query *)search_query)->value) {
+               ((struct bt_ctf_search_query *)search_query)->found = 1;
+       }
+}
diff --git a/src/ctf-writer/functor.h b/src/ctf-writer/functor.h
new file mode 100644 (file)
index 0000000..628f63c
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H
+
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include "common/babeltrace.h"
+
+BT_HIDDEN
+void value_exists(gpointer element, gpointer search_query);
+
+#endif /* BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H */
diff --git a/src/ctf-writer/logging.c b/src/ctf-writer/logging.c
new file mode 100644 (file)
index 0000000..024d118
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_lib_ctf_writer_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_lib_ctf_writer_log_level,
+       "BABELTRACE_CTF_WRITER_LOG_LEVEL");
diff --git a/src/ctf-writer/logging.h b/src/ctf-writer/logging.h
new file mode 100644 (file)
index 0000000..8fb722e
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef BABELTRACE_CTF_WRITER_LOGGING_H
+#define BABELTRACE_CTF_WRITER_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_lib_ctf_writer_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_lib_ctf_writer_log_level);
+
+#endif /* BABELTRACE_CTF_WRITER_LOGGING_H */
diff --git a/src/ctf-writer/object-pool.c b/src/ctf-writer/object-pool.c
new file mode 100644 (file)
index 0000000..831297e
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "OBJECT-POOL"
+#include "logging.h"
+
+#include <stdint.h>
+
+#include "common/assert.h"
+
+#include "object-pool.h"
+
+int bt_ctf_object_pool_initialize(struct bt_ctf_object_pool *pool,
+               bt_ctf_object_pool_new_object_func new_object_func,
+               bt_ctf_object_pool_destroy_object_func destroy_object_func,
+               void *data)
+{
+       int ret = 0;
+
+       BT_ASSERT(new_object_func);
+       BT_ASSERT(destroy_object_func);
+       BT_LOGD("Initializing object pool: addr=%p, data-addr=%p",
+               pool, data);
+       pool->objects = g_ptr_array_new();
+       if (!pool->objects) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       pool->funcs.new_object = new_object_func;
+       pool->funcs.destroy_object = destroy_object_func;
+       pool->data = data;
+       pool->size = 0;
+       BT_LOGD("Initialized object pool.");
+       goto end;
+
+error:
+       if (pool) {
+               bt_ctf_object_pool_finalize(pool);
+       }
+
+       ret = -1;
+
+end:
+       return ret;
+}
+
+void bt_ctf_object_pool_finalize(struct bt_ctf_object_pool *pool)
+{
+       uint64_t i;
+
+       BT_ASSERT(pool);
+       BT_LOGD("Finalizing object pool.");
+
+       if (pool->objects) {
+               for (i = 0; i < pool->size; i++) {
+                       void *obj = pool->objects->pdata[i];
+
+                       if (obj) {
+                               pool->funcs.destroy_object(obj, pool->data);
+                       }
+               }
+
+               g_ptr_array_free(pool->objects, TRUE);
+               pool->objects = NULL;
+       }
+}
diff --git a/src/ctf-writer/object-pool.h b/src/ctf-writer/object-pool.h
new file mode 100644 (file)
index 0000000..c0d8610
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef BABELTRACE_CTF_WRITER_OBJECT_POOL_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_OBJECT_POOL_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This is a generic object pool to avoid memory allocation/deallocation
+ * for objects of which the lifespan is typically short, but which are
+ * created a lot.
+ *
+ * The object pool, thanks to two user functions, knows how to allocate
+ * a brand new object in memory when the pool is empty and how to
+ * destroy an object when we destroy the pool.
+ *
+ * The object pool's user is responsible for:
+ *
+ * * Setting whatever references the object needs to keep and reset some
+ *   properties _after_ calling bt_ctf_object_pool_create_object(). This is
+ *   typically done in the bt_*_create() function which calls
+ *   bt_ctf_object_pool_create_object() (which could call the user-provided
+ *   allocation function if the pool is empty) and then sets the
+ *   appropriate properties on the possibly recycled object.
+ *
+ * * Releasing whatever references the object keeps _before_ calling
+ *   bt_ctf_object_pool_recycle_object(). This is typically done in a custom
+ *   bt_*_recycle() function which does the necessary before calling
+ *   bt_ctf_object_pool_recycle_object() with an object ready to be reused
+ *   at any time.
+ */
+
+#include <glib.h>
+
+#include "object.h"
+
+typedef void *(*bt_ctf_object_pool_new_object_func)(void *data);
+typedef void *(*bt_ctf_object_pool_destroy_object_func)(void *obj, void *data);
+
+struct bt_ctf_object_pool {
+       /*
+        * Container of recycled objects, owned by this. The array's size
+        * is the pool's capacity.
+        */
+       GPtrArray *objects;
+
+       /*
+        * Pool's size, that is, number of elements in the array above,
+        * starting at index 0, which exist as recycled objects.
+        */
+       size_t size;
+
+       /* User functions */
+       struct {
+               /* Allocate a new object in memory */
+               bt_ctf_object_pool_new_object_func new_object;
+
+               /* Free direct and indirect memory occupied by object */
+               bt_ctf_object_pool_destroy_object_func destroy_object;
+       } funcs;
+
+       /* User data passed to user functions */
+       void *data;
+};
+
+/*
+ * Initializes an object pool which is already allocated.
+ */
+int bt_ctf_object_pool_initialize(struct bt_ctf_object_pool *pool,
+               bt_ctf_object_pool_new_object_func new_object_func,
+               bt_ctf_object_pool_destroy_object_func destroy_object_func,
+               void *data);
+
+/*
+ * Finalizes an object pool without deallocating it.
+ */
+void bt_ctf_object_pool_finalize(struct bt_ctf_object_pool *pool);
+
+/*
+ * Creates an object from an object pool. If the pool is empty, this
+ * function calls the "new" user function to allocate a new object
+ * before returning it. Otherwise this function returns a recycled
+ * object, removing it from the pool.
+ *
+ * The returned object is owned by the caller.
+ */
+static inline
+void *bt_ctf_object_pool_create_object(struct bt_ctf_object_pool *pool)
+{
+       struct bt_ctf_object *obj;
+
+       BT_ASSERT(pool);
+
+#ifdef BT_LOGV
+       BT_LOGV("Creating object from pool: pool-addr=%p, pool-size=%zu, pool-cap=%u",
+               pool, pool->size, pool->objects->len);
+#endif
+
+       if (pool->size > 0) {
+               /* Pick one from the pool */
+               pool->size--;
+               obj = pool->objects->pdata[pool->size];
+               pool->objects->pdata[pool->size] = NULL;
+               goto end;
+       }
+
+       /* Pool is empty: create a brand new object */
+#ifdef BT_LOGV
+       BT_LOGV("Pool is empty: allocating new object: pool-addr=%p",
+               pool);
+#endif
+
+       obj = pool->funcs.new_object(pool->data);
+
+end:
+#ifdef BT_LOGV
+       BT_LOGV("Created one object from pool: pool-addr=%p, obj-addr=%p",
+               pool, obj);
+#endif
+
+       return obj;
+}
+
+/*
+ * Recycles an object, that is, puts it back into the pool.
+ *
+ * The pool becomes the sole owner of the object to recycle.
+ */
+static inline
+void bt_ctf_object_pool_recycle_object(struct bt_ctf_object_pool *pool, void *obj)
+{
+       struct bt_ctf_object *bt_obj = obj;
+
+       BT_ASSERT(pool);
+       BT_ASSERT(obj);
+
+#ifdef BT_LOGV
+       BT_LOGV("Recycling object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
+               pool, pool->size, pool->objects->len, obj);
+#endif
+
+       if (pool->size == pool->objects->len) {
+               /* Backing array is full: make place for recycled object */
+#ifdef BT_LOGV
+               BT_LOGV("Object pool is full: increasing object pool capacity: "
+                       "pool-addr=%p, old-pool-cap=%u, new-pool-cap=%u",
+                       pool, pool->objects->len, pool->objects->len + 1);
+#endif
+               g_ptr_array_set_size(pool->objects, pool->size + 1);
+       }
+
+       /* Reset reference count to 1 since it could be 0 now */
+       bt_obj->ref_count = 1;
+
+       /* Back to the pool */
+       pool->objects->pdata[pool->size] = obj;
+       pool->size++;
+
+#ifdef BT_LOGV
+       BT_LOGV("Recycled object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
+               pool, pool->size, pool->objects->len, obj);
+#endif
+}
+
+#endif /* BABELTRACE_CTF_WRITER_OBJECT_POOL_INTERNAL_H */
diff --git a/src/ctf-writer/object.c b/src/ctf-writer/object.c
new file mode 100644 (file)
index 0000000..616fcf3
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "object.h"
+
+void *bt_ctf_object_get_ref(void *obj)
+{
+       if (unlikely(!obj)) {
+               goto end;
+       }
+
+       bt_ctf_object_get_no_null_check(obj);
+
+end:
+       return obj;
+}
+
+void bt_ctf_object_put_ref(void *obj)
+{
+       if (unlikely(!obj)) {
+               return;
+       }
+
+       bt_ctf_object_put_no_null_check(obj);
+}
diff --git a/src/ctf-writer/object.h b/src/ctf-writer/object.h
new file mode 100644 (file)
index 0000000..3231721
--- /dev/null
@@ -0,0 +1,317 @@
+#ifndef BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H
+
+/*
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <stdbool.h>
+
+struct bt_ctf_object;
+
+typedef void (*bt_ctf_object_release_func)(struct bt_ctf_object *);
+typedef void (*bt_ctf_object_parent_is_owner_listener_func)(
+               struct bt_ctf_object *);
+
+static inline
+void *bt_ctf_object_get_no_null_check(struct bt_ctf_object *obj);
+
+static inline
+void bt_ctf_object_put_no_null_check(struct bt_ctf_object *obj);
+
+/*
+ * Babeltrace object base.
+ *
+ * All objects publicly exposed by Babeltrace APIs must contain this
+ * object as their first member.
+ */
+struct bt_ctf_object {
+       /*
+        * True if this object is shared, that is, it has a reference
+        * count.
+        */
+       bool is_shared;
+
+       /*
+        * Current reference count.
+        */
+       unsigned long long ref_count;
+
+       /*
+        * Release function called when the object's reference count
+        * falls to zero. For an object with a parent, this function is
+        * bt_ctf_object_with_parent_release_func(), which calls
+        * `spec_release_func` below if there's no current parent.
+        */
+       bt_ctf_object_release_func release_func;
+
+       /*
+        * Specific release function called by
+        * bt_ctf_object_with_parent_release_func() or directly by a
+        * parent object.
+        */
+       bt_ctf_object_release_func spec_release_func;
+
+       /*
+        * Optional callback for an object with a parent, called by
+        * bt_ctf_object_with_parent_release_func() to indicate to the
+        * object that its parent is its owner.
+        */
+       bt_ctf_object_parent_is_owner_listener_func
+               parent_is_owner_listener_func;
+
+       /*
+        * Optional parent object.
+        */
+       struct bt_ctf_object *parent;
+};
+
+static inline
+unsigned long long bt_ctf_object_get_ref_count(struct bt_ctf_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       return obj->ref_count;
+}
+
+static inline
+struct bt_ctf_object *bt_ctf_object_borrow_parent(struct bt_ctf_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       return obj->parent;
+}
+
+static inline
+struct bt_ctf_object *bt_ctf_object_get_parent(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_object *parent = bt_ctf_object_borrow_parent(obj);
+
+       if (parent) {
+               bt_ctf_object_get_no_null_check(parent);
+       }
+
+       return parent;
+}
+
+static inline
+void bt_ctf_object_set_parent(struct bt_ctf_object *child, struct bt_ctf_object *parent)
+{
+       BT_ASSERT(child);
+       BT_ASSERT(child->is_shared);
+
+#ifdef BT_LOGV
+       BT_LOGV("Setting object's parent: addr=%p, parent-addr=%p",
+               child, parent);
+#endif
+
+       /*
+        * It is assumed that a "child" having a parent is publicly
+        * reachable. Therefore, a reference to its parent must be
+        * taken. The reference to the parent will be released once the
+        * object's reference count falls to zero.
+        */
+       if (parent) {
+               BT_ASSERT(!child->parent);
+               child->parent = parent;
+               bt_ctf_object_get_no_null_check(parent);
+       } else {
+               if (child->parent) {
+                       bt_ctf_object_put_no_null_check(child->parent);
+               }
+
+               child->parent = NULL;
+       }
+}
+
+static inline
+void bt_ctf_object_try_spec_release(struct bt_ctf_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       BT_ASSERT(obj->spec_release_func);
+
+       if (bt_ctf_object_get_ref_count(obj) == 0) {
+               obj->spec_release_func(obj);
+       }
+}
+
+static inline
+void bt_ctf_object_with_parent_release_func(struct bt_ctf_object *obj)
+{
+       if (obj->parent) {
+               /*
+                * Keep our own copy of the parent address because `obj`
+                * could be destroyed in
+                * obj->parent_is_owner_listener_func().
+                */
+               struct bt_ctf_object *parent = obj->parent;
+
+#ifdef BT_LOGV
+               BT_LOGV("Releasing parented object: addr=%p, ref-count=%llu, "
+                       "parent-addr=%p, parent-ref-count=%llu",
+                       obj, obj->ref_count,
+                       parent, parent->ref_count);
+#endif
+
+               if (obj->parent_is_owner_listener_func) {
+                       /*
+                        * Object has a chance to destroy itself here
+                        * under certain conditions and notify its
+                        * parent. At this point the parent is
+                        * guaranteed to exist because it's not put yet.
+                        */
+                       obj->parent_is_owner_listener_func(obj);
+               }
+
+               /* The release function will be invoked by the parent. */
+               bt_ctf_object_put_no_null_check(parent);
+       } else {
+               bt_ctf_object_try_spec_release(obj);
+       }
+}
+
+static inline
+void bt_ctf_object_init(struct bt_ctf_object *obj, bool is_shared,
+               bt_ctf_object_release_func release_func)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(!is_shared || release_func);
+       obj->is_shared = is_shared;
+       obj->release_func = release_func;
+       obj->parent_is_owner_listener_func = NULL;
+       obj->spec_release_func = NULL;
+       obj->parent = NULL;
+       obj->ref_count = 1;
+}
+
+static inline
+void bt_ctf_object_init_shared(struct bt_ctf_object *obj,
+               bt_ctf_object_release_func release_func)
+{
+       bt_ctf_object_init(obj, true, release_func);
+}
+
+static inline
+void bt_ctf_object_init_unique(struct bt_ctf_object *obj)
+{
+       bt_ctf_object_init(obj, false, NULL);
+}
+
+static inline
+void bt_ctf_object_init_shared_with_parent(struct bt_ctf_object *obj,
+               bt_ctf_object_release_func spec_release_func)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(spec_release_func);
+       bt_ctf_object_init_shared(obj, bt_ctf_object_with_parent_release_func);
+       obj->spec_release_func = spec_release_func;
+}
+
+static inline
+void bt_ctf_object_set_parent_is_owner_listener_func(struct bt_ctf_object *obj,
+               bt_ctf_object_parent_is_owner_listener_func func)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       BT_ASSERT(obj->spec_release_func);
+       ((struct bt_ctf_object *) obj)->parent_is_owner_listener_func = func;
+}
+
+static inline
+void bt_ctf_object_inc_ref_count(struct bt_ctf_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       obj->ref_count++;
+       BT_ASSERT(obj->ref_count != 0);
+}
+
+static inline
+void *bt_ctf_object_get_no_null_check_no_parent_check(struct bt_ctf_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+
+#ifdef BT_LOGV
+       BT_LOGV("Incrementing object's reference count: %llu -> %llu: "
+               "addr=%p, cur-count=%llu, new-count=%llu",
+               obj->ref_count, obj->ref_count + 1,
+               obj, obj->ref_count, obj->ref_count + 1);
+#endif
+
+       bt_ctf_object_inc_ref_count(obj);
+       return obj;
+}
+
+static inline
+void *bt_ctf_object_get_no_null_check(struct bt_ctf_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+
+       if (unlikely(obj->parent && bt_ctf_object_get_ref_count(obj) == 0)) {
+#ifdef BT_LOGV
+               BT_LOGV("Incrementing object's parent's reference count: "
+                       "addr=%p, parent-addr=%p", obj, obj->parent);
+#endif
+
+               bt_ctf_object_get_no_null_check(obj->parent);
+       }
+
+#ifdef BT_LOGV
+       BT_LOGV("Incrementing object's reference count: %llu -> %llu: "
+               "addr=%p, cur-count=%llu, new-count=%llu",
+               obj->ref_count, obj->ref_count + 1,
+               obj, obj->ref_count, obj->ref_count + 1);
+#endif
+
+       bt_ctf_object_inc_ref_count(obj);
+       return obj;
+}
+
+static inline
+void bt_ctf_object_put_no_null_check(struct bt_ctf_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       BT_ASSERT(obj->ref_count > 0);
+
+#ifdef BT_LOGV
+       BT_LOGV("Decrementing object's reference count: %llu -> %llu: "
+               "addr=%p, cur-count=%llu, new-count=%llu",
+               obj->ref_count, obj->ref_count - 1,
+               obj, obj->ref_count, obj->ref_count - 1);
+#endif
+
+       obj->ref_count--;
+
+       if (obj->ref_count == 0) {
+               BT_ASSERT(obj->release_func);
+               obj->release_func(obj);
+       }
+}
+
+#endif /* BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H */
diff --git a/src/ctf-writer/resolve.c b/src/ctf-writer/resolve.c
new file mode 100644 (file)
index 0000000..6e9e200
--- /dev/null
@@ -0,0 +1,1342 @@
+/*
+ * resolve.c
+ *
+ * Babeltrace - CTF writer: Type resolving internal
+ *
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Authors: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *          Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-RESOLVE"
+#include "logging.h"
+
+#include <glib.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/types.h>
+
+#include "common/babeltrace.h"
+#include "common/assert.h"
+
+#include "field-path.h"
+#include "resolve.h"
+#include "utils.h"
+#include "values.h"
+
+typedef GPtrArray type_stack;
+
+/*
+ * A stack frame.
+ *
+ * `type` contains a compound field type (structure, variant, array,
+ * or sequence) and `index` indicates the index of the field type in
+ * the upper frame (-1 for array and sequence field types).
+ *
+ * `type` is owned by the stack frame.
+ */
+struct type_stack_frame {
+       struct bt_ctf_field_type_common *type;
+       int index;
+};
+
+/*
+ * The current context of the resolving engine.
+ *
+ * `scopes` contain the 6 CTF scope field types (see CTF, sect. 7.3.2)
+ * in the following order:
+ *
+ *   * Packet header
+ *   * Packet context
+ *   * Event header
+ *   * Stream event context
+ *   * Event context
+ *   * Event payload
+ */
+struct resolve_context {
+       struct bt_ctf_private_value *environment;
+       struct bt_ctf_field_type_common *scopes[6];
+
+       /* Root scope being visited */
+       enum bt_ctf_scope root_scope;
+       type_stack *type_stack;
+       struct bt_ctf_field_type_common *cur_field_type;
+};
+
+/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
+static const char * const absolute_path_prefixes[] = {
+       [BT_CTF_SCOPE_ENV]                              = "env.",
+       [BT_CTF_SCOPE_TRACE_PACKET_HEADER]              = "trace.packet.header.",
+       [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT]    = "stream.packet.context.",
+       [BT_CTF_SCOPE_STREAM_EVENT_HEADER]              = "stream.event.header.",
+       [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT]             = "stream.event.context.",
+       [BT_CTF_SCOPE_EVENT_CONTEXT]            = "event.context.",
+       [BT_CTF_SCOPE_EVENT_FIELDS]                     = "event.fields.",
+};
+
+/* Number of path tokens used for the absolute prefixes */
+static const int absolute_path_prefix_ptoken_counts[] = {
+       [BT_CTF_SCOPE_ENV]                      = 1,
+       [BT_CTF_SCOPE_TRACE_PACKET_HEADER]      = 3,
+       [BT_CTF_SCOPE_STREAM_PACKET_CONTEXT]    = 3,
+       [BT_CTF_SCOPE_STREAM_EVENT_HEADER]      = 3,
+       [BT_CTF_SCOPE_STREAM_EVENT_CONTEXT]     = 3,
+       [BT_CTF_SCOPE_EVENT_CONTEXT]            = 2,
+       [BT_CTF_SCOPE_EVENT_FIELDS]             = 2,
+};
+
+/*
+ * Destroys a type stack frame.
+ */
+static
+void type_stack_destroy_notify(gpointer data)
+{
+       struct type_stack_frame *frame = data;
+
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(frame->type);
+       g_free(frame);
+}
+
+/*
+ * Creates a type stack.
+ *
+ * Return value is owned by the caller.
+ */
+static
+type_stack *type_stack_create(void)
+{
+       return g_ptr_array_new_with_free_func(type_stack_destroy_notify);
+}
+
+/*
+ * Destroys a type stack.
+ */
+static
+void type_stack_destroy(type_stack *stack)
+{
+       g_ptr_array_free(stack, TRUE);
+}
+
+/*
+ * Pushes a field type onto a type stack.
+ *
+ * `type` is owned by the caller (stack frame gets a new reference).
+ */
+static
+int type_stack_push(type_stack *stack, struct bt_ctf_field_type_common *type)
+{
+       int ret = 0;
+       struct type_stack_frame *frame = NULL;
+
+       if (!stack || !type) {
+               BT_LOGW("Invalid parameter: stack or type is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       frame = g_new0(struct type_stack_frame, 1);
+       if (!frame) {
+               BT_LOGE_STR("Failed to allocate one field type stack frame.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Pushing field type on context's stack: "
+               "ft-addr=%p, stack-size-before=%u", type, stack->len);
+       frame->type = bt_ctf_object_get_ref(type);
+       g_ptr_array_add(stack, frame);
+
+end:
+       return ret;
+}
+
+/*
+ * Checks whether or not `stack` is empty.
+ */
+static
+bt_bool type_stack_empty(type_stack *stack)
+{
+       return stack->len == 0;
+}
+
+/*
+ * Returns the number of frames in `stack`.
+ */
+static
+size_t type_stack_size(type_stack *stack)
+{
+       return stack->len;
+}
+
+/*
+ * Returns the top frame of `stack`.
+ *
+ * Return value is owned by `stack`.
+ */
+static
+struct type_stack_frame *type_stack_peek(type_stack *stack)
+{
+       struct type_stack_frame *entry = NULL;
+
+       if (!stack || type_stack_empty(stack)) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, stack->len - 1);
+end:
+       return entry;
+}
+
+/*
+ * Returns the frame at index `index` in `stack`.
+ *
+ * Return value is owned by `stack`.
+ */
+static
+struct type_stack_frame *type_stack_at(type_stack *stack,
+               size_t index)
+{
+       struct type_stack_frame *entry = NULL;
+
+       if (!stack || index >= stack->len) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, index);
+
+end:
+       return entry;
+}
+
+/*
+ * Removes the top frame of `stack`.
+ */
+static
+void type_stack_pop(type_stack *stack)
+{
+       if (!type_stack_empty(stack)) {
+               /*
+                * This will call the frame's destructor and free it, as
+                * well as put its contained field type.
+                */
+               BT_LOGV("Popping context's stack: stack-size-before=%u",
+                       stack->len);
+               g_ptr_array_set_size(stack, stack->len - 1);
+       }
+}
+
+/*
+ * Returns the scope field type of `scope` in the context `ctx`.
+ *
+ * Return value is owned by `ctx` on success.
+ */
+static
+struct bt_ctf_field_type_common *get_type_from_ctx(struct resolve_context *ctx,
+               enum bt_ctf_scope scope)
+{
+       BT_ASSERT(scope >= BT_CTF_SCOPE_TRACE_PACKET_HEADER &&
+               scope <= BT_CTF_SCOPE_EVENT_FIELDS);
+
+       return ctx->scopes[scope - BT_CTF_SCOPE_TRACE_PACKET_HEADER];
+}
+
+/*
+ * Returns the CTF scope from a path string. May return
+ * CTF_NODE_UNKNOWN if the path is found to be relative.
+ */
+static
+enum bt_ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
+{
+       enum bt_ctf_scope scope;
+       enum bt_ctf_scope ret = BT_CTF_SCOPE_UNKNOWN;
+       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
+               sizeof(*absolute_path_prefixes);
+
+       for (scope = BT_CTF_SCOPE_ENV; scope < BT_CTF_SCOPE_ENV +
+                       prefixes_count; scope++) {
+               /*
+                * Chech if path string starts with a known absolute
+                * path prefix.
+                *
+                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
+                */
+               if (strncmp(pathstr, absolute_path_prefixes[scope],
+                               strlen(absolute_path_prefixes[scope]))) {
+                       /* Prefix does not match: try the next one */
+                       BT_LOGV("Prefix does not match: trying the next one: "
+                               "path=\"%s\", path-prefix=\"%s\", scope=%s",
+                               pathstr, absolute_path_prefixes[scope],
+                               bt_ctf_scope_string(scope));
+                       continue;
+               }
+
+               /* Found it! */
+               ret = scope;
+               BT_LOGV("Found root scope from absolute path: "
+                       "path=\"%s\", scope=%s", pathstr,
+                       bt_ctf_scope_string(scope));
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Destroys a path token.
+ */
+static
+void ptokens_destroy_func(gpointer ptoken, gpointer data)
+{
+       g_string_free(ptoken, TRUE);
+}
+
+/*
+ * Destroys a path token list.
+ */
+static
+void ptokens_destroy(GList *ptokens)
+{
+       if (!ptokens) {
+               return;
+       }
+
+       g_list_foreach(ptokens, ptokens_destroy_func, NULL);
+       g_list_free(ptokens);
+}
+
+/*
+ * Returns the string contained in a path token.
+ */
+static
+const char *ptoken_get_string(GList *ptoken)
+{
+       GString *tokenstr = (GString *) ptoken->data;
+
+       return tokenstr->str;
+}
+
+/*
+ * Converts a path string to a path token list, that is, splits the
+ * individual words of a path string into a list of individual
+ * strings.
+ *
+ * Return value is owned by the caller on success.
+ */
+static
+GList *pathstr_to_ptokens(const char *pathstr)
+{
+       const char *at = pathstr;
+       const char *last = at;
+       GList *ptokens = NULL;
+
+       for (;;) {
+               if (*at == '.' || *at == '\0') {
+                       GString *tokenstr;
+
+                       if (at == last) {
+                               /* Error: empty token */
+                               BT_LOGW("Empty path token: path=\"%s\", pos=%u",
+                                       pathstr, (int) (at - pathstr));
+                               goto error;
+                       }
+
+                       tokenstr = g_string_new(NULL);
+                       g_string_append_len(tokenstr, last, at - last);
+                       ptokens = g_list_append(ptokens, tokenstr);
+                       last = at + 1;
+               }
+
+               if (*at == '\0') {
+                       break;
+               }
+
+               at++;
+       }
+
+       return ptokens;
+
+error:
+       ptokens_destroy(ptokens);
+       return NULL;
+}
+
+/*
+ * Converts a path token list to a field path object. The path token
+ * list is relative from `type`. The index of the source looking for
+ * its target within `type` is indicated by `src_index`. This can be
+ * `INT_MAX` if the source is contained in `type`.
+ *
+ * `ptokens` is owned by the caller. `field_path` is an output parameter
+ * owned by the caller that must be filled here. `type` is owned by the
+ * caller.
+ */
+static
+int ptokens_to_field_path(GList *ptokens, struct bt_ctf_field_path *field_path,
+               struct bt_ctf_field_type_common *type, int src_index)
+{
+       int ret = 0;
+       GList *cur_ptoken = ptokens;
+       bt_bool first_level_done = BT_FALSE;
+
+       /* Get our own reference */
+       bt_ctf_object_get_ref(type);
+
+       /* Locate target */
+       while (cur_ptoken) {
+               int child_index;
+               struct bt_ctf_field_type_common *child_type;
+               const char *field_name = ptoken_get_string(cur_ptoken);
+               enum bt_ctf_field_type_id type_id =
+                       bt_ctf_field_type_common_get_type_id(type);
+
+               BT_LOGV("Current path token: token=\"%s\"", field_name);
+
+               /* Find to which index corresponds the current path token */
+               if (type_id == BT_CTF_FIELD_TYPE_ID_ARRAY ||
+                               type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
+                       child_index = -1;
+               } else {
+                       child_index = bt_ctf_field_type_common_get_field_index(type,
+                               field_name);
+                       if (child_index < 0) {
+                               /*
+                                * Error: field name does not exist or
+                                * wrong current type.
+                                */
+                               BT_LOGW("Cannot get index of field type: "
+                                       "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
+                                       field_name, src_index, child_index, first_level_done);
+                               ret = -1;
+                               goto end;
+                       } else if (child_index > src_index &&
+                                       !first_level_done) {
+                               BT_LOGW("Child field type is located after source field type: "
+                                       "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
+                                       field_name, src_index, child_index, first_level_done);
+                               ret = -1;
+                               goto end;
+                       }
+
+                       /* Next path token */
+                       cur_ptoken = g_list_next(cur_ptoken);
+                       first_level_done = BT_TRUE;
+               }
+
+               /* Create new field path entry */
+               g_array_append_val(field_path->indexes, child_index);
+
+               /* Get child field type */
+               child_type = bt_ctf_field_type_common_borrow_field_at_index(type,
+                       child_index);
+               if (!child_type) {
+                       BT_LOGW("Cannot get child field type: "
+                               "field-name=\"%s\", src-index=%d, child-index=%d, first-level-done=%d",
+                               field_name, src_index, child_index, first_level_done);
+                       ret = -1;
+                       goto end;
+               }
+
+               /* Move child type to current type */
+               bt_ctf_object_get_ref(child_type);
+               BT_CTF_OBJECT_MOVE_REF(type, child_type);
+       }
+
+end:
+       bt_ctf_object_put_ref(type);
+       return ret;
+}
+
+/*
+ * Converts a known absolute path token list to a field path object
+ * within the resolving context `ctx`.
+ *
+ * `ptokens` is owned by the caller. `field_path` is an output parameter
+ * owned by the caller that must be filled here.
+ */
+static
+int absolute_ptokens_to_field_path(GList *ptokens,
+               struct bt_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       GList *cur_ptoken;
+       struct bt_ctf_field_type_common *type;
+
+       /* Skip absolute path tokens */
+       cur_ptoken = g_list_nth(ptokens,
+               absolute_path_prefix_ptoken_counts[field_path->root]);
+
+       /* Start with root type */
+       type = get_type_from_ctx(ctx, field_path->root);
+       if (!type) {
+               /* Error: root type is not available */
+               BT_LOGW("Root field type is not available: "
+                       "root-scope=%s",
+                       bt_ctf_scope_string(field_path->root));
+               ret = -1;
+               goto end;
+       }
+
+       /* Locate target */
+       ret = ptokens_to_field_path(cur_ptoken, field_path, type, INT_MAX);
+
+end:
+       return ret;
+}
+
+/*
+ * Converts a known relative path token list to a field path object
+ * within the resolving context `ctx`.
+ *
+ * `ptokens` is owned by the caller. `field_path` is an output parameter
+ * owned by the caller that must be filled here.
+ */
+static
+int relative_ptokens_to_field_path(GList *ptokens,
+               struct bt_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       int parent_pos_in_stack;
+       struct bt_ctf_field_path *tail_field_path = bt_ctf_field_path_create();
+
+       if (!tail_field_path) {
+               BT_LOGE_STR("Cannot create empty field path.");
+               ret = -1;
+               goto end;
+       }
+
+       parent_pos_in_stack = type_stack_size(ctx->type_stack) - 1;
+
+       while (parent_pos_in_stack >= 0) {
+               struct bt_ctf_field_type_common *parent_type =
+                       type_stack_at(ctx->type_stack,
+                               parent_pos_in_stack)->type;
+               int cur_index = type_stack_at(ctx->type_stack,
+                       parent_pos_in_stack)->index;
+
+               BT_LOGV("Locating target field type from current parent field type: "
+                       "parent-pos=%d, parent-ft-addr=%p, cur-index=%d",
+                       parent_pos_in_stack, parent_type, cur_index);
+
+               /* Locate target from current parent type */
+               ret = ptokens_to_field_path(ptokens, tail_field_path,
+                       parent_type, cur_index);
+               if (ret) {
+                       /* Not found... yet */
+                       BT_LOGV_STR("Not found at this point.");
+                       bt_ctf_field_path_clear(tail_field_path);
+               } else {
+                       /* Found: stitch tail field path to head field path */
+                       int i = 0;
+                       int tail_field_path_len =
+                               tail_field_path->indexes->len;
+
+                       while (BT_TRUE) {
+                               struct bt_ctf_field_type_common *cur_type =
+                                       type_stack_at(ctx->type_stack, i)->type;
+                               int index = type_stack_at(
+                                       ctx->type_stack, i)->index;
+
+                               if (cur_type == parent_type) {
+                                       break;
+                               }
+
+                               g_array_append_val(field_path->indexes,
+                                       index);
+                               i++;
+                       }
+
+                       for (i = 0; i < tail_field_path_len; i++) {
+                               int index = g_array_index(
+                                       tail_field_path->indexes,
+                                       int, i);
+
+                               g_array_append_val(field_path->indexes,
+                                       index);
+                       }
+                       break;
+               }
+
+               parent_pos_in_stack--;
+       }
+
+       if (parent_pos_in_stack < 0) {
+               /* Not found: look in previous scopes */
+               field_path->root--;
+
+               while (field_path->root >= BT_CTF_SCOPE_TRACE_PACKET_HEADER) {
+                       struct bt_ctf_field_type_common *root_type;
+                       bt_ctf_field_path_clear(field_path);
+
+                       BT_LOGV("Looking into potential root scope: scope=%s",
+                               bt_ctf_scope_string(field_path->root));
+                       root_type = get_type_from_ctx(ctx, field_path->root);
+                       if (!root_type) {
+                               field_path->root--;
+                               continue;
+                       }
+
+                       /* Locate target in previous scope */
+                       ret = ptokens_to_field_path(ptokens, field_path,
+                               root_type, INT_MAX);
+                       if (ret) {
+                               /* Not found yet */
+                               BT_LOGV_STR("Not found in this scope.");
+                               field_path->root--;
+                               continue;
+                       }
+
+                       /* Found */
+                       BT_LOGV_STR("Found in this scope.");
+                       break;
+               }
+       }
+
+end:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(tail_field_path);
+       return ret;
+}
+
+/*
+ * Converts a path string to a field path object within the resolving
+ * context `ctx`.
+ *
+ * Return value is owned by the caller on success.
+ */
+static
+struct bt_ctf_field_path *pathstr_to_field_path(const char *pathstr,
+               struct resolve_context *ctx)
+{
+       int ret;
+       enum bt_ctf_scope root_scope;
+       GList *ptokens = NULL;
+       struct bt_ctf_field_path *field_path = NULL;
+
+       /* Create field path */
+       field_path = bt_ctf_field_path_create();
+       if (!field_path) {
+               BT_LOGE_STR("Cannot create empty field path.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Convert path string to path tokens */
+       ptokens = pathstr_to_ptokens(pathstr);
+       if (!ptokens) {
+               BT_LOGW("Cannot convert path string to path tokens: "
+                       "path=\"%s\"", pathstr);
+               ret = -1;
+               goto end;
+       }
+
+       /* Absolute or relative path? */
+       root_scope = get_root_scope_from_absolute_pathstr(pathstr);
+
+       if (root_scope == BT_CTF_SCOPE_UNKNOWN) {
+               /* Relative path: start with current root scope */
+               field_path->root = ctx->root_scope;
+               BT_LOGV("Detected relative path: starting with current root scope: "
+                       "scope=%s", bt_ctf_scope_string(field_path->root));
+               ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
+               if (ret) {
+                       BT_LOGW("Cannot get relative field path of path string: "
+                               "path=\"%s\", start-scope=%s, end-scope=%s",
+                               pathstr, bt_ctf_scope_string(ctx->root_scope),
+                               bt_ctf_scope_string(field_path->root));
+                       goto end;
+               }
+       } else if (root_scope == BT_CTF_SCOPE_ENV) {
+               BT_LOGW("Sequence field types referring the trace environment are not supported as of this version: "
+                       "path=\"%s\"", pathstr);
+               ret = -1;
+               goto end;
+       } else {
+               /* Absolute path: use found root scope */
+               field_path->root = root_scope;
+               BT_LOGV("Detected absolute path: using root scope: "
+                       "scope=%s", bt_ctf_scope_string(field_path->root));
+               ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
+               if (ret) {
+                       BT_LOGW("Cannot get absolute field path of path string: "
+                               "path=\"%s\", root-scope=%s",
+                               pathstr, bt_ctf_scope_string(root_scope));
+                       goto end;
+               }
+       }
+
+       if (ret == 0) {
+               GString *field_path_pretty =
+                       bt_ctf_field_path_string(field_path);
+               const char *field_path_pretty_str =
+                       field_path_pretty ? field_path_pretty->str : NULL;
+
+               BT_LOGV("Found field path: path=\"%s\", field-path=\"%s\"",
+                       pathstr, field_path_pretty_str);
+
+               if (field_path_pretty) {
+                       g_string_free(field_path_pretty, TRUE);
+               }
+       }
+
+end:
+       if (ret) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path);
+       }
+
+       ptokens_destroy(ptokens);
+       return field_path;
+}
+
+/*
+ * Retrieves a field type by following the field path `field_path` in
+ * the resolving context `ctx`.
+ *
+ * Return value is owned by the caller on success.
+ */
+static
+struct bt_ctf_field_type_common *field_path_to_field_type(
+               struct bt_ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int i;
+       struct bt_ctf_field_type_common *type;
+
+       /* Start with root type */
+       type = get_type_from_ctx(ctx, field_path->root);
+       bt_ctf_object_get_ref(type);
+       if (!type) {
+               /* Error: root type is not available */
+               BT_LOGW("Root field type is not available: root-scope=%s",
+                       bt_ctf_scope_string(field_path->root));
+               goto error;
+       }
+
+       /* Locate target */
+       for (i = 0; i < field_path->indexes->len; i++) {
+               struct bt_ctf_field_type_common *child_type;
+               int child_index =
+                       g_array_index(field_path->indexes, int, i);
+
+               /* Get child field type */
+               child_type = bt_ctf_field_type_common_borrow_field_at_index(type,
+                       child_index);
+               if (!child_type) {
+                       BT_LOGW("Cannot get field type: "
+                               "parent-ft-addr=%p, index=%d", type, i);
+                       goto error;
+               }
+
+               /* Move child type to current type */
+               bt_ctf_object_get_ref(child_type);
+               BT_CTF_OBJECT_MOVE_REF(type, child_type);
+       }
+
+       return type;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(type);
+       return type;
+}
+
+/*
+ * Returns the equivalent field path object of the context type stack.
+ *
+ * Return value is owned by the caller on success.
+ */
+static
+struct bt_ctf_field_path *get_ctx_stack_field_path(struct resolve_context *ctx)
+{
+       int i;
+       struct bt_ctf_field_path *field_path;
+
+       /* Create field path */
+       field_path = bt_ctf_field_path_create();
+       if (!field_path) {
+               BT_LOGE_STR("Cannot create empty field path.");
+               goto error;
+       }
+
+       field_path->root = ctx->root_scope;
+
+       for (i = 0; i < type_stack_size(ctx->type_stack); i++) {
+               struct type_stack_frame *frame;
+
+               frame = type_stack_at(ctx->type_stack, i);
+               g_array_append_val(field_path->indexes, frame->index);
+       }
+
+       return field_path;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(field_path);
+       return field_path;
+}
+
+/*
+ * Returns the lowest common ancestor of two field path objects
+ * having the same root scope.
+ *
+ * `field_path1` and `field_path2` are owned by the caller.
+ */
+static
+int get_field_paths_lca_index(struct bt_ctf_field_path *field_path1,
+               struct bt_ctf_field_path *field_path2)
+{
+       int lca_index = 0;
+       int field_path1_len, field_path2_len;
+
+       if (BT_LOG_ON_VERBOSE) {
+               GString *field_path1_pretty =
+                       bt_ctf_field_path_string(field_path1);
+               GString *field_path2_pretty =
+                       bt_ctf_field_path_string(field_path2);
+               const char *field_path1_pretty_str =
+                       field_path1_pretty ? field_path1_pretty->str : NULL;
+               const char *field_path2_pretty_str =
+                       field_path2_pretty ? field_path2_pretty->str : NULL;
+
+               BT_LOGV("Finding lowest common ancestor (LCA) between two field paths: "
+                       "field-path-1=\"%s\", field-path-2=\"%s\"",
+                       field_path1_pretty_str, field_path2_pretty_str);
+
+               if (field_path1_pretty) {
+                       g_string_free(field_path1_pretty, TRUE);
+               }
+
+               if (field_path2_pretty) {
+                       g_string_free(field_path2_pretty, TRUE);
+               }
+       }
+
+       /*
+        * Start from both roots and find the first mismatch.
+        */
+       BT_ASSERT(field_path1->root == field_path2->root);
+       field_path1_len = field_path1->indexes->len;
+       field_path2_len = field_path2->indexes->len;
+
+       while (BT_TRUE) {
+               int target_index, ctx_index;
+
+               if (lca_index == field_path2_len ||
+                               lca_index == field_path1_len) {
+                       /*
+                        * This means that both field paths never split.
+                        * This is invalid because the target cannot be
+                        * an ancestor of the source.
+                        */
+                       BT_LOGW("Source field type is an ancestor of target field type or vice versa: "
+                               "lca-index=%d, field-path-1-len=%d, "
+                               "field-path-2-len=%d",
+                               lca_index, field_path1_len, field_path2_len);
+                       lca_index = -1;
+                       break;
+               }
+
+               target_index = g_array_index(field_path1->indexes, int,
+                       lca_index);
+               ctx_index = g_array_index(field_path2->indexes, int,
+                       lca_index);
+
+               if (target_index != ctx_index) {
+                       /* LCA index is the previous */
+                       break;
+               }
+
+               lca_index++;
+       }
+
+       BT_LOGV("Found LCA: lca-index=%d", lca_index);
+       return lca_index;
+}
+
+/*
+ * Validates a target field path.
+ *
+ * `target_field_path` and `target_type` are owned by the caller.
+ */
+static
+int validate_target_field_path(struct bt_ctf_field_path *target_field_path,
+               struct bt_ctf_field_type_common *target_type,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       struct bt_ctf_field_path *ctx_field_path;
+       int target_field_path_len = target_field_path->indexes->len;
+       int lca_index;
+       enum bt_ctf_field_type_id ctx_cur_field_type_id;
+       enum bt_ctf_field_type_id target_type_id;
+
+       /* Get context field path */
+       ctx_field_path = get_ctx_stack_field_path(ctx);
+       if (!ctx_field_path) {
+               BT_LOGW_STR("Cannot get field path from context's stack.");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Make sure the target is not a root.
+        */
+       if (target_field_path_len == 0) {
+               BT_LOGW_STR("Target field path's length is 0 (targeting the root).");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Make sure the root of the target field path is not located
+        * after the context field path's root.
+        */
+       if (target_field_path->root > ctx_field_path->root) {
+               BT_LOGW("Target field type is located after source field type: "
+                       "target-root=%s, source-root=%s",
+                       bt_ctf_scope_string(target_field_path->root),
+                       bt_ctf_scope_string(ctx_field_path->root));
+               ret = -1;
+               goto end;
+       }
+
+       if (target_field_path->root == ctx_field_path->root) {
+               int target_index, ctx_index;
+
+               /*
+                * Find the index of the lowest common ancestor of both field
+                * paths.
+                */
+               lca_index = get_field_paths_lca_index(target_field_path,
+                       ctx_field_path);
+               if (lca_index < 0) {
+                       BT_LOGW_STR("Cannot get least common ancestor.");
+                       ret = -1;
+                       goto end;
+               }
+
+               /*
+                * Make sure the target field path is located before the
+                * context field path.
+                */
+               target_index = g_array_index(target_field_path->indexes,
+                       int, lca_index);
+               ctx_index = g_array_index(ctx_field_path->indexes,
+                       int, lca_index);
+
+               if (target_index >= ctx_index) {
+                       BT_LOGW("Target field type's index is greater than or equal to source field type's index in LCA: "
+                               "lca-index=%d, target-index=%d, source-index=%d",
+                               lca_index, target_index, ctx_index);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /*
+        * Make sure the target type has the right type and properties.
+        */
+       ctx_cur_field_type_id = bt_ctf_field_type_common_get_type_id(
+               ctx->cur_field_type);
+       target_type_id = bt_ctf_field_type_common_get_type_id(target_type);
+
+       switch (ctx_cur_field_type_id) {
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               if (target_type_id != BT_CTF_FIELD_TYPE_ID_ENUM) {
+                       BT_LOGW("Variant field type's tag field type is not an enumeration field type: "
+                               "tag-ft-addr=%p, tag-ft-id=%s",
+                               target_type,
+                               bt_ctf_field_type_id_string(target_type_id));
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               if (target_type_id != BT_CTF_FIELD_TYPE_ID_INTEGER ||
+                               bt_ctf_field_type_common_integer_is_signed(target_type)) {
+                       BT_LOGW("Sequence field type's length field type is not an unsigned integer field type: "
+                               "length-ft-addr=%p, length-ft-id=%s",
+                               target_type,
+                               bt_ctf_field_type_id_string(target_type_id));
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       default:
+               abort();
+       }
+
+end:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(ctx_field_path);
+       return ret;
+}
+
+/*
+ * Resolves a variant or sequence field type `type`.
+ *
+ * `type` is owned by the caller.
+ */
+static
+int resolve_sequence_or_variant_type(struct bt_ctf_field_type_common *type,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       const char *pathstr;
+       enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type);
+       struct bt_ctf_field_path *target_field_path = NULL;
+       struct bt_ctf_field_type_common *target_type = NULL;
+       GString *target_field_path_pretty = NULL;
+       const char *target_field_path_pretty_str;
+
+
+       /* Get path string */
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               pathstr =
+                       bt_ctf_field_type_common_sequence_get_length_field_name(type);
+               break;
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               pathstr =
+                       bt_ctf_field_type_common_variant_get_tag_name(type);
+               break;
+       default:
+               abort();
+       }
+
+       if (!pathstr) {
+               BT_LOGW_STR("Cannot get path string.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Get target field path out of path string */
+       target_field_path = pathstr_to_field_path(pathstr, ctx);
+       if (!target_field_path) {
+               BT_LOGW("Cannot get target field path for path string: "
+                       "path=\"%s\"", pathstr);
+               ret = -1;
+               goto end;
+       }
+
+       target_field_path_pretty = bt_ctf_field_path_string(target_field_path);
+       target_field_path_pretty_str =
+               target_field_path_pretty ? target_field_path_pretty->str : NULL;
+
+       /* Get target field type */
+       target_type = field_path_to_field_type(target_field_path, ctx);
+       if (!target_type) {
+               BT_LOGW("Cannot get target field type for path string: "
+                       "path=\"%s\", target-field-path=\"%s\"",
+                       pathstr, target_field_path_pretty_str);
+               ret = -1;
+               goto end;
+       }
+
+       ret = validate_target_field_path(target_field_path, target_type, ctx);
+       if (ret) {
+               BT_LOGW("Invalid target field path for path string: "
+                       "path=\"%s\", target-field-path=\"%s\"",
+                       pathstr, target_field_path_pretty_str);
+               goto end;
+       }
+
+       /* Set target field path and target field type */
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               ret = bt_ctf_field_type_common_sequence_set_length_field_path(
+                       type, target_field_path);
+               if (ret) {
+                       BT_LOGW("Cannot set sequence field type's length field path: "
+                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
+                               ret, type, pathstr,
+                               target_field_path_pretty_str);
+                       goto end;
+               }
+               break;
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               ret = bt_ctf_field_type_common_variant_set_tag_field_path(
+                       type, target_field_path);
+               if (ret) {
+                       BT_LOGW("Cannot set varaint field type's tag field path: "
+                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
+                               ret, type, pathstr,
+                               target_field_path_pretty_str);
+                       goto end;
+               }
+
+               ret = bt_ctf_field_type_common_variant_set_tag_field_type(
+                       type, target_type);
+               if (ret) {
+                       BT_LOGW("Cannot set varaint field type's tag field type: "
+                               "ret=%d, ft-addr=%p, path=\"%s\", target-field-path=\"%s\"",
+                               ret, type, pathstr,
+                               target_field_path_pretty_str);
+                       goto end;
+               }
+               break;
+       default:
+               abort();
+       }
+
+end:
+       if (target_field_path_pretty) {
+               g_string_free(target_field_path_pretty, TRUE);
+       }
+
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(target_field_path);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(target_type);
+       return ret;
+}
+
+/*
+ * Resolves a field type `type`.
+ *
+ * `type` is owned by the caller.
+ */
+static
+int resolve_type(struct bt_ctf_field_type_common *type, struct resolve_context *ctx)
+{
+       int ret = 0;
+       enum bt_ctf_field_type_id type_id;
+
+       if (!type) {
+               /* Type is not available; still valid */
+               goto end;
+       }
+
+       type_id = bt_ctf_field_type_common_get_type_id(type);
+       ctx->cur_field_type = type;
+
+       /* Resolve sequence/variant field type */
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               ret = resolve_sequence_or_variant_type(type, ctx);
+               if (ret) {
+                       BT_LOGW("Cannot resolve sequence field type's length or variant field type's tag: "
+                               "ret=%d, ft-addr=%p", ret, type);
+                       goto end;
+               }
+               break;
+       default:
+               break;
+       }
+
+       /* Recurse into compound types */
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       {
+               int64_t field_count, f_index;
+
+               ret = type_stack_push(ctx->type_stack, type);
+               if (ret) {
+                       BT_LOGW("Cannot push field type on context's stack: "
+                               "ft-addr=%p", type);
+                       goto end;
+               }
+
+               field_count = bt_ctf_field_type_common_get_field_count(type);
+               if (field_count < 0) {
+                       BT_LOGW("Cannot get field type's field count: "
+                               "ret=%" PRId64 ", ft-addr=%p",
+                               field_count, type);
+                       ret = field_count;
+                       goto end;
+               }
+
+               for (f_index = 0; f_index < field_count; f_index++) {
+                       struct bt_ctf_field_type_common *child_type =
+                               bt_ctf_field_type_common_borrow_field_at_index(type,
+                                       f_index);
+
+                       if (!child_type) {
+                               BT_LOGW("Cannot get field type's child field: "
+                                       "ft-addr=%p, index=%" PRId64 ", "
+                                       "count=%" PRId64, type, f_index,
+                                       field_count);
+                               ret = -1;
+                               goto end;
+                       }
+
+                       if (type_id == BT_CTF_FIELD_TYPE_ID_ARRAY||
+                                       type_id == BT_CTF_FIELD_TYPE_ID_SEQUENCE) {
+                               type_stack_peek(ctx->type_stack)->index = -1;
+                       } else {
+                               type_stack_peek(ctx->type_stack)->index =
+                                       f_index;
+                       }
+
+                       BT_LOGV("Resolving field type's child field type: "
+                               "parent-ft-addr=%p, child-ft-addr=%p, "
+                               "index=%" PRId64 ", count=%" PRId64,
+                               type, child_type, f_index, field_count);
+                       ret = resolve_type(child_type, ctx);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               type_stack_pop(ctx->type_stack);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Resolves the root field type corresponding to the scope `root_scope`.
+ */
+static
+int resolve_root_type(enum bt_ctf_scope root_scope, struct resolve_context *ctx)
+{
+       int ret;
+
+       BT_ASSERT(type_stack_size(ctx->type_stack) == 0);
+       ctx->root_scope = root_scope;
+       ret = resolve_type(get_type_from_ctx(ctx, root_scope), ctx);
+       ctx->root_scope = BT_CTF_SCOPE_UNKNOWN;
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_resolve_types(
+               struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type,
+               struct bt_ctf_field_type_common *event_context_type,
+               struct bt_ctf_field_type_common *event_payload_type,
+               enum bt_ctf_resolve_flag flags)
+{
+       int ret = 0;
+       struct resolve_context ctx = {
+               .environment = environment,
+               .scopes = {
+                       packet_header_type,
+                       packet_context_type,
+                       event_header_type,
+                       stream_event_ctx_type,
+                       event_context_type,
+                       event_payload_type,
+               },
+               .root_scope = BT_CTF_SCOPE_UNKNOWN,
+       };
+
+       BT_LOGV("Resolving field types: "
+               "packet-header-ft-addr=%p, "
+               "packet-context-ft-addr=%p, "
+               "event-header-ft-addr=%p, "
+               "stream-event-context-ft-addr=%p, "
+               "event-context-ft-addr=%p, "
+               "event-payload-ft-addr=%p",
+               packet_header_type, packet_context_type, event_header_type,
+               stream_event_ctx_type, event_context_type, event_payload_type);
+
+       /* Initialize type stack */
+       ctx.type_stack = type_stack_create();
+       if (!ctx.type_stack) {
+               BT_LOGE_STR("Cannot create field type stack.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Resolve packet header type */
+       if (flags & BT_CTF_RESOLVE_FLAG_PACKET_HEADER) {
+               ret = resolve_root_type(BT_CTF_SCOPE_TRACE_PACKET_HEADER, &ctx);
+               if (ret) {
+                       BT_LOGW("Cannot resolve trace packet header field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       /* Resolve packet context type */
+       if (flags & BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT) {
+               ret = resolve_root_type(BT_CTF_SCOPE_STREAM_PACKET_CONTEXT, &ctx);
+               if (ret) {
+                       BT_LOGW("Cannot resolve stream packet context field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       /* Resolve event header type */
+       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_HEADER) {
+               ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_HEADER, &ctx);
+               if (ret) {
+                       BT_LOGW("Cannot resolve stream event header field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       /* Resolve stream event context type */
+       if (flags & BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX) {
+               ret = resolve_root_type(BT_CTF_SCOPE_STREAM_EVENT_CONTEXT, &ctx);
+               if (ret) {
+                       BT_LOGW("Cannot resolve stream event context field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       /* Resolve event context type */
+       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT) {
+               ret = resolve_root_type(BT_CTF_SCOPE_EVENT_CONTEXT, &ctx);
+               if (ret) {
+                       BT_LOGW("Cannot resolve event context field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       /* Resolve event payload type */
+       if (flags & BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD) {
+               ret = resolve_root_type(BT_CTF_SCOPE_EVENT_FIELDS, &ctx);
+               if (ret) {
+                       BT_LOGW("Cannot resolve event payload field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       BT_LOGV_STR("Resolved field types.");
+
+end:
+       type_stack_destroy(ctx.type_stack);
+
+       return ret;
+}
diff --git a/src/ctf-writer/resolve.h b/src/ctf-writer/resolve.h
new file mode 100644 (file)
index 0000000..f153d1c
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef BABELTRACE_CTF_WRITER_RESOLVE_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_RESOLVE_INTERNAL_H
+
+/*
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Authors: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *          Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/ctf-writer/field-types.h>
+#include "common/babeltrace.h"
+#include <glib.h>
+
+#include "field-types.h"
+#include "values.h"
+
+enum bt_ctf_resolve_flag {
+       BT_CTF_RESOLVE_FLAG_PACKET_HEADER       = 0x01,
+       BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT      = 0x02,
+       BT_CTF_RESOLVE_FLAG_EVENT_HEADER        = 0x04,
+       BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX    = 0x08,
+       BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT       = 0x10,
+       BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD       = 0x20,
+};
+
+/*
+ * Resolves CTF IR field types: recursively locates the tag and length
+ * field types of resp. variant and sequence field types.
+ *
+ * All `*_type` parameters may be resolved, and may as well serve as
+ * resolving targets.
+ *
+ * Resolving is performed based on the flags in `flags`.
+ *
+ * It is expected that, amongst all the provided types, no common
+ * references to sequence variant field types exist. In other words,
+ * this function does not copy field types.
+ *
+ * All parameters are owned by the caller.
+ */
+BT_HIDDEN
+int bt_ctf_resolve_types(struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type,
+               struct bt_ctf_field_type_common *event_context_type,
+               struct bt_ctf_field_type_common *event_payload_type,
+               enum bt_ctf_resolve_flag flags);
+
+#endif /* BABELTRACE_CTF_WRITER_RESOLVE_INTERNAL_H */
diff --git a/src/ctf-writer/stream-class.c b/src/ctf-writer/stream-class.c
new file mode 100644 (file)
index 0000000..8b5e39b
--- /dev/null
@@ -0,0 +1,1148 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-STREAM-CLASS"
+#include "logging.h"
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/trace.h>
+#include <babeltrace2/ctf-writer/utils.h>
+
+#include "common/align.h"
+#include "common/assert.h"
+#include "compat/compiler.h"
+#include "compat/endian.h"
+
+#include "assert-pre.h"
+#include "clock-class.h"
+#include "event-class.h"
+#include "event.h"
+#include "fields.h"
+#include "field-types.h"
+#include "field-wrapper.h"
+#include "stream-class.h"
+#include "utils.h"
+#include "validation.h"
+#include "visitor.h"
+#include "writer.h"
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class,
+               const char *name, bt_ctf_object_release_func release_func)
+{
+       BT_LOGD("Initializing common stream class object: name=\"%s\"", name);
+
+       bt_ctf_object_init_shared_with_parent(&stream_class->base, release_func);
+       stream_class->name = g_string_new(name);
+       stream_class->event_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_ctf_object_try_spec_release);
+       if (!stream_class->event_classes) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       stream_class->event_classes_ht = g_hash_table_new_full(g_int64_hash,
+                       g_int64_equal, g_free, NULL);
+       if (!stream_class->event_classes_ht) {
+               BT_LOGE_STR("Failed to allocate a GHashTable.");
+               goto error;
+       }
+
+       BT_LOGD("Initialized common stream class object: addr=%p, name=\"%s\"",
+               stream_class, name);
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class)
+{
+       BT_LOGD("Finalizing common stream class: addr=%p, name=\"%s\", id=%" PRId64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+       bt_ctf_object_put_ref(stream_class->clock_class);
+
+       if (stream_class->event_classes_ht) {
+               g_hash_table_destroy(stream_class->event_classes_ht);
+       }
+       if (stream_class->event_classes) {
+               BT_LOGD_STR("Destroying event classes.");
+               g_ptr_array_free(stream_class->event_classes, TRUE);
+       }
+
+       if (stream_class->name) {
+               g_string_free(stream_class->name, TRUE);
+       }
+
+       BT_LOGD_STR("Putting event header field type.");
+       bt_ctf_object_put_ref(stream_class->event_header_field_type);
+       BT_LOGD_STR("Putting packet context field type.");
+       bt_ctf_object_put_ref(stream_class->packet_context_field_type);
+       BT_LOGD_STR("Putting event context field type.");
+       bt_ctf_object_put_ref(stream_class->event_context_field_type);
+}
+
+static
+void event_class_exists(gpointer element, gpointer query)
+{
+       struct bt_ctf_event_class_common *event_class_a = element;
+       struct bt_ctf_search_query *search_query = query;
+       struct bt_ctf_event_class_common *event_class_b = search_query->value;
+       int64_t id_a, id_b;
+
+       if (search_query->value == element) {
+               search_query->found = 1;
+               goto end;
+       }
+
+       /*
+        * Two event classes cannot share the same ID in a given
+        * stream class.
+        */
+       id_a = bt_ctf_event_class_common_get_id(event_class_a);
+       id_b = bt_ctf_event_class_common_get_id(event_class_b);
+
+       if (id_a < 0 || id_b < 0) {
+               /* at least one ID is not set: will be automatically set later */
+               goto end;
+       }
+
+       if (id_a == id_b) {
+               BT_LOGW("Event class with this ID already exists in the stream class: "
+                       "id=%" PRId64 ", name=\"%s\"",
+                       id_a, bt_ctf_event_class_common_get_name(event_class_a));
+               search_query->found = 1;
+               goto end;
+       }
+
+end:
+       return;
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_add_event_class(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_event_class_common *event_class,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
+{
+       int ret = 0;
+       int64_t *event_id = NULL;
+       struct bt_ctf_trace_common *trace = NULL;
+       struct bt_ctf_stream_class_common *old_stream_class = NULL;
+       struct bt_ctf_validation_output validation_output = { 0 };
+       struct bt_ctf_field_type_common *packet_header_type = NULL;
+       struct bt_ctf_field_type_common *packet_context_type = NULL;
+       struct bt_ctf_field_type_common *event_header_type = NULL;
+       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
+       struct bt_ctf_field_type_common *event_context_type = NULL;
+       struct bt_ctf_field_type_common *event_payload_type = NULL;
+       const enum bt_ctf_validation_flag validation_flags =
+               BT_CTF_VALIDATION_FLAG_EVENT;
+       struct bt_ctf_clock_class *expected_clock_class = NULL;
+
+       BT_ASSERT(copy_field_type_func);
+
+       if (!stream_class || !event_class) {
+               BT_LOGW("Invalid parameter: stream class or event class is NULL: "
+                       "stream-class-addr=%p, event-class-addr=%p",
+                       stream_class, event_class);
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGD("Adding event class to stream class: "
+               "stream-class-addr=%p, stream-class-name=\"%s\", "
+               "stream-class-id=%" PRId64 ", event-class-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class),
+               event_class,
+               bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
+
+       if (stream_class->frozen) {
+               /*
+                * We only check that the event class to be added has a
+                * single class which matches the stream class's
+                * expected clock class if the stream class is frozen.
+                * If it's not, then this event class is added "as is"
+                * and the validation will be performed when calling
+                * either bt_ctf_trace_add_stream_class() or
+                * bt_ctf_event_create(). This is because the stream class's
+                * field types (packet context, event header, event
+                * context) could change before the next call to one of
+                * those two functions.
+                */
+               expected_clock_class = bt_ctf_object_get_ref(stream_class->clock_class);
+
+               /*
+                * At this point, `expected_clock_class` can be NULL,
+                * and bt_ctf_event_class_validate_single_clock_class()
+                * below can set it.
+                */
+               ret = bt_ctf_event_class_common_validate_single_clock_class(
+                       event_class, &expected_clock_class);
+               if (ret) {
+                       BT_LOGW("Event class contains a field type which is not "
+                               "recursively mapped to its stream class's "
+                               "expected clock class: "
+                               "stream-class-addr=%p, "
+                               "stream-class-id=%" PRId64 ", "
+                               "stream-class-name=\"%s\", "
+                               "expected-clock-class-addr=%p, "
+                               "expected-clock-class-name=\"%s\"",
+                               stream_class,
+                               bt_ctf_stream_class_common_get_id(stream_class),
+                               bt_ctf_stream_class_common_get_name(stream_class),
+                               expected_clock_class,
+                               expected_clock_class ?
+                                       bt_ctf_clock_class_get_name(expected_clock_class) :
+                                       NULL);
+                       goto end;
+               }
+       }
+
+       event_id = g_new(int64_t, 1);
+       if (!event_id) {
+               BT_LOGE_STR("Failed to allocate one int64_t.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Check for duplicate event classes */
+       struct bt_ctf_search_query query = { .value = event_class, .found = 0 };
+       g_ptr_array_foreach(stream_class->event_classes, event_class_exists,
+               &query);
+       if (query.found) {
+               BT_LOGW_STR("Another event class part of this stream class has the same ID.");
+               ret = -1;
+               goto end;
+       }
+
+       old_stream_class = bt_ctf_event_class_common_borrow_stream_class(event_class);
+       if (old_stream_class) {
+               /* Event class is already associated to a stream class. */
+               BT_LOGW("Event class is already part of another stream class: "
+                       "event-class-stream-class-addr=%p, "
+                       "event-class-stream-class-name=\"%s\", "
+                       "event-class-stream-class-id=%" PRId64,
+                       old_stream_class,
+                       bt_ctf_stream_class_common_get_name(old_stream_class),
+                       bt_ctf_stream_class_common_get_id(old_stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (trace) {
+               /*
+                * If the stream class is associated with a trace, then
+                * both those objects are frozen. Also, this event class
+                * is about to be frozen.
+                *
+                * Therefore the event class must be validated here.
+                * The trace and stream class should be valid at this
+                * point.
+                */
+               BT_ASSERT(trace->valid);
+               BT_ASSERT(stream_class->valid);
+               packet_header_type =
+                       bt_ctf_trace_common_borrow_packet_header_field_type(trace);
+               packet_context_type =
+                       bt_ctf_stream_class_common_borrow_packet_context_field_type(
+                               stream_class);
+               event_header_type =
+                       bt_ctf_stream_class_common_borrow_event_header_field_type(
+                               stream_class);
+               stream_event_ctx_type =
+                       bt_ctf_stream_class_common_borrow_event_context_field_type(
+                               stream_class);
+               event_context_type =
+                       bt_ctf_event_class_common_borrow_context_field_type(
+                               event_class);
+               event_payload_type =
+                       bt_ctf_event_class_common_borrow_payload_field_type(
+                               event_class);
+               ret = bt_ctf_validate_class_types(
+                       trace->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,
+                       copy_field_type_func);
+
+               if (ret) {
+                       /*
+                        * This means something went wrong during the
+                        * validation process, not that the objects are
+                        * invalid.
+                        */
+                       BT_LOGE("Failed to validate event class: ret=%d", ret);
+                       goto end;
+               }
+
+               if ((validation_output.valid_flags & validation_flags) !=
+                               validation_flags) {
+                       /* Invalid event class */
+                       BT_LOGW("Invalid trace, stream class, or event class: "
+                               "valid-flags=0x%x",
+                               validation_output.valid_flags);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /* Only set an event ID if none was explicitly set before */
+       *event_id = bt_ctf_event_class_common_get_id(event_class);
+       if (*event_id < 0) {
+               BT_LOGV("Event class has no ID: automatically setting it: "
+                       "id=%" PRId64, stream_class->next_event_id);
+
+               if (bt_ctf_event_class_common_set_id(event_class,
+                               stream_class->next_event_id)) {
+                       BT_LOGE("Cannot set event class's ID: id=%" PRId64,
+                               stream_class->next_event_id);
+                       ret = -1;
+                       goto end;
+               }
+               stream_class->next_event_id++;
+               *event_id = stream_class->next_event_id;
+       }
+
+       bt_ctf_object_set_parent(&event_class->base, &stream_class->base);
+
+       if (trace) {
+               /*
+                * At this point we know that the function will be
+                * successful. Therefore we can replace the event
+                * class's field types with what's in the validation
+                * output structure and mark this event class as valid.
+                */
+               bt_ctf_validation_replace_types(NULL, NULL, event_class,
+                       &validation_output, validation_flags);
+               event_class->valid = 1;
+
+               /*
+                * Put what was not moved in
+                * bt_ctf_validation_replace_types().
+                */
+               bt_ctf_validation_output_put_types(&validation_output);
+       }
+
+       /* Add to the event classes of the stream class */
+       g_ptr_array_add(stream_class->event_classes, event_class);
+       g_hash_table_insert(stream_class->event_classes_ht, event_id,
+                       event_class);
+       event_id = NULL;
+
+       /* Freeze the event class */
+       bt_ctf_event_class_common_freeze(event_class);
+
+       /*
+        * It is safe to set the stream class's unique clock class
+        * now if the stream class is frozen.
+        */
+       if (stream_class->frozen && expected_clock_class) {
+               BT_ASSERT(!stream_class->clock_class ||
+                       stream_class->clock_class == expected_clock_class);
+               BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
+       }
+
+       BT_LOGD("Added event class to stream class: "
+               "stream-class-addr=%p, stream-class-name=\"%s\", "
+               "stream-class-id=%" PRId64 ", event-class-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class),
+               event_class,
+               bt_ctf_event_class_common_get_name(event_class),
+               bt_ctf_event_class_common_get_id(event_class));
+
+end:
+       bt_ctf_validation_output_put_types(&validation_output);
+       bt_ctf_object_put_ref(expected_clock_class);
+       g_free(event_id);
+       return ret;
+}
+
+static
+int64_t get_event_class_count(void *element)
+{
+       return bt_ctf_stream_class_get_event_class_count(
+                       (struct bt_ctf_stream_class *) element);
+}
+
+static
+void *get_event_class(void *element, int i)
+{
+       return bt_ctf_stream_class_get_event_class_by_index(
+                       (struct bt_ctf_stream_class *) element, i);
+}
+
+static
+int visit_event_class(void *object, bt_ctf_visitor visitor,void *data)
+{
+       struct bt_ctf_visitor_object obj = {
+               .object = object,
+               .type = BT_CTF_VISITOR_OBJECT_TYPE_EVENT_CLASS
+       };
+
+       return visitor(&obj, data);
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class,
+               bt_ctf_visitor visitor, void *data)
+{
+       int ret;
+       struct bt_ctf_visitor_object obj = {
+               .object = stream_class,
+               .type = BT_CTF_VISITOR_OBJECT_TYPE_STREAM_CLASS
+       };
+
+       if (!stream_class || !visitor) {
+               BT_LOGW("Invalid parameter: stream class or visitor is NULL: "
+                       "stream-class-addr=%p, visitor=%p",
+                       stream_class, visitor);
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_visitor_helper(&obj, get_event_class_count,
+                       get_event_class,
+                       visit_event_class, visitor, data);
+       BT_LOGV("bt_ctf_visitor_helper() returned: ret=%d", ret);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
+               bt_ctf_visitor visitor, void *data)
+{
+       return bt_ctf_stream_class_common_visit(BT_CTF_FROM_COMMON(stream_class),
+               visitor, data);
+}
+
+BT_HIDDEN
+void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class)
+{
+       if (!stream_class || stream_class->frozen) {
+               return;
+       }
+
+       BT_LOGD("Freezing stream class: addr=%p, name=\"%s\", id=%" PRId64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+       stream_class->frozen = 1;
+       bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
+       bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
+       bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
+       bt_ctf_clock_class_freeze(stream_class->clock_class);
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_validate_single_clock_class(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_clock_class **expected_clock_class)
+{
+       int ret;
+       uint64_t i;
+
+       BT_ASSERT(stream_class);
+       BT_ASSERT(expected_clock_class);
+       ret = bt_ctf_field_type_common_validate_single_clock_class(
+               stream_class->packet_context_field_type,
+               expected_clock_class);
+       if (ret) {
+               BT_LOGW("Stream class's packet context field type "
+                       "is not recursively mapped to the "
+                       "expected clock class: "
+                       "stream-class-addr=%p, "
+                       "stream-class-name=\"%s\", "
+                       "stream-class-id=%" PRId64 ", "
+                       "ft-addr=%p",
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       stream_class->id,
+                       stream_class->packet_context_field_type);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_validate_single_clock_class(
+               stream_class->event_header_field_type,
+               expected_clock_class);
+       if (ret) {
+               BT_LOGW("Stream class's event header field type "
+                       "is not recursively mapped to the "
+                       "expected clock class: "
+                       "stream-class-addr=%p, "
+                       "stream-class-name=\"%s\", "
+                       "stream-class-id=%" PRId64 ", "
+                       "ft-addr=%p",
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       stream_class->id,
+                       stream_class->event_header_field_type);
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_common_validate_single_clock_class(
+               stream_class->event_context_field_type,
+               expected_clock_class);
+       if (ret) {
+               BT_LOGW("Stream class's event context field type "
+                       "is not recursively mapped to the "
+                       "expected clock class: "
+                       "stream-class-addr=%p, "
+                       "stream-class-name=\"%s\", "
+                       "stream-class-id=%" PRId64 ", "
+                       "ft-addr=%p",
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       stream_class->id,
+                       stream_class->event_context_field_type);
+               goto end;
+       }
+
+       for (i = 0; i < stream_class->event_classes->len; i++) {
+               struct bt_ctf_event_class_common *event_class =
+                       g_ptr_array_index(stream_class->event_classes, i);
+
+               BT_ASSERT(event_class);
+               ret = bt_ctf_event_class_common_validate_single_clock_class(
+                       event_class, expected_clock_class);
+               if (ret) {
+                       BT_LOGW("Stream class's event class contains a "
+                               "field type which is not recursively mapped to "
+                               "the expected clock class: "
+                               "stream-class-addr=%p, "
+                               "stream-class-name=\"%s\", "
+                               "stream-class-id=%" PRId64,
+                               stream_class,
+                               bt_ctf_stream_class_common_get_name(stream_class),
+                               stream_class->id);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int init_event_header(struct bt_ctf_stream_class *stream_class)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *event_header_type =
+               bt_ctf_field_type_structure_create();
+       struct bt_ctf_field_type *_uint32_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
+       struct bt_ctf_field_type *_uint64_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
+
+       if (!event_header_type) {
+               BT_LOGE_STR("Cannot create empty structure field type.");
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(event_header_type,
+               _uint32_t, "id");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `id` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(event_header_type,
+               _uint64_t, "timestamp");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `timestamp` field to event header field type.");
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(stream_class->common.event_header_field_type);
+       stream_class->common.event_header_field_type =
+               (void *) event_header_type;
+       event_header_type = NULL;
+
+end:
+       if (ret) {
+               bt_ctf_object_put_ref(event_header_type);
+       }
+
+       bt_ctf_object_put_ref(_uint32_t);
+       bt_ctf_object_put_ref(_uint64_t);
+       return ret;
+}
+
+static
+int init_packet_context(struct bt_ctf_stream_class *stream_class)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *packet_context_type =
+               bt_ctf_field_type_structure_create();
+       struct bt_ctf_field_type *_uint64_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT64_T);
+       struct bt_ctf_field_type *ts_begin_end_uint64_t;
+
+       if (!packet_context_type) {
+               BT_LOGE_STR("Cannot create empty structure field type.");
+               ret = -1;
+               goto end;
+       }
+
+       ts_begin_end_uint64_t = bt_ctf_field_type_copy(_uint64_t);
+       if (!ts_begin_end_uint64_t) {
+               BT_LOGE_STR("Cannot copy integer field type for `timestamp_begin` and `timestamp_end` fields.");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * We create a stream packet context as proposed in the CTF
+        * specification.
+        */
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               ts_begin_end_uint64_t, "timestamp_begin");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `timestamp_begin` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               ts_begin_end_uint64_t, "timestamp_end");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `timestamp_end` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               _uint64_t, "content_size");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `content_size` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               _uint64_t, "packet_size");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `packet_size` field to event header field type.");
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(packet_context_type,
+               _uint64_t, "events_discarded");
+       if (ret) {
+               BT_LOGE_STR("Cannot add `events_discarded` field to event header field type.");
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(stream_class->common.packet_context_field_type);
+       stream_class->common.packet_context_field_type =
+               (void *) packet_context_type;
+       packet_context_type = NULL;
+
+end:
+       if (ret) {
+               bt_ctf_object_put_ref(packet_context_type);
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(_uint64_t);
+       bt_ctf_object_put_ref(ts_begin_end_uint64_t);
+       return ret;
+}
+
+static
+void bt_ctf_stream_class_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_stream_class *stream_class;
+
+       stream_class = (void *) obj;
+       BT_LOGD("Destroying CTF writer stream class: addr=%p, name=\"%s\", id=%" PRId64,
+               stream_class, bt_ctf_stream_class_get_name(stream_class),
+               bt_ctf_stream_class_get_id(stream_class));
+       bt_ctf_stream_class_common_finalize(BT_CTF_TO_COMMON(stream_class));
+       bt_ctf_object_put_ref(stream_class->clock);
+       g_free(stream_class);
+}
+
+struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name)
+{
+       struct bt_ctf_stream_class *stream_class;
+       int ret;
+
+       BT_LOGD("Creating CTF writer stream class object: name=\"%s\"", name);
+       stream_class = g_new0(struct bt_ctf_stream_class, 1);
+       if (!stream_class) {
+               BT_LOGE_STR("Failed to allocate one CTF writer stream class.");
+               goto error;
+       }
+
+       ret = bt_ctf_stream_class_common_initialize(BT_CTF_TO_COMMON(stream_class),
+               name, bt_ctf_stream_class_destroy);
+       if (ret) {
+               /* bt_ctf_stream_class_common_initialize() logs errors */
+               goto error;
+       }
+
+       ret = init_event_header(stream_class);
+       if (ret) {
+               BT_LOGE_STR("Cannot initialize stream class's event header field type.");
+               goto error;
+       }
+
+       ret = init_packet_context(stream_class);
+       if (ret) {
+               BT_LOGE_STR("Cannot initialize stream class's packet context field type.");
+               goto error;
+       }
+
+       BT_LOGD("Created CTF writer stream class object: addr=%p, name=\"%s\"",
+               stream_class, name);
+       return stream_class;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_class);
+       return stream_class;
+}
+
+static
+int try_map_clock_class(struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *parent_ft, const char *field_name)
+{
+       struct bt_ctf_clock_class *mapped_clock_class = NULL;
+       int ret = 0;
+       struct bt_ctf_field_type *ft =
+               bt_ctf_field_type_structure_get_field_type_by_name(parent_ft,
+                       field_name);
+
+       BT_ASSERT(stream_class->clock);
+
+       if (!ft) {
+               /* Field does not exist: not an error */
+               goto end;
+       }
+
+       BT_ASSERT(((struct bt_ctf_field_type_common *) ft)->id ==
+               BT_CTF_FIELD_TYPE_ID_INTEGER);
+       mapped_clock_class =
+               bt_ctf_field_type_integer_get_mapped_clock_class(ft);
+       if (!mapped_clock_class) {
+               struct bt_ctf_field_type *ft_copy;
+
+               if (!stream_class->clock) {
+                       BT_LOGW("Cannot automatically set field's type mapped clock class: stream class's clock is not set: "
+                               "stream-class-addr=%p, stream-class-name=\"%s\", "
+                               "stream-class-id=%" PRId64 ", ft-addr=%p",
+                               stream_class,
+                               bt_ctf_stream_class_get_name(stream_class),
+                               bt_ctf_stream_class_get_id(stream_class), ft);
+                       ret = -1;
+                       goto end;
+               }
+
+               ft_copy = bt_ctf_field_type_copy(ft);
+               if (!ft_copy) {
+                       BT_LOGE("Failed to copy integer field type: ft-addr=%p",
+                               ft);
+               }
+
+               ret = bt_ctf_field_type_common_integer_set_mapped_clock_class_no_check_frozen(
+                       (void *) ft_copy, stream_class->clock->clock_class);
+               BT_ASSERT(ret == 0);
+
+               ret = bt_ctf_field_type_common_structure_replace_field(
+                       (void *) parent_ft, field_name, (void *) ft_copy);
+               bt_ctf_object_put_ref(ft_copy);
+               BT_LOGV("Automatically mapped field type to stream class's clock class: "
+                       "stream-class-addr=%p, stream-class-name=\"%s\", "
+                       "stream-class-id=%" PRId64 ", ft-addr=%p, "
+                       "ft-copy-addr=%p",
+                       stream_class,
+                       bt_ctf_stream_class_get_name(stream_class),
+                       bt_ctf_stream_class_get_id(stream_class), ft, ft_copy);
+       }
+
+end:
+       bt_ctf_object_put_ref(ft);
+       bt_ctf_object_put_ref(mapped_clock_class);
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_map_clock_class(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type)
+{
+       int ret = 0;
+
+       BT_ASSERT(stream_class);
+
+       if (!stream_class->clock) {
+               /* No clock class to map to */
+               goto end;
+       }
+
+       if (packet_context_type) {
+               if (try_map_clock_class(stream_class, packet_context_type,
+                               "timestamp_begin")) {
+                       BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_begin` field's mapped clock class.");
+                       ret = -1;
+                       goto end;
+               }
+
+               if (try_map_clock_class(stream_class, packet_context_type,
+                               "timestamp_end")) {
+                       BT_LOGE_STR("Cannot automatically set stream class's packet context field type's `timestamp_end` field's mapped clock class.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       if (event_header_type) {
+               if (try_map_clock_class(stream_class, event_header_type,
+                               "timestamp")) {
+                       BT_LOGE_STR("Cannot automatically set stream class's event header field type's `timestamp` field's mapped clock class.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+struct bt_ctf_clock *bt_ctf_stream_class_get_clock(
+               struct bt_ctf_stream_class *stream_class)
+{
+       struct bt_ctf_clock *clock = NULL;
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               goto end;
+       }
+
+       if (!stream_class->clock) {
+               BT_LOGV("Stream class has no clock: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_get_name(stream_class),
+                       bt_ctf_stream_class_get_id(stream_class));
+               goto end;
+       }
+
+       clock = bt_ctf_object_get_ref(stream_class->clock);
+
+end:
+       return clock;
+}
+
+int bt_ctf_stream_class_set_clock(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_clock *clock)
+{
+       int ret = 0;
+
+       if (!stream_class || !clock) {
+               BT_LOGW("Invalid parameter: stream class or clock is NULL: "
+                       "stream-class-addr=%p, clock-addr=%p",
+                       stream_class, clock);
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->common.frozen) {
+               BT_LOGW("Invalid parameter: stream class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_get_name(stream_class),
+                       bt_ctf_stream_class_get_id(stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       /* Replace the current clock of this stream class. */
+       bt_ctf_object_put_ref(stream_class->clock);
+       stream_class->clock = bt_ctf_object_get_ref(clock);
+       BT_LOGV("Set stream class's clock: "
+               "addr=%p, name=\"%s\", id=%" PRId64 ", "
+               "clock-addr=%p, clock-name=\"%s\"",
+               stream_class,
+               bt_ctf_stream_class_get_name(stream_class),
+               bt_ctf_stream_class_get_id(stream_class),
+               stream_class->clock,
+               bt_ctf_clock_get_name(stream_class->clock));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
+               struct metadata_context *context)
+{
+       int ret = 0;
+       size_t i;
+       struct bt_ctf_trace *trace;
+       struct bt_ctf_field_type *packet_header_type = NULL;
+
+       BT_LOGD("Serializing stream class's metadata: "
+               "stream-class-addr=%p, stream-class-name=\"%s\", "
+               "stream-class-id=%" PRId64 ", metadata-context-addr=%p",
+               stream_class,
+               bt_ctf_stream_class_get_name(stream_class),
+               bt_ctf_stream_class_get_id(stream_class), context);
+       g_string_assign(context->field_name, "");
+       context->current_indentation_level = 1;
+       if (!stream_class->common.id_set) {
+               BT_LOGW_STR("Stream class's ID is not set.");
+               ret = -1;
+               goto end;
+       }
+
+       g_string_append(context->string, "stream {\n");
+
+       /*
+        * The reference to the trace is only borrowed since the
+        * serialization of the stream class might have been triggered
+        * by the trace's destruction. In such a case, the trace's
+        * reference count would, unexepectedly, go through the sequence
+        * 1 -> 0 -> 1 -> 0 -> ..., provoking an endless loop of destruction
+        * and serialization.
+        */
+       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
+               BT_CTF_TO_COMMON(stream_class)));
+       BT_ASSERT(trace);
+       packet_header_type = bt_ctf_trace_get_packet_header_field_type(trace);
+       trace = NULL;
+       if (packet_header_type) {
+               struct bt_ctf_field_type *stream_id_type;
+
+               stream_id_type =
+                       bt_ctf_field_type_structure_get_field_type_by_name(
+                               packet_header_type, "stream_id");
+               if (stream_id_type) {
+                       /*
+                        * Only set the stream's id if the trace's packet header
+                        * contains a stream_id field. This field is only
+                        * needed if the trace contains only one stream
+                        * class.
+                        */
+                       g_string_append_printf(context->string,
+                               "\tid = %" PRId64 ";\n",
+                               stream_class->common.id);
+               }
+               bt_ctf_object_put_ref(stream_id_type);
+       }
+       if (stream_class->common.event_header_field_type) {
+               BT_LOGD_STR("Serializing stream class's event header field type's metadata.");
+               g_string_append(context->string, "\tevent.header := ");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) stream_class->common.event_header_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream class's event header field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";");
+       }
+
+
+       if (stream_class->common.packet_context_field_type) {
+               BT_LOGD_STR("Serializing stream class's packet context field type's metadata.");
+               g_string_append(context->string, "\n\n\tpacket.context := ");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) stream_class->common.packet_context_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream class's packet context field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";");
+       }
+
+       if (stream_class->common.event_context_field_type) {
+               BT_LOGD_STR("Serializing stream class's event context field type's metadata.");
+               g_string_append(context->string, "\n\n\tevent.context := ");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) stream_class->common.event_context_field_type,
+                       context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream class's event context field type's metadata: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+               g_string_append(context->string, ";");
+       }
+
+       g_string_append(context->string, "\n};\n\n");
+
+       for (i = 0; i < stream_class->common.event_classes->len; i++) {
+               struct bt_ctf_event_class *event_class =
+                       stream_class->common.event_classes->pdata[i];
+
+               ret = bt_ctf_event_class_serialize(event_class, context);
+               if (ret) {
+                       BT_LOGW("Cannot serialize event class's metadata: "
+                               "event-class-addr=%p, event-class-name=\"%s\", "
+                               "event-class-id=%" PRId64,
+                               event_class,
+                               bt_ctf_event_class_get_name(event_class),
+                               bt_ctf_event_class_get_id(event_class));
+                       goto end;
+               }
+       }
+
+end:
+       bt_ctf_object_put_ref(packet_header_type);
+       context->current_indentation_level = 0;
+       return ret;
+}
+
+struct bt_ctf_trace *bt_ctf_stream_class_get_trace(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_object_get_ref(bt_ctf_stream_class_common_borrow_trace(
+               BT_CTF_TO_COMMON(stream_class)));
+}
+
+const char *bt_ctf_stream_class_get_name(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_stream_class_common_get_name(BT_CTF_TO_COMMON(stream_class));
+}
+
+int bt_ctf_stream_class_set_name(
+               struct bt_ctf_stream_class *stream_class, const char *name)
+{
+       return bt_ctf_stream_class_common_set_name(BT_CTF_TO_COMMON(stream_class),
+               name);
+}
+
+int64_t bt_ctf_stream_class_get_id(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_stream_class_common_get_id(BT_CTF_TO_COMMON(stream_class));
+}
+
+int bt_ctf_stream_class_set_id(
+               struct bt_ctf_stream_class *stream_class, uint64_t id)
+{
+       return bt_ctf_stream_class_common_set_id(BT_CTF_TO_COMMON(stream_class), id);
+}
+
+struct bt_ctf_field_type *bt_ctf_stream_class_get_packet_context_type(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_packet_context_field_type(
+                       BT_CTF_TO_COMMON(stream_class)));
+}
+
+int bt_ctf_stream_class_set_packet_context_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *packet_context_type)
+{
+       return bt_ctf_stream_class_common_set_packet_context_field_type(
+               BT_CTF_TO_COMMON(stream_class), (void *) packet_context_type);
+}
+
+struct bt_ctf_field_type *
+bt_ctf_stream_class_get_event_header_type(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_event_header_field_type(
+                       BT_CTF_TO_COMMON(stream_class)));
+}
+
+int bt_ctf_stream_class_set_event_header_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *event_header_type)
+{
+       return bt_ctf_stream_class_common_set_event_header_field_type(
+               BT_CTF_TO_COMMON(stream_class), (void *) event_header_type);
+}
+
+struct bt_ctf_field_type *
+bt_ctf_stream_class_get_event_context_type(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_event_context_field_type(
+                       BT_CTF_TO_COMMON(stream_class)));
+}
+
+int bt_ctf_stream_class_set_event_context_type(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *event_context_type)
+{
+       return bt_ctf_stream_class_common_set_event_context_field_type(
+               BT_CTF_TO_COMMON(stream_class), (void *) event_context_type);
+}
+
+int64_t bt_ctf_stream_class_get_event_class_count(
+               struct bt_ctf_stream_class *stream_class)
+{
+       return bt_ctf_stream_class_common_get_event_class_count(
+               BT_CTF_TO_COMMON(stream_class));
+}
+
+struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_index(
+               struct bt_ctf_stream_class *stream_class, uint64_t index)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_event_class_by_index(
+                       BT_CTF_TO_COMMON(stream_class), index));
+}
+
+struct bt_ctf_event_class *bt_ctf_stream_class_get_event_class_by_id(
+               struct bt_ctf_stream_class *stream_class, uint64_t id)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_stream_class_common_borrow_event_class_by_id(
+                       BT_CTF_TO_COMMON(stream_class), id));
+}
+
+int bt_ctf_stream_class_add_event_class(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_event_class *event_class)
+{
+       return bt_ctf_stream_class_common_add_event_class(
+               BT_CTF_TO_COMMON(stream_class), BT_CTF_TO_COMMON(event_class),
+               (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy);
+}
diff --git a/src/ctf-writer/stream-class.h b/src/ctf-writer/stream-class.h
new file mode 100644 (file)
index 0000000..c008a1f
--- /dev/null
@@ -0,0 +1,539 @@
+#ifndef BABELTRACE_CTF_WRITER_STREAM_CLASS_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_STREAM_CLASS_INTERNAL_H
+
+/*
+ * Copyright 2014 EfficiOS Inc.
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include "common/assert.h"
+#include "common/babeltrace.h"
+#include "common/common.h"
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/visitor.h>
+#include <inttypes.h>
+
+#include "clock.h"
+#include "field-types.h"
+#include "object.h"
+#include "stream-class.h"
+#include "utils.h"
+#include "validation.h"
+
+struct bt_ctf_stream_class_common {
+       struct bt_ctf_object base;
+       GString *name;
+
+       /* Array of pointers to event class addresses */
+       GPtrArray *event_classes;
+
+       /* event class id (int64_t) to event class address */
+       GHashTable *event_classes_ht;
+       int id_set;
+       int64_t id;
+       int64_t next_event_id;
+       struct bt_ctf_field_type_common *packet_context_field_type;
+       struct bt_ctf_field_type_common *event_header_field_type;
+       struct bt_ctf_field_type_common *event_context_field_type;
+       int frozen;
+       int byte_order;
+
+       /*
+        * This flag indicates if the stream class is valid. A valid
+        * stream class is _always_ frozen.
+        */
+       int valid;
+
+       /*
+        * Unique clock class mapped to any field type within this
+        * stream class, including all the stream class's event class
+        * field types. This is only set if the stream class is frozen.
+        *
+        * If the stream class is frozen and this is still NULL, it is
+        * still possible that it becomes non-NULL because
+        * bt_ctf_stream_class_add_event_class() can add an event class
+        * containing a field type mapped to some clock class. In this
+        * case, this is the mapped clock class, and at this point, both
+        * the new event class and the stream class are frozen, so the
+        * next added event classes are expected to contain field types
+        * which only map to this specific clock class.
+        *
+        * If this is a CTF writer stream class, then this is the
+        * backing clock class of the `clock` member above.
+        */
+       struct bt_ctf_clock_class *clock_class;
+};
+
+struct bt_ctf_event_class_common;
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_initialize(struct bt_ctf_stream_class_common *stream_class,
+               const char *name, bt_ctf_object_release_func release_func);
+
+BT_HIDDEN
+void bt_ctf_stream_class_common_finalize(struct bt_ctf_stream_class_common *stream_class);
+
+BT_HIDDEN
+void bt_ctf_stream_class_common_freeze(struct bt_ctf_stream_class_common *stream_class);
+
+static inline
+const char *bt_ctf_stream_class_common_get_name(
+               struct bt_ctf_stream_class_common *stream_class)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->name->len > 0 ? stream_class->name->str : NULL;
+}
+
+static inline
+int64_t bt_ctf_stream_class_common_get_id(
+               struct bt_ctf_stream_class_common *stream_class)
+{
+       int64_t ret;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+
+       if (!stream_class->id_set) {
+               BT_LOGV("Stream class's ID is not set: addr=%p, name=\"%s\"",
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class));
+               ret = (int64_t) -1;
+               goto end;
+       }
+
+       ret = stream_class->id;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_stream_class_common_set_byte_order(
+               struct bt_ctf_stream_class_common *stream_class, int byte_order);
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_validate_single_clock_class(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_clock_class **expected_clock_class);
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_add_event_class(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_event_class_common *event_class,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func);
+
+BT_HIDDEN
+int bt_ctf_stream_class_common_visit(struct bt_ctf_stream_class_common *stream_class,
+               bt_ctf_visitor visitor, void *data);
+
+BT_HIDDEN
+int bt_ctf_stream_class_visit(struct bt_ctf_stream_class *stream_class,
+               bt_ctf_visitor visitor, void *data);
+
+static inline
+struct bt_ctf_trace_common *bt_ctf_stream_class_common_borrow_trace(
+               struct bt_ctf_stream_class_common *stream_class)
+{
+       BT_ASSERT(stream_class);
+       return (void *) bt_ctf_object_borrow_parent(&stream_class->base);
+}
+
+static inline
+int bt_ctf_stream_class_common_set_name(struct bt_ctf_stream_class_common *stream_class,
+               const char *name)
+{
+       int ret = 0;
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->frozen) {
+               BT_LOGW("Invalid parameter: stream class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (!name) {
+               g_string_assign(stream_class->name, "");
+       } else {
+               if (strlen(name) == 0) {
+                       BT_LOGW("Invalid parameter: name is empty.");
+                       ret = -1;
+                       goto end;
+               }
+
+               g_string_assign(stream_class->name, name);
+       }
+
+       BT_LOGV("Set stream class's name: "
+               "addr=%p, name=\"%s\", id=%" PRId64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+end:
+       return ret;
+}
+
+static inline
+void _bt_ctf_stream_class_common_set_id(
+               struct bt_ctf_stream_class_common *stream_class, int64_t id)
+{
+       BT_ASSERT(stream_class);
+       stream_class->id = id;
+       stream_class->id_set = 1;
+       BT_LOGV("Set stream class's ID (internal): "
+               "addr=%p, name=\"%s\", id=%" PRId64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+}
+
+static inline
+int bt_ctf_stream_class_common_set_id_no_check(
+               struct bt_ctf_stream_class_common *stream_class, int64_t id)
+{
+       _bt_ctf_stream_class_common_set_id(stream_class, id);
+       return 0;
+}
+
+static inline
+int bt_ctf_stream_class_common_set_id(struct bt_ctf_stream_class_common *stream_class,
+               uint64_t id_param)
+{
+       int ret = 0;
+       int64_t id = (int64_t) id_param;
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->frozen) {
+               BT_LOGW("Invalid parameter: stream class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (id < 0) {
+               BT_LOGW("Invalid parameter: invalid stream class's ID: "
+                       "stream-class-addr=%p, stream-class-name=\"%s\", "
+                       "stream-class-id=%" PRId64 ", id=%" PRIu64,
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class),
+                       id_param);
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_stream_class_common_set_id_no_check(stream_class, id);
+       if (ret == 0) {
+               BT_LOGV("Set stream class's ID: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class));
+       }
+end:
+       return ret;
+}
+
+static inline
+int64_t bt_ctf_stream_class_common_get_event_class_count(
+               struct bt_ctf_stream_class_common *stream_class)
+{
+       int64_t ret;
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = (int64_t) -1;
+               goto end;
+       }
+
+       ret = (int64_t) stream_class->event_classes->len;
+end:
+       return ret;
+}
+
+static inline
+struct bt_ctf_event_class_common *bt_ctf_stream_class_common_borrow_event_class_by_index(
+               struct bt_ctf_stream_class_common *stream_class, uint64_t index)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_ASSERT_PRE(index < stream_class->event_classes->len,
+               "Index is out of bounds: index=%" PRIu64 ", "
+               "count=%u",
+               index, stream_class->event_classes->len);
+       return g_ptr_array_index(stream_class->event_classes, index);
+}
+
+static inline
+struct bt_ctf_event_class_common *bt_ctf_stream_class_common_borrow_event_class_by_id(
+               struct bt_ctf_stream_class_common *stream_class, uint64_t id)
+{
+       int64_t id_key = (int64_t) id;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_CTF_ASSERT_PRE(id_key >= 0,
+               "Invalid event class ID: %" PRIu64, id);
+       return g_hash_table_lookup(stream_class->event_classes_ht,
+                       &id_key);
+}
+
+static inline
+struct bt_ctf_field_type_common *
+bt_ctf_stream_class_common_borrow_packet_context_field_type(
+               struct bt_ctf_stream_class_common *stream_class)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->packet_context_field_type;
+}
+
+static inline
+int bt_ctf_stream_class_common_set_packet_context_field_type(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *packet_context_type)
+{
+       int ret = 0;
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->frozen) {
+               BT_LOGW("Invalid parameter: stream class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (packet_context_type &&
+                       bt_ctf_field_type_common_get_type_id(packet_context_type) !=
+                               BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               /* A packet context must be a structure. */
+               BT_LOGW("Invalid parameter: stream class's packet context field type must be a structure: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
+                       "packet-context-ft-addr=%p, packet-context-ft-id=%s",
+                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class),
+                       packet_context_type,
+                       bt_ctf_field_type_id_string(
+                               bt_ctf_field_type_common_get_type_id(packet_context_type)));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(stream_class->packet_context_field_type);
+       stream_class->packet_context_field_type = packet_context_type;
+       bt_ctf_object_get_ref(stream_class->packet_context_field_type);
+       BT_LOGV("Set stream class's packet context field type: "
+               "addr=%p, name=\"%s\", id=%" PRId64 ", "
+               "packet-context-ft-addr=%p",
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class),
+               packet_context_type);
+
+end:
+       return ret;
+}
+
+static inline
+struct bt_ctf_field_type_common *
+bt_ctf_stream_class_common_borrow_event_header_field_type(
+               struct bt_ctf_stream_class_common *stream_class)
+{
+       struct bt_ctf_field_type_common *ret = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+
+       if (!stream_class->event_header_field_type) {
+               BT_LOGV("Stream class has no event header field type: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class));
+               goto end;
+       }
+
+       ret = stream_class->event_header_field_type;
+
+end:
+       return ret;
+}
+
+static inline
+int bt_ctf_stream_class_common_set_event_header_field_type(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *event_header_type)
+{
+       int ret = 0;
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->frozen) {
+               BT_LOGW("Invalid parameter: stream class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (event_header_type &&
+                       bt_ctf_field_type_common_get_type_id(event_header_type) !=
+                               BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               /* An event header must be a structure. */
+               BT_LOGW("Invalid parameter: stream class's event header field type must be a structure: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
+                       "event-header-ft-addr=%p, event-header-ft-id=%s",
+                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class),
+                       event_header_type,
+                       bt_ctf_field_type_id_string(
+                               bt_ctf_field_type_common_get_type_id(event_header_type)));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(stream_class->event_header_field_type);
+       stream_class->event_header_field_type = event_header_type;
+       bt_ctf_object_get_ref(stream_class->event_header_field_type);
+       BT_LOGV("Set stream class's event header field type: "
+               "addr=%p, name=\"%s\", id=%" PRId64 ", "
+               "event-header-ft-addr=%p",
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class),
+               event_header_type);
+end:
+       return ret;
+}
+
+static inline
+struct bt_ctf_field_type_common *
+bt_ctf_stream_class_common_borrow_event_context_field_type(
+               struct bt_ctf_stream_class_common *stream_class)
+{
+       struct bt_ctf_field_type_common *ret = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+
+       if (!stream_class->event_context_field_type) {
+               goto end;
+       }
+
+       ret = stream_class->event_context_field_type;
+
+end:
+       return ret;
+}
+
+static inline
+int bt_ctf_stream_class_common_set_event_context_field_type(
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *event_context_type)
+{
+       int ret = 0;
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->frozen) {
+               BT_LOGW("Invalid parameter: stream class is frozen: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class));
+               ret = -1;
+               goto end;
+       }
+
+       if (event_context_type &&
+                       bt_ctf_field_type_common_get_type_id(event_context_type) !=
+                               BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               /* A packet context must be a structure. */
+               BT_LOGW("Invalid parameter: stream class's event context field type must be a structure: "
+                       "addr=%p, name=\"%s\", id=%" PRId64 ", "
+                       "event-context-ft-addr=%p, event-context-ft-id=%s",
+                       stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+                       bt_ctf_stream_class_common_get_id(stream_class),
+                       event_context_type,
+                       bt_ctf_field_type_id_string(
+                               bt_ctf_field_type_common_get_type_id(event_context_type)));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(stream_class->event_context_field_type);
+       stream_class->event_context_field_type = event_context_type;
+       bt_ctf_object_get_ref(stream_class->event_context_field_type);
+       BT_LOGV("Set stream class's event context field type: "
+               "addr=%p, name=\"%s\", id=%" PRId64 ", "
+               "event-context-ft-addr=%p",
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class),
+               event_context_type);
+end:
+       return ret;
+}
+
+struct bt_ctf_stream_class {
+       struct bt_ctf_stream_class_common common;
+       struct bt_ctf_clock *clock;
+       int64_t next_stream_id;
+};
+
+struct metadata_context;
+
+BT_HIDDEN
+int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class,
+               struct metadata_context *context);
+
+BT_HIDDEN
+int bt_ctf_stream_class_map_clock_class(
+               struct bt_ctf_stream_class *stream_class,
+               struct bt_ctf_field_type *packet_context_type,
+               struct bt_ctf_field_type *event_header_type);
+
+#endif /* BABELTRACE_CTF_WRITER_STREAM_CLASS_INTERNAL_H */
diff --git a/src/ctf-writer/stream.c b/src/ctf-writer/stream.c
new file mode 100644 (file)
index 0000000..a1025c7
--- /dev/null
@@ -0,0 +1,1956 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-STREAM"
+#include "logging.h"
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/stream-class.h>
+#include <babeltrace2/ctf-writer/stream.h>
+#include <babeltrace2/ctf-writer/trace.h>
+
+#include "common/align.h"
+#include "common/assert.h"
+#include "compat/compiler.h"
+#include "ctfser/ctfser.h"
+
+#include "assert-pre.h"
+#include "event-class.h"
+#include "event.h"
+#include "fields.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "trace.h"
+#include "writer.h"
+
+BT_HIDDEN
+void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream)
+{
+       BT_LOGD("Finalizing common stream object: addr=%p, name=\"%s\"",
+               stream, bt_ctf_stream_common_get_name(stream));
+
+       if (stream->name) {
+               g_string_free(stream->name, TRUE);
+       }
+}
+
+BT_HIDDEN
+int bt_ctf_stream_common_initialize(
+               struct bt_ctf_stream_common *stream,
+               struct bt_ctf_stream_class_common *stream_class, const char *name,
+               uint64_t id, bt_ctf_object_release_func release_func)
+{
+       int ret = 0;
+       struct bt_ctf_trace_common *trace = NULL;
+
+       bt_ctf_object_init_shared_with_parent(&stream->base, release_func);
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               goto error;
+       }
+
+       BT_LOGD("Initializing common stream object: stream-class-addr=%p, "
+               "stream-class-name=\"%s\", stream-name=\"%s\", "
+               "stream-id=%" PRIu64,
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               name, id);
+       trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
+       if (!trace) {
+               BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
+                       "stream-class-addr=%p, stream-class-name=\"%s\", "
+                       "stream-name=\"%s\"",
+                       stream_class,
+                       bt_ctf_stream_class_common_get_name(stream_class), name);
+               goto error;
+       }
+
+       if (id != -1ULL) {
+               /*
+                * Validate that the given ID is unique amongst all the
+                * existing trace's streams created from the same stream
+                * class.
+                */
+               size_t i;
+
+               for (i = 0; i < trace->streams->len; i++) {
+                       struct bt_ctf_stream_common *trace_stream =
+                               g_ptr_array_index(trace->streams, i);
+
+                       if (trace_stream->stream_class != (void *) stream_class) {
+                               continue;
+                       }
+
+                       if (trace_stream->id == id) {
+                               BT_LOGW_STR("Invalid parameter: another stream in the same trace already has this ID.");
+                               goto error;
+                       }
+               }
+       }
+
+       /*
+        * Acquire reference to parent since stream will become publicly
+        * reachable; it needs its parent to remain valid.
+        */
+       bt_ctf_object_set_parent(&stream->base, &trace->base);
+       stream->stream_class = stream_class;
+       stream->id = (int64_t) id;
+
+       if (name) {
+               stream->name = g_string_new(name);
+               if (!stream->name) {
+                       BT_LOGE_STR("Failed to allocate a GString.");
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Set common stream's trace parent: trace-addr=%p", trace);
+
+       /* Add this stream to the trace's streams */
+       BT_LOGD("Created common stream object: addr=%p", stream);
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+void bt_ctf_stream_destroy(struct bt_ctf_object *obj);
+
+static
+int try_set_structure_field_integer(struct bt_ctf_field *, char *, uint64_t);
+
+static
+int set_integer_field_value(struct bt_ctf_field* field, uint64_t value)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (!field) {
+               BT_LOGW_STR("Invalid parameter: field is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(field);
+       BT_ASSERT(field_type);
+
+       if (bt_ctf_field_type_get_type_id(field_type) !=
+                       BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               /* Not an integer and the value is unset, error. */
+               BT_LOGW("Invalid parameter: field's type is not an integer field type: "
+                       "field-addr=%p, ft-addr=%p, ft-id=%s",
+                       field, field_type,
+                       bt_ctf_field_type_id_string((int)
+                               bt_ctf_field_type_get_type_id(field_type)));
+               ret = -1;
+               goto end;
+       }
+
+       if (bt_ctf_field_type_integer_is_signed(field_type)) {
+               ret = bt_ctf_field_integer_signed_set_value(field, (int64_t) value);
+               if (ret) {
+                       /* Value is out of range, error. */
+                       BT_LOGW("Cannot set signed integer field's value: "
+                               "addr=%p, value=%" PRId64,
+                               field, (int64_t) value);
+                       goto end;
+               }
+       } else {
+               ret = bt_ctf_field_integer_unsigned_set_value(field, value);
+               if (ret) {
+                       /* Value is out of range, error. */
+                       BT_LOGW("Cannot set unsigned integer field's value: "
+                               "addr=%p, value=%" PRIu64,
+                               field, value);
+                       goto end;
+               }
+       }
+end:
+       bt_ctf_object_put_ref(field_type);
+       return ret;
+}
+
+static
+int set_packet_header_magic(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       struct bt_ctf_field *magic_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_header, "magic");
+       const uint32_t magic_value = 0xc1fc1fc1;
+
+       BT_ASSERT(stream);
+
+       if (!magic_field) {
+               /* No magic field found. Not an error, skip. */
+               BT_LOGV("No field named `magic` in packet header: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_set_value(magic_field,
+               (uint64_t) magic_value);
+
+       if (ret) {
+               BT_LOGW("Cannot set packet header field's `magic` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       magic_field, (uint64_t) magic_value);
+       } else {
+               BT_LOGV("Set packet header field's `magic` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       magic_field, (uint64_t) magic_value);
+       }
+end:
+       bt_ctf_object_put_ref(magic_field);
+       return ret;
+}
+
+static
+int set_packet_header_uuid(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       int64_t i;
+       struct bt_ctf_trace *trace = NULL;
+       struct bt_ctf_field *uuid_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_header, "uuid");
+
+       BT_ASSERT(stream);
+
+       if (!uuid_field) {
+               /* No uuid field found. Not an error, skip. */
+               BT_LOGV("No field named `uuid` in packet header: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       trace = (struct bt_ctf_trace *)
+               bt_ctf_object_get_parent(&stream->common.base);
+
+       for (i = 0; i < 16; i++) {
+               struct bt_ctf_field *uuid_element =
+                       bt_ctf_field_array_get_field(uuid_field, i);
+
+               ret = bt_ctf_field_integer_unsigned_set_value(
+                       uuid_element, (uint64_t) trace->common.uuid[i]);
+               bt_ctf_object_put_ref(uuid_element);
+               if (ret) {
+                       BT_LOGW("Cannot set integer field's value (for `uuid` packet header field): "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
+                               "value=%" PRIu64 ", index=%" PRId64,
+                               stream, bt_ctf_stream_get_name(stream),
+                               uuid_element, (uint64_t) trace->common.uuid[i], i);
+                       goto end;
+               }
+       }
+
+       BT_LOGV("Set packet header field's `uuid` field's value: "
+               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), uuid_field);
+
+end:
+       bt_ctf_object_put_ref(uuid_field);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
+       return ret;
+}
+static
+int set_packet_header_stream_id(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       uint32_t stream_id;
+       struct bt_ctf_field *stream_id_field =
+               bt_ctf_field_structure_get_field_by_name(
+                       stream->packet_header, "stream_id");
+
+       if (!stream_id_field) {
+               /* No stream_id field found. Not an error, skip. */
+               BT_LOGV("No field named `stream_id` in packet header: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       stream_id = stream->common.stream_class->id;
+       ret = bt_ctf_field_integer_unsigned_set_value(stream_id_field,
+               (uint64_t) stream_id);
+       if (ret) {
+               BT_LOGW("Cannot set packet header field's `stream_id` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       stream_id_field, (uint64_t) stream_id);
+       } else {
+               BT_LOGV("Set packet header field's `stream_id` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       stream_id_field, (uint64_t) stream_id);
+       }
+
+end:
+       bt_ctf_object_put_ref(stream_id_field);
+       return ret;
+}
+
+static
+int auto_populate_packet_header(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+
+       if (!stream->packet_header) {
+               goto end;
+       }
+
+       ret = set_packet_header_magic(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's magic number field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_header_uuid(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's UUID field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_header_stream_id(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet header's stream class ID field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       BT_LOGV("Automatically populated stream's packet header's known fields: "
+               "stream-addr=%p, stream-name=\"%s\"",
+               stream, bt_ctf_stream_get_name(stream));
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_packet_size(struct bt_ctf_stream *stream,
+               uint64_t packet_size_bits)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "packet_size");
+
+       ret = bt_ctf_field_integer_unsigned_set_value(field, packet_size_bits);
+       if (ret) {
+               BT_LOGW("Cannot set packet context field's `packet_size` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, packet_size_bits);
+       } else {
+               BT_LOGV("Set packet context field's `packet_size` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, packet_size_bits);
+       }
+
+       bt_ctf_object_put_ref(field);
+       return ret;
+}
+
+static
+int set_packet_context_content_size(struct bt_ctf_stream *stream,
+               uint64_t content_size_bits)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "content_size");
+
+       BT_ASSERT(stream);
+
+       if (!field) {
+               /* No content size field found. Not an error, skip. */
+               BT_LOGV("No field named `content_size` in packet context: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_set_value(field, content_size_bits);
+       if (ret) {
+               BT_LOGW("Cannot set packet context field's `content_size` integer field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, content_size_bits);
+       } else {
+               BT_LOGV("Set packet context field's `content_size` field's value: "
+                       "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, content_size_bits);
+       }
+
+end:
+       bt_ctf_object_put_ref(field);
+       return ret;
+}
+
+static
+int set_packet_context_events_discarded(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       struct bt_ctf_field *field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "events_discarded");
+
+       BT_ASSERT(stream);
+
+       if (!field) {
+               /* No discarded events count field found. Not an error, skip. */
+               BT_LOGV("No field named `events_discarded` in packet context: skipping: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       /*
+        * If the field is set by the user, make sure that the value is
+        * greater than or equal to the stream's current count of
+        * discarded events. We do not allow wrapping here. If it's
+        * valid, update the stream's current count.
+        */
+       if (bt_ctf_field_is_set_recursive(field)) {
+               uint64_t user_val;
+
+               ret = bt_ctf_field_integer_unsigned_get_value(field,
+                       &user_val);
+               if (ret) {
+                       BT_LOGW("Cannot get packet context `events_discarded` field's unsigned value: "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p",
+                               stream, bt_ctf_stream_get_name(stream), field);
+                       goto end;
+               }
+
+               if (user_val < stream->discarded_events) {
+                       BT_LOGW("Invalid packet context `events_discarded` field's unsigned value: "
+                               "value is lesser than the stream's current discarded events count: "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, "
+                               "value=%" PRIu64 ", "
+                               "stream-discarded-events-count=%" PRIu64,
+                               stream, bt_ctf_stream_get_name(stream), field,
+                               user_val, stream->discarded_events);
+                       goto end;
+               }
+
+               stream->discarded_events = user_val;
+       } else {
+               ret = bt_ctf_field_integer_unsigned_set_value(field,
+                       stream->discarded_events);
+               if (ret) {
+                       BT_LOGW("Cannot set packet context field's `events_discarded` integer field's value: "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                               stream, bt_ctf_stream_get_name(stream),
+                               field, stream->discarded_events);
+               } else {
+                       BT_LOGV("Set packet context field's `events_discarded` field's value: "
+                               "stream-addr=%p, stream-name=\"%s\", field-addr=%p, value=%" PRIu64,
+                               stream, bt_ctf_stream_get_name(stream),
+                               field, stream->discarded_events);
+               }
+       }
+
+end:
+       bt_ctf_object_put_ref(field);
+       return ret;
+}
+
+static
+void update_clock_value(uint64_t *val, uint64_t new_val,
+               unsigned int new_val_size)
+{
+       const uint64_t pow2 = 1ULL << new_val_size;
+       const uint64_t mask = pow2 - 1;
+       uint64_t val_masked;
+
+#ifdef BT_LOG_ENABLED_VERBOSE
+       uint64_t old_val = *val;
+#endif
+
+       if (new_val_size == 64) {
+               *val = new_val;
+               goto end;
+       }
+
+       val_masked = *val & mask;
+
+       if (new_val < val_masked) {
+               /* Wrapped once */
+               new_val |= pow2;
+       }
+
+       *val &= ~mask;
+       *val |= new_val;
+
+end:
+       BT_LOGV("Updated clock value: old-val=%" PRIu64 ", new-val=%" PRIu64,
+               old_val, *val);
+       return;
+}
+
+static
+int visit_field_update_clock_value(struct bt_ctf_field *field, uint64_t *val)
+{
+       int ret = 0;
+       struct bt_ctf_field_common *field_common = (void *) field;
+
+       if (!field) {
+               goto end;
+       }
+
+       switch (bt_ctf_field_get_type_id(field)) {
+       case BT_CTF_FIELD_TYPE_ID_INTEGER:
+       {
+               struct bt_ctf_clock_class *cc =
+                       bt_ctf_field_type_integer_get_mapped_clock_class(
+                               (void *) field_common->type);
+               int val_size;
+               uint64_t uval;
+
+               if (!cc) {
+                       goto end;
+               }
+
+               bt_ctf_object_put_ref(cc);
+               val_size = bt_ctf_field_type_integer_get_size(
+                       (void *) field_common->type);
+               BT_ASSERT(val_size >= 1);
+
+               if (bt_ctf_field_type_integer_is_signed(
+                               (void *) field_common->type)) {
+                       int64_t ival;
+
+                       ret = bt_ctf_field_integer_signed_get_value(field, &ival);
+                       uval = (uint64_t) ival;
+               } else {
+                       ret = bt_ctf_field_integer_unsigned_get_value(field, &uval);
+               }
+
+               if (ret) {
+                       /* Not set */
+                       goto end;
+               }
+
+               update_clock_value(val, uval, val_size);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ENUM:
+       {
+               struct bt_ctf_field *int_field =
+                       bt_ctf_field_enumeration_get_container(field);
+
+               BT_ASSERT(int_field);
+               ret = visit_field_update_clock_value(int_field, val);
+               bt_ctf_object_put_ref(int_field);
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       {
+               uint64_t i;
+               int64_t len = bt_ctf_field_type_array_get_length(
+                       (void *) field_common->type);
+
+               BT_ASSERT(len >= 0);
+
+               for (i = 0; i < len; i++) {
+                       struct bt_ctf_field *elem_field =
+                               bt_ctf_field_array_get_field(field, i);
+
+                       BT_ASSERT(elem_field);
+                       ret = visit_field_update_clock_value(elem_field, val);
+                       bt_ctf_object_put_ref(elem_field);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       {
+               uint64_t i;
+               int64_t len = bt_ctf_field_common_sequence_get_length(
+                       (void *) field);
+
+               if (len < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               for (i = 0; i < len; i++) {
+                       struct bt_ctf_field *elem_field =
+                               bt_ctf_field_sequence_get_field(field, i);
+
+                       BT_ASSERT(elem_field);
+                       ret = visit_field_update_clock_value(elem_field, val);
+                       bt_ctf_object_put_ref(elem_field);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               uint64_t i;
+               int64_t len = bt_ctf_field_type_structure_get_field_count(
+                       (void *) field_common->type);
+
+               BT_ASSERT(len >= 0);
+
+               for (i = 0; i < len; i++) {
+                       struct bt_ctf_field *member_field =
+                               bt_ctf_field_structure_get_field_by_index(field, i);
+
+                       BT_ASSERT(member_field);
+                       ret = visit_field_update_clock_value(member_field, val);
+                       bt_ctf_object_put_ref(member_field);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               break;
+       }
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+       {
+               struct bt_ctf_field *cur_field =
+                       bt_ctf_field_variant_get_current_field(field);
+
+               if (!cur_field) {
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = visit_field_update_clock_value(cur_field, val);
+               bt_ctf_object_put_ref(cur_field);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+int visit_event_update_clock_value(struct bt_ctf_event *event, uint64_t *val)
+{
+       int ret = 0;
+       struct bt_ctf_field *field;
+
+       field = bt_ctf_event_get_header(event);
+       ret = visit_field_update_clock_value(field, val);
+       bt_ctf_object_put_ref(field);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically update clock value in "
+                       "event's header.");
+               goto end;
+       }
+
+       field = bt_ctf_event_get_stream_event_context(event);
+       ret = visit_field_update_clock_value(field, val);
+       bt_ctf_object_put_ref(field);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically update clock value in "
+                       "event's stream event context.");
+               goto end;
+       }
+
+       field = bt_ctf_event_get_context(event);
+       ret = visit_field_update_clock_value(field, val);
+       bt_ctf_object_put_ref(field);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically update clock value in "
+                       "event's context.");
+               goto end;
+       }
+
+       field = bt_ctf_event_get_payload_field(event);
+       ret = visit_field_update_clock_value(field, val);
+       bt_ctf_object_put_ref(field);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically update clock value in "
+                       "event's payload.");
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_timestamps(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       uint64_t val;
+       uint64_t cur_clock_value;
+       uint64_t init_clock_value = 0;
+       struct bt_ctf_field *ts_begin_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "timestamp_begin");
+       struct bt_ctf_field *ts_end_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "timestamp_end");
+       struct bt_ctf_field_common *packet_context =
+               (void *) stream->packet_context;
+       uint64_t i;
+       int64_t len;
+
+       if (ts_begin_field && bt_ctf_field_is_set_recursive(ts_begin_field)) {
+               /* Use provided `timestamp_begin` value as starting value */
+               ret = bt_ctf_field_integer_unsigned_get_value(ts_begin_field, &val);
+               BT_ASSERT(ret == 0);
+               init_clock_value = val;
+       } else if (stream->last_ts_end != -1ULL) {
+               /* Use last packet's ending timestamp as starting value */
+               init_clock_value = stream->last_ts_end;
+       }
+
+       cur_clock_value = init_clock_value;
+
+       if (stream->last_ts_end != -1ULL &&
+                       cur_clock_value < stream->last_ts_end) {
+               BT_LOGW("Packet's initial timestamp is less than previous "
+                       "packet's final timestamp: "
+                       "stream-addr=%p, stream-name=\"%s\", "
+                       "cur-packet-ts-begin=%" PRIu64 ", "
+                       "prev-packet-ts-end=%" PRIu64,
+                       stream, bt_ctf_stream_get_name(stream),
+                       cur_clock_value, stream->last_ts_end);
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Visit all the packet context fields, followed by all the
+        * fields of all the events, in order, updating our current
+        * clock value as we visit.
+        *
+        * While visiting the packet context fields, do not consider
+        * `timestamp_begin` and `timestamp_end` because this function's
+        * purpose is to set them anyway. Also do not consider
+        * `packet_size`, `content_size`, `events_discarded`, and
+        * `packet_seq_num` if they are not set because those are
+        * autopopulating fields.
+        */
+       len = bt_ctf_field_type_structure_get_field_count(
+               (void *) packet_context->type);
+       BT_ASSERT(len >= 0);
+
+       for (i = 0; i < len; i++) {
+               const char *member_name;
+               struct bt_ctf_field *member_field;
+
+               ret = bt_ctf_field_type_structure_get_field_by_index(
+                       (void *) packet_context->type, &member_name, NULL, i);
+               BT_ASSERT(ret == 0);
+
+               if (strcmp(member_name, "timestamp_begin") == 0 ||
+                               strcmp(member_name, "timestamp_end") == 0) {
+                       continue;
+               }
+
+               member_field = bt_ctf_field_structure_get_field_by_index(
+                       stream->packet_context, i);
+               BT_ASSERT(member_field);
+
+               if (strcmp(member_name, "packet_size") == 0 &&
+                               !bt_ctf_field_is_set_recursive(member_field)) {
+                       bt_ctf_object_put_ref(member_field);
+                       continue;
+               }
+
+               if (strcmp(member_name, "content_size") == 0 &&
+                               !bt_ctf_field_is_set_recursive(member_field)) {
+                       bt_ctf_object_put_ref(member_field);
+                       continue;
+               }
+
+               if (strcmp(member_name, "events_discarded") == 0 &&
+                               !bt_ctf_field_is_set_recursive(member_field)) {
+                       bt_ctf_object_put_ref(member_field);
+                       continue;
+               }
+
+               if (strcmp(member_name, "packet_seq_num") == 0 &&
+                               !bt_ctf_field_is_set_recursive(member_field)) {
+                       bt_ctf_object_put_ref(member_field);
+                       continue;
+               }
+
+               ret = visit_field_update_clock_value(member_field,
+                       &cur_clock_value);
+               bt_ctf_object_put_ref(member_field);
+               if (ret) {
+                       BT_LOGW("Cannot automatically update clock value "
+                               "in stream's packet context: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "field-name=\"%s\"",
+                               stream, bt_ctf_stream_get_name(stream),
+                               member_name);
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < stream->events->len; i++) {
+               struct bt_ctf_event *event = g_ptr_array_index(stream->events, i);
+
+               BT_ASSERT(event);
+               ret = visit_event_update_clock_value(event, &cur_clock_value);
+               if (ret) {
+                       BT_LOGW("Cannot automatically update clock value "
+                               "in stream's packet context: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "index=%" PRIu64 ", event-addr=%p, "
+                               "event-class-id=%" PRId64 ", "
+                               "event-class-name=\"%s\"",
+                               stream, bt_ctf_stream_get_name(stream),
+                               i, event,
+                               bt_ctf_event_class_common_get_id(event->common.class),
+                               bt_ctf_event_class_common_get_name(event->common.class));
+                       goto end;
+               }
+       }
+
+       /*
+        * Everything is visited, thus the current clock value
+        * corresponds to the ending timestamp. Validate this value
+        * against the provided value of `timestamp_end`, if any,
+        * otherwise set it.
+        */
+       if (ts_end_field && bt_ctf_field_is_set_recursive(ts_end_field)) {
+               ret = bt_ctf_field_integer_unsigned_get_value(ts_end_field, &val);
+               BT_ASSERT(ret == 0);
+
+               if (val < cur_clock_value) {
+                       BT_LOGW("Packet's final timestamp is less than "
+                               "computed packet's final timestamp: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "cur-packet-ts-end=%" PRIu64 ", "
+                               "computed-packet-ts-end=%" PRIu64,
+                               stream, bt_ctf_stream_get_name(stream),
+                               val, cur_clock_value);
+                       ret = -1;
+                       goto end;
+               }
+
+               stream->last_ts_end = val;
+       }
+
+       if (ts_end_field && !bt_ctf_field_is_set_recursive(ts_end_field)) {
+               ret = set_integer_field_value(ts_end_field, cur_clock_value);
+               BT_ASSERT(ret == 0);
+               stream->last_ts_end = cur_clock_value;
+       }
+
+       if (!ts_end_field) {
+               stream->last_ts_end = cur_clock_value;
+       }
+
+       /* Set `timestamp_begin` field to initial clock value */
+       if (ts_begin_field && !bt_ctf_field_is_set_recursive(ts_begin_field)) {
+               ret = set_integer_field_value(ts_begin_field, init_clock_value);
+               BT_ASSERT(ret == 0);
+       }
+
+end:
+       bt_ctf_object_put_ref(ts_begin_field);
+       bt_ctf_object_put_ref(ts_end_field);
+       return ret;
+}
+
+static
+int auto_populate_packet_context(struct bt_ctf_stream *stream, bool set_ts,
+               uint64_t packet_size_bits, uint64_t content_size_bits)
+{
+       int ret = 0;
+
+       if (!stream->packet_context) {
+               goto end;
+       }
+
+       ret = set_packet_context_packet_size(stream, packet_size_bits);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's packet size field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       ret = set_packet_context_content_size(stream, content_size_bits);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's content size field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       if (set_ts) {
+               ret = set_packet_context_timestamps(stream);
+               if (ret) {
+                       BT_LOGW("Cannot set packet context's timestamp fields: "
+                               "stream-addr=%p, stream-name=\"%s\"",
+                               stream, bt_ctf_stream_get_name(stream));
+                       goto end;
+               }
+       }
+
+       ret = set_packet_context_events_discarded(stream);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's discarded events count field: "
+                       "stream-addr=%p, stream-name=\"%s\"",
+                       stream, bt_ctf_stream_get_name(stream));
+               goto end;
+       }
+
+       BT_LOGV("Automatically populated stream's packet context's known fields: "
+               "stream-addr=%p, stream-name=\"%s\"",
+               stream, bt_ctf_stream_get_name(stream));
+
+end:
+       return ret;
+}
+
+static
+void release_event(struct bt_ctf_event *event)
+{
+       if (bt_ctf_object_get_ref_count(&event->common.base)) {
+               /*
+                * The event is being orphaned, but it must guarantee the
+                * existence of its event class for the duration of its
+                * lifetime.
+                */
+               bt_ctf_object_get_ref(event->common.class);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(event->common.base.parent);
+       } else {
+               bt_ctf_object_try_spec_release(&event->common.base);
+       }
+}
+
+static
+int create_stream_file(struct bt_ctf_writer *writer,
+               struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       GString *filename = g_string_new(NULL);
+       int64_t stream_class_id;
+       char *file_path = NULL;
+
+       BT_LOGD("Creating stream file: writer-addr=%p, stream-addr=%p, "
+               "stream-name=\"%s\", stream-class-addr=%p, stream-class-name=\"%s\"",
+               writer, stream, bt_ctf_stream_get_name(stream),
+               stream->common.stream_class,
+               stream->common.stream_class->name->str);
+
+       if (stream->common.name && stream->common.name->len > 0) {
+               /* Use stream name's base name as prefix */
+               gchar *basename = g_path_get_basename(stream->common.name->str);
+
+               BT_ASSERT(basename);
+
+               if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
+                       g_string_assign(filename, "stream");
+               } else {
+                       g_string_assign(filename, basename);
+               }
+
+               g_free(basename);
+               goto append_ids;
+       }
+
+       if (stream->common.stream_class->name &&
+                       stream->common.stream_class->name->len > 0) {
+               /* Use stream class name's base name as prefix */
+               gchar *basename =
+                       g_path_get_basename(
+                               stream->common.stream_class->name->str);
+
+               BT_ASSERT(basename);
+
+               if (strcmp(basename, G_DIR_SEPARATOR_S) == 0) {
+                       g_string_assign(filename, "stream");
+               } else {
+                       g_string_assign(filename, basename);
+               }
+
+               g_free(basename);
+               goto append_ids;
+       }
+
+       /* Default to using `stream-` as prefix */
+       g_string_assign(filename, "stream");
+
+append_ids:
+       stream_class_id = bt_ctf_stream_class_common_get_id(stream->common.stream_class);
+       BT_ASSERT(stream_class_id >= 0);
+       BT_ASSERT(stream->common.id >= 0);
+       g_string_append_printf(filename, "-%" PRId64 "-%" PRId64,
+               stream_class_id, stream->common.id);
+
+       file_path = g_build_filename(writer->path->str, filename->str, NULL);
+       if (file_path == NULL) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctfser_init(&stream->ctfser, file_path);
+       g_free(file_path);
+       if (ret) {
+               /* bt_ctfser_init() logs errors */
+               goto end;
+       }
+
+       BT_LOGD("Created stream file for writing: "
+               "stream-addr=%p, stream-name=\"%s\", "
+               "filename=\"%s\"", stream, bt_ctf_stream_get_name(stream),
+               filename->str);
+
+end:
+       g_string_free(filename, TRUE);
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_ctf_stream *bt_ctf_stream_create_with_id(
+               struct bt_ctf_stream_class *stream_class,
+               const char *name, uint64_t id)
+{
+       int ret;
+       int fd;
+       struct bt_ctf_stream *stream = NULL;
+       struct bt_ctf_trace *trace = NULL;
+       struct bt_ctf_writer *writer = NULL;
+
+       BT_LOGD("Creating CTF writer stream object: stream-class-addr=%p, "
+               "stream-class-name=\"%s\", stream-name=\"%s\", "
+               "stream-id=%" PRIu64,
+               stream_class, bt_ctf_stream_class_get_name(stream_class),
+               name, id);
+       stream = g_new0(struct bt_ctf_stream, 1);
+       if (!stream) {
+               BT_LOGE_STR("Failed to allocate one stream.");
+               goto error;
+       }
+
+       if (id == -1ULL) {
+               id = stream_class->next_stream_id;
+       }
+
+       ret = bt_ctf_stream_common_initialize(BT_CTF_TO_COMMON(stream),
+               BT_CTF_TO_COMMON(stream_class), name, id, bt_ctf_stream_destroy);
+       if (ret) {
+               /* bt_ctf_stream_common_initialize() logs errors */
+               goto error;
+       }
+
+       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
+               BT_CTF_TO_COMMON(stream_class)));
+       if (!trace) {
+               BT_LOGW("Invalid parameter: cannot create stream from a stream class which is not part of trace: "
+                       "stream-class-addr=%p, stream-class-name=\"%s\", "
+                       "stream-name=\"%s\"",
+                       stream_class, bt_ctf_stream_class_get_name(stream_class),
+                       name);
+               goto error;
+       }
+
+       writer = (struct bt_ctf_writer *)
+               bt_ctf_object_get_parent(&trace->common.base);
+       stream->last_ts_end = -1ULL;
+       BT_LOGD("CTF writer stream object belongs writer's trace: "
+               "writer-addr=%p", writer);
+       BT_ASSERT(writer);
+
+       if (stream_class->common.packet_context_field_type) {
+               BT_LOGD("Creating stream's packet context field: "
+                       "ft-addr=%p",
+                       stream_class->common.packet_context_field_type);
+               stream->packet_context = bt_ctf_field_create(
+                       (void *) stream_class->common.packet_context_field_type);
+               if (!stream->packet_context) {
+                       BT_LOGW_STR("Cannot create stream's packet context field.");
+                       goto error;
+               }
+
+               /* Initialize events_discarded */
+               ret = try_set_structure_field_integer(
+                       stream->packet_context, "events_discarded", 0);
+               if (ret < 0) {
+                       BT_LOGW("Cannot set `events_discarded` field in packet context: "
+                               "ret=%d, packet-context-field-addr=%p",
+                               ret, stream->packet_context);
+                       goto error;
+               }
+       }
+
+       stream->events = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) release_event);
+       if (!stream->events) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       if (trace->common.packet_header_field_type) {
+               BT_LOGD("Creating stream's packet header field: "
+                       "ft-addr=%p", trace->common.packet_header_field_type);
+               stream->packet_header =
+                       bt_ctf_field_create(
+                               (void *) trace->common.packet_header_field_type);
+               if (!stream->packet_header) {
+                       BT_LOGW_STR("Cannot create stream's packet header field.");
+                       goto error;
+               }
+       }
+
+       /*
+        * Attempt to populate the default trace packet header fields
+        * (magic, uuid and stream_id). This will _not_ fail shall the
+        * fields not be found or be of an incompatible type; they will
+        * simply not be populated automatically. The user will have to
+        * make sure to set the trace packet header fields himself
+        * before flushing.
+        */
+       ret = auto_populate_packet_header(stream);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically populate the stream's packet header.");
+               goto error;
+       }
+
+       /* Create file associated with this stream */
+       fd = create_stream_file(writer, stream);
+       if (fd < 0) {
+               BT_LOGW_STR("Cannot create stream file.");
+               goto error;
+       }
+
+       /* Freeze the writer */
+       BT_LOGD_STR("Freezing stream's CTF writer.");
+       bt_ctf_writer_freeze(writer);
+
+       /* Add this stream to the trace's streams */
+       g_ptr_array_add(trace->common.streams, stream);
+       stream_class->next_stream_id++;
+       BT_LOGD("Created stream object: addr=%p", stream);
+       goto end;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
+
+end:
+       bt_ctf_object_put_ref(writer);
+       return stream;
+}
+
+struct bt_ctf_stream *bt_ctf_stream_create(
+               struct bt_ctf_stream_class *stream_class,
+               const char *name, uint64_t id_param)
+{
+       return bt_ctf_stream_create_with_id(stream_class,
+               name, id_param);
+}
+
+int bt_ctf_stream_get_discarded_events_count(
+               struct bt_ctf_stream *stream, uint64_t *count)
+{
+       int ret = 0;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!count) {
+               BT_LOGW_STR("Invalid parameter: count is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       *count = (uint64_t) stream->discarded_events;
+
+end:
+       return ret;
+}
+
+static
+int set_packet_context_events_discarded_field(struct bt_ctf_stream *stream,
+       uint64_t count)
+{
+       int ret = 0;
+       struct bt_ctf_field *events_discarded_field = NULL;
+
+       if (!stream->packet_context) {
+               goto end;
+       }
+
+       events_discarded_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "events_discarded");
+       if (!events_discarded_field) {
+               goto end;
+       }
+
+       ret = bt_ctf_field_integer_unsigned_set_value(
+               events_discarded_field, count);
+       if (ret) {
+               BT_LOGW("Cannot set packet context's `events_discarded` field: "
+                       "field-addr=%p, value=%" PRIu64,
+                       events_discarded_field, count);
+               goto end;
+       }
+
+end:
+       bt_ctf_object_put_ref(events_discarded_field);
+       return ret;
+}
+
+void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream,
+               uint64_t event_count)
+{
+       int ret;
+       uint64_t new_count;
+       struct bt_ctf_field *events_discarded_field = NULL;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               goto end;
+       }
+
+       BT_LOGV("Appending discarded events to stream: "
+               "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
+               stream, bt_ctf_stream_get_name(stream), event_count);
+
+       if (!stream->packet_context) {
+               BT_LOGW_STR("Invalid parameter: stream has no packet context field.");
+               goto end;
+       }
+
+       events_discarded_field = bt_ctf_field_structure_get_field_by_name(
+               stream->packet_context, "events_discarded");
+       if (!events_discarded_field) {
+               BT_LOGW_STR("No field named `events_discarded` in stream's packet context.");
+               goto end;
+       }
+
+       new_count = stream->discarded_events + event_count;
+       if (new_count < stream->discarded_events) {
+               BT_LOGW("New discarded events count is less than the stream's current discarded events count: "
+                       "cur-count=%" PRIu64 ", new-count=%" PRIu64,
+                       stream->discarded_events, new_count);
+               goto end;
+       }
+
+       ret = set_packet_context_events_discarded_field(stream, new_count);
+       if (ret) {
+               /* set_packet_context_events_discarded_field() logs errors */
+               goto end;
+       }
+
+       stream->discarded_events = new_count;
+       BT_LOGV("Appended discarded events to stream: "
+               "stream-addr=%p, stream-name=\"%s\", append-count=%" PRIu64,
+               stream, bt_ctf_stream_get_name(stream), event_count);
+
+end:
+       bt_ctf_object_put_ref(events_discarded_field);
+}
+
+static int auto_populate_event_header(struct bt_ctf_stream *stream,
+               struct bt_ctf_event *event)
+{
+       int ret = 0;
+       struct bt_ctf_field *id_field = NULL, *timestamp_field = NULL;
+       struct bt_ctf_clock_class *mapped_clock_class = NULL;
+       struct bt_ctf_stream_class *stream_class =
+               BT_CTF_FROM_COMMON(bt_ctf_stream_common_borrow_class(
+                       BT_CTF_TO_COMMON(stream)));
+       int64_t event_class_id;
+
+       BT_ASSERT(event);
+
+       if (!event->common.header_field) {
+               goto end;
+       }
+
+       if (event->common.frozen) {
+               BT_LOGW_STR("Cannot populate event header field: event is frozen.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Automatically populating event's header field: "
+               "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), event);
+
+       id_field = bt_ctf_field_structure_get_field_by_name(
+               (void *) event->common.header_field->field, "id");
+       event_class_id = bt_ctf_event_class_common_get_id(event->common.class);
+       BT_ASSERT(event_class_id >= 0);
+
+       if (id_field && bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               ret = set_integer_field_value(id_field, event_class_id);
+               if (ret) {
+                       BT_LOGW("Cannot set event header's `id` field's value: "
+                               "addr=%p, value=%" PRIu64, id_field,
+                               event_class_id);
+                       goto end;
+               }
+       }
+
+       /*
+        * The conditions to automatically set the timestamp are:
+        *
+        * 1. The event header field "timestamp" exists and is an
+        *    integer field.
+        * 2. This stream's class has a registered clock (set with
+        *    bt_ctf_stream_class_set_clock()).
+        * 3. The "timestamp" field is not set.
+        */
+       timestamp_field = bt_ctf_field_structure_get_field_by_name(
+                       (void *) event->common.header_field->field, "timestamp");
+       if (timestamp_field && stream_class->clock &&
+                       bt_ctf_field_get_type_id(id_field) == BT_CTF_FIELD_TYPE_ID_INTEGER &&
+                       !bt_ctf_field_is_set_recursive(timestamp_field)) {
+               mapped_clock_class =
+                       bt_ctf_field_type_integer_get_mapped_clock_class(
+                               (void *) ((struct bt_ctf_field_common *) timestamp_field)->type);
+               if (mapped_clock_class) {
+                       uint64_t timestamp;
+
+                       BT_ASSERT(mapped_clock_class ==
+                               stream_class->clock->clock_class);
+                       ret = bt_ctf_clock_get_value(
+                               stream_class->clock,
+                               &timestamp);
+                       BT_ASSERT(ret == 0);
+                       ret = set_integer_field_value(timestamp_field,
+                                       timestamp);
+                       if (ret) {
+                               BT_LOGW("Cannot set event header's `timestamp` field's value: "
+                                       "addr=%p, value=%" PRIu64,
+                                       timestamp_field, timestamp);
+                               goto end;
+                       }
+               }
+       }
+
+       BT_LOGV("Automatically populated event's header field: "
+               "stream-addr=%p, stream-name=\"%s\", event-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), event);
+
+end:
+       bt_ctf_object_put_ref(id_field);
+       bt_ctf_object_put_ref(timestamp_field);
+       bt_ctf_object_put_ref(mapped_clock_class);
+       return ret;
+}
+
+int bt_ctf_stream_append_event(struct bt_ctf_stream *stream,
+               struct bt_ctf_event *event)
+{
+       int ret = 0;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!event) {
+               BT_LOGW_STR("Invalid parameter: event is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Appending event to stream: "
+               "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               stream, bt_ctf_stream_get_name(stream), event,
+               bt_ctf_event_class_common_get_name(
+                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
+               bt_ctf_event_class_common_get_id(
+                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
+
+       /*
+        * The event is not supposed to have a parent stream at this
+        * point. The only other way an event can have a parent stream
+        * is if it was assigned when setting a packet to the event,
+        * in which case the packet's stream is not a writer stream,
+        * and thus the user is trying to append an event which belongs
+        * to another stream.
+        */
+       if (event->common.base.parent) {
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_set_parent(&event->common.base, &stream->common.base);
+       BT_LOGV_STR("Automatically populating the header of the event to append.");
+       ret = auto_populate_event_header(stream, event);
+       if (ret) {
+               /* auto_populate_event_header() reports errors */
+               goto error;
+       }
+
+       /* Make sure the various scopes of the event are set */
+       BT_LOGV_STR("Validating event to append.");
+       BT_CTF_ASSERT_PRE(bt_ctf_event_common_validate(BT_CTF_TO_COMMON(event)) == 0,
+               "Invalid event: event-addr=%p", event);
+
+       /* Save the new event and freeze it */
+       BT_LOGV_STR("Freezing the event to append.");
+       bt_ctf_event_common_set_is_frozen(BT_CTF_TO_COMMON(event), true);
+       g_ptr_array_add(stream->events, event);
+
+       /*
+        * Event had to hold a reference to its event class as long as it wasn't
+        * part of the same trace hierarchy. From now on, the event and its
+        * class share the same lifetime guarantees and the reference is no
+        * longer needed.
+        */
+       BT_LOGV_STR("Putting the event's class.");
+       bt_ctf_object_put_ref(event->common.class);
+       BT_LOGV("Appended event to stream: "
+               "stream-addr=%p, stream-name=\"%s\", event-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64,
+               stream, bt_ctf_stream_get_name(stream), event,
+               bt_ctf_event_class_common_get_name(
+                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))),
+               bt_ctf_event_class_common_get_id(
+                       bt_ctf_event_common_borrow_class(BT_CTF_TO_COMMON(event))));
+
+end:
+       return ret;
+
+error:
+       /*
+        * Orphan the event; we were not successful in associating it to
+        * a stream.
+        */
+       bt_ctf_object_set_parent(&event->common.base, NULL);
+       return ret;
+}
+
+struct bt_ctf_field *bt_ctf_stream_get_packet_context(struct bt_ctf_stream *stream)
+{
+       struct bt_ctf_field *packet_context = NULL;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               goto end;
+       }
+
+       packet_context = stream->packet_context;
+       if (packet_context) {
+               bt_ctf_object_get_ref(packet_context);
+       }
+end:
+       return packet_context;
+}
+
+int bt_ctf_stream_set_packet_context(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *field)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field_type;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(field);
+       if (bt_ctf_field_type_common_compare((void *) field_type,
+                       stream->common.stream_class->packet_context_field_type)) {
+               BT_LOGW("Invalid parameter: packet context's field type is different from the stream's packet context field type: "
+                       "stream-addr=%p, stream-name=\"%s\", "
+                       "packet-context-field-addr=%p, "
+                       "packet-context-ft-addr=%p",
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, field_type);
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(field_type);
+       bt_ctf_object_put_ref(stream->packet_context);
+       stream->packet_context = bt_ctf_object_get_ref(field);
+       BT_LOGV("Set stream's packet context field: "
+               "stream-addr=%p, stream-name=\"%s\", "
+               "packet-context-field-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), field);
+end:
+       return ret;
+}
+
+struct bt_ctf_field *bt_ctf_stream_get_packet_header(struct bt_ctf_stream *stream)
+{
+       struct bt_ctf_field *packet_header = NULL;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               goto end;
+       }
+
+       packet_header = stream->packet_header;
+       if (packet_header) {
+               bt_ctf_object_get_ref(packet_header);
+       }
+end:
+       return packet_header;
+}
+
+int bt_ctf_stream_set_packet_header(struct bt_ctf_stream *stream,
+               struct bt_ctf_field *field)
+{
+       int ret = 0;
+       struct bt_ctf_trace *trace = NULL;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       trace = (struct bt_ctf_trace *)
+               bt_ctf_object_get_parent(&stream->common.base);
+
+       if (!field) {
+               if (trace->common.packet_header_field_type) {
+                       BT_LOGW("Invalid parameter: setting no packet header but packet header field type is not NULL: "
+                               "stream-addr=%p, stream-name=\"%s\", "
+                               "packet-header-field-addr=%p, "
+                               "expected-ft-addr=%p",
+                               stream, bt_ctf_stream_get_name(stream),
+                               field, trace->common.packet_header_field_type);
+                       ret = -1;
+                       goto end;
+               }
+
+               goto skip_validation;
+       }
+
+       field_type = bt_ctf_field_get_type(field);
+       BT_ASSERT(field_type);
+
+       if (bt_ctf_field_type_common_compare((void *) field_type,
+                       trace->common.packet_header_field_type)) {
+               BT_LOGW("Invalid parameter: packet header's field type is different from the stream's packet header field type: "
+                       "stream-addr=%p, stream-name=\"%s\", "
+                       "packet-header-field-addr=%p, "
+                       "packet-header-ft-addr=%p",
+                       stream, bt_ctf_stream_get_name(stream),
+                       field, field_type);
+               ret = -1;
+               goto end;
+       }
+
+skip_validation:
+       bt_ctf_object_put_ref(stream->packet_header);
+       stream->packet_header = bt_ctf_object_get_ref(field);
+       BT_LOGV("Set stream's packet header field: "
+               "stream-addr=%p, stream-name=\"%s\", "
+               "packet-header-field-addr=%p",
+               stream, bt_ctf_stream_get_name(stream), field);
+end:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
+       bt_ctf_object_put_ref(field_type);
+       return ret;
+}
+
+static
+void reset_structure_field(struct bt_ctf_field *structure, const char *name)
+{
+       struct bt_ctf_field *member;
+
+       member = bt_ctf_field_structure_get_field_by_name(structure, name);
+       if (member) {
+               bt_ctf_field_common_reset_recursive((void *) member);
+               bt_ctf_object_put_ref(member);
+       }
+}
+
+int bt_ctf_stream_flush(struct bt_ctf_stream *stream)
+{
+       int ret = 0;
+       size_t i;
+       uint64_t packet_context_offset_bits = 0;
+       struct bt_ctf_trace *trace;
+       enum bt_ctf_byte_order native_byte_order;
+       bool has_packet_size = false;
+       uint64_t packet_size_bits = 0;
+       uint64_t content_size_bits = 0;
+
+       if (!stream) {
+               BT_LOGW_STR("Invalid parameter: stream is NULL.");
+               ret = -1;
+               goto end_no_stream;
+       }
+
+       if (stream->packet_context) {
+               struct bt_ctf_field *packet_size_field;
+
+               packet_size_field = bt_ctf_field_structure_get_field_by_name(
+                               stream->packet_context, "packet_size");
+               has_packet_size = (packet_size_field != NULL);
+               bt_ctf_object_put_ref(packet_size_field);
+       }
+
+       if (stream->flushed_packet_count == 1) {
+               if (!stream->packet_context) {
+                       BT_LOGW_STR("Cannot flush a stream which has no packet context field more than once.");
+                       ret = -1;
+                       goto end;
+               }
+
+               if (!has_packet_size) {
+                       BT_LOGW_STR("Cannot flush a stream which has no packet context's `packet_size` field more than once.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       BT_LOGV("Flushing stream's current packet: stream-addr=%p, "
+               "stream-name=\"%s\", packet-index=%u", stream,
+               bt_ctf_stream_get_name(stream), stream->flushed_packet_count);
+       trace = BT_CTF_FROM_COMMON(bt_ctf_stream_class_common_borrow_trace(
+               stream->common.stream_class));
+       BT_ASSERT(trace);
+       native_byte_order = bt_ctf_trace_get_native_byte_order(trace);
+
+       ret = auto_populate_packet_header(stream);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically populate the stream's packet header field.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Initialize packet/content sizes to `0`; we will overwrite later */
+       ret = auto_populate_packet_context(stream, true, 0, 0);
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctfser_open_packet(&stream->ctfser);
+       if (ret) {
+               /* bt_ctfser_open_packet() logs errors */
+               ret = -1;
+               goto end;
+       }
+
+       if (stream->packet_header) {
+               BT_LOGV_STR("Serializing packet header field (initial).");
+               ret = bt_ctf_field_serialize_recursive(stream->packet_header,
+                       &stream->ctfser, native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream's packet header field: "
+                               "field-addr=%p", stream->packet_header);
+                       goto end;
+               }
+       }
+
+       if (stream->packet_context) {
+               /* Save packet context's position to overwrite it later */
+               packet_context_offset_bits =
+                       bt_ctfser_get_offset_in_current_packet_bits(
+                               &stream->ctfser);
+
+               /* Write packet context */
+               BT_LOGV_STR("Serializing packet context field (initial).");
+               ret = bt_ctf_field_serialize_recursive(stream->packet_context,
+                       &stream->ctfser, native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream's packet context field: "
+                               "field-addr=%p", stream->packet_context);
+                       goto end;
+               }
+       }
+
+       BT_LOGV("Serializing events: count=%u", stream->events->len);
+
+       for (i = 0; i < stream->events->len; i++) {
+               struct bt_ctf_event *event = g_ptr_array_index(
+                       stream->events, i);
+               struct bt_ctf_event_class *event_class =
+                       BT_CTF_FROM_COMMON(bt_ctf_event_common_borrow_class(
+                               BT_CTF_TO_COMMON(event)));
+
+               BT_LOGV("Serializing event: index=%zu, event-addr=%p, "
+                       "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+                       "ser-offset=%" PRIu64,
+                       i, event, bt_ctf_event_class_get_name(event_class),
+                       bt_ctf_event_class_get_id(event_class),
+                       bt_ctfser_get_offset_in_current_packet_bits(
+                               &stream->ctfser));
+
+               /* Write event header */
+               if (event->common.header_field) {
+                       BT_LOGV_STR("Serializing event's header field.");
+                       ret = bt_ctf_field_serialize_recursive(
+                               (void *) event->common.header_field->field,
+                               &stream->ctfser, native_byte_order);
+                       if (ret) {
+                               BT_LOGW("Cannot serialize event's header field: "
+                                       "field-addr=%p",
+                                       event->common.header_field->field);
+                               goto end;
+                       }
+               }
+
+               /* Write stream event context */
+               if (event->common.stream_event_context_field) {
+                       BT_LOGV_STR("Serializing event's stream event context field.");
+                       ret = bt_ctf_field_serialize_recursive(
+                               (void *) event->common.stream_event_context_field,
+                               &stream->ctfser, native_byte_order);
+                       if (ret) {
+                               BT_LOGW("Cannot serialize event's stream event context field: "
+                                       "field-addr=%p",
+                                       event->common.stream_event_context_field);
+                               goto end;
+                       }
+               }
+
+               /* Write event content */
+               ret = bt_ctf_event_serialize(event, &stream->ctfser,
+                       native_byte_order);
+               if (ret) {
+                       /* bt_ctf_event_serialize() logs errors */
+                       goto end;
+               }
+       }
+
+       content_size_bits = bt_ctfser_get_offset_in_current_packet_bits(
+               &stream->ctfser);
+
+       if (!has_packet_size && content_size_bits % 8 != 0) {
+               BT_LOGW("Stream's packet context field type has no `packet_size` field, "
+                       "but current content size is not a multiple of 8 bits: "
+                       "content-size=%" PRIu64 ", "
+                       "packet-size=%" PRIu64,
+                       content_size_bits,
+                       packet_size_bits);
+               ret = -1;
+               goto end;
+       }
+
+       /* Set packet size; make it a multiple of 8 */
+       packet_size_bits = (content_size_bits + 7) & ~UINT64_C(7);
+
+       if (stream->packet_context) {
+               /*
+                * The whole packet is serialized at this point. Make
+                * sure that, if `packet_size` is missing, the current
+                * content size is equal to the current packet size.
+                */
+               struct bt_ctf_field *field =
+                       bt_ctf_field_structure_get_field_by_name(
+                               stream->packet_context, "content_size");
+
+               bt_ctf_object_put_ref(field);
+               if (!field) {
+                       if (content_size_bits != packet_size_bits) {
+                               BT_LOGW("Stream's packet context's `content_size` field is missing, "
+                                       "but current packet's content size is not equal to its packet size: "
+                                       "content-size=%" PRIu64 ", "
+                                       "packet-size=%" PRIu64,
+                                       bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser),
+                                       packet_size_bits);
+                               ret = -1;
+                               goto end;
+                       }
+               }
+
+               /*
+                * Overwrite the packet context now that the stream
+                * position's packet and content sizes have the correct
+                * values.
+                */
+               bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser,
+                       packet_context_offset_bits);
+               ret = auto_populate_packet_context(stream, false,
+                       packet_size_bits, content_size_bits);
+               if (ret) {
+                       BT_LOGW_STR("Cannot automatically populate the stream's packet context field.");
+                       ret = -1;
+                       goto end;
+               }
+
+               BT_LOGV("Rewriting (serializing) packet context field.");
+               ret = bt_ctf_field_serialize_recursive(stream->packet_context,
+                       &stream->ctfser, native_byte_order);
+               if (ret) {
+                       BT_LOGW("Cannot serialize stream's packet context field: "
+                               "field-addr=%p", stream->packet_context);
+                       goto end;
+               }
+       }
+
+       g_ptr_array_set_size(stream->events, 0);
+       stream->flushed_packet_count++;
+       bt_ctfser_close_current_packet(&stream->ctfser, packet_size_bits / 8);
+
+end:
+       /* Reset automatically-set fields. */
+       if (stream->packet_context) {
+               reset_structure_field(stream->packet_context, "timestamp_begin");
+               reset_structure_field(stream->packet_context, "timestamp_end");
+               reset_structure_field(stream->packet_context, "packet_size");
+               reset_structure_field(stream->packet_context, "content_size");
+               reset_structure_field(stream->packet_context, "events_discarded");
+       }
+
+       if (ret == 0) {
+               BT_LOGV("Flushed stream's current packet: "
+                       "content-size=%" PRIu64 ", packet-size=%" PRIu64,
+                       content_size_bits, packet_size_bits);
+       }
+
+end_no_stream:
+       return ret;
+}
+
+static
+void bt_ctf_stream_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_stream *stream = (void *) obj;
+
+       BT_LOGD("Destroying CTF writer stream object: addr=%p, name=\"%s\"",
+               stream, bt_ctf_stream_get_name(stream));
+
+       bt_ctf_stream_common_finalize(BT_CTF_TO_COMMON(stream));
+       bt_ctfser_fini(&stream->ctfser);
+
+       if (stream->events) {
+               BT_LOGD_STR("Putting events.");
+               g_ptr_array_free(stream->events, TRUE);
+       }
+
+       BT_LOGD_STR("Putting packet header field.");
+       bt_ctf_object_put_ref(stream->packet_header);
+       BT_LOGD_STR("Putting packet context field.");
+       bt_ctf_object_put_ref(stream->packet_context);
+       g_free(stream);
+}
+
+static
+int _set_structure_field_integer(struct bt_ctf_field *structure, char *name,
+               uint64_t value, bt_bool force)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *field_type = NULL;
+       struct bt_ctf_field *integer;
+
+       BT_ASSERT(structure);
+       BT_ASSERT(name);
+
+       integer = bt_ctf_field_structure_get_field_by_name(structure, name);
+       if (!integer) {
+               /* Field not found, not an error. */
+               BT_LOGV("Field not found: struct-field-addr=%p, "
+                       "name=\"%s\", force=%d", structure, name, force);
+               goto end;
+       }
+
+       /* Make sure the payload has not already been set. */
+       if (!force && bt_ctf_field_is_set_recursive(integer)) {
+               /* Payload already set, not an error */
+               BT_LOGV("Field's payload is already set: struct-field-addr=%p, "
+                       "name=\"%s\", force=%d", structure, name, force);
+               goto end;
+       }
+
+       field_type = bt_ctf_field_get_type(integer);
+       BT_ASSERT(field_type);
+       if (bt_ctf_field_type_get_type_id(field_type) != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+               /*
+                * The user most likely meant for us to populate this field
+                * automatically. However, we can only do this if the field
+                * is an integer. Return an error.
+                */
+               BT_LOGW("Invalid parameter: field's type is not an integer field type: "
+                       "field-addr=%p, ft-addr=%p, ft-id=%s",
+                       integer, field_type,
+                       bt_ctf_field_type_id_string((int)
+                               bt_ctf_field_type_get_type_id(field_type)));
+               ret = -1;
+               goto end;
+       }
+
+       if (bt_ctf_field_type_integer_is_signed(field_type)) {
+               ret = bt_ctf_field_integer_signed_set_value(integer,
+                       (int64_t) value);
+       } else {
+               ret = bt_ctf_field_integer_unsigned_set_value(integer, value);
+       }
+       ret = !ret ? 1 : ret;
+end:
+       bt_ctf_object_put_ref(integer);
+       bt_ctf_object_put_ref(field_type);
+       return ret;
+}
+
+/*
+ * Returns the following codes:
+ * 1 if the field was found and set,
+ * 0 if nothing was done (field not found, or was already set),
+ * <0 if an error was encoutered
+ */
+static
+int try_set_structure_field_integer(struct bt_ctf_field *structure, char *name,
+               uint64_t value)
+{
+       return _set_structure_field_integer(structure, name, value, BT_FALSE);
+}
+
+struct bt_ctf_stream_class *bt_ctf_stream_get_class(
+               struct bt_ctf_stream *stream)
+{
+       return bt_ctf_object_get_ref(bt_ctf_stream_common_borrow_class(BT_CTF_TO_COMMON(stream)));
+}
+
+const char *bt_ctf_stream_get_name(struct bt_ctf_stream *stream)
+{
+       return bt_ctf_stream_common_get_name(BT_CTF_TO_COMMON(stream));
+}
+
+int64_t bt_ctf_stream_get_id(struct bt_ctf_stream *stream)
+{
+       return bt_ctf_stream_common_get_id(BT_CTF_TO_COMMON(stream));
+}
diff --git a/src/ctf-writer/stream.h b/src/ctf-writer/stream.h
new file mode 100644 (file)
index 0000000..8c3d7d7
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H
+
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include "common/assert.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/ctf-writer/stream.h>
+#include "ctfser/ctfser.h"
+#include <stdint.h>
+
+#include "assert-pre.h"
+#include "object.h"
+#include "stream.h"
+#include "utils.h"
+
+struct bt_ctf_stream_common;
+
+struct bt_ctf_stream_common {
+       struct bt_ctf_object base;
+       int64_t id;
+       struct bt_ctf_stream_class_common *stream_class;
+       GString *name;
+};
+
+BT_HIDDEN
+int bt_ctf_stream_common_initialize(
+               struct bt_ctf_stream_common *stream,
+               struct bt_ctf_stream_class_common *stream_class, const char *name,
+               uint64_t id, bt_ctf_object_release_func release_func);
+
+BT_HIDDEN
+void bt_ctf_stream_common_finalize(struct bt_ctf_stream_common *stream);
+
+static inline
+struct bt_ctf_stream_class_common *bt_ctf_stream_common_borrow_class(
+               struct bt_ctf_stream_common *stream)
+{
+       BT_ASSERT(stream);
+       return stream->stream_class;
+}
+
+static inline
+const char *bt_ctf_stream_common_get_name(struct bt_ctf_stream_common *stream)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(stream, "Stream");
+       return stream->name ? stream->name->str : NULL;
+}
+
+static inline
+int64_t bt_ctf_stream_common_get_id(struct bt_ctf_stream_common *stream)
+{
+       int64_t ret;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(stream, "Stream");
+       ret = stream->id;
+       if (ret < 0) {
+               BT_LOGV("Stream's ID is not set: addr=%p, name=\"%s\"",
+                       stream, bt_ctf_stream_common_get_name(stream));
+       }
+
+       return ret;
+}
+
+struct bt_ctf_stream {
+       struct bt_ctf_stream_common common;
+       struct bt_ctf_field *packet_header;
+       struct bt_ctf_field *packet_context;
+
+       /* Array of pointers to bt_ctf_event for the current packet */
+       GPtrArray *events;
+       struct bt_ctfser ctfser;
+       unsigned int flushed_packet_count;
+       uint64_t discarded_events;
+       uint64_t last_ts_end;
+};
+
+BT_HIDDEN
+struct bt_ctf_stream *bt_ctf_stream_create_with_id(
+               struct bt_ctf_stream_class *stream_class,
+               const char *name, uint64_t id);
+
+#endif /* BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H */
diff --git a/src/ctf-writer/trace.c b/src/ctf-writer/trace.c
new file mode 100644 (file)
index 0000000..f2ce714
--- /dev/null
@@ -0,0 +1,1886 @@
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-TRACE"
+#include "logging.h"
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <babeltrace2/ctf-writer/event.h>
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/types.h>
+
+#include "common/assert.h"
+#include "compat/compiler.h"
+#include "compat/endian.h"
+
+#include "attributes.h"
+#include "clock-class.h"
+#include "clock.h"
+#include "event-class.h"
+#include "event.h"
+#include "field-types.h"
+#include "field-wrapper.h"
+#include "functor.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "trace.h"
+#include "utils.h"
+#include "validation.h"
+#include "values.h"
+#include "visitor.h"
+#include "writer.h"
+
+#define DEFAULT_IDENTIFIER_SIZE                128
+#define DEFAULT_METADATA_STRING_SIZE   4096
+
+BT_HIDDEN
+int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace,
+               bt_ctf_object_release_func release_func)
+{
+       int ret = 0;
+
+       BT_LOGD_STR("Initializing common trace object.");
+       trace->native_byte_order = BT_CTF_BYTE_ORDER_UNSPECIFIED;
+       bt_ctf_object_init_shared_with_parent(&trace->base, release_func);
+       trace->clock_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       if (!trace->clock_classes) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+
+       trace->streams = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_ctf_object_try_spec_release);
+       if (!trace->streams) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+
+       trace->stream_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_ctf_object_try_spec_release);
+       if (!trace->stream_classes) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+
+       /* Create the environment array object */
+       trace->environment = bt_ctf_attributes_create();
+       if (!trace->environment) {
+               BT_LOGE_STR("Cannot create empty attributes object.");
+               goto error;
+       }
+
+       BT_LOGD("Initialized common trace object: addr=%p", trace);
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace)
+{
+       BT_LOGD("Finalizing common trace object: addr=%p, name=\"%s\"",
+               trace, bt_ctf_trace_common_get_name(trace));
+
+       if (trace->environment) {
+               BT_LOGD_STR("Destroying environment attributes.");
+               bt_ctf_attributes_destroy(trace->environment);
+       }
+
+       if (trace->name) {
+               g_string_free(trace->name, TRUE);
+       }
+
+       if (trace->clock_classes) {
+               BT_LOGD_STR("Putting clock classes.");
+               g_ptr_array_free(trace->clock_classes, TRUE);
+       }
+
+       if (trace->streams) {
+               BT_LOGD_STR("Destroying streams.");
+               g_ptr_array_free(trace->streams, TRUE);
+       }
+
+       if (trace->stream_classes) {
+               BT_LOGD_STR("Destroying stream classes.");
+               g_ptr_array_free(trace->stream_classes, TRUE);
+       }
+
+       BT_LOGD_STR("Putting packet header field type.");
+       bt_ctf_object_put_ref(trace->packet_header_field_type);
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char *name)
+{
+       int ret = 0;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!name) {
+               BT_LOGW_STR("Invalid parameter: name is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (trace->frozen) {
+               BT_LOGW("Invalid parameter: trace is frozen: "
+                       "addr=%p, name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       trace->name = trace->name ? g_string_assign(trace->name, name) :
+                       g_string_new(name);
+       if (!trace->name) {
+               BT_LOGE_STR("Failed to allocate one GString.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace,
+               const unsigned char *uuid)
+{
+       int ret = 0;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!uuid) {
+               BT_LOGW_STR("Invalid parameter: UUID is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (trace->frozen) {
+               BT_LOGW("Invalid parameter: trace is frozen: "
+                       "addr=%p, name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       memcpy(trace->uuid, uuid, BABELTRACE_UUID_LEN);
+       trace->uuid_set = BT_TRUE;
+       BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
+               "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+               trace, bt_ctf_trace_common_get_name(trace),
+               (unsigned int) uuid[0],
+               (unsigned int) uuid[1],
+               (unsigned int) uuid[2],
+               (unsigned int) uuid[3],
+               (unsigned int) uuid[4],
+               (unsigned int) uuid[5],
+               (unsigned int) uuid[6],
+               (unsigned int) uuid[7],
+               (unsigned int) uuid[8],
+               (unsigned int) uuid[9],
+               (unsigned int) uuid[10],
+               (unsigned int) uuid[11],
+               (unsigned int) uuid[12],
+               (unsigned int) uuid[13],
+               (unsigned int) uuid[14],
+               (unsigned int) uuid[15]);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace,
+               const char *name, struct bt_ctf_private_value *value)
+{
+       int ret = 0;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!name) {
+               BT_LOGW_STR("Invalid parameter: name is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!value) {
+               BT_LOGW_STR("Invalid parameter: value is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_identifier_is_valid(name)) {
+               BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
+                       "trace-addr=%p, trace-name=\"%s\", "
+                       "env-name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace), name);
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_value_is_integer(bt_ctf_private_value_as_value(value)) &&
+                       !bt_ctf_value_is_string(bt_ctf_private_value_as_value(value))) {
+               BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
+                       "trace-addr=%p, trace-name=\"%s\", "
+                       "env-name=\"%s\", env-value-type=%s",
+                       trace, bt_ctf_trace_common_get_name(trace), name,
+                       bt_ctf_value_type_string(
+                               bt_ctf_value_get_type(
+                                       bt_ctf_private_value_as_value(value))));
+               ret = -1;
+               goto end;
+       }
+
+       if (trace->frozen) {
+               /*
+                * New environment fields may be added to a frozen trace,
+                * but existing fields may not be changed.
+                *
+                * The object passed is frozen like all other attributes.
+                */
+               struct bt_ctf_private_value *attribute =
+                       bt_ctf_attributes_borrow_field_value_by_name(
+                               trace->environment, name);
+
+               if (attribute) {
+                       BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
+                               "trace-addr=%p, trace-name=\"%s\", "
+                               "env-name=\"%s\"",
+                               trace, bt_ctf_trace_common_get_name(trace), name);
+                       ret = -1;
+                       goto end;
+               }
+
+               bt_ctf_value_freeze(bt_ctf_private_value_as_value(value));
+       }
+
+       ret = bt_ctf_attributes_set_field_value(trace->environment, name,
+               value);
+       if (ret) {
+               BT_LOGE("Cannot set environment field's value: "
+                       "trace-addr=%p, trace-name=\"%s\", "
+                       "env-name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace), name);
+       } else {
+               BT_LOGV("Set environment field's value: "
+                       "trace-addr=%p, trace-name=\"%s\", "
+                       "env-name=\"%s\", value-addr=%p",
+                       trace, bt_ctf_trace_common_get_name(trace), name, value);
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace,
+               const char *name, const char *value)
+{
+       int ret = 0;
+       struct bt_ctf_private_value *env_value_string_obj = NULL;
+
+       if (!value) {
+               BT_LOGW_STR("Invalid parameter: value is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       env_value_string_obj = bt_ctf_private_value_string_create_init(value);
+       if (!env_value_string_obj) {
+               BT_LOGE_STR("Cannot create string value object.");
+               ret = -1;
+               goto end;
+       }
+
+       /* bt_ctf_trace_common_set_environment_field() logs errors */
+       ret = bt_ctf_trace_common_set_environment_field(trace, name,
+               env_value_string_obj);
+
+end:
+       bt_ctf_object_put_ref(env_value_string_obj);
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_environment_field_integer(
+               struct bt_ctf_trace_common *trace, const char *name, int64_t value)
+{
+       int ret = 0;
+       struct bt_ctf_private_value *env_value_integer_obj = NULL;
+
+       env_value_integer_obj = bt_ctf_private_value_integer_create_init(value);
+       if (!env_value_integer_obj) {
+               BT_LOGE_STR("Cannot create integer value object.");
+               ret = -1;
+               goto end;
+       }
+
+       /* bt_ctf_trace_common_set_environment_field() logs errors */
+       ret = bt_ctf_trace_common_set_environment_field(trace, name,
+               env_value_integer_obj);
+
+end:
+       bt_ctf_object_put_ref(env_value_integer_obj);
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_clock_class *clock_class)
+{
+       int ret = 0;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!bt_ctf_clock_class_is_valid(clock_class)) {
+               BT_LOGW("Invalid parameter: clock class is invalid: "
+                       "trace-addr=%p, trace-name=\"%s\", "
+                       "clock-class-addr=%p, clock-class-name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace),
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       /* Check for duplicate clock classes */
+       if (bt_ctf_trace_common_has_clock_class(trace, clock_class)) {
+               BT_LOGW("Invalid parameter: clock class already exists in trace: "
+                       "trace-addr=%p, trace-name=\"%s\", "
+                       "clock-class-addr=%p, clock-class-name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace),
+                       clock_class, bt_ctf_clock_class_get_name(clock_class));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_get_ref(clock_class);
+       g_ptr_array_add(trace->clock_classes, clock_class);
+
+       if (trace->frozen) {
+               BT_LOGV_STR("Freezing added clock class because trace is frozen.");
+               bt_ctf_clock_class_freeze(clock_class);
+       }
+
+       BT_LOGV("Added clock class to trace: "
+               "trace-addr=%p, trace-name=\"%s\", "
+               "clock-class-addr=%p, clock-class-name=\"%s\"",
+               trace, bt_ctf_trace_common_get_name(trace),
+               clock_class, bt_ctf_clock_class_get_name(clock_class));
+
+end:
+       return ret;
+}
+
+static
+bool packet_header_field_type_is_valid(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_field_type_common *packet_header_type)
+{
+       int ret;
+       bool is_valid = true;
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       if (!packet_header_type) {
+               /*
+                * No packet header field type: trace must have only
+                * one stream. At this point the stream class being
+                * added is not part of the trace yet, so we validate
+                * that the trace contains no stream classes yet.
+                */
+               if (trace->stream_classes->len >= 1) {
+                       BT_LOGW_STR("Invalid packet header field type: "
+                               "packet header field type does not exist but there's more than one stream class in the trace.");
+                       goto invalid;
+               }
+
+               /* No packet header field type: valid at this point */
+               goto end;
+       }
+
+       /* Packet header field type, if it exists, must be a structure */
+       if (packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
+                       "ft-addr=%p, ft-id=%s",
+                       packet_header_type,
+                       bt_ctf_field_type_id_string(packet_header_type->id));
+               goto invalid;
+       }
+
+       /*
+        * If there's a `magic` field, it must be a 32-bit unsigned
+        * integer field type. Also it must be the first field of the
+        * packet header field type.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_header_type, "magic");
+       if (field_type) {
+               const char *field_name;
+
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
+                               "magic-ft-addr=%p, magic-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
+                       BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
+                               "magic-ft-addr=%p", field_type);
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_get_size(field_type) != 32) {
+                       BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
+                               "magic-ft-addr=%p, magic-ft-size=%u",
+                               field_type,
+                               bt_ctf_field_type_common_integer_get_size(field_type));
+                       goto invalid;
+               }
+
+               ret = bt_ctf_field_type_common_structure_borrow_field_by_index(
+                       packet_header_type, &field_name, NULL, 0);
+               BT_ASSERT(ret == 0);
+
+               if (strcmp(field_name, "magic") != 0) {
+                       BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
+                               "magic-ft-addr=%p, first-field-name=\"%s\"",
+                               field_type, field_name);
+                       goto invalid;
+               }
+       }
+
+       /*
+        * If there's a `uuid` field, it must be an array field type of
+        * length 16 with an 8-bit unsigned integer element field type.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_header_type, "uuid");
+       if (field_type) {
+               struct bt_ctf_field_type_common *elem_ft;
+
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_ARRAY) {
+                       BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
+                               "uuid-ft-addr=%p, uuid-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_array_get_length(field_type) != 16) {
+                       BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
+                               "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
+                               field_type,
+                               bt_ctf_field_type_common_array_get_length(field_type));
+                       goto invalid;
+               }
+
+               elem_ft = bt_ctf_field_type_common_array_borrow_element_field_type(field_type);
+               BT_ASSERT(elem_ft);
+
+               if (elem_ft->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
+                               "elem-ft-addr=%p, elem-ft-id=%s",
+                               elem_ft,
+                               bt_ctf_field_type_id_string(elem_ft->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(elem_ft)) {
+                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
+                               "elem-ft-addr=%p", elem_ft);
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_get_size(elem_ft) != 8) {
+                       BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
+                               "elem-ft-addr=%p, elem-ft-size=%u",
+                               elem_ft,
+                               bt_ctf_field_type_common_integer_get_size(elem_ft));
+                       goto invalid;
+               }
+       }
+
+       /*
+        * The `stream_id` field must exist if there's more than one
+        * stream classes in the trace.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_header_type, "stream_id");
+
+       if (!field_type && trace->stream_classes->len >= 1) {
+               BT_LOGW_STR("Invalid packet header field type: "
+                       "`stream_id` field does not exist but there's more than one stream class in the trace.");
+               goto invalid;
+       }
+
+       /*
+        * If there's a `stream_id` field, it must be an unsigned
+        * integer field type.
+        */
+       if (field_type) {
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
+                               "stream-id-ft-addr=%p, stream-id-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
+                       BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
+                               "stream-id-ft-addr=%p", field_type);
+                       goto invalid;
+               }
+       }
+
+       /*
+        * If there's a `packet_seq_num` field, it must be an unsigned
+        * integer field type.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_header_type, "packet_seq_num");
+       if (field_type) {
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: "
+                               "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
+                       BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: "
+                               "packet-seq-num-ft-addr=%p", field_type);
+                       goto invalid;
+               }
+       }
+
+       goto end;
+
+invalid:
+       is_valid = false;
+
+end:
+       return is_valid;
+}
+
+static
+bool packet_context_field_type_is_valid(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *packet_context_type,
+               bool check_ts_begin_end_mapped)
+{
+       bool is_valid = true;
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       if (!packet_context_type) {
+               /* No packet context field type: valid at this point */
+               goto end;
+       }
+
+       /* Packet context field type, if it exists, must be a structure */
+       if (packet_context_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
+                       "ft-addr=%p, ft-id=%s",
+                       packet_context_type,
+                       bt_ctf_field_type_id_string(packet_context_type->id));
+               goto invalid;
+       }
+
+       /*
+        * If there's a `packet_size` field, it must be an unsigned
+        * integer field type.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "packet_size");
+       if (field_type) {
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
+                               "packet-size-ft-addr=%p, packet-size-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
+                       BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
+                               "packet-size-ft-addr=%p", field_type);
+                       goto invalid;
+               }
+       }
+
+       /*
+        * If there's a `content_size` field, it must be an unsigned
+        * integer field type.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "content_size");
+       if (field_type) {
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
+                               "content-size-ft-addr=%p, content-size-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
+                       BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
+                               "content-size-ft-addr=%p", field_type);
+                       goto invalid;
+               }
+       }
+
+       /*
+        * If there's a `events_discarded` field, it must be an unsigned
+        * integer field type.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "events_discarded");
+       if (field_type) {
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
+                               "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
+                       BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
+                               "events-discarded-ft-addr=%p", field_type);
+                       goto invalid;
+               }
+       }
+
+       /*
+        * If there's a `timestamp_begin` field, it must be an unsigned
+        * integer field type. Also, if the trace is not a CTF writer's
+        * trace, then we cannot automatically set the mapped clock
+        * class of this field, so it must have a mapped clock class.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "timestamp_begin");
+       if (field_type) {
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
+                               "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
+                       BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
+                               "timestamp-begin-ft-addr=%p", field_type);
+                       goto invalid;
+               }
+
+               if (check_ts_begin_end_mapped) {
+                       struct bt_ctf_clock_class *clock_class =
+                               bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
+                                       field_type);
+
+                       if (!clock_class) {
+                               BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
+                                       "timestamp-begin-ft-addr=%p", field_type);
+                               goto invalid;
+                       }
+               }
+       }
+
+       /*
+        * If there's a `timestamp_end` field, it must be an unsigned
+        * integer field type. Also, if the trace is not a CTF writer's
+        * trace, then we cannot automatically set the mapped clock
+        * class of this field, so it must have a mapped clock class.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               packet_context_type, "timestamp_end");
+       if (field_type) {
+               if (field_type->id != BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
+                               "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               if (bt_ctf_field_type_common_integer_is_signed(field_type)) {
+                       BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
+                               "timestamp-end-ft-addr=%p", field_type);
+                       goto invalid;
+               }
+
+               if (check_ts_begin_end_mapped) {
+                       struct bt_ctf_clock_class *clock_class =
+                               bt_ctf_field_type_common_integer_borrow_mapped_clock_class(
+                                       field_type);
+
+                       if (!clock_class) {
+                               BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
+                                       "timestamp-end-ft-addr=%p", field_type);
+                               goto invalid;
+                       }
+               }
+       }
+
+       goto end;
+
+invalid:
+       is_valid = false;
+
+end:
+       return is_valid;
+}
+
+static
+bool event_header_field_type_is_valid(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *event_header_type)
+{
+       bool is_valid = true;
+       struct bt_ctf_field_type_common *field_type = NULL;
+
+       /*
+        * We do not validate that the `timestamp` field exists here
+        * because CTF does not require this exact name to be mapped to
+        * a clock class.
+        */
+
+       if (!event_header_type) {
+               /*
+                * No event header field type: stream class must have
+                * only one event class.
+                */
+               if (bt_ctf_stream_class_common_get_event_class_count(stream_class) > 1) {
+                       BT_LOGW_STR("Invalid event header field type: "
+                               "event header field type does not exist but there's more than one event class in the stream class.");
+                       goto invalid;
+               }
+
+               /* No event header field type: valid at this point */
+               goto end;
+       }
+
+       /* Event header field type, if it exists, must be a structure */
+       if (event_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
+                       "ft-addr=%p, ft-id=%s",
+                       event_header_type,
+                       bt_ctf_field_type_id_string(event_header_type->id));
+               goto invalid;
+       }
+
+       /*
+        * If there's an `id` field, it must be an unsigned integer
+        * field type or an enumeration field type with an unsigned
+        * integer container field type.
+        */
+       field_type = bt_ctf_field_type_common_structure_borrow_field_type_by_name(
+               event_header_type, "id");
+       if (field_type) {
+               struct bt_ctf_field_type_common *int_ft;
+
+               if (field_type->id == BT_CTF_FIELD_TYPE_ID_INTEGER) {
+                       int_ft = field_type;
+               } else if (field_type->id == BT_CTF_FIELD_TYPE_ID_ENUM) {
+                       int_ft = bt_ctf_field_type_common_enumeration_borrow_container_field_type(
+                               field_type);
+               } else {
+                       BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
+                               "id-ft-addr=%p, id-ft-id=%s",
+                               field_type,
+                               bt_ctf_field_type_id_string(field_type->id));
+                       goto invalid;
+               }
+
+               BT_ASSERT(int_ft);
+               if (bt_ctf_field_type_common_integer_is_signed(int_ft)) {
+                       BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
+                               "id-ft-addr=%p", int_ft);
+                       goto invalid;
+               }
+       }
+
+       goto end;
+
+invalid:
+       is_valid = false;
+
+end:
+       return is_valid;
+}
+
+static
+int check_packet_header_type_has_no_clock_class(struct bt_ctf_trace_common *trace)
+{
+       int ret = 0;
+
+       if (trace->packet_header_field_type) {
+               struct bt_ctf_clock_class *clock_class = NULL;
+
+               ret = bt_ctf_field_type_common_validate_single_clock_class(
+                       trace->packet_header_field_type,
+                       &clock_class);
+               bt_ctf_object_put_ref(clock_class);
+               if (ret || clock_class) {
+                       BT_LOGW("Trace's packet header field type cannot "
+                               "contain a field type which is mapped to "
+                               "a clock class: "
+                               "trace-addr=%p, trace-name=\"%s\", "
+                               "clock-class-name=\"%s\"",
+                               trace, bt_ctf_trace_common_get_name(trace),
+                               clock_class ?
+                                       bt_ctf_clock_class_get_name(clock_class) :
+                                       NULL);
+                       ret = -1;
+               }
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func,
+               struct bt_ctf_clock_class *init_expected_clock_class,
+               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
+                       struct bt_ctf_field_type_common *packet_context_field_type,
+                       struct bt_ctf_field_type_common *event_header_field_type),
+               bool check_ts_begin_end_mapped)
+{
+       int ret;
+       int64_t i;
+       int64_t stream_id;
+       struct bt_ctf_validation_output trace_sc_validation_output = { 0 };
+       struct bt_ctf_validation_output *ec_validation_outputs = NULL;
+       const enum bt_ctf_validation_flag trace_sc_validation_flags =
+               BT_CTF_VALIDATION_FLAG_TRACE |
+               BT_CTF_VALIDATION_FLAG_STREAM;
+       const enum bt_ctf_validation_flag ec_validation_flags =
+               BT_CTF_VALIDATION_FLAG_EVENT;
+       struct bt_ctf_field_type_common *packet_header_type = NULL;
+       struct bt_ctf_field_type_common *packet_context_type = NULL;
+       struct bt_ctf_field_type_common *event_header_type = NULL;
+       struct bt_ctf_field_type_common *stream_event_ctx_type = NULL;
+       int64_t event_class_count;
+       struct bt_ctf_trace_common *current_parent_trace = NULL;
+       struct bt_ctf_clock_class *expected_clock_class =
+               bt_ctf_object_get_ref(init_expected_clock_class);
+
+       BT_ASSERT(copy_field_type_func);
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGD("Adding stream class to trace: "
+               "trace-addr=%p, trace-name=\"%s\", "
+               "stream-class-addr=%p, stream-class-name=\"%s\", "
+               "stream-class-id=%" PRId64,
+               trace, bt_ctf_trace_common_get_name(trace),
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+
+       current_parent_trace = bt_ctf_stream_class_common_borrow_trace(stream_class);
+       if (current_parent_trace) {
+               /* Stream class is already associated to a trace, abort. */
+               BT_LOGW("Invalid parameter: stream class is already part of a trace: "
+                       "stream-class-trace-addr=%p, "
+                       "stream-class-trace-name=\"%s\"",
+                       current_parent_trace,
+                       bt_ctf_trace_common_get_name(current_parent_trace));
+               ret = -1;
+               goto end;
+       }
+
+       event_class_count =
+               bt_ctf_stream_class_common_get_event_class_count(stream_class);
+       BT_ASSERT(event_class_count >= 0);
+
+       if (!stream_class->frozen) {
+               /*
+                * Stream class is not frozen yet. Validate that the
+                * stream class contains at most a single clock class
+                * because the previous
+                * bt_ctf_stream_class_common_add_event_class() calls did
+                * not make this validation since the stream class's
+                * direct field types (packet context, event header,
+                * event context) could change afterwards. This stream
+                * class is about to be frozen and those field types
+                * won't be changed if this function succeeds.
+                *
+                * At this point we're also sure that the stream class's
+                * clock, if any, has the same class as the stream
+                * class's expected clock class, if any. This is why, if
+                * bt_ctf_stream_class_common_validate_single_clock_class()
+                * succeeds below, the call to
+                * bt_ctf_stream_class_map_clock_class() at the end of this
+                * function is safe because it maps to the same, single
+                * clock class.
+                */
+               ret = bt_ctf_stream_class_common_validate_single_clock_class(
+                       stream_class, &expected_clock_class);
+               if (ret) {
+                       BT_LOGW("Invalid parameter: stream class or one of its "
+                               "event classes contains a field type which is "
+                               "not recursively mapped to the expected "
+                               "clock class: "
+                               "stream-class-addr=%p, "
+                               "stream-class-id=%" PRId64 ", "
+                               "stream-class-name=\"%s\", "
+                               "expected-clock-class-addr=%p, "
+                               "expected-clock-class-name=\"%s\"",
+                               stream_class, bt_ctf_stream_class_common_get_id(stream_class),
+                               bt_ctf_stream_class_common_get_name(stream_class),
+                               expected_clock_class,
+                               expected_clock_class ?
+                                       bt_ctf_clock_class_get_name(expected_clock_class) :
+                                       NULL);
+                       goto end;
+               }
+       }
+
+       ret = check_packet_header_type_has_no_clock_class(trace);
+       if (ret) {
+               /* check_packet_header_type_has_no_clock_class() logs errors */
+               goto end;
+       }
+
+       /*
+        * We're about to freeze both the trace and the stream class.
+        * Also, each event class contained in this stream class are
+        * already frozen.
+        *
+        * This trace, this stream class, and all its event classes
+        * should be valid at this point.
+        *
+        * Validate trace and stream class first, then each event
+        * class of this stream class can be validated individually.
+        */
+       packet_header_type =
+               bt_ctf_trace_common_borrow_packet_header_field_type(trace);
+       packet_context_type =
+               bt_ctf_stream_class_common_borrow_packet_context_field_type(stream_class);
+       event_header_type =
+               bt_ctf_stream_class_common_borrow_event_header_field_type(stream_class);
+       stream_event_ctx_type =
+               bt_ctf_stream_class_common_borrow_event_context_field_type(stream_class);
+
+       BT_LOGD("Validating trace and stream class field types.");
+       ret = bt_ctf_validate_class_types(trace->environment,
+               packet_header_type, packet_context_type, event_header_type,
+               stream_event_ctx_type, NULL, NULL, trace->valid,
+               stream_class->valid, 1, &trace_sc_validation_output,
+               trace_sc_validation_flags, copy_field_type_func);
+
+       if (ret) {
+               /*
+                * This means something went wrong during the validation
+                * process, not that the objects are invalid.
+                */
+               BT_LOGE("Failed to validate trace and stream class field types: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       if ((trace_sc_validation_output.valid_flags &
+                       trace_sc_validation_flags) !=
+                       trace_sc_validation_flags) {
+               /* Invalid trace/stream class */
+               BT_LOGW("Invalid trace or stream class field types: "
+                       "valid-flags=0x%x",
+                       trace_sc_validation_output.valid_flags);
+               ret = -1;
+               goto end;
+       }
+
+       if (event_class_count > 0) {
+               ec_validation_outputs = g_new0(struct bt_ctf_validation_output,
+                       event_class_count);
+               if (!ec_validation_outputs) {
+                       BT_LOGE_STR("Failed to allocate one validation output structure.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /* Validate each event class individually */
+       for (i = 0; i < event_class_count; i++) {
+               struct bt_ctf_event_class_common *event_class =
+                       bt_ctf_stream_class_common_borrow_event_class_by_index(
+                               stream_class, i);
+               struct bt_ctf_field_type_common *event_context_type = NULL;
+               struct bt_ctf_field_type_common *event_payload_type = NULL;
+
+               event_context_type =
+                       bt_ctf_event_class_common_borrow_context_field_type(
+                               event_class);
+               event_payload_type =
+                       bt_ctf_event_class_common_borrow_payload_field_type(
+                               event_class);
+
+               /*
+                * It is important to use the field types returned by
+                * the previous trace and stream class validation here
+                * because copies could have been made.
+                */
+               BT_LOGD("Validating event class's field types: "
+                       "addr=%p, name=\"%s\", id=%" PRId64,
+                       event_class, bt_ctf_event_class_common_get_name(event_class),
+                       bt_ctf_event_class_common_get_id(event_class));
+               ret = bt_ctf_validate_class_types(trace->environment,
+                       trace_sc_validation_output.packet_header_type,
+                       trace_sc_validation_output.packet_context_type,
+                       trace_sc_validation_output.event_header_type,
+                       trace_sc_validation_output.stream_event_ctx_type,
+                       event_context_type, event_payload_type,
+                       1, 1, event_class->valid, &ec_validation_outputs[i],
+                       ec_validation_flags, copy_field_type_func);
+
+               if (ret) {
+                       BT_LOGE("Failed to validate event class field types: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+
+               if ((ec_validation_outputs[i].valid_flags &
+                               ec_validation_flags) != ec_validation_flags) {
+                       /* Invalid event class */
+                       BT_LOGW("Invalid event class field types: "
+                               "valid-flags=0x%x",
+                               ec_validation_outputs[i].valid_flags);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       stream_id = bt_ctf_stream_class_common_get_id(stream_class);
+       if (stream_id < 0) {
+               stream_id = trace->next_stream_id++;
+               if (stream_id < 0) {
+                       BT_LOGE_STR("No more stream class IDs available.");
+                       ret = -1;
+                       goto end;
+               }
+
+               /* Try to assign a new stream id */
+               for (i = 0; i < trace->stream_classes->len; i++) {
+                       if (stream_id == bt_ctf_stream_class_common_get_id(
+                               trace->stream_classes->pdata[i])) {
+                               /* Duplicate stream id found */
+                               BT_LOGW("Duplicate stream class ID: "
+                                       "id=%" PRId64, (int64_t) stream_id);
+                               ret = -1;
+                               goto end;
+                       }
+               }
+
+               if (bt_ctf_stream_class_common_set_id_no_check(stream_class,
+                               stream_id)) {
+                       /* TODO Should retry with a different stream id */
+                       BT_LOGE("Cannot set stream class's ID: "
+                               "id=%" PRId64, (int64_t) stream_id);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /*
+        * At this point all the field types in the validation output
+        * are valid. Validate the semantics of some scopes according to
+        * the CTF specification.
+        */
+       if (!packet_header_field_type_is_valid(trace,
+                       trace_sc_validation_output.packet_header_type)) {
+               BT_LOGW_STR("Invalid trace's packet header field type.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!packet_context_field_type_is_valid(trace,
+                       stream_class,
+                       trace_sc_validation_output.packet_context_type,
+                       check_ts_begin_end_mapped)) {
+               BT_LOGW_STR("Invalid stream class's packet context field type.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!event_header_field_type_is_valid(trace,
+                       stream_class,
+                       trace_sc_validation_output.event_header_type)) {
+               BT_LOGW_STR("Invalid steam class's event header field type.");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Now is the time to automatically map specific field types of
+        * the stream class's packet context and event header field
+        * types to the stream class's clock's class if they are not
+        * mapped to a clock class yet. We do it here because we know
+        * that after this point, everything is frozen so it won't be
+        * possible for the user to modify the stream class's clock, or
+        * to map those field types to other clock classes.
+        */
+       if (map_clock_classes_func) {
+               if (map_clock_classes_func(stream_class,
+                               trace_sc_validation_output.packet_context_type,
+                               trace_sc_validation_output.event_header_type)) {
+                       /* map_clock_classes_func() logs errors */
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       bt_ctf_object_set_parent(&stream_class->base, &trace->base);
+       g_ptr_array_add(trace->stream_classes, stream_class);
+
+       /*
+        * At this point we know that the function will be successful.
+        * Therefore we can replace the trace and stream class field
+        * types with what's in their validation output structure and
+        * mark them as valid. We can also replace the field types of
+        * all the event classes of the stream class and mark them as
+        * valid.
+        */
+       bt_ctf_validation_replace_types(trace, stream_class, NULL,
+               &trace_sc_validation_output, trace_sc_validation_flags);
+       trace->valid = 1;
+       stream_class->valid = 1;
+
+       /*
+        * Put what was not moved in bt_ctf_validation_replace_types().
+        */
+       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
+
+       for (i = 0; i < event_class_count; i++) {
+               struct bt_ctf_event_class_common *event_class =
+                       bt_ctf_stream_class_common_borrow_event_class_by_index(
+                               stream_class, i);
+
+               bt_ctf_validation_replace_types(NULL, NULL, event_class,
+                       &ec_validation_outputs[i], ec_validation_flags);
+               event_class->valid = 1;
+
+               /*
+                * Put what was not moved in
+                * bt_ctf_validation_replace_types().
+                */
+               bt_ctf_validation_output_put_types(&ec_validation_outputs[i]);
+       }
+
+       /*
+        * Freeze the trace and the stream class.
+        */
+       bt_ctf_stream_class_common_freeze(stream_class);
+       bt_ctf_trace_common_freeze(trace);
+
+       /*
+        * It is safe to set the stream class's unique clock class
+        * now because the stream class is frozen.
+        */
+       if (expected_clock_class) {
+               BT_CTF_OBJECT_MOVE_REF(stream_class->clock_class, expected_clock_class);
+       }
+
+       BT_LOGD("Added stream class to trace: "
+               "trace-addr=%p, trace-name=\"%s\", "
+               "stream-class-addr=%p, stream-class-name=\"%s\", "
+               "stream-class-id=%" PRId64,
+               trace, bt_ctf_trace_common_get_name(trace),
+               stream_class, bt_ctf_stream_class_common_get_name(stream_class),
+               bt_ctf_stream_class_common_get_id(stream_class));
+
+end:
+       if (ret) {
+               bt_ctf_object_set_parent(&stream_class->base, NULL);
+
+               if (ec_validation_outputs) {
+                       for (i = 0; i < event_class_count; i++) {
+                               bt_ctf_validation_output_put_types(
+                                       &ec_validation_outputs[i]);
+                       }
+               }
+       }
+
+       g_free(ec_validation_outputs);
+       bt_ctf_validation_output_put_types(&trace_sc_validation_output);
+       bt_ctf_object_put_ref(expected_clock_class);
+       return ret;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_clock_class *clock_class)
+{
+       struct bt_ctf_search_query query = { .value = clock_class, .found = 0 };
+
+       BT_ASSERT(trace);
+       BT_ASSERT(clock_class);
+
+       g_ptr_array_foreach(trace->clock_classes, value_exists, &query);
+       return query.found;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace,
+               enum bt_ctf_byte_order byte_order, bool allow_unspecified)
+{
+       int ret = 0;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (trace->frozen) {
+               BT_LOGW("Invalid parameter: trace is frozen: "
+                       "addr=%p, name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       if (byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED && !allow_unspecified) {
+               BT_LOGW("Invalid parameter: BT_CTF_BYTE_ORDER_UNSPECIFIED byte order is not allowed: "
+                       "addr=%p, name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       if (byte_order != BT_CTF_BYTE_ORDER_LITTLE_ENDIAN &&
+                       byte_order != BT_CTF_BYTE_ORDER_BIG_ENDIAN &&
+                       byte_order != BT_CTF_BYTE_ORDER_NETWORK) {
+               BT_LOGW("Invalid parameter: invalid byte order: "
+                       "addr=%p, name=\"%s\", bo=%s",
+                       trace, bt_ctf_trace_common_get_name(trace),
+                       bt_ctf_byte_order_string(byte_order));
+               ret = -1;
+               goto end;
+       }
+
+       trace->native_byte_order = byte_order;
+       BT_LOGV("Set trace's native byte order: "
+               "addr=%p, name=\"%s\", bo=%s",
+               trace, bt_ctf_trace_common_get_name(trace),
+               bt_ctf_byte_order_string(byte_order));
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_field_type_common *packet_header_type)
+{
+       int ret = 0;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (trace->frozen) {
+               BT_LOGW("Invalid parameter: trace is frozen: "
+                       "addr=%p, name=\"%s\"",
+                       trace, bt_ctf_trace_common_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       /* packet_header_type must be a structure. */
+       if (packet_header_type &&
+                       packet_header_type->id != BT_CTF_FIELD_TYPE_ID_STRUCT) {
+               BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
+                       "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
+                       trace, bt_ctf_trace_common_get_name(trace),
+                       packet_header_type,
+                       bt_ctf_field_type_id_string(packet_header_type->id));
+               ret = -1;
+               goto end;
+       }
+
+       bt_ctf_object_put_ref(trace->packet_header_field_type);
+       trace->packet_header_field_type = bt_ctf_object_get_ref(packet_header_type);
+       BT_LOGV("Set trace's packet header field type: "
+               "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
+               trace, bt_ctf_trace_common_get_name(trace), packet_header_type);
+end:
+       return ret;
+}
+
+static
+int64_t get_stream_class_count(void *element)
+{
+       return bt_ctf_trace_get_stream_class_count(
+                       (struct bt_ctf_trace *) element);
+}
+
+static
+void *get_stream_class(void *element, int i)
+{
+       return bt_ctf_trace_get_stream_class_by_index(
+                       (struct bt_ctf_trace *) element, i);
+}
+
+static
+int visit_stream_class(void *object, bt_ctf_visitor visitor,void *data)
+{
+       return bt_ctf_stream_class_visit(object, visitor, data);
+}
+
+int bt_ctf_trace_visit(struct bt_ctf_trace *trace,
+               bt_ctf_visitor visitor, void *data)
+{
+       int ret;
+       struct bt_ctf_visitor_object obj = {
+               .object = trace,
+               .type = BT_CTF_VISITOR_OBJECT_TYPE_TRACE
+       };
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!visitor) {
+               BT_LOGW_STR("Invalid parameter: visitor is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
+               trace, bt_ctf_trace_get_name(trace));
+       ret = bt_ctf_visitor_helper(&obj, get_stream_class_count,
+                       get_stream_class, visit_stream_class, visitor, data);
+end:
+       return ret;
+}
+
+static
+void bt_ctf_trace_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_trace *trace = (void *) obj;
+
+       BT_LOGD("Destroying CTF writer trace object: addr=%p, name=\"%s\"",
+               trace, bt_ctf_trace_get_name(trace));
+       bt_ctf_trace_common_finalize(BT_CTF_TO_COMMON(trace));
+       g_free(trace);
+}
+
+BT_HIDDEN
+struct bt_ctf_trace *bt_ctf_trace_create(void)
+{
+       struct bt_ctf_trace *trace = NULL;
+       int ret;
+
+       BT_LOGD_STR("Creating CTF writer trace object.");
+       trace = g_new0(struct bt_ctf_trace, 1);
+       if (!trace) {
+               BT_LOGE_STR("Failed to allocate one CTF writer trace.");
+               goto error;
+       }
+
+       ret = bt_ctf_trace_common_initialize(BT_CTF_TO_COMMON(trace),
+               bt_ctf_trace_destroy);
+       if (ret) {
+               /* bt_ctf_trace_common_initialize() logs errors */
+               goto error;
+       }
+
+       BT_LOGD("Created CTF writer trace object: addr=%p", trace);
+       return trace;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(trace);
+       return trace;
+}
+
+const unsigned char *bt_ctf_trace_get_uuid(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_uuid(BT_CTF_TO_COMMON(trace));
+}
+
+int bt_ctf_trace_set_uuid(struct bt_ctf_trace *trace,
+               const unsigned char *uuid)
+{
+       return bt_ctf_trace_common_set_uuid(BT_CTF_TO_COMMON(trace), uuid);
+}
+
+int bt_ctf_trace_set_environment_field_string(struct bt_ctf_trace *trace,
+               const char *name, const char *value)
+{
+       return bt_ctf_trace_common_set_environment_field_string(BT_CTF_TO_COMMON(trace),
+               name, value);
+}
+
+int bt_ctf_trace_set_environment_field_integer(
+               struct bt_ctf_trace *trace, const char *name, int64_t value)
+{
+       return bt_ctf_trace_common_set_environment_field_integer(
+               BT_CTF_TO_COMMON(trace), name, value);
+}
+
+int64_t bt_ctf_trace_get_environment_field_count(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_environment_field_count(BT_CTF_TO_COMMON(trace));
+}
+
+const char *
+bt_ctf_trace_get_environment_field_name_by_index(struct bt_ctf_trace *trace,
+               uint64_t index)
+{
+       return bt_ctf_trace_common_get_environment_field_name_by_index(
+               BT_CTF_TO_COMMON(trace), index);
+}
+
+struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_index(
+               struct bt_ctf_trace *trace, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_index(
+               BT_CTF_TO_COMMON(trace), index));
+}
+
+struct bt_ctf_value *bt_ctf_trace_get_environment_field_value_by_name(
+               struct bt_ctf_trace *trace, const char *name)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_environment_field_value_by_name(
+               BT_CTF_TO_COMMON(trace), name));
+}
+
+BT_HIDDEN
+int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
+               struct bt_ctf_clock_class *clock_class)
+{
+       return bt_ctf_trace_common_add_clock_class(BT_CTF_TO_COMMON(trace),
+               (void *) clock_class);
+}
+
+BT_HIDDEN
+int64_t bt_ctf_trace_get_clock_class_count(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_clock_class_count(BT_CTF_TO_COMMON(trace));
+}
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
+               struct bt_ctf_trace *trace, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_clock_class_by_index(
+               BT_CTF_TO_COMMON(trace), index));
+}
+
+static
+int map_clock_classes_func(struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type)
+{
+       int ret = bt_ctf_stream_class_map_clock_class(
+               BT_CTF_FROM_COMMON(stream_class),
+               BT_CTF_FROM_COMMON(packet_context_type),
+               BT_CTF_FROM_COMMON(event_header_type));
+
+       if (ret) {
+               BT_LOGW_STR("Cannot automatically map selected stream class's field types to stream class's clock's class.");
+       }
+
+       return ret;
+}
+
+int bt_ctf_trace_add_stream_class(struct bt_ctf_trace *trace,
+               struct bt_ctf_stream_class *stream_class)
+{
+       int ret = 0;
+       struct bt_ctf_clock_class *expected_clock_class = NULL;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!stream_class) {
+               BT_LOGW_STR("Invalid parameter: stream class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       if (stream_class->clock) {
+               struct bt_ctf_clock_class *stream_clock_class =
+                       stream_class->clock->clock_class;
+
+               /*
+                * Make sure this clock was also added to the
+                * trace (potentially through its CTF writer
+                * owner).
+                */
+               size_t i;
+
+               for (i = 0; i < trace->common.clock_classes->len; i++) {
+                       if (trace->common.clock_classes->pdata[i] ==
+                                       stream_clock_class) {
+                               /* Found! */
+                               break;
+                       }
+               }
+
+               if (i == trace->common.clock_classes->len) {
+                       /* Not found */
+                       BT_LOGW("Stream class's clock's class is not part of the trace: "
+                               "clock-class-addr=%p, clock-class-name=\"%s\"",
+                               stream_clock_class,
+                               bt_ctf_clock_class_get_name(stream_clock_class));
+                       ret = -1;
+                       goto end;
+               }
+
+               if (stream_class->common.clock_class &&
+                               stream_class->common.clock_class !=
+                               stream_class->clock->clock_class) {
+                       /*
+                        * Stream class already has an expected clock
+                        * class, but it does not match its clock's
+                        * class.
+                        */
+                       BT_LOGW("Invalid parameter: stream class's clock's "
+                               "class does not match stream class's "
+                               "expected clock class: "
+                               "stream-class-addr=%p, "
+                               "stream-class-id=%" PRId64 ", "
+                               "stream-class-name=\"%s\", "
+                               "expected-clock-class-addr=%p, "
+                               "expected-clock-class-name=\"%s\"",
+                               stream_class,
+                               bt_ctf_stream_class_get_id(stream_class),
+                               bt_ctf_stream_class_get_name(stream_class),
+                               stream_class->common.clock_class,
+                               bt_ctf_clock_class_get_name(stream_class->common.clock_class));
+               } else if (!stream_class->common.clock_class) {
+                       /*
+                        * Set expected clock class to stream class's
+                        * clock's class.
+                        */
+                       expected_clock_class = stream_class->clock->clock_class;
+               }
+       }
+
+
+       ret = bt_ctf_trace_common_add_stream_class(BT_CTF_TO_COMMON(trace),
+               BT_CTF_TO_COMMON(stream_class),
+               (bt_ctf_validation_flag_copy_field_type_func) bt_ctf_field_type_copy,
+               expected_clock_class, map_clock_classes_func,
+               false);
+
+end:
+       return ret;
+}
+
+int64_t bt_ctf_trace_get_stream_count(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_stream_count(BT_CTF_TO_COMMON(trace));
+}
+
+struct bt_ctf_stream *bt_ctf_trace_get_stream_by_index(
+               struct bt_ctf_trace *trace, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_by_index(
+               BT_CTF_TO_COMMON(trace), index));
+}
+
+int64_t bt_ctf_trace_get_stream_class_count(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_stream_class_count(BT_CTF_TO_COMMON(trace));
+}
+
+struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_index(
+               struct bt_ctf_trace *trace, uint64_t index)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_index(
+               BT_CTF_TO_COMMON(trace), index));
+}
+
+struct bt_ctf_stream_class *bt_ctf_trace_get_stream_class_by_id(
+               struct bt_ctf_trace *trace, uint64_t id)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_stream_class_by_id(
+               BT_CTF_TO_COMMON(trace), id));
+}
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
+               struct bt_ctf_trace *trace, const char *name)
+{
+       return bt_ctf_object_get_ref(
+               bt_ctf_trace_common_borrow_clock_class_by_name(BT_CTF_TO_COMMON(trace),
+                       name));
+}
+
+static
+int append_trace_metadata(struct bt_ctf_trace *trace,
+               struct metadata_context *context)
+{
+       unsigned char *uuid = trace->common.uuid;
+       int ret = 0;
+
+       if (trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NATIVE ||
+                       trace->common.native_byte_order == BT_CTF_BYTE_ORDER_UNSPECIFIED) {
+               BT_LOGW("Invalid parameter: trace's byte order cannot be BT_CTF_BYTE_ORDER_NATIVE or BT_CTF_BYTE_ORDER_UNSPECIFIED at this point; "
+                       "set it with bt_ctf_trace_set_native_byte_order(): "
+                       "addr=%p, name=\"%s\"",
+                       trace, bt_ctf_trace_get_name(trace));
+               ret = -1;
+               goto end;
+       }
+
+       g_string_append(context->string, "trace {\n");
+       g_string_append(context->string, "\tmajor = 1;\n");
+       g_string_append(context->string, "\tminor = 8;\n");
+       BT_ASSERT(trace->common.native_byte_order == BT_CTF_BYTE_ORDER_LITTLE_ENDIAN ||
+               trace->common.native_byte_order == BT_CTF_BYTE_ORDER_BIG_ENDIAN ||
+               trace->common.native_byte_order == BT_CTF_BYTE_ORDER_NETWORK);
+
+       if (trace->common.uuid_set) {
+               g_string_append_printf(context->string,
+                       "\tuuid = \"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\";\n",
+                       uuid[0], uuid[1], uuid[2], uuid[3],
+                       uuid[4], uuid[5], uuid[6], uuid[7],
+                       uuid[8], uuid[9], uuid[10], uuid[11],
+                       uuid[12], uuid[13], uuid[14], uuid[15]);
+       }
+
+       g_string_append_printf(context->string, "\tbyte_order = %s;\n",
+               bt_ctf_get_byte_order_string(trace->common.native_byte_order));
+
+       if (trace->common.packet_header_field_type) {
+               g_string_append(context->string, "\tpacket.header := ");
+               context->current_indentation_level++;
+               g_string_assign(context->field_name, "");
+               BT_LOGD_STR("Serializing trace's packet header field type's metadata.");
+               ret = bt_ctf_field_type_serialize_recursive(
+                       (void *) trace->common.packet_header_field_type,
+                       context);
+               if (ret) {
+                       goto end;
+               }
+               context->current_indentation_level--;
+       }
+
+       g_string_append(context->string, ";\n};\n\n");
+end:
+       return ret;
+}
+
+static
+void append_env_metadata(struct bt_ctf_trace *trace,
+               struct metadata_context *context)
+{
+       int64_t i;
+       int64_t env_size;
+
+       env_size = bt_ctf_attributes_get_count(trace->common.environment);
+       if (env_size <= 0) {
+               return;
+       }
+
+       g_string_append(context->string, "env {\n");
+
+       for (i = 0; i < env_size; i++) {
+               struct bt_ctf_private_value *env_field_value_obj = NULL;
+               const char *entry_name;
+
+               entry_name = bt_ctf_attributes_get_field_name(
+                       trace->common.environment, i);
+               env_field_value_obj = bt_ctf_attributes_borrow_field_value(
+                       trace->common.environment, i);
+
+               BT_ASSERT(entry_name);
+               BT_ASSERT(env_field_value_obj);
+
+               switch (bt_ctf_value_get_type(
+                       bt_ctf_private_value_as_value(env_field_value_obj))) {
+               case BT_CTF_VALUE_TYPE_INTEGER:
+               {
+                       int64_t int_value;
+
+                       int_value = bt_ctf_value_integer_get(
+                               bt_ctf_private_value_as_value(
+                                       env_field_value_obj));
+                       g_string_append_printf(context->string,
+                               "\t%s = %" PRId64 ";\n", entry_name,
+                               int_value);
+                       break;
+               }
+               case BT_CTF_VALUE_TYPE_STRING:
+               {
+                       const char *str_value;
+                       char *escaped_str = NULL;
+
+                       str_value = bt_ctf_value_string_get(
+                               bt_ctf_private_value_as_value(
+                                       env_field_value_obj));
+                       escaped_str = g_strescape(str_value, NULL);
+                       if (!escaped_str) {
+                               BT_LOGE("Cannot escape string: string=\"%s\"",
+                                       str_value);
+                               continue;
+                       }
+
+                       g_string_append_printf(context->string,
+                               "\t%s = \"%s\";\n", entry_name, escaped_str);
+                       free(escaped_str);
+                       break;
+               }
+               default:
+                       continue;
+               }
+       }
+
+       g_string_append(context->string, "};\n\n");
+}
+
+char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace)
+{
+       char *metadata = NULL;
+       struct metadata_context *context = NULL;
+       int err = 0;
+       size_t i;
+
+       if (!trace) {
+               BT_LOGW_STR("Invalid parameter: trace is NULL.");
+               goto end;
+       }
+
+       context = g_new0(struct metadata_context, 1);
+       if (!context) {
+               BT_LOGE_STR("Failed to allocate one metadata context.");
+               goto end;
+       }
+
+       context->field_name = g_string_sized_new(DEFAULT_IDENTIFIER_SIZE);
+       context->string = g_string_sized_new(DEFAULT_METADATA_STRING_SIZE);
+       g_string_append(context->string, "/* CTF 1.8 */\n\n");
+       if (append_trace_metadata(trace, context)) {
+               /* append_trace_metadata() logs errors */
+               goto error;
+       }
+       append_env_metadata(trace, context);
+       g_ptr_array_foreach(trace->common.clock_classes,
+               (GFunc) bt_ctf_clock_class_serialize, context);
+
+       for (i = 0; i < trace->common.stream_classes->len; i++) {
+               /* bt_ctf_stream_class_serialize() logs details */
+               err = bt_ctf_stream_class_serialize(
+                       trace->common.stream_classes->pdata[i], context);
+               if (err) {
+                       /* bt_ctf_stream_class_serialize() logs errors */
+                       goto error;
+               }
+       }
+
+       metadata = context->string->str;
+
+error:
+       g_string_free(context->string, err ? TRUE : FALSE);
+       g_string_free(context->field_name, TRUE);
+       g_free(context);
+
+end:
+       return metadata;
+}
+
+enum bt_ctf_byte_order bt_ctf_trace_get_native_byte_order(
+               struct bt_ctf_trace *trace)
+{
+       return (int) bt_ctf_trace_common_get_native_byte_order(BT_CTF_TO_COMMON(trace));
+}
+
+int bt_ctf_trace_set_native_byte_order(struct bt_ctf_trace *trace,
+               enum bt_ctf_byte_order byte_order)
+{
+       return bt_ctf_trace_common_set_native_byte_order(BT_CTF_TO_COMMON(trace),
+               (int) byte_order, false);
+}
+
+struct bt_ctf_field_type *bt_ctf_trace_get_packet_header_field_type(
+               struct bt_ctf_trace *trace)
+{
+       return bt_ctf_object_get_ref(bt_ctf_trace_common_borrow_packet_header_field_type(
+               BT_CTF_TO_COMMON(trace)));
+}
+
+int bt_ctf_trace_set_packet_header_field_type(struct bt_ctf_trace *trace,
+               struct bt_ctf_field_type *packet_header_type)
+{
+       return bt_ctf_trace_common_set_packet_header_field_type(BT_CTF_TO_COMMON(trace),
+               (void *) packet_header_type);
+}
+
+const char *bt_ctf_trace_get_name(struct bt_ctf_trace *trace)
+{
+       return bt_ctf_trace_common_get_name(BT_CTF_TO_COMMON(trace));
+}
diff --git a/src/ctf-writer/trace.h b/src/ctf-writer/trace.h
new file mode 100644 (file)
index 0000000..ae5f1ec
--- /dev/null
@@ -0,0 +1,391 @@
+#ifndef BABELTRACE_CTF_WRITER_TRACE_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_TRACE_INTERNAL_H
+
+/*
+ * Copyright 2014 EfficiOS Inc.
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include "common/babeltrace.h"
+#include "compat/uuid.h"
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/fields.h>
+#include <babeltrace2/ctf-writer/trace.h>
+#include <babeltrace2/types.h>
+#include <glib.h>
+#include <sys/types.h>
+
+#include "assert-pre.h"
+#include "attributes.h"
+#include "clock-class.h"
+#include "object.h"
+#include "stream-class.h"
+#include "validation.h"
+#include "values.h"
+
+struct bt_ctf_trace_common {
+       struct bt_ctf_object base;
+       GString *name;
+       int frozen;
+       unsigned char uuid[BABELTRACE_UUID_LEN];
+       bt_bool uuid_set;
+       enum bt_ctf_byte_order native_byte_order;
+       struct bt_ctf_private_value *environment;
+       GPtrArray *clock_classes; /* Array of pointers to bt_ctf_clock_class */
+       GPtrArray *stream_classes; /* Array of ptrs to bt_ctf_stream_class_common */
+       GPtrArray *streams; /* Array of ptrs to bt_ctf_stream_common */
+       struct bt_ctf_field_type_common *packet_header_field_type;
+       int64_t next_stream_id;
+
+       /*
+        * This flag indicates if the trace is valid. A valid
+        * trace is _always_ frozen.
+        */
+       int valid;
+};
+
+BT_HIDDEN
+bt_bool bt_ctf_trace_common_has_clock_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_clock_class *clock_class);
+
+BT_HIDDEN
+int bt_ctf_trace_common_initialize(struct bt_ctf_trace_common *trace,
+               bt_ctf_object_release_func release_func);
+
+BT_HIDDEN
+void bt_ctf_trace_common_finalize(struct bt_ctf_trace_common *trace);
+
+static inline
+const char *bt_ctf_trace_common_get_name(struct bt_ctf_trace_common *trace)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return trace->name ? trace->name->str : NULL;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_name(struct bt_ctf_trace_common *trace, const char *name);
+
+static inline
+const unsigned char *bt_ctf_trace_common_get_uuid(struct bt_ctf_trace_common *trace)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return trace->uuid_set ? trace->uuid : NULL;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_uuid(struct bt_ctf_trace_common *trace, const unsigned char *uuid);
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_environment_field(struct bt_ctf_trace_common *trace,
+               const char *name, struct bt_ctf_private_value *value);
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_environment_field_string(struct bt_ctf_trace_common *trace,
+               const char *name, const char *value);
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_environment_field_integer(struct bt_ctf_trace_common *trace,
+               const char *name, int64_t value);
+
+static inline
+int64_t bt_ctf_trace_common_get_environment_field_count(
+               struct bt_ctf_trace_common *trace)
+{
+       int64_t ret;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       ret = bt_ctf_attributes_get_count(trace->environment);
+       BT_ASSERT(ret >= 0);
+       return ret;
+}
+
+static inline
+const char *
+bt_ctf_trace_common_get_environment_field_name_by_index(
+               struct bt_ctf_trace_common *trace, uint64_t index)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return bt_ctf_attributes_get_field_name(trace->environment, index);
+}
+
+static inline
+struct bt_ctf_private_value *
+bt_ctf_trace_common_borrow_environment_field_value_by_index(
+               struct bt_ctf_trace_common *trace, uint64_t index)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return bt_ctf_attributes_borrow_field_value(trace->environment, index);
+}
+
+static inline
+struct bt_ctf_private_value *
+bt_ctf_trace_common_borrow_environment_field_value_by_name(
+               struct bt_ctf_trace_common *trace, const char *name)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+       return bt_ctf_attributes_borrow_field_value_by_name(trace->environment,
+               name);
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_add_clock_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_clock_class *clock_class);
+
+static inline
+int64_t bt_ctf_trace_common_get_clock_class_count(struct bt_ctf_trace_common *trace)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return trace->clock_classes->len;
+}
+
+static inline
+struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_index(
+               struct bt_ctf_trace_common *trace, uint64_t index)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE(index < trace->clock_classes->len,
+               "Index is out of bounds: index=%" PRIu64 ", "
+               "count=%u",
+               index, trace->clock_classes->len);
+       return g_ptr_array_index(trace->clock_classes, index);
+}
+
+static inline
+int64_t bt_ctf_trace_common_get_stream_count(struct bt_ctf_trace_common *trace)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return (int64_t) trace->streams->len;
+}
+
+static inline
+struct bt_ctf_stream_common *bt_ctf_trace_common_borrow_stream_by_index(
+               struct bt_ctf_trace_common *trace,
+               uint64_t index)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE(index < trace->streams->len,
+               "Index is out of bounds: index=%" PRIu64 ", "
+               "count=%u",
+               index, trace->streams->len);
+       return g_ptr_array_index(trace->streams, index);
+}
+
+static inline
+int64_t bt_ctf_trace_common_get_stream_class_count(struct bt_ctf_trace_common *trace)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return (int64_t) trace->stream_classes->len;
+}
+
+static inline
+struct bt_ctf_stream_class_common *bt_ctf_trace_common_borrow_stream_class_by_index(
+               struct bt_ctf_trace_common *trace, uint64_t index)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE(index < trace->stream_classes->len,
+               "Index is out of bounds: index=%" PRIu64 ", "
+               "count=%u",
+               index, trace->stream_classes->len);
+       return g_ptr_array_index(trace->stream_classes, index);
+}
+
+static inline
+struct bt_ctf_stream_class_common *bt_ctf_trace_common_borrow_stream_class_by_id(
+               struct bt_ctf_trace_common *trace, uint64_t id_param)
+{
+       int i;
+       struct bt_ctf_stream_class_common *stream_class = NULL;
+       int64_t id = (int64_t) id_param;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE(id >= 0,
+               "Invalid stream class ID: %" PRIu64, id_param);
+
+       for (i = 0; i < trace->stream_classes->len; i++) {
+               struct bt_ctf_stream_class_common *stream_class_candidate;
+
+               stream_class_candidate =
+                       g_ptr_array_index(trace->stream_classes, i);
+
+               if (bt_ctf_stream_class_common_get_id(stream_class_candidate) ==
+                               (int64_t) id) {
+                       stream_class = stream_class_candidate;
+                       goto end;
+               }
+       }
+
+end:
+       return stream_class;
+}
+
+static inline
+struct bt_ctf_clock_class *bt_ctf_trace_common_borrow_clock_class_by_name(
+               struct bt_ctf_trace_common *trace, const char *name)
+{
+       size_t i;
+       struct bt_ctf_clock_class *clock_class = NULL;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_CTF_ASSERT_PRE_NON_NULL(name, "Name");
+
+       for (i = 0; i < trace->clock_classes->len; i++) {
+               struct bt_ctf_clock_class *cur_clk =
+                       g_ptr_array_index(trace->clock_classes, i);
+               const char *cur_clk_name = bt_ctf_clock_class_get_name(cur_clk);
+
+               if (!cur_clk_name) {
+                       goto end;
+               }
+
+               if (!strcmp(cur_clk_name, name)) {
+                       clock_class = cur_clk;
+                       goto end;
+               }
+       }
+
+end:
+       return clock_class;
+}
+
+static inline
+enum bt_ctf_byte_order bt_ctf_trace_common_get_native_byte_order(
+               struct bt_ctf_trace_common *trace)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return trace->native_byte_order;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_native_byte_order(struct bt_ctf_trace_common *trace,
+               enum bt_ctf_byte_order byte_order, bool allow_unspecified);
+
+static inline
+struct bt_ctf_field_type_common *bt_ctf_trace_common_borrow_packet_header_field_type(
+               struct bt_ctf_trace_common *trace)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return trace->packet_header_field_type;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_set_packet_header_field_type(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_field_type_common *packet_header_field_type);
+
+static inline
+void bt_ctf_trace_common_freeze(struct bt_ctf_trace_common *trace)
+{
+       int i;
+
+       if (trace->frozen) {
+               return;
+       }
+
+       BT_LOGD("Freezing trace: addr=%p, name=\"%s\"",
+               trace, bt_ctf_trace_common_get_name(trace));
+       BT_LOGD_STR("Freezing packet header field type.");
+       bt_ctf_field_type_common_freeze(trace->packet_header_field_type);
+       BT_LOGD_STR("Freezing environment attributes.");
+       bt_ctf_attributes_freeze(trace->environment);
+
+       if (trace->clock_classes->len > 0) {
+               BT_LOGD_STR("Freezing clock classes.");
+       }
+
+       for (i = 0; i < trace->clock_classes->len; i++) {
+               struct bt_ctf_clock_class *clock_class =
+                       g_ptr_array_index(trace->clock_classes, i);
+
+               bt_ctf_clock_class_freeze(clock_class);
+       }
+
+       trace->frozen = 1;
+}
+
+BT_HIDDEN
+int bt_ctf_trace_common_add_stream_class(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func,
+               struct bt_ctf_clock_class *init_expected_clock_class,
+               int (*map_clock_classes_func)(struct bt_ctf_stream_class_common *stream_class,
+                       struct bt_ctf_field_type_common *packet_context_field_type,
+                       struct bt_ctf_field_type_common *event_header_field_type),
+               bool check_ts_begin_end_mapped);
+
+struct bt_ctf_trace {
+       struct bt_ctf_trace_common common;
+};
+
+/*
+ * bt_ctf_trace_get_metadata_string: get metadata string.
+ *
+ * Get the trace's TSDL metadata. The caller assumes the ownership of the
+ * returned string.
+ *
+ * @param trace Trace instance.
+ *
+ * Returns the metadata string on success, NULL on error.
+ */
+BT_HIDDEN
+char *bt_ctf_trace_get_metadata_string(struct bt_ctf_trace *trace);
+
+BT_HIDDEN
+struct bt_ctf_trace *bt_ctf_trace_create(void);
+
+BT_HIDDEN
+int64_t bt_ctf_trace_get_clock_class_count(
+               struct bt_ctf_trace *trace);
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_index(
+               struct bt_ctf_trace *trace, uint64_t index);
+
+BT_HIDDEN
+struct bt_ctf_clock_class *bt_ctf_trace_get_clock_class_by_name(
+               struct bt_ctf_trace *trace, const char *name);
+
+BT_HIDDEN
+int bt_ctf_trace_add_clock_class(struct bt_ctf_trace *trace,
+               struct bt_ctf_clock_class *clock_class);
+
+BT_HIDDEN
+int64_t bt_ctf_trace_get_environment_field_count(
+               struct bt_ctf_trace *trace);
+
+BT_HIDDEN
+const char *bt_ctf_trace_get_environment_field_name_by_index(
+               struct bt_ctf_trace *trace, uint64_t index);
+
+BT_HIDDEN
+struct bt_ctf_value *
+bt_ctf_trace_get_environment_field_value_by_index(struct bt_ctf_trace *trace,
+               uint64_t index);
+
+BT_HIDDEN
+struct bt_ctf_value *
+bt_ctf_trace_get_environment_field_value_by_name(
+               struct bt_ctf_trace *trace, const char *name);
+
+#endif /* BABELTRACE_CTF_WRITER_TRACE_INTERNAL_H */
diff --git a/src/ctf-writer/utils.c b/src/ctf-writer/utils.c
new file mode 100644 (file)
index 0000000..b63883e
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * utils.c
+ *
+ * Babeltrace CTF writer - Utilities
+ *
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-UTILS"
+#include "logging.h"
+
+#include <glib.h>
+#include <stdlib.h>
+
+#include <babeltrace2/ctf-writer/utils.h>
+#include <babeltrace2/ctf-writer/object.h>
+
+#include "common/assert.h"
+
+#include "clock-class.h"
+#include "field-types.h"
+
+static
+const char * const reserved_keywords_str[] = {"align", "callsite",
+       "const", "char", "clock", "double", "enum", "env", "event",
+       "floating_point", "float", "integer", "int", "long", "short", "signed",
+       "stream", "string", "struct", "trace", "typealias", "typedef",
+       "unsigned", "variant", "void" "_Bool", "_Complex", "_Imaginary"};
+
+static GHashTable *reserved_keywords_set;
+static int init_done;
+
+static
+void try_init_reserved_keywords(void)
+{
+       size_t i;
+       const size_t reserved_keywords_count =
+               sizeof(reserved_keywords_str) / sizeof(char *);
+
+       if (reserved_keywords_set) {
+               return;
+       }
+
+       reserved_keywords_set = g_hash_table_new(g_direct_hash, g_direct_equal);
+       BT_ASSERT(reserved_keywords_set);
+
+       for (i = 0; i < reserved_keywords_count; i++) {
+               gpointer quark = GINT_TO_POINTER(g_quark_from_string(
+                       reserved_keywords_str[i]));
+
+               g_hash_table_insert(reserved_keywords_set, quark, quark);
+       }
+
+       init_done = 1;
+}
+
+static __attribute__((destructor))
+void trace_finalize(void)
+{
+       if (reserved_keywords_set) {
+               g_hash_table_destroy(reserved_keywords_set);
+       }
+}
+
+bt_bool bt_ctf_identifier_is_valid(const char *identifier)
+{
+       bt_bool is_valid = BT_TRUE;
+       char *string = NULL;
+       char *save_ptr, *token;
+
+       if (!identifier) {
+               BT_LOGV_STR("Invalid parameter: input string is NULL.");
+               is_valid = BT_FALSE;
+               goto end;
+       }
+
+       try_init_reserved_keywords();
+
+       if (identifier[0] == '\0') {
+               is_valid = BT_FALSE;
+               goto end;
+       }
+
+       string = strdup(identifier);
+       if (!string) {
+               BT_LOGE("strdup() failed.");
+               is_valid = BT_FALSE;
+               goto end;
+       }
+
+       token = strtok_r(string, " ", &save_ptr);
+       while (token) {
+               if (g_hash_table_lookup_extended(reserved_keywords_set,
+                       GINT_TO_POINTER(g_quark_from_string(token)),
+                       NULL, NULL)) {
+                       is_valid = BT_FALSE;
+                       goto end;
+               }
+
+               token = strtok_r(NULL, " ", &save_ptr);
+       }
+end:
+       free(string);
+       return is_valid;
+}
diff --git a/src/ctf-writer/utils.h b/src/ctf-writer/utils.h
new file mode 100644 (file)
index 0000000..488251c
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef BABELTRACE_CTF_WRITER_UTILS_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_UTILS_INTERNAL_H
+
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/ctf-writer/field-types.h>
+#include <babeltrace2/ctf-writer/event.h>
+#include <stdint.h>
+
+#include "field-path.h"
+
+#define BT_CTF_TO_COMMON(_obj)         (&(_obj)->common)
+#define BT_CTF_FROM_COMMON(_obj)       ((void *) _obj)
+
+struct bt_ctf_search_query {
+       gpointer value;
+       int found;
+};
+
+BT_HIDDEN
+const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order);
+
+static inline
+const char *bt_ctf_field_type_id_string(enum bt_ctf_field_type_id type_id)
+{
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_UNKNOWN:
+               return "BT_CTF_FIELD_TYPE_ID_UNKNOWN";
+       case BT_CTF_FIELD_TYPE_ID_INTEGER:
+               return "BT_CTF_FIELD_TYPE_ID_INTEGER";
+       case BT_CTF_FIELD_TYPE_ID_FLOAT:
+               return "BT_CTF_FIELD_TYPE_ID_FLOAT";
+       case BT_CTF_FIELD_TYPE_ID_ENUM:
+               return "BT_CTF_FIELD_TYPE_ID_ENUM";
+       case BT_CTF_FIELD_TYPE_ID_STRING:
+               return "BT_CTF_FIELD_TYPE_ID_STRING";
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+               return "BT_CTF_FIELD_TYPE_ID_STRUCT";
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+               return "BT_CTF_FIELD_TYPE_ID_ARRAY";
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+               return "BT_CTF_FIELD_TYPE_ID_SEQUENCE";
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               return "BT_CTF_FIELD_TYPE_ID_VARIANT";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline
+const char *bt_ctf_byte_order_string(enum bt_ctf_byte_order bo)
+{
+       switch (bo) {
+       case BT_CTF_BYTE_ORDER_UNKNOWN:
+               return "BT_CTF_BYTE_ORDER_UNKNOWN";
+       case BT_CTF_BYTE_ORDER_UNSPECIFIED:
+               return "BT_CTF_BYTE_ORDER_UNSPECIFIED";
+       case BT_CTF_BYTE_ORDER_NATIVE:
+               return "BT_CTF_BYTE_ORDER_NATIVE";
+       case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
+               return "BT_CTF_BYTE_ORDER_LITTLE_ENDIAN";
+       case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
+               return "BT_CTF_BYTE_ORDER_BIG_ENDIAN";
+       case BT_CTF_BYTE_ORDER_NETWORK:
+               return "BT_CTF_BYTE_ORDER_NETWORK";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline
+const char *bt_ctf_string_encoding_string(enum bt_ctf_string_encoding encoding)
+{
+       switch (encoding) {
+       case BT_CTF_STRING_ENCODING_UNKNOWN:
+               return "BT_CTF_STRING_ENCODING_UNKNOWN";
+       case BT_CTF_STRING_ENCODING_NONE:
+               return "BT_CTF_STRING_ENCODING_NONE";
+       case BT_CTF_STRING_ENCODING_UTF8:
+               return "BT_CTF_STRING_ENCODING_UTF8";
+       case BT_CTF_STRING_ENCODING_ASCII:
+               return "BT_CTF_STRING_ENCODING_ASCII";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline
+const char *bt_ctf_integer_base_string(enum bt_ctf_integer_base base)
+{
+       switch (base) {
+       case BT_CTF_INTEGER_BASE_UNKNOWN:
+               return "BT_CTF_INTEGER_BASE_UNKNOWN";
+       case BT_CTF_INTEGER_BASE_UNSPECIFIED:
+               return "BT_CTF_INTEGER_BASE_UNSPECIFIED";
+       case BT_CTF_INTEGER_BASE_BINARY:
+               return "BT_CTF_INTEGER_BASE_BINARY";
+       case BT_CTF_INTEGER_BASE_OCTAL:
+               return "BT_CTF_INTEGER_BASE_OCTAL";
+       case BT_CTF_INTEGER_BASE_DECIMAL:
+               return "BT_CTF_INTEGER_BASE_DECIMAL";
+       case BT_CTF_INTEGER_BASE_HEXADECIMAL:
+               return "BT_CTF_INTEGER_BASE_HEXADECIMAL";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+const char *bt_ctf_scope_string(enum bt_ctf_scope scope)
+{
+       switch (scope) {
+       case BT_CTF_SCOPE_UNKNOWN:
+               return "BT_CTF_SCOPE_UNKNOWN";
+       case BT_CTF_SCOPE_TRACE_PACKET_HEADER:
+               return "BT_CTF_SCOPE_TRACE_PACKET_HEADER";
+       case BT_CTF_SCOPE_STREAM_PACKET_CONTEXT:
+               return "BT_CTF_SCOPE_STREAM_PACKET_CONTEXT";
+       case BT_CTF_SCOPE_STREAM_EVENT_HEADER:
+               return "BT_CTF_SCOPE_STREAM_EVENT_HEADER";
+       case BT_CTF_SCOPE_STREAM_EVENT_CONTEXT:
+               return "BT_CTF_SCOPE_STREAM_EVENT_CONTEXT";
+       case BT_CTF_SCOPE_EVENT_CONTEXT:
+               return "BT_CTF_SCOPE_EVENT_CONTEXT";
+       case BT_CTF_SCOPE_EVENT_PAYLOAD:
+               return "BT_CTF_SCOPE_EVENT_PAYLOAD";
+       case BT_CTF_SCOPE_ENV:
+               return "BT_CTF_SCOPE_ENV";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+const char *bt_ctf_event_class_log_level_string(
+               enum bt_ctf_event_class_log_level level)
+{
+       switch (level) {
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_UNKNOWN:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_UNKNOWN";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_UNSPECIFIED";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_EMERGENCY";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_ALERT:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_ALERT";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_CRITICAL:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_CRITICAL";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_ERROR:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_ERROR";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_WARNING:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_WARNING";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_NOTICE:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_NOTICE";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_INFO:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_INFO";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE";
+       case BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG:
+               return "BT_CTF_EVENT_CLASS_LOG_LEVEL_DEBUG";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline
+GString *bt_ctf_field_path_string(struct bt_ctf_field_path *path)
+{
+       GString *str = g_string_new(NULL);
+       size_t i;
+
+       BT_ASSERT(path);
+
+       if (!str) {
+               goto end;
+       }
+
+       g_string_append_printf(str, "[%s", bt_common_scope_string(
+               bt_ctf_field_path_get_root_scope(path)));
+
+       for (i = 0; i < bt_ctf_field_path_get_index_count(path); i++) {
+               int index = bt_ctf_field_path_get_index(path, i);
+
+               g_string_append_printf(str, ", %d", index);
+       }
+
+       g_string_append(str, "]");
+
+end:
+       return str;
+}
+
+#endif /* BABELTRACE_CTF_WRITER_UTILS_INTERNAL_H */
diff --git a/src/ctf-writer/validation.c b/src/ctf-writer/validation.c
new file mode 100644 (file)
index 0000000..1d50d4d
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * validation.c
+ *
+ * Babeltrace - CTF writer: Validation of trace, stream class, and event class
+ *
+ * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-VALIDATION"
+#include "logging.h"
+
+#include <babeltrace2/ctf-writer/object.h>
+
+#include "common/babeltrace.h"
+
+#include "assert-pre.h"
+#include "event-class.h"
+#include "field-types.h"
+#include "field-types.h"
+#include "resolve.h"
+#include "stream-class.h"
+#include "trace.h"
+#include "validation.h"
+#include "values.h"
+
+/*
+ * This function resolves and validates the field types of an event
+ * class. Only `event_context_type` and `event_payload_type` are
+ * resolved and validated; the other field types are used as eventual
+ * resolving targets.
+ *
+ * All parameters are owned by the caller.
+ */
+static
+int validate_event_class_types(struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type,
+               struct bt_ctf_field_type_common *event_context_type,
+               struct bt_ctf_field_type_common *event_payload_type)
+{
+       int ret = 0;
+
+       BT_LOGV("Validating event class field types: "
+               "packet-header-ft-addr=%p, "
+               "packet-context-ft-addr=%p, "
+               "event-header-ft-addr=%p, "
+               "stream-event-context-ft-addr=%p, "
+               "event-context-ft-addr=%p, "
+               "event-payload-ft-addr=%p",
+               packet_header_type, packet_context_type, event_header_type,
+               stream_event_ctx_type, event_context_type, event_payload_type);
+
+       /* Resolve sequence type lengths and variant type tags first */
+       ret = bt_ctf_resolve_types(environment, packet_header_type,
+               packet_context_type, event_header_type, stream_event_ctx_type,
+               event_context_type, event_payload_type,
+               BT_CTF_RESOLVE_FLAG_EVENT_CONTEXT |
+               BT_CTF_RESOLVE_FLAG_EVENT_PAYLOAD);
+       if (ret) {
+               BT_LOGW("Cannot resolve event class field types: ret=%d",
+                       ret);
+               goto end;
+       }
+
+       /* Validate field types individually */
+       if (event_context_type) {
+               ret = bt_ctf_field_type_common_validate(event_context_type);
+               if (ret) {
+                       BT_LOGW("Invalid event class's context field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       if (event_payload_type) {
+               ret = bt_ctf_field_type_common_validate(event_payload_type);
+               if (ret) {
+                       BT_LOGW("Invalid event class's payload field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * This function resolves and validates the field types of a stream
+ * class. Only `packet_context_type`, `event_header_type`, and
+ * `stream_event_ctx_type` are resolved and validated; the other field
+ * type is used as an eventual resolving target.
+ *
+ * All parameters are owned by the caller.
+ */
+static
+int validate_stream_class_types(struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type)
+{
+       int ret = 0;
+
+       BT_LOGV("Validating stream class field types: "
+               "packet-header-ft-addr=%p, "
+               "packet-context-ft-addr=%p, "
+               "event-header-ft-addr=%p, "
+               "stream-event-context-ft-addr=%p",
+               packet_header_type, packet_context_type, event_header_type,
+               stream_event_ctx_type);
+
+       /* Resolve sequence type lengths and variant type tags first */
+       ret = bt_ctf_resolve_types(environment, packet_header_type,
+               packet_context_type, event_header_type, stream_event_ctx_type,
+               NULL, NULL,
+               BT_CTF_RESOLVE_FLAG_PACKET_CONTEXT |
+               BT_CTF_RESOLVE_FLAG_EVENT_HEADER |
+               BT_CTF_RESOLVE_FLAG_STREAM_EVENT_CTX);
+       if (ret) {
+               BT_LOGW("Cannot resolve stream class field types: ret=%d",
+                       ret);
+               goto end;
+       }
+
+       /* Validate field types individually */
+       if (packet_context_type) {
+               ret = bt_ctf_field_type_common_validate(packet_context_type);
+               if (ret) {
+                       BT_LOGW("Invalid stream class's packet context field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       if (event_header_type) {
+               ret = bt_ctf_field_type_common_validate(event_header_type);
+               if (ret) {
+                       BT_LOGW("Invalid stream class's event header field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       if (stream_event_ctx_type) {
+               ret = bt_ctf_field_type_common_validate(
+                       stream_event_ctx_type);
+               if (ret) {
+                       BT_LOGW("Invalid stream class's event context field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * This function resolves and validates the field types of a trace.
+ *
+ * All parameters are owned by the caller.
+ */
+static
+int validate_trace_types(struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type)
+{
+       int ret = 0;
+
+       BT_LOGV("Validating event class field types: "
+               "packet-header-ft-addr=%p", packet_header_type);
+
+       /* Resolve sequence type lengths and variant type tags first */
+       ret = bt_ctf_resolve_types(environment, packet_header_type,
+               NULL, NULL, NULL, NULL, NULL,
+               BT_CTF_RESOLVE_FLAG_PACKET_HEADER);
+       if (ret) {
+               BT_LOGW("Cannot resolve trace field types: ret=%d",
+                       ret);
+               goto end;
+       }
+
+       /* Validate field types individually */
+       if (packet_header_type) {
+               ret = bt_ctf_field_type_common_validate(packet_header_type);
+               if (ret) {
+                       BT_LOGW("Invalid trace's packet header field type: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Checks whether or not `field_type` contains a variant or a sequence
+ * field type, recursively. Returns 1 if it's the case.
+ *
+ * `field_type` is owned by the caller.
+ */
+static
+int field_type_contains_sequence_or_variant_ft(struct bt_ctf_field_type_common *type)
+{
+       int ret = 0;
+       enum bt_ctf_field_type_id type_id = bt_ctf_field_type_common_get_type_id(type);
+
+       switch (type_id) {
+       case BT_CTF_FIELD_TYPE_ID_SEQUENCE:
+       case BT_CTF_FIELD_TYPE_ID_VARIANT:
+               ret = 1;
+               goto end;
+       case BT_CTF_FIELD_TYPE_ID_ARRAY:
+       case BT_CTF_FIELD_TYPE_ID_STRUCT:
+       {
+               int i;
+               int field_count = bt_ctf_field_type_common_get_field_count(type);
+
+               if (field_count < 0) {
+                       ret = -1;
+                       goto end;
+               }
+
+               for (i = 0; i < field_count; ++i) {
+                       struct bt_ctf_field_type_common *child_type =
+                               bt_ctf_field_type_common_borrow_field_at_index(
+                                       type, i);
+
+                       ret = field_type_contains_sequence_or_variant_ft(
+                               child_type);
+                       if (ret != 0) {
+                               goto end;
+                       }
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctf_validate_class_types(struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type,
+               struct bt_ctf_field_type_common *event_context_type,
+               struct bt_ctf_field_type_common *event_payload_type,
+               int trace_valid, int stream_class_valid, int event_class_valid,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag validate_flags,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func)
+{
+       int ret = 0;
+       int contains_seq_var;
+       int valid_ret;
+
+       BT_LOGV("Validating field types: "
+               "packet-header-ft-addr=%p, "
+               "packet-context-ft-addr=%p, "
+               "event-header-ft-addr=%p, "
+               "stream-event-context-ft-addr=%p, "
+               "event-context-ft-addr=%p, "
+               "event-payload-ft-addr=%p, "
+               "trace-is-valid=%d, stream-class-is-valid=%d, "
+               "event-class-is-valid=%d, validation-flags=%x",
+               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,
+               (unsigned int) validate_flags);
+
+       /* Clean output values */
+       memset(output, 0, sizeof(*output));
+
+       /* Set initial valid flags according to valid parameters */
+       if (trace_valid) {
+               output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE;
+       }
+
+       if (stream_class_valid) {
+               output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM;
+       }
+
+       if (event_class_valid) {
+               output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT;
+       }
+
+       /* Own the type parameters */
+       bt_ctf_object_get_ref(packet_header_type);
+       bt_ctf_object_get_ref(packet_context_type);
+       bt_ctf_object_get_ref(event_header_type);
+       bt_ctf_object_get_ref(stream_event_ctx_type);
+       bt_ctf_object_get_ref(event_context_type);
+       bt_ctf_object_get_ref(event_payload_type);
+
+       /* Validate trace */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_TRACE) && !trace_valid) {
+               struct bt_ctf_field_type_common *packet_header_type_copy = NULL;
+
+               /* Create field type copies */
+               if (packet_header_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       packet_header_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               packet_header_type_copy = packet_header_type;
+                               bt_ctf_object_get_ref(packet_header_type_copy);
+                               goto skip_packet_header_type_copy;
+                       }
+
+                       BT_LOGV_STR("Copying packet header field type because it contains at least one sequence or variant field type.");
+                       packet_header_type_copy =
+                               copy_field_type_func(packet_header_type);
+                       if (!packet_header_type_copy) {
+                               ret = -1;
+                               BT_LOGE_STR("Cannot copy packet header field type.");
+                               goto error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_common_freeze(packet_header_type_copy);
+               }
+
+skip_packet_header_type_copy:
+               /* Put original reference and move copy */
+               BT_CTF_OBJECT_MOVE_REF(packet_header_type, packet_header_type_copy);
+
+               /* Validate trace field types */
+               valid_ret = validate_trace_types(environment,
+                       packet_header_type);
+               if (valid_ret == 0) {
+                       /* Trace is valid */
+                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_TRACE;
+               }
+       }
+
+       /* Validate stream class */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_STREAM) &&
+                       !stream_class_valid) {
+               struct bt_ctf_field_type_common *packet_context_type_copy = NULL;
+               struct bt_ctf_field_type_common *event_header_type_copy = NULL;
+               struct bt_ctf_field_type_common *stream_event_ctx_type_copy = NULL;
+
+               if (packet_context_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       packet_context_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               packet_context_type_copy = packet_context_type;
+                               bt_ctf_object_get_ref(packet_context_type_copy);
+                               goto skip_packet_context_type_copy;
+                       }
+
+                       BT_LOGV_STR("Copying packet context field type because it contains at least one sequence or variant field type.");
+                       packet_context_type_copy =
+                               copy_field_type_func(packet_context_type);
+                       if (!packet_context_type_copy) {
+                               BT_LOGE_STR("Cannot copy packet context field type.");
+                               goto sc_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_common_freeze(packet_context_type_copy);
+               }
+
+skip_packet_context_type_copy:
+               if (event_header_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       event_header_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               event_header_type_copy = event_header_type;
+                               bt_ctf_object_get_ref(event_header_type_copy);
+                               goto skip_event_header_type_copy;
+                       }
+
+                       BT_LOGV_STR("Copying event header field type because it contains at least one sequence or variant field type.");
+                       event_header_type_copy =
+                               copy_field_type_func(event_header_type);
+                       if (!event_header_type_copy) {
+                               BT_LOGE_STR("Cannot copy event header field type.");
+                               goto sc_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_common_freeze(event_header_type_copy);
+               }
+
+skip_event_header_type_copy:
+               if (stream_event_ctx_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       stream_event_ctx_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               stream_event_ctx_type_copy =
+                                       stream_event_ctx_type;
+                               bt_ctf_object_get_ref(stream_event_ctx_type_copy);
+                               goto skip_stream_event_ctx_type_copy;
+                       }
+
+                       BT_LOGV_STR("Copying stream event context field type because it contains at least one sequence or variant field type.");
+                       stream_event_ctx_type_copy =
+                               copy_field_type_func(stream_event_ctx_type);
+                       if (!stream_event_ctx_type_copy) {
+                               BT_LOGE_STR("Cannot copy stream event context field type.");
+                               goto sc_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_common_freeze(stream_event_ctx_type_copy);
+               }
+
+skip_stream_event_ctx_type_copy:
+               /* Put original references and move copies */
+               BT_CTF_OBJECT_MOVE_REF(packet_context_type, packet_context_type_copy);
+               BT_CTF_OBJECT_MOVE_REF(event_header_type, event_header_type_copy);
+               BT_CTF_OBJECT_MOVE_REF(stream_event_ctx_type, stream_event_ctx_type_copy);
+
+               /* Validate stream class field types */
+               valid_ret = validate_stream_class_types(environment,
+                       packet_header_type, packet_context_type,
+                       event_header_type, stream_event_ctx_type);
+               if (valid_ret == 0) {
+                       /* Stream class is valid */
+                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_STREAM;
+               }
+
+               goto sc_validation_done;
+
+sc_validation_error:
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type_copy);
+               ret = -1;
+               goto error;
+       }
+
+sc_validation_done:
+       /* Validate event class */
+       if ((validate_flags & BT_CTF_VALIDATION_FLAG_EVENT) &&
+                       !event_class_valid) {
+               struct bt_ctf_field_type_common *event_context_type_copy = NULL;
+               struct bt_ctf_field_type_common *event_payload_type_copy = NULL;
+
+               if (event_context_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       event_context_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               event_context_type_copy = event_context_type;
+                               bt_ctf_object_get_ref(event_context_type_copy);
+                               goto skip_event_context_type_copy;
+                       }
+
+                       BT_LOGV_STR("Copying event context field type because it contains at least one sequence or variant field type.");
+                       event_context_type_copy =
+                               copy_field_type_func(event_context_type);
+                       if (!event_context_type_copy) {
+                               BT_LOGE_STR("Cannot copy event context field type.");
+                               goto ec_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_common_freeze(event_context_type_copy);
+               }
+
+skip_event_context_type_copy:
+               if (event_payload_type) {
+                       contains_seq_var =
+                               field_type_contains_sequence_or_variant_ft(
+                                       event_payload_type);
+                       if (contains_seq_var < 0) {
+                               ret = contains_seq_var;
+                               goto error;
+                       } else if (!contains_seq_var) {
+                               /* No copy is needed */
+                               event_payload_type_copy = event_payload_type;
+                               bt_ctf_object_get_ref(event_payload_type_copy);
+                               goto skip_event_payload_type_copy;
+                       }
+
+                       BT_LOGV_STR("Copying event payload field type because it contains at least one sequence or variant field type.");
+                       event_payload_type_copy =
+                               copy_field_type_func(event_payload_type);
+                       if (!event_payload_type_copy) {
+                               BT_LOGE_STR("Cannot copy event payload field type.");
+                               goto ec_validation_error;
+                       }
+
+                       /*
+                        * Freeze this copy: if it's returned to the
+                        * caller, it cannot be modified any way since
+                        * it will be resolved.
+                        */
+                       bt_ctf_field_type_common_freeze(event_payload_type_copy);
+               }
+
+skip_event_payload_type_copy:
+               /* Put original references and move copies */
+               BT_CTF_OBJECT_MOVE_REF(event_context_type, event_context_type_copy);
+               BT_CTF_OBJECT_MOVE_REF(event_payload_type, event_payload_type_copy);
+
+               /* Validate event class field types */
+               valid_ret = validate_event_class_types(environment,
+                       packet_header_type, packet_context_type,
+                       event_header_type, stream_event_ctx_type,
+                       event_context_type, event_payload_type);
+               if (valid_ret == 0) {
+                       /* Event class is valid */
+                       output->valid_flags |= BT_CTF_VALIDATION_FLAG_EVENT;
+               }
+
+               goto ec_validation_done;
+
+ec_validation_error:
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type_copy);
+               ret = -1;
+               goto error;
+       }
+
+ec_validation_done:
+       /*
+        * Validation is complete. Move the field types that were used
+        * to validate (and that were possibly altered by the validation
+        * process) to the output values.
+        */
+       BT_CTF_OBJECT_MOVE_REF(output->packet_header_type, packet_header_type);
+       BT_CTF_OBJECT_MOVE_REF(output->packet_context_type, packet_context_type);
+       BT_CTF_OBJECT_MOVE_REF(output->event_header_type, event_header_type);
+       BT_CTF_OBJECT_MOVE_REF(output->stream_event_ctx_type, stream_event_ctx_type);
+       BT_CTF_OBJECT_MOVE_REF(output->event_context_type, event_context_type);
+       BT_CTF_OBJECT_MOVE_REF(output->event_payload_type, event_payload_type);
+       return ret;
+
+error:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_header_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(packet_context_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_header_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(stream_event_ctx_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_context_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(event_payload_type);
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_validation_replace_types(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag replace_flags)
+{
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_TRACE) && trace) {
+               bt_ctf_field_type_common_freeze(trace->packet_header_field_type);
+               BT_CTF_OBJECT_MOVE_REF(trace->packet_header_field_type,
+                       output->packet_header_type);
+       }
+
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_STREAM) && stream_class) {
+               bt_ctf_field_type_common_freeze(stream_class->packet_context_field_type);
+               bt_ctf_field_type_common_freeze(stream_class->event_header_field_type);
+               bt_ctf_field_type_common_freeze(stream_class->event_context_field_type);
+               BT_CTF_OBJECT_MOVE_REF(stream_class->packet_context_field_type,
+                       output->packet_context_type);
+               BT_CTF_OBJECT_MOVE_REF(stream_class->event_header_field_type,
+                       output->event_header_type);
+               BT_CTF_OBJECT_MOVE_REF(stream_class->event_context_field_type,
+                       output->stream_event_ctx_type);
+       }
+
+       if ((replace_flags & BT_CTF_VALIDATION_FLAG_EVENT) && event_class) {
+               bt_ctf_field_type_common_freeze(event_class->context_field_type);
+               bt_ctf_field_type_common_freeze(event_class->payload_field_type);
+               BT_CTF_OBJECT_MOVE_REF(event_class->context_field_type, output->event_context_type);
+               BT_CTF_OBJECT_MOVE_REF(event_class->payload_field_type, output->event_payload_type);
+       }
+}
+
+BT_HIDDEN
+void bt_ctf_validation_output_put_types(
+               struct bt_ctf_validation_output *output)
+{
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_header_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->packet_context_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_header_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->stream_event_ctx_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_context_type);
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(output->event_payload_type);
+}
diff --git a/src/ctf-writer/validation.h b/src/ctf-writer/validation.h
new file mode 100644 (file)
index 0000000..18e6ff7
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef BABELTRACE_CTF_WRITER_VALIDATION_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_VALIDATION_INTERNAL_H
+
+/*
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+
+#include "values.h"
+
+struct bt_ctf_trace_common;
+struct bt_ctf_stream_class_common;
+struct bt_ctf_event_class_common;
+struct bt_ctf_field_type_common;
+
+typedef struct bt_ctf_field_type_common *(*bt_ctf_validation_flag_copy_field_type_func)(
+               struct bt_ctf_field_type_common *);
+
+enum bt_ctf_validation_flag {
+       BT_CTF_VALIDATION_FLAG_TRACE    = 1,
+       BT_CTF_VALIDATION_FLAG_STREAM   = 2,
+       BT_CTF_VALIDATION_FLAG_EVENT    = 4,
+};
+
+/*
+ * Validation output structure.
+ *
+ * This is where the results of the validation function go. The field
+ * types are the validated ones which should replace the original field
+ * types of a trace, a stream class, and an event class.
+ *
+ * `valid_flags` contains the results of the validation.
+ */
+struct bt_ctf_validation_output {
+       struct bt_ctf_field_type_common *packet_header_type;
+       struct bt_ctf_field_type_common *packet_context_type;
+       struct bt_ctf_field_type_common *event_header_type;
+       struct bt_ctf_field_type_common *stream_event_ctx_type;
+       struct bt_ctf_field_type_common *event_context_type;
+       struct bt_ctf_field_type_common *event_payload_type;
+       enum bt_ctf_validation_flag valid_flags;
+};
+
+/*
+ * This function resolves and validates the field types of an event
+ * class, a stream class, and a trace. Copies are created if needed
+ * and the resulting field types to use are placed in the `output`
+ * validation structure, which also contains the results of the
+ * validation. Copies can replace the original field types of a trace,
+ * a stream class, and an event class using
+ * bt_ctf_validation_replace_types().
+ *
+ * The current known validity of the field types of the trace,
+ * stream class, and event class must be indicated with the
+ * `trace_valid`, `stream_class_valid`, and `event_class_valid`
+ * parameters. If a class is valid, its field types are not copied,
+ * validated, or resolved during this call.
+ *
+ * The validation flags `validate_flags` indicate which classes should
+ * have their field types validated.
+ *
+ * All parameters are owned by the caller.
+ */
+BT_HIDDEN
+int bt_ctf_validate_class_types(struct bt_ctf_private_value *environment,
+               struct bt_ctf_field_type_common *packet_header_type,
+               struct bt_ctf_field_type_common *packet_context_type,
+               struct bt_ctf_field_type_common *event_header_type,
+               struct bt_ctf_field_type_common *stream_event_ctx_type,
+               struct bt_ctf_field_type_common *event_context_type,
+               struct bt_ctf_field_type_common *event_payload_type,
+               int trace_valid, int stream_class_valid, int event_class_valid,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag validate_flags,
+               bt_ctf_validation_flag_copy_field_type_func copy_field_type_func);
+
+/*
+ * This function replaces the actual field types of a trace, a stream
+ * class, and an event class with the appropriate field types contained
+ * in a validation output structure.
+ *
+ * The replace flags `replace_flags` indicate which classes should have
+ * their field types replaced.
+ *
+ * Note that the field types that are not used in the validation output
+ * structure are still owned by it at the end of this call.
+ * bt_ctf_validation_output_put_types() should be called to clean the
+ * structure.
+ *
+ * All parameters are owned by the caller.
+ */
+BT_HIDDEN
+void bt_ctf_validation_replace_types(struct bt_ctf_trace_common *trace,
+               struct bt_ctf_stream_class_common *stream_class,
+               struct bt_ctf_event_class_common *event_class,
+               struct bt_ctf_validation_output *output,
+               enum bt_ctf_validation_flag replace_flags);
+
+/*
+ * This function puts all the field types contained in a given
+ * validation output structure.
+ *
+ * `output` is owned by the caller and is not freed here.
+ */
+BT_HIDDEN
+void bt_ctf_validation_output_put_types(
+               struct bt_ctf_validation_output *output);
+
+#endif /* BABELTRACE_CTF_WRITER_VALIDATION_INTERNAL_H */
diff --git a/src/ctf-writer/values.c b/src/ctf-writer/values.c
new file mode 100644 (file)
index 0000000..fb5ffa6
--- /dev/null
@@ -0,0 +1,1345 @@
+/*
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER-VALUES"
+#include "logging.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <babeltrace2/ctf-writer/object.h>
+#include <babeltrace2/types.h>
+
+#include "common/assert.h"
+#include "common/common.h"
+#include "compat/compiler.h"
+#include "compat/glib.h"
+
+#include "assert-pre.h"
+#include "object.h"
+#include "values.h"
+
+#define BT_CTF_VALUE_FROM_CONCRETE(_concrete) ((struct bt_ctf_value *) (_concrete))
+#define BT_CTF_VALUE_TO_BOOL(_base) ((struct bt_ctf_value_bool *) (_base))
+#define BT_CTF_VALUE_TO_INTEGER(_base) ((struct bt_ctf_value_integer *) (_base))
+#define BT_CTF_VALUE_TO_REAL(_base) ((struct bt_ctf_value_real *) (_base))
+#define BT_CTF_VALUE_TO_STRING(_base) ((struct bt_ctf_value_string *) (_base))
+#define BT_CTF_VALUE_TO_ARRAY(_base) ((struct bt_ctf_value_array *) (_base))
+#define BT_CTF_VALUE_TO_MAP(_base) ((struct bt_ctf_value_map *) (_base))
+
+#define BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(_value, _type)                 \
+       BT_CTF_ASSERT_PRE(((struct bt_ctf_value *) (_value))->type == (_type),  \
+               "Value has the wrong type ID: expected-type=%d", (_type))
+
+#define BT_CTF_ASSERT_PRE_VALUE_HOT(_value, _name)                             \
+       BT_CTF_ASSERT_PRE_HOT(((struct bt_ctf_value *) (_value)), (_name), "")
+
+#define BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count)                \
+       BT_CTF_ASSERT_PRE((_index) < (_count),                          \
+               "Index is out of bound: "                               \
+               "index=%" PRIu64 ", count=%u", (_index), (_count));
+
+struct bt_ctf_value {
+       struct bt_ctf_object base;
+       enum bt_ctf_value_type type;
+       bt_bool frozen;
+};
+
+static
+void bt_ctf_value_null_instance_release_func(struct bt_ctf_object *obj)
+{
+       BT_LOGW("Releasing the null value singleton: addr=%p", obj);
+}
+
+static
+struct bt_ctf_value bt_ctf_value_null_instance = {
+       .base = {
+               .is_shared = true,
+               .ref_count = 1,
+               .release_func = bt_ctf_value_null_instance_release_func,
+               .spec_release_func = NULL,
+               .parent_is_owner_listener_func = NULL,
+               .parent = NULL,
+       },
+       .type = BT_CTF_VALUE_TYPE_NULL,
+       .frozen = BT_TRUE,
+};
+
+struct bt_ctf_value *const bt_ctf_value_null = &bt_ctf_value_null_instance;
+struct bt_ctf_private_value *const bt_ctf_private_value_null =
+       (void *) &bt_ctf_value_null_instance;
+
+struct bt_ctf_value_bool {
+       struct bt_ctf_value base;
+       bt_bool value;
+};
+
+struct bt_ctf_value_integer {
+       struct bt_ctf_value base;
+       int64_t value;
+};
+
+struct bt_ctf_value_real {
+       struct bt_ctf_value base;
+       double value;
+};
+
+struct bt_ctf_value_string {
+       struct bt_ctf_value base;
+       GString *gstr;
+};
+
+struct bt_ctf_value_array {
+       struct bt_ctf_value base;
+       GPtrArray *garray;
+};
+
+struct bt_ctf_value_map {
+       struct bt_ctf_value base;
+       GHashTable *ght;
+};
+
+static
+void bt_ctf_value_destroy(struct bt_ctf_object *obj);
+
+static
+void bt_ctf_value_string_destroy(struct bt_ctf_value *object)
+{
+       g_string_free(BT_CTF_VALUE_TO_STRING(object)->gstr, TRUE);
+       BT_CTF_VALUE_TO_STRING(object)->gstr = NULL;
+}
+
+static
+void bt_ctf_value_array_destroy(struct bt_ctf_value *object)
+{
+       /*
+        * Pointer array's registered value destructor will take care
+        * of putting each contained object.
+        */
+       g_ptr_array_free(BT_CTF_VALUE_TO_ARRAY(object)->garray, TRUE);
+       BT_CTF_VALUE_TO_ARRAY(object)->garray = NULL;
+}
+
+static
+void bt_ctf_value_map_destroy(struct bt_ctf_value *object)
+{
+       /*
+        * Hash table's registered value destructor will take care of
+        * putting each contained object. Keys are GQuarks and cannot
+        * be destroyed anyway.
+        */
+       g_hash_table_destroy(BT_CTF_VALUE_TO_MAP(object)->ght);
+       BT_CTF_VALUE_TO_MAP(object)->ght = NULL;
+}
+
+static
+void (* const destroy_funcs[])(struct bt_ctf_value *) = {
+       [BT_CTF_VALUE_TYPE_NULL] =              NULL,
+       [BT_CTF_VALUE_TYPE_BOOL] =              NULL,
+       [BT_CTF_VALUE_TYPE_INTEGER] =   NULL,
+       [BT_CTF_VALUE_TYPE_REAL] =              NULL,
+       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_destroy,
+       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_destroy,
+       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_destroy,
+};
+
+static
+struct bt_ctf_private_value *bt_ctf_value_null_copy(const struct bt_ctf_value *null_obj)
+{
+       return (void *) bt_ctf_value_null;
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_bool_copy(const struct bt_ctf_value *bool_obj)
+{
+       return bt_ctf_private_value_bool_create_init(
+               BT_CTF_VALUE_TO_BOOL(bool_obj)->value);
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_integer_copy(
+               const struct bt_ctf_value *integer_obj)
+{
+       return bt_ctf_private_value_integer_create_init(
+               BT_CTF_VALUE_TO_INTEGER(integer_obj)->value);
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_real_copy(const struct bt_ctf_value *real_obj)
+{
+       return bt_ctf_private_value_real_create_init(
+               BT_CTF_VALUE_TO_REAL(real_obj)->value);
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_string_copy(const struct bt_ctf_value *string_obj)
+{
+       return bt_ctf_private_value_string_create_init(
+               BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str);
+}
+
+static
+struct bt_ctf_private_value *bt_ctf_value_array_copy(const struct bt_ctf_value *array_obj)
+{
+       int i;
+       int ret;
+       struct bt_ctf_private_value *copy_obj;
+       struct bt_ctf_value_array *typed_array_obj;
+
+       BT_LOGD("Copying array value: addr=%p", array_obj);
+       typed_array_obj = BT_CTF_VALUE_TO_ARRAY(array_obj);
+       copy_obj = bt_ctf_private_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_ctf_private_value *element_obj_copy = NULL;
+               struct bt_ctf_value *element_obj =
+                       bt_ctf_value_array_borrow_element_by_index(
+                               array_obj, i);
+
+               BT_ASSERT(element_obj);
+               BT_LOGD("Copying array value's element: element-addr=%p, "
+                       "index=%d", element_obj, i);
+               ret = bt_ctf_value_copy(&element_obj_copy, element_obj);
+               if (ret) {
+                       BT_LOGE("Cannot copy array value's element: "
+                               "array-addr=%p, index=%d",
+                               array_obj, i);
+                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
+                       goto end;
+               }
+
+               BT_ASSERT(element_obj_copy);
+               ret = bt_ctf_private_value_array_append_element(copy_obj,
+                       (void *) element_obj_copy);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(element_obj_copy);
+               if (ret) {
+                       BT_LOGE("Cannot append to array value: addr=%p",
+                               array_obj);
+                       BT_CTF_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_ctf_private_value *bt_ctf_value_map_copy(const struct bt_ctf_value *map_obj)
+{
+       int ret;
+       GHashTableIter iter;
+       gpointer key, element_obj;
+       struct bt_ctf_private_value *copy_obj;
+       struct bt_ctf_private_value *element_obj_copy = NULL;
+       struct bt_ctf_value_map *typed_map_obj;
+
+       BT_LOGD("Copying map value: addr=%p", map_obj);
+       typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj);
+       copy_obj = bt_ctf_private_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_ctf_value_copy(&element_obj_copy, element_obj);
+               if (ret) {
+                       BT_LOGE("Cannot copy map value's element: "
+                               "map-addr=%p, key=\"%s\"",
+                               map_obj, key_str);
+                       BT_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
+                       goto end;
+               }
+
+               BT_ASSERT(element_obj_copy);
+               ret = bt_ctf_private_value_map_insert_entry(copy_obj, key_str,
+                       (void *) element_obj_copy);
+               BT_CTF_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_CTF_OBJECT_PUT_REF_AND_RESET(copy_obj);
+                       goto end;
+               }
+       }
+
+       BT_LOGD("Copied map value: addr=%p", map_obj);
+
+end:
+       return copy_obj;
+}
+
+static
+struct bt_ctf_private_value *(* const copy_funcs[])(const struct bt_ctf_value *) = {
+       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_copy,
+       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_bool_copy,
+       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_integer_copy,
+       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_real_copy,
+       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_copy,
+       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_copy,
+       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_copy,
+};
+
+static
+bt_bool bt_ctf_value_null_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       /*
+        * Always BT_TRUE since bt_ctf_value_compare() already checks if both
+        * object_a and object_b have the same type, and in the case of
+        * null value objects, they're always the same if it is so.
+        */
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_bool_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       if (BT_CTF_VALUE_TO_BOOL(object_a)->value !=
+                       BT_CTF_VALUE_TO_BOOL(object_b)->value) {
+               BT_LOGV("Boolean value objects are different: "
+                       "bool-a-val=%d, bool-b-val=%d",
+                       BT_CTF_VALUE_TO_BOOL(object_a)->value,
+                       BT_CTF_VALUE_TO_BOOL(object_b)->value);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_integer_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       if (BT_CTF_VALUE_TO_INTEGER(object_a)->value !=
+                       BT_CTF_VALUE_TO_INTEGER(object_b)->value) {
+               BT_LOGV("Integer value objects are different: "
+                       "int-a-val=%" PRId64 ", int-b-val=%" PRId64,
+                       BT_CTF_VALUE_TO_INTEGER(object_a)->value,
+                       BT_CTF_VALUE_TO_INTEGER(object_b)->value);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_real_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       if (BT_CTF_VALUE_TO_REAL(object_a)->value !=
+                       BT_CTF_VALUE_TO_REAL(object_b)->value) {
+               BT_LOGV("Real number value objects are different: "
+                       "real-a-val=%f, real-b-val=%f",
+                       BT_CTF_VALUE_TO_REAL(object_a)->value,
+                       BT_CTF_VALUE_TO_REAL(object_b)->value);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_string_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       if (strcmp(BT_CTF_VALUE_TO_STRING(object_a)->gstr->str,
+                       BT_CTF_VALUE_TO_STRING(object_b)->gstr->str) != 0) {
+               BT_LOGV("String value objects are different: "
+                       "string-a-val=\"%s\", string-b-val=\"%s\"",
+                       BT_CTF_VALUE_TO_STRING(object_a)->gstr->str,
+                       BT_CTF_VALUE_TO_STRING(object_b)->gstr->str);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_ctf_value_array_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       int i;
+       bt_bool ret = BT_TRUE;
+       const struct bt_ctf_value_array *array_obj_a =
+               BT_CTF_VALUE_TO_ARRAY(object_a);
+
+       if (bt_ctf_value_array_get_size(object_a) !=
+                       bt_ctf_value_array_get_size(object_b)) {
+               BT_LOGV("Array values are different: size mismatch "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
+                       object_a, object_b,
+                       bt_ctf_value_array_get_size(object_a),
+                       bt_ctf_value_array_get_size(object_b));
+               ret = BT_FALSE;
+               goto end;
+       }
+
+       for (i = 0; i < array_obj_a->garray->len; ++i) {
+               struct bt_ctf_value *element_obj_a;
+               struct bt_ctf_value *element_obj_b;
+
+               element_obj_a = bt_ctf_value_array_borrow_element_by_index(
+                       object_a, i);
+               element_obj_b = bt_ctf_value_array_borrow_element_by_index(
+                       object_b, i);
+
+               if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) {
+                       BT_LOGV("Array values's elements are different: "
+                               "value-a-addr=%p, value-b-addr=%p, index=%d",
+                               element_obj_a, element_obj_b, i);
+                       ret = BT_FALSE;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_bool bt_ctf_value_map_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b)
+{
+       bt_bool ret = BT_TRUE;
+       GHashTableIter iter;
+       gpointer key, element_obj_a;
+       const struct bt_ctf_value_map *map_obj_a = BT_CTF_VALUE_TO_MAP(object_a);
+
+       if (bt_ctf_value_map_get_size(object_a) !=
+                       bt_ctf_value_map_get_size(object_b)) {
+               BT_LOGV("Map values are different: size mismatch "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
+                       object_a, object_b,
+                       bt_ctf_value_map_get_size(object_a),
+                       bt_ctf_value_map_get_size(object_b));
+               ret = BT_FALSE;
+               goto end;
+       }
+
+       g_hash_table_iter_init(&iter, map_obj_a->ght);
+
+       while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) {
+               struct bt_ctf_value *element_obj_b;
+               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
+
+               element_obj_b = bt_ctf_value_map_borrow_entry_value(object_b,
+                       key_str);
+
+               if (!bt_ctf_value_compare(element_obj_a, element_obj_b)) {
+                       BT_LOGV("Map values's elements are different: "
+                               "value-a-addr=%p, value-b-addr=%p, key=\"%s\"",
+                               element_obj_a, element_obj_b, key_str);
+                       ret = BT_FALSE;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_bool (* const compare_funcs[])(const struct bt_ctf_value *,
+               const struct bt_ctf_value *) = {
+       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_compare,
+       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_bool_compare,
+       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_integer_compare,
+       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_real_compare,
+       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_string_compare,
+       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_compare,
+       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_compare,
+};
+
+static
+void bt_ctf_value_null_freeze(struct bt_ctf_value *object)
+{
+}
+
+static
+void bt_ctf_value_generic_freeze(struct bt_ctf_value *object)
+{
+       object->frozen = BT_TRUE;
+}
+
+static
+void bt_ctf_value_array_freeze(struct bt_ctf_value *object)
+{
+       int i;
+       struct bt_ctf_value_array *typed_array_obj =
+               BT_CTF_VALUE_TO_ARRAY(object);
+
+       for (i = 0; i < typed_array_obj->garray->len; ++i) {
+               bt_ctf_value_freeze(g_ptr_array_index(typed_array_obj->garray, i));
+       }
+
+       bt_ctf_value_generic_freeze(object);
+}
+
+static
+void bt_ctf_value_map_freeze(struct bt_ctf_value *object)
+{
+       GHashTableIter iter;
+       gpointer key, element_obj;
+       const struct bt_ctf_value_map *map_obj = BT_CTF_VALUE_TO_MAP(object);
+
+       g_hash_table_iter_init(&iter, map_obj->ght);
+
+       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
+               bt_ctf_value_freeze(element_obj);
+       }
+
+       bt_ctf_value_generic_freeze(object);
+}
+
+static
+void (* const freeze_funcs[])(struct bt_ctf_value *) = {
+       [BT_CTF_VALUE_TYPE_NULL] =              bt_ctf_value_null_freeze,
+       [BT_CTF_VALUE_TYPE_BOOL] =              bt_ctf_value_generic_freeze,
+       [BT_CTF_VALUE_TYPE_INTEGER] =   bt_ctf_value_generic_freeze,
+       [BT_CTF_VALUE_TYPE_REAL] =              bt_ctf_value_generic_freeze,
+       [BT_CTF_VALUE_TYPE_STRING] =    bt_ctf_value_generic_freeze,
+       [BT_CTF_VALUE_TYPE_ARRAY] =             bt_ctf_value_array_freeze,
+       [BT_CTF_VALUE_TYPE_MAP] =               bt_ctf_value_map_freeze,
+};
+
+static
+void bt_ctf_value_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_value *value;
+
+       value = container_of(obj, struct bt_ctf_value, base);
+       BT_LOGD("Destroying value: addr=%p", value);
+
+       if (bt_ctf_value_is_null(value)) {
+               BT_LOGD_STR("Not destroying the null value singleton.");
+               return;
+       }
+
+       if (destroy_funcs[value->type]) {
+               destroy_funcs[value->type](value);
+       }
+
+       g_free(value);
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status _bt_ctf_value_freeze(struct bt_ctf_value *object)
+{
+       enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK;
+
+       BT_ASSERT(object);
+
+       if (object->frozen) {
+               goto end;
+       }
+
+       BT_LOGD("Freezing value: addr=%p", object);
+       freeze_funcs[object->type](object);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_type bt_ctf_value_get_type(const struct bt_ctf_value *object)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(object, "Value object");
+       return object->type;
+}
+
+static
+struct bt_ctf_value bt_ctf_value_create_base(enum bt_ctf_value_type type)
+{
+       struct bt_ctf_value value;
+
+       value.type = type;
+       value.frozen = BT_FALSE;
+       bt_ctf_object_init_shared(&value.base, bt_ctf_value_destroy);
+       return value;
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_bool_create_init(bt_bool val)
+{
+       struct bt_ctf_value_bool *bool_obj;
+
+       BT_LOGD("Creating boolean value object: val=%d", val);
+       bool_obj = g_new0(struct bt_ctf_value_bool, 1);
+       if (!bool_obj) {
+               BT_LOGE_STR("Failed to allocate one boolean value object.");
+               goto end;
+       }
+
+       bool_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_BOOL);
+       bool_obj->value = val;
+       BT_LOGD("Created boolean value object: addr=%p", bool_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(bool_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_bool_create(void)
+{
+       return bt_ctf_private_value_bool_create_init(BT_FALSE);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_integer_create_init(int64_t val)
+{
+       struct bt_ctf_value_integer *integer_obj;
+
+       BT_LOGD("Creating integer value object: val=%" PRId64, val);
+       integer_obj = g_new0(struct bt_ctf_value_integer, 1);
+       if (!integer_obj) {
+               BT_LOGE_STR("Failed to allocate one integer value object.");
+               goto end;
+       }
+
+       integer_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_INTEGER);
+       integer_obj->value = val;
+       BT_LOGD("Created integer value object: addr=%p",
+               integer_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(integer_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_integer_create(void)
+{
+       return bt_ctf_private_value_integer_create_init(0);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_real_create_init(double val)
+{
+       struct bt_ctf_value_real *real_obj;
+
+       BT_LOGD("Creating real number value object: val=%f", val);
+       real_obj = g_new0(struct bt_ctf_value_real, 1);
+       if (!real_obj) {
+               BT_LOGE_STR("Failed to allocate one real number value object.");
+               goto end;
+       }
+
+       real_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_REAL);
+       real_obj->value = val;
+       BT_LOGD("Created real number value object: addr=%p",
+               real_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(real_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_real_create(void)
+{
+       return bt_ctf_private_value_real_create_init(0.);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_string_create_init(const char *val)
+{
+       struct bt_ctf_value_string *string_obj = NULL;
+
+       if (!val) {
+               BT_LOGW_STR("Invalid parameter: value is NULL.");
+               goto end;
+       }
+
+       BT_LOGD("Creating string value object: val-len=%zu", strlen(val));
+       string_obj = g_new0(struct bt_ctf_value_string, 1);
+       if (!string_obj) {
+               BT_LOGE_STR("Failed to allocate one string object.");
+               goto end;
+       }
+
+       string_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_STRING);
+       string_obj->gstr = g_string_new(val);
+       if (!string_obj->gstr) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               g_free(string_obj);
+               string_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created string value object: addr=%p",
+               string_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(string_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_string_create(void)
+{
+       return bt_ctf_private_value_string_create_init("");
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_array_create(void)
+{
+       struct bt_ctf_value_array *array_obj;
+
+       BT_LOGD_STR("Creating empty array value object.");
+       array_obj = g_new0(struct bt_ctf_value_array, 1);
+       if (!array_obj) {
+               BT_LOGE_STR("Failed to allocate one array object.");
+               goto end;
+       }
+
+       array_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_ARRAY);
+       array_obj->garray = bt_g_ptr_array_new_full(0,
+               (GDestroyNotify) bt_ctf_object_put_ref);
+       if (!array_obj->garray) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               g_free(array_obj);
+               array_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created array value object: addr=%p",
+               array_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(array_obj);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_map_create(void)
+{
+       struct bt_ctf_value_map *map_obj;
+
+       BT_LOGD_STR("Creating empty map value object.");
+       map_obj = g_new0(struct bt_ctf_value_map, 1);
+       if (!map_obj) {
+               BT_LOGE_STR("Failed to allocate one map object.");
+               goto end;
+       }
+
+       map_obj->base = bt_ctf_value_create_base(BT_CTF_VALUE_TYPE_MAP);
+       map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+               NULL, (GDestroyNotify) bt_ctf_object_put_ref);
+       if (!map_obj->ght) {
+               BT_LOGE_STR("Failed to allocate a GHashTable.");
+               g_free(map_obj);
+               map_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created map value object: addr=%p",
+               map_obj);
+
+end:
+       return (void *) BT_CTF_VALUE_FROM_CONCRETE(map_obj);
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_value_bool_get(const struct bt_ctf_value *bool_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL);
+       return BT_CTF_VALUE_TO_BOOL(bool_obj)->value;
+}
+
+BT_HIDDEN
+void bt_ctf_private_value_bool_set(struct bt_ctf_private_value *bool_obj, bt_bool val)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_CTF_VALUE_TYPE_BOOL);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object");
+       BT_CTF_VALUE_TO_BOOL(bool_obj)->value = val;
+       BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d",
+               bool_obj, val);
+}
+
+BT_HIDDEN
+int64_t bt_ctf_value_integer_get(const struct bt_ctf_value *integer_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER);
+       return BT_CTF_VALUE_TO_INTEGER(integer_obj)->value;
+}
+
+BT_HIDDEN
+void bt_ctf_private_value_integer_set(struct bt_ctf_private_value *integer_obj,
+               int64_t val)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, BT_CTF_VALUE_TYPE_INTEGER);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object");
+       BT_CTF_VALUE_TO_INTEGER(integer_obj)->value = val;
+       BT_LOGV("Set integer value's raw value: value-addr=%p, value=%" PRId64,
+               integer_obj, val);
+}
+
+BT_HIDDEN
+double bt_ctf_value_real_get(const struct bt_ctf_value *real_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(real_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL);
+       return BT_CTF_VALUE_TO_REAL(real_obj)->value;
+}
+
+BT_HIDDEN
+void bt_ctf_private_value_real_set(struct bt_ctf_private_value *real_obj, double val)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(real_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_CTF_VALUE_TYPE_REAL);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(real_obj, "Value object");
+       BT_CTF_VALUE_TO_REAL(real_obj)->value = val;
+       BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f",
+               real_obj, val);
+}
+
+BT_HIDDEN
+const char *bt_ctf_value_string_get(const struct bt_ctf_value *string_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(string_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING);
+       return BT_CTF_VALUE_TO_STRING(string_obj)->gstr->str;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_string_set(
+               struct bt_ctf_private_value *string_obj, const char *val)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(string_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_CTF_VALUE_TYPE_STRING);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(string_obj, "Value object");
+       g_string_assign(BT_CTF_VALUE_TO_STRING(string_obj)->gstr, val);
+       BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p",
+               string_obj, val);
+       return BT_CTF_VALUE_STATUS_OK;
+}
+
+BT_HIDDEN
+uint64_t bt_ctf_value_array_get_size(const struct bt_ctf_value *array_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
+       return (uint64_t) BT_CTF_VALUE_TO_ARRAY(array_obj)->garray->len;
+}
+
+BT_HIDDEN
+struct bt_ctf_value *bt_ctf_value_array_borrow_element_by_index(
+               const struct bt_ctf_value *array_obj,
+               uint64_t index)
+{
+       struct bt_ctf_value_array *typed_array_obj =
+               BT_CTF_VALUE_TO_ARRAY(array_obj);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
+       BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
+               typed_array_obj->garray->len);
+       return g_ptr_array_index(typed_array_obj->garray, index);
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_array_borrow_element_by_index(
+               const struct bt_ctf_private_value *array_obj,
+               uint64_t index)
+{
+       return (void *) bt_ctf_value_array_borrow_element_by_index(
+               (void *) array_obj, index);
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_element(
+               struct bt_ctf_private_value *array_obj,
+               struct bt_ctf_value *element_obj)
+{
+       struct bt_ctf_value_array *typed_array_obj =
+               BT_CTF_VALUE_TO_ARRAY(array_obj);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
+       g_ptr_array_add(typed_array_obj->garray, element_obj);
+       bt_ctf_object_get_ref(element_obj);
+       BT_LOGV("Appended element to array value: array-value-addr=%p, "
+               "element-value-addr=%p, new-size=%u",
+               array_obj, element_obj, typed_array_obj->garray->len);
+       return BT_CTF_VALUE_STATUS_OK;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_bool_element(
+               struct bt_ctf_private_value *array_obj, bt_bool val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *bool_obj = NULL;
+
+       bool_obj = bt_ctf_private_value_bool_create_init(val);
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) bool_obj);
+       bt_ctf_object_put_ref(bool_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_integer_element(
+               struct bt_ctf_private_value *array_obj, int64_t val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *integer_obj = NULL;
+
+       integer_obj = bt_ctf_private_value_integer_create_init(val);
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) integer_obj);
+       bt_ctf_object_put_ref(integer_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_real_element(
+               struct bt_ctf_private_value *array_obj, double val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *real_obj = NULL;
+
+       real_obj = bt_ctf_private_value_real_create_init(val);
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) real_obj);
+       bt_ctf_object_put_ref(real_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_string_element(
+               struct bt_ctf_private_value *array_obj, const char *val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *string_obj = NULL;
+
+       string_obj = bt_ctf_private_value_string_create_init(val);
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) string_obj);
+       bt_ctf_object_put_ref(string_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_array_element(
+               struct bt_ctf_private_value *array_obj)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *empty_array_obj = NULL;
+
+       empty_array_obj = bt_ctf_private_value_array_create();
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) empty_array_obj);
+       bt_ctf_object_put_ref(empty_array_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_map_element(
+               struct bt_ctf_private_value *array_obj)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *map_obj = NULL;
+
+       map_obj = bt_ctf_private_value_map_create();
+       ret = bt_ctf_private_value_array_append_element(array_obj,
+               (void *) map_obj);
+       bt_ctf_object_put_ref(map_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_set_element_by_index(
+               struct bt_ctf_private_value *array_obj, uint64_t index,
+               struct bt_ctf_value *element_obj)
+{
+       struct bt_ctf_value_array *typed_array_obj =
+               BT_CTF_VALUE_TO_ARRAY(array_obj);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_CTF_VALUE_TYPE_ARRAY);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
+       BT_CTF_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
+               typed_array_obj->garray->len);
+       bt_ctf_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index));
+       g_ptr_array_index(typed_array_obj->garray, index) = element_obj;
+       bt_ctf_object_get_ref(element_obj);
+       BT_LOGV("Set array value's element: array-value-addr=%p, "
+               "index=%" PRIu64 ", element-value-addr=%p",
+               array_obj, index, element_obj);
+       return BT_CTF_VALUE_STATUS_OK;
+}
+
+BT_HIDDEN
+uint64_t bt_ctf_value_map_get_size(const struct bt_ctf_value *map_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       return (uint64_t) g_hash_table_size(BT_CTF_VALUE_TO_MAP(map_obj)->ght);
+}
+
+BT_HIDDEN
+struct bt_ctf_value *bt_ctf_value_map_borrow_entry_value(const struct bt_ctf_value *map_obj,
+               const char *key)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       return g_hash_table_lookup(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)));
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_map_borrow_entry_value(
+               const struct bt_ctf_private_value *map_obj, const char *key)
+{
+       return (void *) bt_ctf_value_map_borrow_entry_value((void *) map_obj, key);
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_value_map_has_entry(const struct bt_ctf_value *map_obj, const char *key)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       return bt_g_hash_table_contains(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)));
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_entry(
+               struct bt_ctf_private_value *map_obj,
+               const char *key, struct bt_ctf_value *element_obj)
+{
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Map value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_CTF_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       BT_CTF_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object");
+       g_hash_table_insert(BT_CTF_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)), element_obj);
+       bt_ctf_object_get_ref(element_obj);
+       BT_LOGV("Inserted value into map value: map-value-addr=%p, "
+               "key=\"%s\", element-value-addr=%p",
+               map_obj, key, element_obj);
+       return BT_CTF_VALUE_STATUS_OK;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_bool_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, bt_bool val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *bool_obj = NULL;
+
+       bool_obj = bt_ctf_private_value_bool_create_init(val);
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) bool_obj);
+       bt_ctf_object_put_ref(bool_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_integer_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, int64_t val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *integer_obj = NULL;
+
+       integer_obj = bt_ctf_private_value_integer_create_init(val);
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) integer_obj);
+       bt_ctf_object_put_ref(integer_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_real_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, double val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *real_obj = NULL;
+
+       real_obj = bt_ctf_private_value_real_create_init(val);
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) real_obj);
+       bt_ctf_object_put_ref(real_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_string_entry(
+               struct bt_ctf_private_value *map_obj, const char *key,
+               const char *val)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *string_obj = NULL;
+
+       string_obj = bt_ctf_private_value_string_create_init(val);
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) string_obj);
+       bt_ctf_object_put_ref(string_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_array_entry(
+               struct bt_ctf_private_value *map_obj, const char *key)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *array_obj = NULL;
+
+       array_obj = bt_ctf_private_value_array_create();
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) array_obj);
+       bt_ctf_object_put_ref(array_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_map_entry(
+               struct bt_ctf_private_value *map_obj, const char *key)
+{
+       enum bt_ctf_value_status ret;
+       struct bt_ctf_private_value *empty_map_obj = NULL;
+
+       empty_map_obj = bt_ctf_private_value_map_create();
+       ret = bt_ctf_private_value_map_insert_entry(map_obj, key,
+               (void *) empty_map_obj);
+       bt_ctf_object_put_ref(empty_map_obj);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_map_foreach_entry(const struct bt_ctf_value *map_obj,
+               bt_ctf_value_map_foreach_entry_cb cb, void *data)
+{
+       enum bt_ctf_value_status ret = BT_CTF_VALUE_STATUS_OK;
+       gpointer key, element_obj;
+       GHashTableIter iter;
+       struct bt_ctf_value_map *typed_map_obj = BT_CTF_VALUE_TO_MAP(map_obj);
+
+       BT_CTF_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(cb, "Callback");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_CTF_VALUE_TYPE_MAP);
+       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));
+
+               if (!cb(key_str, element_obj, data)) {
+                       BT_LOGV("User canceled the loop: key=\"%s\", "
+                               "value-addr=%p, data=%p",
+                               key_str, element_obj, data);
+                       ret = BT_CTF_VALUE_STATUS_CANCELED;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_foreach_entry(
+               const struct bt_ctf_private_value *map_obj,
+               bt_ctf_private_value_map_foreach_entry_cb cb, void *data)
+{
+       return bt_ctf_value_map_foreach_entry((void *) map_obj,
+               (bt_ctf_value_map_foreach_entry_cb) cb, data);
+}
+
+struct extend_map_element_data {
+       struct bt_ctf_private_value *extended_obj;
+       enum bt_ctf_value_status status;
+};
+
+static
+bt_bool extend_map_element(const char *key,
+               struct bt_ctf_value *extension_obj_elem, void *data)
+{
+       bt_bool ret = BT_TRUE;
+       struct extend_map_element_data *extend_data = data;
+       struct bt_ctf_private_value *extension_obj_elem_copy = NULL;
+
+       /* Copy object which is to replace the current one */
+       extend_data->status = bt_ctf_value_copy(&extension_obj_elem_copy,
+               extension_obj_elem);
+       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_ctf_private_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_CTF_VALUE_STATUS_OK);
+       ret = BT_FALSE;
+
+end:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(extension_obj_elem_copy);
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_map_extend(
+               struct bt_ctf_private_value **extended_map_obj,
+               const struct bt_ctf_value *base_map_obj,
+               const struct bt_ctf_value *extension_obj)
+{
+       struct extend_map_element_data extend_data = {
+               .extended_obj = NULL,
+               .status = BT_CTF_VALUE_STATUS_OK,
+       };
+
+       BT_CTF_ASSERT_PRE_NON_NULL(base_map_obj, "Base value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(extension_obj, "Extension value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(extended_map_obj,
+               "Extended value object (output)");
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(base_map_obj, BT_CTF_VALUE_TYPE_MAP);
+       BT_CTF_ASSERT_PRE_VALUE_IS_TYPE(extension_obj, BT_CTF_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_ctf_value_copy(extended_map_obj, base_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_ctf_value_map_foreach_entry(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_CTF_OBJECT_PUT_REF_AND_RESET(*extended_map_obj);
+       *extended_map_obj = NULL;
+
+end:
+       return extend_data.status;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_copy(struct bt_ctf_private_value **copy_obj,
+               const struct bt_ctf_value *object)
+{
+       enum bt_ctf_value_status status = BT_CTF_VALUE_STATUS_OK;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(object, "Value object");
+       BT_CTF_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)");
+       BT_LOGD("Copying value object: addr=%p", object);
+       *copy_obj = copy_funcs[object->type](object);
+       if (*copy_obj) {
+               BT_LOGD("Copied value object: copy-value-addr=%p",
+                       copy_obj);
+       } else {
+               status = BT_CTF_VALUE_STATUS_NOMEM;
+               *copy_obj = NULL;
+               BT_LOGE_STR("Failed to copy value object.");
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+bt_bool bt_ctf_value_compare(const struct bt_ctf_value *object_a,
+       const struct bt_ctf_value *object_b)
+{
+       bt_bool ret = BT_FALSE;
+
+       BT_CTF_ASSERT_PRE_NON_NULL(object_a, "Value object A");
+       BT_CTF_ASSERT_PRE_NON_NULL(object_b, "Value object B");
+
+       if (object_a->type != object_b->type) {
+               BT_LOGV("Values are different: type mismatch: "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-type=%d, value-b-type=%d",
+                       object_a, object_b, object_a->type, object_b->type);
+               goto end;
+       }
+
+       ret = compare_funcs[object_a->type](object_a, object_b);
+
+end:
+       return ret;
+}
diff --git a/src/ctf-writer/values.h b/src/ctf-writer/values.h
new file mode 100644 (file)
index 0000000..b9137ef
--- /dev/null
@@ -0,0 +1,357 @@
+#ifndef BABELTRACE_CTF_WRITER_VALUES_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_VALUES_INTERNAL_H
+
+/*
+ * Copyright (c) 2015-2017 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+
+struct bt_ctf_value;
+struct bt_ctf_private_value;
+
+/**
+@brief Status codes.
+*/
+enum bt_ctf_value_status {
+       /// Operation canceled.
+       BT_CTF_VALUE_STATUS_CANCELED    = 125,
+
+       /// Cannot allocate memory.
+       BT_CTF_VALUE_STATUS_NOMEM       = -12,
+
+       /// Okay, no error.
+       BT_CTF_VALUE_STATUS_OK          = 0,
+};
+
+BT_HIDDEN
+enum bt_ctf_value_status _bt_ctf_value_freeze(struct bt_ctf_value *object);
+
+#ifdef BT_DEV_MODE
+# define bt_ctf_value_freeze   _bt_ctf_value_freeze
+#else
+# define bt_ctf_value_freeze(_value)
+#endif /* BT_DEV_MODE */
+
+extern struct bt_ctf_value *const bt_ctf_value_null;
+
+enum bt_ctf_value_type {
+       /// Null value object.
+       BT_CTF_VALUE_TYPE_NULL =                0,
+
+       /// Boolean value object (holds #BT_TRUE or #BT_FALSE).
+       BT_CTF_VALUE_TYPE_BOOL =                1,
+
+       /// Integer value object (holds a signed 64-bit integer raw value).
+       BT_CTF_VALUE_TYPE_INTEGER =             2,
+
+       /// Floating point number value object (holds a \c double raw value).
+       BT_CTF_VALUE_TYPE_REAL =                3,
+
+       /// String value object.
+       BT_CTF_VALUE_TYPE_STRING =              4,
+
+       /// Array value object.
+       BT_CTF_VALUE_TYPE_ARRAY =               5,
+
+       /// Map value object.
+       BT_CTF_VALUE_TYPE_MAP =         6,
+};
+
+BT_HIDDEN
+enum bt_ctf_value_type bt_ctf_value_get_type(const struct bt_ctf_value *object);
+
+static inline
+bt_bool bt_ctf_value_is_null(const struct bt_ctf_value *object)
+{
+       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_NULL;
+}
+
+static inline
+bt_bool bt_ctf_value_is_bool(const struct bt_ctf_value *object)
+{
+       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_BOOL;
+}
+
+static inline
+bt_bool bt_ctf_value_is_integer(const struct bt_ctf_value *object)
+{
+       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_INTEGER;
+}
+
+static inline
+bt_bool bt_ctf_value_is_real(const struct bt_ctf_value *object)
+{
+       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_REAL;
+}
+
+static inline
+bt_bool bt_ctf_value_is_string(const struct bt_ctf_value *object)
+{
+       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_STRING;
+}
+
+static inline
+bt_bool bt_ctf_value_is_array(const struct bt_ctf_value *object)
+{
+       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_ARRAY;
+}
+
+static inline
+bt_bool bt_ctf_value_is_map(const struct bt_ctf_value *object)
+{
+       return bt_ctf_value_get_type(object) == BT_CTF_VALUE_TYPE_MAP;
+}
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_copy(struct bt_ctf_private_value **copy,
+               const struct bt_ctf_value *object);
+
+BT_HIDDEN
+bt_bool bt_ctf_value_compare(const struct bt_ctf_value *object_a,
+               const struct bt_ctf_value *object_b);
+
+BT_HIDDEN
+bt_bool bt_ctf_value_bool_get(const struct bt_ctf_value *bool_obj);
+
+BT_HIDDEN
+int64_t bt_ctf_value_integer_get(const struct bt_ctf_value *integer_obj);
+
+BT_HIDDEN
+double bt_ctf_value_real_get(const struct bt_ctf_value *real_obj);
+
+BT_HIDDEN
+const char *bt_ctf_value_string_get(const struct bt_ctf_value *string_obj);
+
+BT_HIDDEN
+uint64_t bt_ctf_value_array_get_size(const struct bt_ctf_value *array_obj);
+
+static inline
+bt_bool bt_ctf_value_array_is_empty(const struct bt_ctf_value *array_obj)
+{
+       return bt_ctf_value_array_get_size(array_obj) == 0;
+}
+
+BT_HIDDEN
+struct bt_ctf_value *bt_ctf_value_array_borrow_element_by_index(
+               const struct bt_ctf_value *array_obj, uint64_t index);
+
+BT_HIDDEN
+uint64_t bt_ctf_value_map_get_size(const struct bt_ctf_value *map_obj);
+
+static inline
+bt_bool bt_ctf_value_map_is_empty(const struct bt_ctf_value *map_obj)
+{
+       return bt_ctf_value_map_get_size(map_obj) == 0;
+}
+
+BT_HIDDEN
+struct bt_ctf_value *bt_ctf_value_map_borrow_entry_value(
+               const struct bt_ctf_value *map_obj, const char *key);
+
+typedef bt_bool (* bt_ctf_value_map_foreach_entry_cb)(const char *key,
+       struct bt_ctf_value *object, void *data);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_map_foreach_entry(
+               const struct bt_ctf_value *map_obj,
+               bt_ctf_value_map_foreach_entry_cb cb, void *data);
+
+BT_HIDDEN
+bt_bool bt_ctf_value_map_has_entry(const struct bt_ctf_value *map_obj,
+               const char *key);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_value_map_extend(
+               struct bt_ctf_private_value **extended_map_obj,
+               const struct bt_ctf_value *base_map_obj,
+               const struct bt_ctf_value *extension_map_obj);
+
+
+struct bt_ctf_value;
+struct bt_ctf_private_value;
+
+extern struct bt_ctf_private_value *const bt_ctf_private_value_null;
+
+static inline
+struct bt_ctf_value *bt_ctf_private_value_as_value(
+               struct bt_ctf_private_value *priv_value)
+{
+       return (void *) priv_value;
+}
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_bool_create(void);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_bool_create_init(bt_bool val);
+
+BT_HIDDEN
+void bt_ctf_private_value_bool_set(struct bt_ctf_private_value *bool_obj,
+               bt_bool val);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_integer_create(void);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_integer_create_init(
+               int64_t val);
+
+BT_HIDDEN
+void bt_ctf_private_value_integer_set(
+               struct bt_ctf_private_value *integer_obj, int64_t val);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_real_create(void);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_real_create_init(double val);
+
+BT_HIDDEN
+void bt_ctf_private_value_real_set(
+               struct bt_ctf_private_value *real_obj, double val);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_string_create(void);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_string_create_init(
+               const char *val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_string_set(
+               struct bt_ctf_private_value *string_obj,
+               const char *val);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_array_create(void);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_array_borrow_element_by_index(
+               const struct bt_ctf_private_value *array_obj, uint64_t index);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_element(
+               struct bt_ctf_private_value *array_obj,
+               struct bt_ctf_value *element_obj);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_bool_element(
+               struct bt_ctf_private_value *array_obj,
+               bt_bool val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_integer_element(
+               struct bt_ctf_private_value *array_obj,
+               int64_t val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_real_element(
+               struct bt_ctf_private_value *array_obj,
+               double val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_string_element(
+               struct bt_ctf_private_value *array_obj, const char *val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_array_element(
+               struct bt_ctf_private_value *array_obj);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_append_empty_map_element(
+               struct bt_ctf_private_value *array_obj);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_array_set_element_by_index(
+               struct bt_ctf_private_value *array_obj, uint64_t index,
+               struct bt_ctf_value *element_obj);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_map_create(void);
+
+BT_HIDDEN
+struct bt_ctf_private_value *bt_ctf_private_value_map_borrow_entry_value(
+               const struct bt_ctf_private_value *map_obj, const char *key);
+
+typedef bt_bool (* bt_ctf_private_value_map_foreach_entry_cb)(const char *key,
+               struct bt_ctf_private_value *object, void *data);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_foreach_entry(
+               const struct bt_ctf_private_value *map_obj,
+               bt_ctf_private_value_map_foreach_entry_cb cb, void *data);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_entry(
+               struct bt_ctf_private_value *map_obj, const char *key,
+               struct bt_ctf_value *element_obj);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_bool_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, bt_bool val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_integer_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, int64_t val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_real_entry(
+               struct bt_ctf_private_value *map_obj, const char *key, double val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_string_entry(
+               struct bt_ctf_private_value *map_obj, const char *key,
+               const char *val);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_array_entry(
+               struct bt_ctf_private_value *map_obj, const char *key);
+
+BT_HIDDEN
+enum bt_ctf_value_status bt_ctf_private_value_map_insert_empty_map_entry(
+               struct bt_ctf_private_value *map_obj, const char *key);
+
+static inline
+const char *bt_ctf_value_type_string(enum bt_ctf_value_type type)
+{
+       switch (type) {
+       case BT_CTF_VALUE_TYPE_NULL:
+               return "BT_CTF_VALUE_TYPE_NULL";
+       case BT_CTF_VALUE_TYPE_BOOL:
+               return "BT_CTF_VALUE_TYPE_BOOL";
+       case BT_CTF_VALUE_TYPE_INTEGER:
+               return "BT_CTF_VALUE_TYPE_INTEGER";
+       case BT_CTF_VALUE_TYPE_REAL:
+               return "BT_CTF_VALUE_TYPE_REAL";
+       case BT_CTF_VALUE_TYPE_STRING:
+               return "BT_CTF_VALUE_TYPE_STRING";
+       case BT_CTF_VALUE_TYPE_ARRAY:
+               return "BT_CTF_VALUE_TYPE_ARRAY";
+       case BT_CTF_VALUE_TYPE_MAP:
+               return "BT_CTF_VALUE_TYPE_MAP";
+       default:
+               return "(unknown)";
+       }
+};
+
+#endif /* BABELTRACE_CTF_WRITER_VALUES_INTERNAL_H */
diff --git a/src/ctf-writer/visitor.c b/src/ctf-writer/visitor.c
new file mode 100644 (file)
index 0000000..6cb5bab
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * visitor.c
+ *
+ * Babeltrace CTF writer - Visitor
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/ctf-writer/object.h>
+
+#include "common/babeltrace.h"
+
+#include "visitor.h"
+
+BT_HIDDEN
+int bt_ctf_visitor_helper(struct bt_ctf_visitor_object *root,
+               bt_ctf_child_count_accessor child_counter,
+               bt_ctf_child_accessor child_accessor,
+               bt_ctf_child_visitor child_visitor,
+               bt_ctf_visitor visitor,
+               void *data)
+{
+       int ret, child_count, i;
+
+       ret = visitor(root, data);
+       if (ret) {
+               goto end;
+       }
+
+       child_count = child_counter(root->object);
+       if (child_count < 0) {
+               ret = child_count;
+               goto end;
+       }
+
+       for (i = 0; i < child_count; i++) {
+               void *child;
+
+               child = child_accessor(root->object, i);
+               if (!child) {
+                       ret = -1;
+                       goto end;
+               }
+               ret = child_visitor(child, visitor, data);
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(child);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+enum bt_ctf_visitor_object_type bt_ctf_visitor_object_get_type(
+               struct bt_ctf_visitor_object *object)
+{
+       enum bt_ctf_visitor_object_type ret = BT_CTF_VISITOR_OBJECT_TYPE_UNKNOWN;
+
+       if (!object) {
+               goto end;
+       }
+
+       ret = object->type;
+end:
+       return ret;
+}
+
+void *bt_ctf_visitor_object_get_object(struct bt_ctf_visitor_object *object)
+{
+       void *ret = NULL;
+
+       if (!object) {
+               goto end;
+       }
+
+       ret = object->object;
+end:
+       return ret;
+}
diff --git a/src/ctf-writer/visitor.h b/src/ctf-writer/visitor.h
new file mode 100644 (file)
index 0000000..549285e
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef BABELTRACE_CTF_WRITER_VISITOR_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_VISITOR_INTERNAL_H
+
+/*
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/ctf-writer/visitor.h>
+#include "common/babeltrace.h"
+
+typedef void *(*bt_ctf_child_accessor)(void *object, int index);
+typedef int64_t (*bt_ctf_child_count_accessor)(void *object);
+typedef int (*bt_ctf_child_visitor)(void *object, bt_ctf_visitor visitor,
+               void *data);
+
+struct bt_ctf_visitor_object {
+       enum bt_ctf_visitor_object_type type;
+       void *object;
+};
+
+BT_HIDDEN
+int bt_ctf_visitor_helper(struct bt_ctf_visitor_object *root,
+               bt_ctf_child_count_accessor child_counter,
+               bt_ctf_child_accessor child_accessor,
+               bt_ctf_child_visitor child_visitor,
+               bt_ctf_visitor visitor,
+               void *data);
+
+#endif /* BABELTRACE_CTF_WRITER_VISITOR_INTERNAL_H */
diff --git a/src/ctf-writer/writer.c b/src/ctf-writer/writer.c
new file mode 100644 (file)
index 0000000..6c72aca
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * writer.c
+ *
+ * Babeltrace CTF Writer
+ *
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTF-WRITER"
+#include "logging.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <babeltrace2/ctf-writer/object.h>
+
+#include "common/assert.h"
+#include "compat/compiler.h"
+#include "compat/endian.h"
+#include "compat/uuid.h"
+
+#include "clock.h"
+#include "fields.h"
+#include "field-types.h"
+#include "functor.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "trace.h"
+#include "writer.h"
+
+static
+void bt_ctf_writer_destroy(struct bt_ctf_object *obj);
+
+static
+int init_trace_packet_header(struct bt_ctf_trace *trace)
+{
+       int ret = 0;
+       struct bt_ctf_field_type *_uint32_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT32_T);
+       struct bt_ctf_field_type *_uint8_t =
+               get_field_type(FIELD_TYPE_ALIAS_UINT8_T);
+       struct bt_ctf_field_type *trace_packet_header_type =
+               bt_ctf_field_type_structure_create();
+       struct bt_ctf_field_type *uuid_array_type =
+               bt_ctf_field_type_array_create(_uint8_t, 16);
+
+       if (!trace_packet_header_type || !uuid_array_type) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
+               _uint32_t, "magic");
+       if (ret) {
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
+               uuid_array_type, "uuid");
+       if (ret) {
+               goto end;
+       }
+
+       ret = bt_ctf_field_type_structure_add_field(trace_packet_header_type,
+               _uint32_t, "stream_id");
+       if (ret) {
+               goto end;
+       }
+
+       ret = bt_ctf_trace_set_packet_header_field_type(trace,
+               trace_packet_header_type);
+       if (ret) {
+               goto end;
+       }
+end:
+       bt_ctf_object_put_ref(uuid_array_type);
+       bt_ctf_object_put_ref(_uint32_t);
+       bt_ctf_object_put_ref(_uint8_t);
+       bt_ctf_object_put_ref(trace_packet_header_type);
+       return ret;
+}
+
+struct bt_ctf_writer *bt_ctf_writer_create(const char *path)
+{
+       int ret;
+       struct bt_ctf_writer *writer = NULL;
+       unsigned char uuid[16];
+       char *metadata_path = NULL;
+
+       if (!path) {
+               goto error;
+       }
+
+       writer = g_new0(struct bt_ctf_writer, 1);
+       if (!writer) {
+               goto error;
+       }
+
+       metadata_path = g_build_filename(path, "metadata", NULL);
+
+       bt_ctf_object_init_shared(&writer->base, bt_ctf_writer_destroy);
+       writer->path = g_string_new(path);
+       if (!writer->path) {
+               goto error_destroy;
+       }
+
+       writer->trace = bt_ctf_trace_create();
+       if (!writer->trace) {
+               goto error_destroy;
+       }
+
+       ret = init_trace_packet_header(writer->trace);
+       if (ret) {
+               goto error_destroy;
+       }
+
+       /* Generate a UUID for this writer's trace */
+       ret = bt_uuid_generate(uuid);
+       if (ret) {
+               BT_LOGE_STR("Cannot generate UUID for CTF writer's trace.");
+               goto error_destroy;
+       }
+
+       ret = bt_ctf_trace_set_uuid(writer->trace, uuid);
+       if (ret) {
+               goto error_destroy;
+       }
+
+       bt_ctf_object_set_parent(&writer->trace->common.base, &writer->base);
+       bt_ctf_object_put_ref(writer->trace);
+
+       /* Default to little-endian */
+       ret = bt_ctf_writer_set_byte_order(writer, BT_CTF_BYTE_ORDER_NATIVE);
+       BT_ASSERT(ret == 0);
+
+       /* Create trace directory if necessary and open a metadata file */
+       if (g_mkdir_with_parents(path, S_IRWXU | S_IRWXG)) {
+               perror("g_mkdir_with_parents");
+               goto error_destroy;
+       }
+
+       writer->metadata_fd = open(metadata_path,
+               O_WRONLY | O_CREAT | O_TRUNC,
+               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+       if (writer->metadata_fd < 0) {
+               perror("open");
+               goto error_destroy;
+       }
+
+       g_free(metadata_path);
+       return writer;
+
+error_destroy:
+       BT_CTF_OBJECT_PUT_REF_AND_RESET(writer);
+error:
+       g_free(metadata_path);
+       return writer;
+}
+
+void bt_ctf_writer_destroy(struct bt_ctf_object *obj)
+{
+       struct bt_ctf_writer *writer;
+
+       writer = container_of(obj, struct bt_ctf_writer, base);
+       bt_ctf_writer_flush_metadata(writer);
+       if (writer->path) {
+               g_string_free(writer->path, TRUE);
+       }
+
+       if (writer->metadata_fd > 0) {
+               if (close(writer->metadata_fd)) {
+                       perror("close");
+               }
+       }
+
+       bt_ctf_object_try_spec_release(&writer->trace->common.base);
+       g_free(writer);
+}
+
+struct bt_ctf_trace *bt_ctf_writer_get_trace(struct bt_ctf_writer *writer)
+{
+       struct bt_ctf_trace *trace = NULL;
+
+       if (!writer) {
+               goto end;
+       }
+
+       trace = writer->trace;
+       bt_ctf_object_get_ref(trace);
+end:
+       return trace;
+}
+
+struct bt_ctf_stream *bt_ctf_writer_create_stream(struct bt_ctf_writer *writer,
+               struct bt_ctf_stream_class *stream_class)
+{
+       struct bt_ctf_stream *stream = NULL;
+       int stream_class_count;
+       bt_bool stream_class_found = BT_FALSE;
+       int i;
+
+       if (!writer || !stream_class) {
+               goto error;
+       }
+
+       /* Make sure the stream class is part of the writer's trace */
+       stream_class_count = bt_ctf_trace_get_stream_class_count(writer->trace);
+       if (stream_class_count < 0) {
+               goto error;
+       }
+
+       for (i = 0; i < stream_class_count; i++) {
+               struct bt_ctf_stream_class *existing_stream_class =
+                       bt_ctf_trace_get_stream_class_by_index(
+                               writer->trace, i);
+
+               if (existing_stream_class == stream_class) {
+                       stream_class_found = BT_TRUE;
+               }
+
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(existing_stream_class);
+
+               if (stream_class_found) {
+                       break;
+               }
+       }
+
+       if (!stream_class_found) {
+               int ret = bt_ctf_trace_add_stream_class(writer->trace,
+                       stream_class);
+
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       stream = bt_ctf_stream_create_with_id(stream_class, NULL, -1ULL);
+       if (!stream) {
+               goto error;
+       }
+
+       return stream;
+
+error:
+        BT_CTF_OBJECT_PUT_REF_AND_RESET(stream);
+       return stream;
+}
+
+int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer,
+               const char *name,
+               const char *value)
+{
+       int ret = -1;
+
+       if (!writer || !name || !value) {
+               goto end;
+       }
+
+       ret = bt_ctf_trace_set_environment_field_string(writer->trace,
+               name, value);
+end:
+       return ret;
+}
+
+int bt_ctf_writer_add_environment_field_int64(struct bt_ctf_writer *writer,
+               const char *name, int64_t value)
+{
+       int ret = -1;
+
+       if (!writer || !name) {
+               goto end;
+       }
+
+       ret = bt_ctf_trace_set_environment_field_integer(writer->trace, name,
+               value);
+end:
+       return ret;
+}
+
+int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer,
+               struct bt_ctf_clock *clock)
+{
+       int ret = -1;
+
+       if (!writer || !clock) {
+               goto end;
+       }
+
+       ret = bt_ctf_trace_add_clock_class(writer->trace, clock->clock_class);
+end:
+       return ret;
+}
+
+char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer)
+{
+       char *metadata_string = NULL;
+
+       if (!writer) {
+               goto end;
+       }
+
+       metadata_string = bt_ctf_trace_get_metadata_string(
+               writer->trace);
+end:
+       return metadata_string;
+}
+
+void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer)
+{
+       int ret;
+       char *metadata_string = NULL;
+
+       if (!writer) {
+               goto end;
+       }
+
+       metadata_string = bt_ctf_trace_get_metadata_string(
+               writer->trace);
+       if (!metadata_string) {
+               goto end;
+       }
+
+       if (lseek(writer->metadata_fd, 0, SEEK_SET) == (off_t)-1) {
+               perror("lseek");
+               goto end;
+       }
+
+       if (ftruncate(writer->metadata_fd, 0)) {
+               perror("ftruncate");
+               goto end;
+       }
+
+       ret = write(writer->metadata_fd, metadata_string,
+               strlen(metadata_string));
+       if (ret < 0) {
+               perror("write");
+               goto end;
+       }
+end:
+       g_free(metadata_string);
+}
+
+int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer,
+               enum bt_ctf_byte_order byte_order)
+{
+       int ret = 0;
+
+       if (!writer || writer->frozen) {
+               ret = -1;
+               goto end;
+       }
+
+       if (byte_order == BT_CTF_BYTE_ORDER_NATIVE) {
+               if (BYTE_ORDER == LITTLE_ENDIAN) {
+                       byte_order = BT_CTF_BYTE_ORDER_LITTLE_ENDIAN;
+               } else {
+                       byte_order = BT_CTF_BYTE_ORDER_BIG_ENDIAN;
+               }
+       }
+
+       ret = bt_ctf_trace_set_native_byte_order(writer->trace,
+               byte_order);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctf_writer_freeze(struct bt_ctf_writer *writer)
+{
+       writer->frozen = 1;
+}
+
+static
+const unsigned int field_type_aliases_alignments[] = {
+       [FIELD_TYPE_ALIAS_UINT5_T] = 1,
+       [FIELD_TYPE_ALIAS_UINT8_T ... FIELD_TYPE_ALIAS_UINT16_T] = 8,
+       [FIELD_TYPE_ALIAS_UINT27_T] = 1,
+       [FIELD_TYPE_ALIAS_UINT32_T ... FIELD_TYPE_ALIAS_UINT64_T] = 8,
+};
+
+static
+const unsigned int field_type_aliases_sizes[] = {
+       [FIELD_TYPE_ALIAS_UINT5_T] = 5,
+       [FIELD_TYPE_ALIAS_UINT8_T] = 8,
+       [FIELD_TYPE_ALIAS_UINT16_T] = 16,
+       [FIELD_TYPE_ALIAS_UINT27_T] = 27,
+       [FIELD_TYPE_ALIAS_UINT32_T] = 32,
+       [FIELD_TYPE_ALIAS_UINT64_T] = 64,
+};
+
+BT_HIDDEN
+struct bt_ctf_field_type *get_field_type(enum field_type_alias alias)
+{
+       int ret;
+       unsigned int alignment, size;
+       struct bt_ctf_field_type *field_type = NULL;
+
+       if (alias >= NR_FIELD_TYPE_ALIAS) {
+               goto end;
+       }
+
+       alignment = field_type_aliases_alignments[alias];
+       size = field_type_aliases_sizes[alias];
+       field_type = bt_ctf_field_type_integer_create(size);
+       ret = bt_ctf_field_type_set_alignment(field_type, alignment);
+       if (ret) {
+               BT_CTF_OBJECT_PUT_REF_AND_RESET(field_type);
+       }
+end:
+       return field_type;
+}
+
+BT_HIDDEN
+const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order)
+{
+       const char *string;
+
+       switch (byte_order) {
+       case BT_CTF_BYTE_ORDER_LITTLE_ENDIAN:
+               string = "le";
+               break;
+       case BT_CTF_BYTE_ORDER_BIG_ENDIAN:
+               string = "be";
+               break;
+       case BT_CTF_BYTE_ORDER_NATIVE:
+               string = "native";
+               break;
+       default:
+               abort();
+       }
+
+       return string;
+}
diff --git a/src/ctf-writer/writer.h b/src/ctf-writer/writer.h
new file mode 100644 (file)
index 0000000..37e6a58
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H
+#define BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H
+
+/*
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <dirent.h>
+#include <glib.h>
+#include <sys/types.h>
+
+#include <babeltrace2/ctf-writer/trace.h>
+#include <babeltrace2/ctf-writer/writer.h>
+
+#include "common/babeltrace.h"
+
+#include "object.h"
+
+struct metadata_context {
+       GString *string;
+       GString *field_name;
+       unsigned int current_indentation_level;
+};
+
+struct bt_ctf_writer {
+       struct bt_ctf_object base;
+       int frozen; /* Protects attributes that can't be changed mid-trace */
+       struct bt_ctf_trace *trace;
+       GString *path;
+       int metadata_fd;
+};
+
+enum field_type_alias {
+       FIELD_TYPE_ALIAS_UINT5_T = 0,
+       FIELD_TYPE_ALIAS_UINT8_T,
+       FIELD_TYPE_ALIAS_UINT16_T,
+       FIELD_TYPE_ALIAS_UINT27_T,
+       FIELD_TYPE_ALIAS_UINT32_T,
+       FIELD_TYPE_ALIAS_UINT64_T,
+       NR_FIELD_TYPE_ALIAS,
+};
+
+BT_HIDDEN
+struct bt_ctf_field_type *get_field_type(enum field_type_alias alias);
+
+BT_HIDDEN
+const char *bt_ctf_get_byte_order_string(enum bt_ctf_byte_order byte_order);
+
+BT_HIDDEN
+void bt_ctf_writer_freeze(struct bt_ctf_writer *writer);
+
+#endif /* BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H */
diff --git a/src/ctfser/Makefile.am b/src/ctfser/Makefile.am
new file mode 100644 (file)
index 0000000..e6ae86f
--- /dev/null
@@ -0,0 +1,9 @@
+AM_CPPFLAGS += -DINSTALL_LIBDIR=\"$(libdir)\"
+
+noinst_LTLIBRARIES = libbabeltrace2-ctfser.la
+
+libbabeltrace2_ctfser_la_SOURCES = \
+       ctfser.c \
+       ctfser.h \
+       logging.c \
+       logging.h
diff --git a/src/ctfser/ctfser.c b/src/ctfser/ctfser.c
new file mode 100644 (file)
index 0000000..6203246
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CTFSER"
+#include "logging.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "common/assert.h"
+#include <stdarg.h>
+#include <ctype.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdbool.h>
+#include "common/babeltrace.h"
+#include "common/common.h"
+#include "ctfser/ctfser.h"
+#include "compat/unistd.h"
+#include "compat/fcntl.h"
+
+static inline
+uint64_t get_packet_size_increment_bytes(void)
+{
+       return bt_common_get_page_size() * 8;
+}
+
+static inline
+void mmap_align_ctfser(struct bt_ctfser *ctfser)
+{
+       ctfser->base_mma = mmap_align(ctfser->cur_packet_size_bytes,
+               PROT_READ | PROT_WRITE,
+               MAP_SHARED, ctfser->fd, ctfser->mmap_offset);
+}
+
+BT_HIDDEN
+int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser)
+{
+       int ret;
+
+       BT_ASSERT(ctfser);
+       BT_LOGV("Increasing stream file's current packet size: "
+               "path=\"%s\", fd=%d, "
+               "offset-in-cur-packet-bits=%" PRIu64 ", "
+               "cur-packet-size-bytes=%" PRIu64,
+               ctfser->path->str, ctfser->fd,
+               ctfser->offset_in_cur_packet_bits,
+               ctfser->cur_packet_size_bytes);
+       ret = munmap_align(ctfser->base_mma);
+       if (ret) {
+               BT_LOGE_ERRNO("Failed to perform an aligned memory unmapping",
+                       ": ret=%d", ret);
+               goto end;
+       }
+
+       ctfser->cur_packet_size_bytes += get_packet_size_increment_bytes();
+
+       do {
+               ret = bt_posix_fallocate(ctfser->fd, ctfser->mmap_offset,
+                       ctfser->cur_packet_size_bytes);
+       } while (ret == EINTR);
+
+       if (ret) {
+               BT_LOGE("Failed to preallocate memory space: ret=%d", ret);
+               goto end;
+       }
+
+       mmap_align_ctfser(ctfser);
+       if (ctfser->base_mma == MAP_FAILED) {
+               BT_LOGE_ERRNO("Failed to perform an aligned memory mapping",
+                       ": ret=%d", ret);
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Increased packet size: "
+               "path=\"%s\", fd=%d, "
+               "offset-in-cur-packet-bits=%" PRIu64 ", "
+               "new-packet-size-bytes=%" PRIu64,
+               ctfser->path->str, ctfser->fd,
+               ctfser->offset_in_cur_packet_bits,
+               ctfser->cur_packet_size_bytes);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path)
+{
+       int ret = 0;
+
+       BT_ASSERT(ctfser);
+       memset(ctfser, 0, sizeof(*ctfser));
+       ctfser->fd = open(path, O_RDWR | O_CREAT | O_TRUNC,
+               S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+       if (ctfser->fd < 0) {
+               BT_LOGW_ERRNO("Failed to open stream file for writing",
+                       ": path=\"%s\", ret=%d",
+                       path, ctfser->fd);
+               ret = -1;
+               goto end;
+       }
+
+       ctfser->path = g_string_new(path);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctfser_fini(struct bt_ctfser *ctfser)
+{
+       int ret = 0;
+
+       if (ctfser->fd == -1) {
+               goto free_path;
+       }
+
+       /*
+        * Truncate the stream file's size to the minimum required to
+        * fit the last packet as we might have grown it too much during
+        * the last memory map.
+        */
+       do {
+               ret = ftruncate(ctfser->fd, ctfser->stream_size_bytes);
+       } while (ret == -1 && errno == EINTR);
+
+       if (ret) {
+               BT_LOGE_ERRNO("Failed to truncate stream file",
+                       ": ret=%d, size-bytes=%" PRIu64,
+                       ret, ctfser->stream_size_bytes);
+               goto end;
+       }
+
+       if (ctfser->base_mma) {
+               /* Unmap old base */
+               ret = munmap_align(ctfser->base_mma);
+               if (ret) {
+                       BT_LOGE_ERRNO("Failed to unmap stream file",
+                               ": ret=%d, size-bytes=%" PRIu64,
+                               ret, ctfser->stream_size_bytes);
+                       goto end;
+               }
+
+               ctfser->base_mma = NULL;
+       }
+
+       ret = close(ctfser->fd);
+       if (ret) {
+               BT_LOGE_ERRNO("Failed to close stream file",
+                       ": ret=%d", ret);
+               goto end;
+       }
+
+       ctfser->fd = -1;
+
+free_path:
+       if (ctfser->path) {
+               g_string_free(ctfser->path, TRUE);
+               ctfser->path = NULL;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int bt_ctfser_open_packet(struct bt_ctfser *ctfser)
+{
+       int ret = 0;
+
+       BT_LOGV("Opening packet: path=\"%s\", fd=%d, "
+               "prev-packet-size-bytes=%" PRIu64,
+               ctfser->path->str, ctfser->fd,
+               ctfser->prev_packet_size_bytes);
+
+       if (ctfser->base_mma) {
+               /* Unmap old base (previous packet) */
+               ret = munmap_align(ctfser->base_mma);
+               if (ret) {
+                       BT_LOGE_ERRNO("Failed to unmap stream file",
+                               ": ret=%d, size-bytes=%" PRIu64,
+                               ret, ctfser->stream_size_bytes);
+                       goto end;
+               }
+
+               ctfser->base_mma = NULL;
+       }
+
+       /*
+        * Add the previous packet's size to the memory map address
+        * offset to start writing immediately after it.
+        */
+       ctfser->mmap_offset += ctfser->prev_packet_size_bytes;
+       ctfser->prev_packet_size_bytes = 0;
+
+       /* Make initial space for the current packet */
+       ctfser->cur_packet_size_bytes = get_packet_size_increment_bytes();
+
+       do {
+               ret = bt_posix_fallocate(ctfser->fd, ctfser->mmap_offset,
+                       ctfser->cur_packet_size_bytes);
+       } while (ret == EINTR);
+
+       if (ret) {
+               BT_LOGE("Failed to preallocate memory space: ret=%d", ret);
+               goto end;
+       }
+
+       /* Start writing at the beginning of the current packet */
+       ctfser->offset_in_cur_packet_bits = 0;
+
+       /* Get new base address */
+       mmap_align_ctfser(ctfser);
+       if (ctfser->base_mma == MAP_FAILED) {
+               BT_LOGE_ERRNO("Failed to perform an aligned memory mapping",
+                       ": ret=%d", ret);
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Opened packet: path=\"%s\", fd=%d, "
+               "cur-packet-size-bytes=%" PRIu64,
+               ctfser->path->str, ctfser->fd,
+               ctfser->cur_packet_size_bytes);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
+               uint64_t packet_size_bytes)
+{
+       BT_LOGV("Closing packet: path=\"%s\", fd=%d, "
+               "offset-in-cur-packet-bits=%" PRIu64
+               "cur-packet-size-bytes=%" PRIu64,
+               ctfser->path->str, ctfser->fd,
+               ctfser->offset_in_cur_packet_bits,
+               ctfser->cur_packet_size_bytes);
+
+       /*
+        * This will be used during the next call to
+        * bt_ctfser_open_packet(): we add
+        * `ctfser->prev_packet_size_bytes` to the current memory map
+        * address offset (first byte of _this_ packet), effectively
+        * making _this_ packet the required size.
+        */
+       ctfser->prev_packet_size_bytes = packet_size_bytes;
+       ctfser->stream_size_bytes += packet_size_bytes;
+       BT_LOGV("Closed packet: path=\"%s\", fd=%d, "
+               "stream-file-size-bytes=%" PRIu64,
+               ctfser->path->str, ctfser->fd,
+               ctfser->stream_size_bytes);
+}
diff --git a/src/ctfser/ctfser.h b/src/ctfser/ctfser.h
new file mode 100644 (file)
index 0000000..c270faf
--- /dev/null
@@ -0,0 +1,576 @@
+#ifndef BABELTRACE_CTFSER_INTERNAL_H
+#define BABELTRACE_CTFSER_INTERNAL_H
+
+/*
+ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017-2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include "compat/mman.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "common/align.h"
+#include "compat/endian.h"
+#include "common/common.h"
+#include "common/mmap-align.h"
+#include <babeltrace2/types.h>
+#include "common/assert.h"
+#include "compat/bitfield.h"
+#include <glib.h>
+
+struct bt_ctfser {
+       /* Stream file's descriptor */
+       int fd;
+
+       /* Offset (bytes) of memory map (current packet) in the stream file */
+       off_t mmap_offset;
+
+       /* Offset (bytes) of packet's first byte in the memory map */
+       off_t mmap_base_offset;
+
+       /* Current offset (bits) within current packet */
+       uint64_t offset_in_cur_packet_bits;
+
+       /* Current packet size (bytes) */
+       uint64_t cur_packet_size_bytes;
+
+       /* Previous packet size (bytes) */
+       uint64_t prev_packet_size_bytes;
+
+       /* Current stream size (bytes) */
+       uint64_t stream_size_bytes;
+
+       /* Memory map base address */
+       struct mmap_align *base_mma;
+
+       /* Stream file's path (for debugging) */
+       GString *path;
+};
+
+/*
+ * Initializes a CTF serializer.
+ *
+ * This function opens the file `path` for writing.
+ */
+BT_HIDDEN
+int bt_ctfser_init(struct bt_ctfser *ctfser, const char *path);
+
+/*
+ * Finalizes a CTF serializer.
+ *
+ * This function truncates the stream file so that there's no extra
+ * padding after the last packet, and then closes the file.
+ */
+BT_HIDDEN
+int bt_ctfser_fini(struct bt_ctfser *ctfser);
+
+/*
+ * Opens a new packet.
+ *
+ * All the next writing functions are performed within this new packet.
+ */
+BT_HIDDEN
+int bt_ctfser_open_packet(struct bt_ctfser *ctfser);
+
+/*
+ * Closes the current packet, making its size `packet_size_bytes`.
+ */
+BT_HIDDEN
+void bt_ctfser_close_current_packet(struct bt_ctfser *ctfser,
+               uint64_t packet_size_bytes);
+
+BT_HIDDEN
+int _bt_ctfser_increase_cur_packet_size(struct bt_ctfser *ctfser);
+
+static inline
+uint64_t _bt_ctfser_cur_packet_size_bits(struct bt_ctfser *ctfser)
+{
+       return ctfser->cur_packet_size_bytes * 8;
+}
+
+static inline
+uint64_t _bt_ctfser_prev_packet_size_bits(struct bt_ctfser *ctfser)
+{
+       return ctfser->prev_packet_size_bytes * 8;
+}
+
+static inline
+uint64_t _bt_ctfser_offset_bytes(struct bt_ctfser *ctfser)
+{
+       return ctfser->offset_in_cur_packet_bits / 8;
+}
+
+static inline
+uint8_t *_bt_ctfser_get_addr(struct bt_ctfser *ctfser)
+{
+       /* Only makes sense to get the address after aligning on byte */
+       BT_ASSERT(ctfser->offset_in_cur_packet_bits % 8 == 0);
+       return ((uint8_t *) mmap_align_addr(ctfser->base_mma)) +
+               ctfser->mmap_base_offset + _bt_ctfser_offset_bytes(ctfser);
+}
+
+static inline
+bool _bt_ctfser_has_space_left(struct bt_ctfser *ctfser, uint64_t size_bits)
+{
+       bool has_space_left = true;
+
+       if (unlikely((ctfser->offset_in_cur_packet_bits + size_bits >
+                       _bt_ctfser_cur_packet_size_bits(ctfser)))) {
+               has_space_left = false;
+               goto end;
+       }
+
+       if (unlikely(size_bits > UINT64_MAX - ctfser->offset_in_cur_packet_bits)) {
+               has_space_left = false;
+               goto end;
+       }
+
+end:
+       return has_space_left;
+}
+
+static inline
+void _bt_ctfser_incr_offset(struct bt_ctfser *ctfser, uint64_t size_bits)
+{
+       BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
+       ctfser->offset_in_cur_packet_bits += size_bits;
+}
+
+/*
+ * Aligns the current offset within the current packet to
+ * `alignment_bits` bits (power of two, > 0).
+ */
+static inline
+int bt_ctfser_align_offset_in_current_packet(struct bt_ctfser *ctfser,
+               uint64_t alignment_bits)
+{
+       int ret = 0;
+       uint64_t align_size_bits;
+
+       BT_ASSERT(alignment_bits > 0);
+       align_size_bits = ALIGN(ctfser->offset_in_cur_packet_bits,
+                       alignment_bits) - ctfser->offset_in_cur_packet_bits;
+
+       if (unlikely(!_bt_ctfser_has_space_left(ctfser, align_size_bits))) {
+               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       _bt_ctfser_incr_offset(ctfser, align_size_bits);
+
+end:
+       return ret;
+}
+
+static inline
+int _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
+               struct bt_ctfser *ctfser, uint64_t value,
+               unsigned int size_bits, int byte_order)
+{
+       int ret = 0;
+
+       /* Reverse byte order? */
+       bool rbo = byte_order != BYTE_ORDER;
+
+       BT_ASSERT(size_bits % 8 == 0);
+       BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
+
+       switch (size_bits) {
+       case 8:
+       {
+               uint8_t v = (uint8_t) value;
+
+               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+               break;
+       }
+       case 16:
+       {
+               uint16_t v = (uint16_t) value;
+
+               if (rbo) {
+                       v = GUINT16_SWAP_LE_BE(v);
+               }
+
+               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+               break;
+       }
+       case 32:
+       {
+               uint32_t v = (uint32_t) value;
+
+               if (rbo) {
+                       v = GUINT32_SWAP_LE_BE(v);
+               }
+
+               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+               break;
+       }
+       case 64:
+       {
+               uint64_t v = (uint64_t) value;
+
+               if (rbo) {
+                       v = GUINT64_SWAP_LE_BE(v);
+               }
+
+               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+               break;
+       }
+       default:
+               abort();
+       }
+
+       _bt_ctfser_incr_offset(ctfser, size_bits);
+       return ret;
+}
+
+static inline
+int _bt_ctfser_write_byte_aligned_signed_int_no_align(
+               struct bt_ctfser *ctfser, int64_t value,
+               unsigned int size_bits, int byte_order)
+{
+       int ret = 0;
+
+       /* Reverse byte order? */
+       bool rbo = byte_order != BYTE_ORDER;
+
+       BT_ASSERT(size_bits % 8 == 0);
+       BT_ASSERT(_bt_ctfser_has_space_left(ctfser, size_bits));
+
+       switch (size_bits) {
+       case 8:
+       {
+               int8_t v = (int8_t) value;
+
+               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+               break;
+       }
+       case 16:
+       {
+               int16_t v = (int16_t) value;
+
+               if (rbo) {
+                       v = GUINT16_SWAP_LE_BE(v);
+               }
+
+               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+               break;
+       }
+       case 32:
+       {
+               int32_t v = (int32_t) value;
+
+               if (rbo) {
+                       v = GUINT32_SWAP_LE_BE(v);
+               }
+
+               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+               break;
+       }
+       case 64:
+       {
+               int64_t v = (int64_t) value;
+
+               if (rbo) {
+                       v = GUINT64_SWAP_LE_BE(v);
+               }
+
+               memcpy(_bt_ctfser_get_addr(ctfser), &v, sizeof(v));
+               break;
+       }
+       default:
+               abort();
+       }
+
+       _bt_ctfser_incr_offset(ctfser, size_bits);
+       return ret;
+}
+
+/*
+ * Writes an unsigned integer known to have a size that is a multiple of
+ * 8 and an alignment that is >= 8 at the current offset within the
+ * current packet.
+ */
+static inline
+int bt_ctfser_write_byte_aligned_unsigned_int(struct bt_ctfser *ctfser,
+       uint64_t value, unsigned int alignment_bits,
+       unsigned int size_bits, int byte_order)
+{
+       int ret;
+
+       BT_ASSERT(alignment_bits % 8 == 0);
+       ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+       if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
+               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       ret = _bt_ctfser_write_byte_aligned_unsigned_int_no_align(ctfser, value,
+               size_bits, byte_order);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Writes a signed integer known to have a size that is a multiple of 8
+ * and an alignment that is >= 8 at the current offset within the
+ * current packet.
+ */
+static inline
+int bt_ctfser_write_byte_aligned_signed_int(struct bt_ctfser *ctfser,
+       int64_t value, unsigned int alignment_bits,
+       unsigned int size_bits, int byte_order)
+{
+       int ret;
+
+       BT_ASSERT(alignment_bits % 8 == 0);
+       ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+       if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
+               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       ret = _bt_ctfser_write_byte_aligned_signed_int_no_align(ctfser, value,
+               size_bits, byte_order);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Writes an unsigned integer at the current offset within the current
+ * packet.
+ */
+static inline
+int bt_ctfser_write_unsigned_int(struct bt_ctfser *ctfser, uint64_t value,
+       unsigned int alignment_bits, unsigned int size_bits,
+       int byte_order)
+{
+       int ret = 0;
+
+       ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+       if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
+               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       if (alignment_bits % 8 == 0 && size_bits % 8 == 0) {
+               ret = _bt_ctfser_write_byte_aligned_unsigned_int_no_align(
+                       ctfser, value, size_bits, byte_order);
+               goto end;
+       }
+
+       if (byte_order == LITTLE_ENDIAN) {
+               bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
+                       ctfser->mmap_base_offset, uint8_t,
+                       ctfser->offset_in_cur_packet_bits, size_bits, value);
+       } else {
+               bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
+                       ctfser->mmap_base_offset, uint8_t,
+                       ctfser->offset_in_cur_packet_bits, size_bits, value);
+       }
+
+       _bt_ctfser_incr_offset(ctfser, size_bits);
+
+end:
+       return ret;
+}
+
+/*
+ * Writes a signed integer at the current offset within the current
+ * packet.
+ */
+static inline
+int bt_ctfser_write_signed_int(struct bt_ctfser *ctfser, int64_t value,
+       unsigned int alignment_bits, unsigned int size_bits,
+       int byte_order)
+{
+       int ret = 0;
+
+       ret = bt_ctfser_align_offset_in_current_packet(ctfser, alignment_bits);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+       if (unlikely(!_bt_ctfser_has_space_left(ctfser, size_bits))) {
+               ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       if (alignment_bits % 8 == 0 && size_bits % 8 == 0) {
+               ret = _bt_ctfser_write_byte_aligned_signed_int_no_align(
+                       ctfser, value, size_bits, byte_order);
+               goto end;
+       }
+
+       if (byte_order == LITTLE_ENDIAN) {
+               bt_bitfield_write_le(mmap_align_addr(ctfser->base_mma) +
+                       ctfser->mmap_base_offset, uint8_t,
+                       ctfser->offset_in_cur_packet_bits, size_bits, value);
+       } else {
+               bt_bitfield_write_be(mmap_align_addr(ctfser->base_mma) +
+                       ctfser->mmap_base_offset, uint8_t,
+                       ctfser->offset_in_cur_packet_bits, size_bits, value);
+       }
+
+       _bt_ctfser_incr_offset(ctfser, size_bits);
+
+end:
+       return ret;
+}
+
+/*
+ * Writes a 32-bit floating point number at the current offset within
+ * the current packet.
+ */
+static inline
+int bt_ctfser_write_float32(struct bt_ctfser *ctfser, double value,
+       unsigned int alignment_bits, int byte_order)
+{
+       union u32f {
+               uint32_t u;
+               float f;
+       } u32f;
+
+       u32f.f = (float) value;
+       return bt_ctfser_write_unsigned_int(ctfser, (uint64_t) u32f.u,
+               alignment_bits, 32, byte_order);
+}
+
+/*
+ * Writes a 64-bit floating point number at the current offset within
+ * the current packet.
+ */
+static inline
+int bt_ctfser_write_float64(struct bt_ctfser *ctfser, double value,
+       unsigned int alignment_bits, int byte_order)
+{
+       union u64f {
+               uint64_t u;
+               float f;
+       } u64f;
+
+       u64f.f = value;
+       return bt_ctfser_write_unsigned_int(ctfser, u64f.u, alignment_bits,
+               64, byte_order);
+}
+
+/*
+ * Writes a C string, including the terminating null character, at the
+ * current offset within the current packet.
+ */
+static inline
+int bt_ctfser_write_string(struct bt_ctfser *ctfser, const char *value)
+{
+       int ret = 0;
+       const char *at = value;
+
+       ret = bt_ctfser_align_offset_in_current_packet(ctfser, 8);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+       while (true) {
+               if (unlikely(!_bt_ctfser_has_space_left(ctfser, 8))) {
+                       ret = _bt_ctfser_increase_cur_packet_size(ctfser);
+                       if (unlikely(ret)) {
+                               goto end;
+                       }
+               }
+
+               memcpy(_bt_ctfser_get_addr(ctfser), at, sizeof(*at));
+               _bt_ctfser_incr_offset(ctfser, 8);
+
+               if (unlikely(*at == '\0')) {
+                       break;
+               }
+
+               at++;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Returns the current offset within the current packet (bits).
+ */
+static inline
+uint64_t bt_ctfser_get_offset_in_current_packet_bits(struct bt_ctfser *ctfser)
+{
+       return ctfser->offset_in_cur_packet_bits;
+}
+
+/*
+ * Sets the current offset within the current packet (bits).
+ */
+static inline
+void bt_ctfser_set_offset_in_current_packet_bits(struct bt_ctfser *ctfser,
+               uint64_t offset_bits)
+{
+       BT_ASSERT(offset_bits <= _bt_ctfser_cur_packet_size_bits(ctfser));
+       ctfser->offset_in_cur_packet_bits = offset_bits;
+}
+
+static inline
+const char *bt_ctfser_get_file_path(struct bt_ctfser *ctfser)
+{
+       return ctfser->path->str;
+}
+
+#endif /* BABELTRACE_CTFSER_INTERNAL_H */
diff --git a/src/ctfser/logging.c b/src/ctfser/logging.c
new file mode 100644 (file)
index 0000000..779078d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_ctfser_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_ctfser_log_level, "BABELTRACE_CTFSER_LOG_LEVEL");
diff --git a/src/ctfser/logging.h b/src/ctfser/logging.h
new file mode 100644 (file)
index 0000000..547f1ac
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef COMMON_LOGGING_H
+#define COMMON_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_ctfser_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_ctfser_log_level);
+
+#endif /* COMMON_LOGGING_H */
diff --git a/src/fd-cache/Makefile.am b/src/fd-cache/Makefile.am
new file mode 100644 (file)
index 0000000..c4a1288
--- /dev/null
@@ -0,0 +1,9 @@
+AM_CPPFLAGS += -DINSTALL_LIBDIR=\"$(libdir)\"
+
+noinst_LTLIBRARIES = libbabeltrace2-fd-cache.la
+
+libbabeltrace2_fd_cache_la_SOURCES = \
+       fd-cache.c \
+       fd-cache.h \
+       logging.c \
+       logging.h
diff --git a/src/fd-cache/fd-cache.c b/src/fd-cache/fd-cache.c
new file mode 100644 (file)
index 0000000..6d62518
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * fd-cache.c
+ *
+ * Babeltrace - File descriptor cache
+ *
+ * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Author: Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "FD-CACHE"
+#include "logging.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "common/assert.h"
+#include "fd-cache.h"
+
+struct file_key {
+       uint64_t dev;
+       uint64_t ino;
+};
+
+struct fd_handle_internal {
+       struct bt_fd_cache_handle fd_handle;
+       uint64_t ref_count;
+       struct file_key *key;
+};
+
+static
+void fd_cache_handle_internal_destroy(
+               struct fd_handle_internal *internal_fd)
+{
+       if (!internal_fd) {
+               goto end;
+       }
+
+       if (internal_fd->fd_handle.fd >= 0) {
+               close(internal_fd->fd_handle.fd);
+               internal_fd->fd_handle.fd = -1;
+       }
+
+end:
+       g_free(internal_fd);
+}
+
+/*
+ * Using simple hash algorithm found on stackoverflow:
+ * https://stackoverflow.com/questions/664014/
+ */
+static inline
+uint64_t hash_uint64_t(uint64_t x) {
+       x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9);
+       x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb);
+       x = x ^ (x >> 31);
+       return x;
+}
+
+static
+guint file_key_hash(gconstpointer v)
+{
+       const struct file_key *fk = v;
+       return hash_uint64_t(fk->dev) ^ hash_uint64_t(fk->ino);
+}
+
+static
+gboolean file_key_equal(gconstpointer v1, gconstpointer v2)
+{
+       const struct file_key *fk1 = v1;
+       const struct file_key *fk2 = v2;
+
+       return (fk1->dev == fk2->dev) && (fk1->ino == fk2->ino);
+}
+
+static
+void file_key_destroy(gpointer data)
+{
+       struct file_key *fk = data;
+       g_free(fk);
+}
+
+BT_HIDDEN
+int bt_fd_cache_init(struct bt_fd_cache *fdc)
+{
+       int ret = 0;
+
+       fdc->cache = g_hash_table_new_full(file_key_hash, file_key_equal,
+               file_key_destroy, (GDestroyNotify) fd_cache_handle_internal_destroy);
+       if (!fdc->cache) {
+               ret = -1;
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+void bt_fd_cache_fini(struct bt_fd_cache *fdc)
+{
+       BT_ASSERT(fdc->cache);
+       /*
+        * All handle should have been removed for the hashtable at this point.
+        */
+       BT_ASSERT(g_hash_table_size(fdc->cache) == 0);
+       g_hash_table_destroy(fdc->cache);
+
+       return;
+}
+
+BT_HIDDEN
+struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc,
+               const char *path)
+{
+       struct fd_handle_internal *fd_internal = NULL;
+       struct stat statbuf;
+       struct file_key fk;
+       int ret, fd = -1;
+
+       ret = stat(path, &statbuf);
+       if (ret < 0) {
+               /*
+                * This is not necessarily an error as we sometimes try to open
+                * files to see if they exist. Log the error as DEBUG severity
+                * level.
+                */
+               BT_LOGD_ERRNO("Failed to stat file", ": path=%s", path);
+               goto end;
+       }
+
+       /*
+        * Use the device number and inode number to uniquely identify a file.
+        * Even if the file has the same path, it may have been replaced so we
+        * must open a new FD for it. This replacement of file is more likely
+        * to happen with a lttng-live source component.
+        */
+       fk.dev = statbuf.st_dev;
+       fk.ino = statbuf.st_ino;
+
+       fd_internal = g_hash_table_lookup(fdc->cache, &fk);
+       if (!fd_internal) {
+               struct file_key *file_key;
+
+               fd = open(path, O_RDONLY);
+               if (fd < 0) {
+                       BT_LOGE_ERRNO("Failed to open file", "path=%s", path);
+                       goto error;
+               }
+
+               fd_internal = g_new0(struct fd_handle_internal, 1);
+               if (!fd_internal) {
+                       BT_LOGE("Failed to allocate fd internal handle");
+                       goto error;
+               }
+
+               file_key = g_new0(struct file_key, 1);
+               if (!fd_internal) {
+                       BT_LOGE("Failed to allocate file key");
+                       goto error;
+               }
+
+               *file_key = fk;
+
+               fd_internal->fd_handle.fd = fd;
+               fd_internal->ref_count = 0;
+               fd_internal->key = file_key;
+
+               /* Insert the newly created fd handle. */
+               g_hash_table_insert(fdc->cache, fd_internal->key, fd_internal);
+       }
+
+       fd_internal->ref_count++;
+       goto end;
+
+error:
+       /*
+        * Close file descriptor if it was open() and we are currently on error
+        * path.
+        */
+       if (fd != -1) {
+               ret = close(fd);
+               if (ret) {
+                       BT_LOGE_ERRNO("Failed to close file descriptor",
+                               ": fd=%i, path=%s", fd, path);
+               }
+       }
+
+       fd_cache_handle_internal_destroy(fd_internal);
+       fd_internal = NULL;
+end:
+       return (struct bt_fd_cache_handle *) fd_internal;
+}
+
+BT_HIDDEN
+void bt_fd_cache_put_handle(struct bt_fd_cache *fdc,
+               struct bt_fd_cache_handle *handle)
+{
+       struct fd_handle_internal *fd_internal;
+
+       if (!handle) {
+               goto end;
+       }
+
+       fd_internal = (struct fd_handle_internal *) handle;
+
+       BT_ASSERT(fd_internal->ref_count > 0);
+
+       if (fd_internal->ref_count > 1) {
+               fd_internal->ref_count--;
+       } else {
+               gboolean ret;
+               int close_ret;
+
+               close_ret = close(fd_internal->fd_handle.fd);
+               if (close_ret == -1) {
+                       BT_LOGW_ERRNO("Failed to close file descriptor",
+                               ": fd=%d", fd_internal->fd_handle.fd);
+               }
+               ret = g_hash_table_remove(fdc->cache, fd_internal->key);
+               BT_ASSERT(ret);
+       }
+
+end:
+       return;
+}
diff --git a/src/fd-cache/fd-cache.h b/src/fd-cache/fd-cache.h
new file mode 100644 (file)
index 0000000..fb70a07
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef BABELTRACE_FD_CACHE_INTERNAL_H
+#define BABELTRACE_FD_CACHE_INTERNAL_H
+/*
+ * fd-cache.h
+ *
+ * Babeltrace - File descriptor cache
+ *
+ * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Author: Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+
+struct bt_fd_cache_handle {
+       int fd;
+};
+
+struct bt_fd_cache {
+       GHashTable *cache;
+};
+
+static inline
+int bt_fd_cache_handle_get_fd(struct bt_fd_cache_handle *handle)
+{
+       return handle->fd;
+}
+
+BT_HIDDEN
+int bt_fd_cache_init(struct bt_fd_cache *fdc);
+
+BT_HIDDEN
+void bt_fd_cache_fini(struct bt_fd_cache *fdc);
+
+BT_HIDDEN
+struct bt_fd_cache_handle *bt_fd_cache_get_handle(struct bt_fd_cache *fdc,
+               const char *path);
+
+BT_HIDDEN
+void bt_fd_cache_put_handle(struct bt_fd_cache *fdc,
+               struct bt_fd_cache_handle *handle);
+
+#endif /* BABELTRACE_FD_CACHE_INTERNAL_H */
diff --git a/src/fd-cache/logging.c b/src/fd-cache/logging.c
new file mode 100644 (file)
index 0000000..875f3ba
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_fd_cache_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_fd_cache_log_level, "BABELTRACE_FD_CACHE_LOG_LEVEL");
diff --git a/src/fd-cache/logging.h b/src/fd-cache/logging.h
new file mode 100644 (file)
index 0000000..89a783b
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef FD_CACHE_LOGGING_H
+#define FD_CACHE_LOGGING_H
+
+/*
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_fd_cache_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_fd_cache_log_level);
+
+#endif /* FD_CACHE_LOGGING_H */
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644 (file)
index 0000000..51da351
--- /dev/null
@@ -0,0 +1,33 @@
+SUBDIRS = trace-ir prio-heap plugin graph
+
+lib_LTLIBRARIES = libbabeltrace2.la
+
+libbabeltrace2_la_SOURCES = \
+       assert-pre.h \
+       babeltrace2.c \
+       lib-logging.c \
+       lib-logging.h \
+       logging.c \
+       object.h \
+       object-pool.c \
+       object-pool.h \
+       property.h \
+       util.c \
+       value.c \
+       value.h
+
+libbabeltrace2_la_LDFLAGS = $(LT_NO_UNDEFINED) \
+                       -version-info $(BABELTRACE_LIBRARY_VERSION)
+
+libbabeltrace2_la_LIBADD = \
+       prio-heap/libprio-heap.la \
+       graph/libgraph.la \
+       plugin/libplugin.la \
+       trace-ir/libtrace-ir.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/compat/libcompat.la
+
+if ENABLE_BUILT_IN_PYTHON_PLUGIN_SUPPORT
+libbabeltrace2_la_LIBADD += $(top_builddir)/src/python-plugin-provider/libbabeltrace2-python-plugin-provider.la
+endif
diff --git a/src/lib/assert-pre.h b/src/lib/assert-pre.h
new file mode 100644 (file)
index 0000000..6264c8a
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef BABELTRACE_ASSERT_PRE_INTERNAL_H
+#define BABELTRACE_ASSERT_PRE_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * The macros in this header use macros defined in
+ * <lib/lib-logging.h>. We don't want this header to
+ * automatically include <lib/lib-logging.h> because you
+ * need to manually define BT_LOG_TAG before including
+ * <lib/lib-logging.h> and it is unexpected that you
+ * also need to define it before including this header.
+ *
+ * This is a reminder that in order to use
+ * <lib/assert-pre.h>, you also need to use logging
+ * explicitly.
+ */
+
+#ifndef BABELTRACE_LIB_LOGGING_INTERNAL_H
+# error Include <lib/lib-logging.h> before this header.
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include "common/babeltrace.h"
+
+#ifdef BT_DEV_MODE
+/*
+ * Asserts that the library precondition _cond is satisfied.
+ *
+ * If _cond is false, log a fatal statement using _fmt and the optional
+ * arguments using BT_LIB_LOGF(), and abort.
+ *
+ * To assert that a postcondition is satisfied or that some internal
+ * object/context/value is in the expected state, use BT_ASSERT().
+ */
+# define BT_ASSERT_PRE(_cond, _fmt, ...)                               \
+       do {                                                            \
+               if (!(_cond)) {                                         \
+                       BT_LOGF_STR("Library precondition not satisfied; error is:"); \
+                       BT_LIB_LOGF((_fmt), ##__VA_ARGS__);             \
+                       BT_LOGF_STR("Aborting...");                     \
+                       abort();                                        \
+               }                                                       \
+       } while (0)
+
+/*
+ * Marks a function as being only used within a BT_ASSERT_PRE() context.
+ */
+# define BT_ASSERT_PRE_FUNC
+
+/*
+ * Prints the details of an unsatisfied precondition without immediately
+ * aborting. You should use this within a function which checks
+ * preconditions, but which is called from a BT_ASSERT_PRE() context, so
+ * that the function can still return its result for BT_ASSERT_PRE() to
+ * evaluate it.
+ *
+ * Example:
+ *
+ *     BT_ASSERT_PRE_FUNC
+ *     static inline bool check_complex_precond(...)
+ *     {
+ *         ...
+ *
+ *         if (...) {
+ *             BT_ASSERT_PRE_MSG("Invalid object: ...", ...);
+ *             return false;
+ *         }
+ *
+ *         ...
+ *     }
+ *
+ *     ...
+ *
+ *     BT_ASSERT_PRE(check_complex_precond(...),
+ *                   "Precondition is not satisfied: ...", ...);
+ */
+# define BT_ASSERT_PRE_MSG     BT_LIB_LOGF
+#else
+# define BT_ASSERT_PRE(_cond, _fmt, ...)       ((void) sizeof((void) (_cond), 0))
+# define BT_ASSERT_PRE_FUNC    BT_UNUSED
+# define BT_ASSERT_PRE_MSG(_fmt, ...)
+#endif /* BT_DEV_MODE */
+
+/*
+ * Developer mode: asserts that a given variable is not NULL.
+ */
+#define BT_ASSERT_PRE_NON_NULL(_obj, _obj_name)                                \
+       BT_ASSERT_PRE((_obj) != NULL, "%s is NULL: ", _obj_name)
+
+/*
+ * Developer mode: asserts that a given object is NOT frozen. This macro
+ * checks the `frozen` field of _obj.
+ */
+#define BT_ASSERT_PRE_HOT(_obj, _obj_name, _fmt, ...)                  \
+       BT_ASSERT_PRE(!(_obj)->frozen, "%s is frozen" _fmt, _obj_name,  \
+               ##__VA_ARGS__)
+
+/*
+ * Developer mode: asserts that a given index is less than a given size.
+ */
+#define BT_ASSERT_PRE_VALID_INDEX(_index, _length)                     \
+       BT_ASSERT_PRE((_index) < (_length),                             \
+               "Index is out of bounds: index=%" PRIu64 ", "           \
+               "count=%" PRIu64, (uint64_t) (_index), (uint64_t) (_length))
+
+#endif /* BABELTRACE_ASSERT_PRE_INTERNAL_H */
diff --git a/src/lib/babeltrace2.c b/src/lib/babeltrace2.c
new file mode 100644 (file)
index 0000000..4a74214
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
+ *
+ * Author: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/version.h>
+#include <babeltrace2/types.h>
+#include <stdlib.h>
+
+int bt_version_get_major(void)
+{
+       return BT_VERSION_MAJOR;
+}
+
+int bt_version_get_minor(void)
+{
+       return BT_VERSION_MINOR;
+}
+
+int bt_version_get_patch(void) {
+       return BT_VERSION_PATCH;
+}
+
+const char *bt_version_get_extra(void)
+{
+       return BT_VERSION_EXTRA;
+}
diff --git a/src/lib/graph/Makefile.am b/src/lib/graph/Makefile.am
new file mode 100644 (file)
index 0000000..a7376fb
--- /dev/null
@@ -0,0 +1,30 @@
+SUBDIRS = message
+
+noinst_LTLIBRARIES = libgraph.la
+
+# Graph library
+libgraph_la_SOURCES = \
+       component.c \
+       component-class.c \
+       component-class.h \
+       component-class-sink-colander.c \
+       component-class-sink-colander.h \
+       component-filter.c \
+       component-filter.h \
+       component.h \
+       component-sink.c \
+       component-sink.h \
+       component-source.c \
+       component-source.h \
+       connection.c \
+       connection.h \
+       graph.c \
+       graph.h \
+       iterator.c \
+       port.c \
+       port.h \
+       query-executor.c \
+       query-executor.h
+
+libgraph_la_LIBADD = \
+       message/libgraph-message.la
diff --git a/src/lib/graph/component-class-sink-colander.c b/src/lib/graph/component-class-sink-colander.c
new file mode 100644 (file)
index 0000000..667b997
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COLANDER"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "lib/object.h"
+#include <babeltrace2/graph/component-class-sink.h>
+#include <babeltrace2/graph/self-component-sink.h>
+#include <babeltrace2/graph/self-component-port.h>
+#include <babeltrace2/graph/self-component-port-input-message-iterator.h>
+#include <babeltrace2/graph/self-component.h>
+#include <glib.h>
+
+#include "component-class-sink-colander.h"
+
+static
+struct bt_component_class_sink *colander_comp_cls;
+
+static
+enum bt_self_component_status colander_init(
+               struct bt_self_component_sink *self_comp,
+               const struct bt_value *params, void *init_method_data)
+{
+       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct bt_component_class_sink_colander_priv_data *colander_data = NULL;
+       struct bt_component_class_sink_colander_data *user_provided_data =
+               init_method_data;
+
+       if (!init_method_data) {
+               BT_LOGW_STR("Component initialization method data is NULL.");
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       colander_data = g_new0(
+               struct bt_component_class_sink_colander_priv_data, 1);
+       if (!colander_data) {
+               BT_LOGE_STR("Failed to allocate colander data.");
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       colander_data->msgs = user_provided_data->msgs;
+       colander_data->count_addr = user_provided_data->count_addr;
+       status = bt_self_component_sink_add_input_port(self_comp, "in",
+               NULL, NULL);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               BT_LOGE_STR("Cannot add input port.");
+               goto end;
+       }
+
+       bt_self_component_set_data(
+               bt_self_component_sink_as_self_component(self_comp),
+               colander_data);
+
+end:
+       return status;
+}
+
+static
+void colander_finalize(struct bt_self_component_sink *self_comp)
+{
+       struct bt_component_class_sink_colander_priv_data *colander_data =
+               bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(self_comp));
+
+       if (!colander_data) {
+               return;
+       }
+
+       BT_OBJECT_PUT_REF_AND_RESET(colander_data->msg_iter);
+       g_free(colander_data);
+}
+
+static
+enum bt_self_component_status colander_graph_is_configured(
+       bt_self_component_sink *self_comp)
+{
+       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct bt_component_class_sink_colander_priv_data *colander_data =
+               bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(self_comp));
+
+       struct bt_self_component_port_input *self_port =
+               bt_self_component_sink_borrow_input_port_by_name(self_comp, "in");
+       BT_ASSERT(self_port);
+
+       BT_ASSERT(colander_data);
+       BT_OBJECT_PUT_REF_AND_RESET(colander_data->msg_iter);
+       colander_data->msg_iter =
+               bt_self_component_port_input_message_iterator_create(
+                       self_port);
+       if (!colander_data->msg_iter) {
+               BT_LIB_LOGE("Cannot create message iterator on "
+                       "self component input port: %![port-]+p",
+                       self_port);
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_self_component_status colander_consume(
+               struct bt_self_component_sink *self_comp)
+{
+       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       enum bt_message_iterator_status msg_iter_status;
+       struct bt_component_class_sink_colander_priv_data *colander_data =
+               bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(self_comp));
+       bt_message_array_const msgs;
+
+       BT_ASSERT(colander_data);
+
+       if (!colander_data->msg_iter) {
+               BT_LIB_LOGW("Trying to consume without an "
+                       "upstream message iterator: %![comp-]+c",
+                       self_comp);
+               goto end;
+       }
+
+       msg_iter_status =
+               bt_self_component_port_input_message_iterator_next(
+                       colander_data->msg_iter, &msgs,
+                       colander_data->count_addr);
+       switch (msg_iter_status) {
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               status = BT_SELF_COMPONENT_STATUS_AGAIN;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_END:
+               status = BT_SELF_COMPONENT_STATUS_END;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+               /* Move messages to user (count already set) */
+               memcpy(colander_data->msgs, msgs,
+                       sizeof(*msgs) * *colander_data->count_addr);
+               break;
+       default:
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+struct bt_component_class_sink *bt_component_class_sink_colander_get(void)
+{
+       if (colander_comp_cls) {
+               goto end;
+       }
+
+       colander_comp_cls = bt_component_class_sink_create("colander",
+               colander_consume);
+       if (!colander_comp_cls) {
+               BT_LOGE_STR("Cannot create sink colander component class.");
+               goto end;
+       }
+
+       (void) bt_component_class_sink_set_init_method(
+               colander_comp_cls, colander_init);
+       (void) bt_component_class_sink_set_finalize_method(
+               colander_comp_cls, colander_finalize);
+       (void) bt_component_class_sink_set_graph_is_configured_method(
+               colander_comp_cls, colander_graph_is_configured);
+
+end:
+       bt_object_get_ref(colander_comp_cls);
+       return (void *) colander_comp_cls;
+}
+
+__attribute__((destructor)) static
+void put_colander(void) {
+       BT_OBJECT_PUT_REF_AND_RESET(colander_comp_cls);
+}
diff --git a/src/lib/graph/component-class-sink-colander.h b/src/lib/graph/component-class-sink-colander.h
new file mode 100644 (file)
index 0000000..faa7a6e
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H
+#define BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <babeltrace2/types.h>
+#include <babeltrace2/graph/message-const.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bt_component_class_sink_colander_priv_data {
+       bt_message_array_const msgs;
+       uint64_t *count_addr;
+       struct bt_self_component_port_input_message_iterator *msg_iter;
+};
+
+struct bt_component_class_sink_colander_data {
+       bt_message_array_const msgs;
+       uint64_t *count_addr;
+};
+
+extern struct bt_component_class_sink *
+bt_component_class_sink_colander_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_GRAPH_COMPONENT_CLASS_SINK_COLANDER_H */
diff --git a/src/lib/graph/component-class.c b/src/lib/graph/component-class.c
new file mode 100644 (file)
index 0000000..87bdb93
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COMP-CLASS"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "compat/compiler.h"
+#include <babeltrace2/graph/component-class.h>
+#include <babeltrace2/graph/component-class-const.h>
+#include <babeltrace2/graph/component-class-source.h>
+#include <babeltrace2/graph/component-class-source-const.h>
+#include <babeltrace2/graph/component-class-filter.h>
+#include <babeltrace2/graph/component-class-filter-const.h>
+#include <babeltrace2/graph/component-class-sink.h>
+#include <babeltrace2/graph/component-class-sink-const.h>
+#include <babeltrace2/types.h>
+#include <glib.h>
+
+#include "component-class.h"
+
+#define BT_ASSERT_PRE_COMP_CLS_HOT(_cc) \
+       BT_ASSERT_PRE_HOT(((const struct bt_component_class *) (_cc)),  \
+               "Component class", ": %!+C", (_cc))
+
+static
+void destroy_component_class(struct bt_object *obj)
+{
+       struct bt_component_class *class;
+       int i;
+
+       BT_ASSERT(obj);
+       class = container_of(obj, struct bt_component_class, base);
+
+       BT_LIB_LOGD("Destroying component class: %!+C", class);
+
+       /* Call destroy listeners in reverse registration order */
+       for (i = class->destroy_listeners->len - 1; i >= 0; i--) {
+               struct bt_component_class_destroy_listener *listener =
+                       &g_array_index(class->destroy_listeners,
+                               struct bt_component_class_destroy_listener,
+                               i);
+
+               BT_LOGD("Calling destroy listener: func-addr=%p, data-addr=%p",
+                       listener->func, listener->data);
+               listener->func(class, listener->data);
+       }
+
+       if (class->name) {
+               g_string_free(class->name, TRUE);
+               class->name = NULL;
+       }
+
+       if (class->description) {
+               g_string_free(class->description, TRUE);
+               class->description = NULL;
+       }
+
+       if (class->help) {
+               g_string_free(class->help, TRUE);
+               class->help = NULL;
+       }
+
+       if (class->destroy_listeners) {
+               g_array_free(class->destroy_listeners, TRUE);
+               class->destroy_listeners = NULL;
+       }
+
+       g_free(class);
+}
+
+static
+int bt_component_class_init(struct bt_component_class *class,
+               enum bt_component_class_type type, const char *name)
+{
+       int ret = 0;
+
+       bt_object_init_shared(&class->base, destroy_component_class);
+       class->type = type;
+       class->name = g_string_new(name);
+       if (!class->name) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       class->description = g_string_new(NULL);
+       if (!class->description) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       class->help = g_string_new(NULL);
+       if (!class->help) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       class->destroy_listeners = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_component_class_destroy_listener));
+       if (!class->destroy_listeners) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(class);
+       ret = -1;
+
+end:
+       return ret;
+}
+
+struct bt_component_class_source *bt_component_class_source_create(
+               const char *name,
+               bt_component_class_source_message_iterator_next_method method)
+{
+       struct bt_component_class_source *source_class = NULL;
+       int ret;
+
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(method, "Message iterator next method");
+       BT_LOGD("Creating source component class: "
+               "name=\"%s\", msg-iter-next-method-addr=%p",
+               name, method);
+       source_class = g_new0(struct bt_component_class_source, 1);
+       if (!source_class) {
+               BT_LOGE_STR("Failed to allocate one source component class.");
+               goto end;
+       }
+
+       /* bt_component_class_init() logs errors */
+       ret = bt_component_class_init(&source_class->parent,
+               BT_COMPONENT_CLASS_TYPE_SOURCE, name);
+       if (ret) {
+               /*
+                * If bt_component_class_init() fails, the component
+                * class is put, therefore its memory is already
+                * freed.
+                */
+               source_class = NULL;
+               goto end;
+       }
+
+       source_class->methods.msg_iter_next = method;
+       BT_LIB_LOGD("Created source component class: %!+C", source_class);
+
+end:
+       return (void *) source_class;
+}
+
+struct bt_component_class_filter *bt_component_class_filter_create(
+               const char *name,
+               bt_component_class_filter_message_iterator_next_method method)
+{
+       struct bt_component_class_filter *filter_class = NULL;
+       int ret;
+
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(method, "Message iterator next method");
+       BT_LOGD("Creating filter component class: "
+               "name=\"%s\", msg-iter-next-method-addr=%p",
+               name, method);
+       filter_class = g_new0(struct bt_component_class_filter, 1);
+       if (!filter_class) {
+               BT_LOGE_STR("Failed to allocate one filter component class.");
+               goto end;
+       }
+
+       /* bt_component_class_init() logs errors */
+       ret = bt_component_class_init(&filter_class->parent,
+               BT_COMPONENT_CLASS_TYPE_FILTER, name);
+       if (ret) {
+               /*
+                * If bt_component_class_init() fails, the component
+                * class is put, therefore its memory is already
+                * freed.
+                */
+               filter_class = NULL;
+               goto end;
+       }
+
+       filter_class->methods.msg_iter_next = method;
+       BT_LIB_LOGD("Created filter component class: %!+C", filter_class);
+
+end:
+       return (void *) filter_class;
+}
+
+struct bt_component_class_sink *bt_component_class_sink_create(
+               const char *name, bt_component_class_sink_consume_method method)
+{
+       struct bt_component_class_sink *sink_class = NULL;
+       int ret;
+
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(method, "Consume next method");
+       BT_LOGD("Creating sink component class: "
+               "name=\"%s\", consume-method-addr=%p",
+               name, method);
+       sink_class = g_new0(struct bt_component_class_sink, 1);
+       if (!sink_class) {
+               BT_LOGE_STR("Failed to allocate one sink component class.");
+               goto end;
+       }
+
+       /* bt_component_class_init() logs errors */
+       ret = bt_component_class_init(&sink_class->parent,
+               BT_COMPONENT_CLASS_TYPE_SINK, name);
+       if (ret) {
+               /*
+                * If bt_component_class_init() fails, the component
+                * class is put, therefore its memory is already
+                * freed.
+                */
+               sink_class = NULL;
+               goto end;
+       }
+
+       sink_class->methods.consume = method;
+       BT_LIB_LOGD("Created sink component class: %!+C", sink_class);
+
+end:
+       return (void *) sink_class;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_init_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_init_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.init = method;
+       BT_LIB_LOGV("Set source component class's initialization method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_init_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_init_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.init = method;
+       BT_LIB_LOGV("Set filter component class's initialization method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_sink_set_init_method(
+               struct bt_component_class_sink *comp_cls,
+               bt_component_class_sink_init_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.init = method;
+       BT_LIB_LOGV("Set sink component class's initialization method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_finalize_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_finalize_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.finalize = method;
+       BT_LIB_LOGV("Set source component class's finalization method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_finalize_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_finalize_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.finalize = method;
+       BT_LIB_LOGV("Set filter component class's finalization method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_sink_set_finalize_method(
+               struct bt_component_class_sink *comp_cls,
+               bt_component_class_sink_finalize_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.finalize = method;
+       BT_LIB_LOGV("Set sink component class's finalization method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_query_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_query_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.query = method;
+       BT_LIB_LOGV("Set source component class's query method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_query_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_query_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.query = method;
+       BT_LIB_LOGV("Set filter component class's query method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_sink_set_query_method(
+               struct bt_component_class_sink *comp_cls,
+               bt_component_class_sink_query_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.query = method;
+       BT_LIB_LOGV("Set sink component class's query method: "
+               "%!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_accept_input_port_connection_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_accept_input_port_connection_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.accept_input_port_connection = method;
+       BT_LIB_LOGV("Set filter component class's \"accept input port connection\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_sink_set_accept_input_port_connection_method(
+               struct bt_component_class_sink *comp_cls,
+               bt_component_class_sink_accept_input_port_connection_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.accept_input_port_connection = method;
+       BT_LIB_LOGV("Set sink component class's \"accept input port connection\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_accept_output_port_connection_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_accept_output_port_connection_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.accept_output_port_connection = method;
+       BT_LIB_LOGV("Set source component class's \"accept output port connection\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_accept_output_port_connection_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_accept_output_port_connection_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.accept_output_port_connection = method;
+       BT_LIB_LOGV("Set filter component class's \"accept output port connection\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_input_port_connected_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_input_port_connected_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.input_port_connected = method;
+       BT_LIB_LOGV("Set filter component class's \"input port connected\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_sink_set_input_port_connected_method(
+               struct bt_component_class_sink *comp_cls,
+               bt_component_class_sink_input_port_connected_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.input_port_connected = method;
+       BT_LIB_LOGV("Set sink component class's \"input port connected\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_output_port_connected_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_output_port_connected_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.output_port_connected = method;
+       BT_LIB_LOGV("Set source component class's \"output port connected\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_output_port_connected_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_output_port_connected_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.output_port_connected = method;
+       BT_LIB_LOGV("Set filter component class's \"output port connected\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_sink_set_graph_is_configured_method(
+               struct bt_component_class_sink *comp_cls,
+               bt_component_class_sink_graph_is_configured_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.graph_is_configured = method;
+       BT_LIB_LOGV("Set sink component class's \"graph is configured\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+int bt_component_class_source_set_message_iterator_init_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_message_iterator_init_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_init = method;
+       BT_LIB_LOGV("Set source component class's message iterator initialization method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_message_iterator_init_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_message_iterator_init_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_init = method;
+       BT_LIB_LOGV("Set filter component class's message iterator initialization method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_message_iterator_finalize_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_message_iterator_finalize_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_finalize = method;
+       BT_LIB_LOGV("Set source component class's message iterator finalization method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_message_iterator_finalize_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_message_iterator_finalize_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_finalize = method;
+       BT_LIB_LOGV("Set filter component class's message iterator finalization method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_message_iterator_seek_ns_from_origin_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_message_iterator_seek_ns_from_origin_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_seek_ns_from_origin = method;
+       BT_LIB_LOGV("Set filter component class's message iterator \"seek nanoseconds from origin\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_message_iterator_seek_ns_from_origin_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_message_iterator_seek_ns_from_origin_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_seek_ns_from_origin = method;
+       BT_LIB_LOGV("Set source component class's message iterator \"seek nanoseconds from origin\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_message_iterator_seek_beginning_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_message_iterator_seek_beginning_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_seek_beginning = method;
+       BT_LIB_LOGV("Set filter component class's message iterator \"seek beginning\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_message_iterator_seek_beginning_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_message_iterator_seek_beginning_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_seek_beginning = method;
+       BT_LIB_LOGV("Set source component class's message iterator \"seek beginning\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_message_iterator_can_seek_beginning_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_message_iterator_can_seek_beginning_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_can_seek_beginning = method;
+       BT_LIB_LOGV("Set filter component class's message iterator \"can seek beginning\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_message_iterator_can_seek_beginning_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_message_iterator_can_seek_beginning_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_can_seek_beginning = method;
+       BT_LIB_LOGV("Set source component class's message iterator \"can seek beginning\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_filter_set_message_iterator_can_seek_ns_from_origin_method(
+               struct bt_component_class_filter *comp_cls,
+               bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_can_seek_ns_from_origin = method;
+       BT_LIB_LOGV("Set filter component class's message iterator \"can seek nanoseconds from origin\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+enum bt_component_class_status
+bt_component_class_source_set_message_iterator_can_seek_ns_from_origin_method(
+               struct bt_component_class_source *comp_cls,
+               bt_component_class_source_message_iterator_can_seek_ns_from_origin_method method)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(method, "Method");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       comp_cls->methods.msg_iter_can_seek_ns_from_origin = method;
+       BT_LIB_LOGV("Set source component class's message iterator \"can seek nanoseconds from origin\" method"
+               ": %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+bt_component_class_status bt_component_class_set_description(
+               struct bt_component_class *comp_cls,
+               const char *description)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(description, "Description");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       g_string_assign(comp_cls->description, description);
+       BT_LIB_LOGV("Set component class's description: "
+               "addr=%p, name=\"%s\", type=%s",
+               comp_cls,
+               bt_component_class_get_name(comp_cls),
+               bt_component_class_type_string(comp_cls->type));
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+bt_component_class_status bt_component_class_set_help(
+               struct bt_component_class *comp_cls,
+               const char *help)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(help, "Help");
+       BT_ASSERT_PRE_COMP_CLS_HOT(comp_cls);
+       g_string_assign(comp_cls->help, help);
+       BT_LIB_LOGV("Set component class's help text: %!+C", comp_cls);
+       return BT_COMPONENT_CLASS_STATUS_OK;
+}
+
+const char *bt_component_class_get_name(const struct bt_component_class *comp_cls)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       return comp_cls->name->str;
+}
+
+enum bt_component_class_type bt_component_class_get_type(
+               const struct bt_component_class *comp_cls)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       return comp_cls->type;
+}
+
+const char *bt_component_class_get_description(
+               const struct bt_component_class *comp_cls)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       return comp_cls->description &&
+               comp_cls->description->str[0] != '\0' ?
+               comp_cls->description->str : NULL;
+}
+
+const char *bt_component_class_get_help(
+               const struct bt_component_class *comp_cls)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       return comp_cls->help &&
+               comp_cls->help->str[0] != '\0' ? comp_cls->help->str : NULL;
+}
+
+BT_HIDDEN
+void bt_component_class_add_destroy_listener(
+               struct bt_component_class *comp_cls,
+               bt_component_class_destroy_listener_func func, void *data)
+{
+       struct bt_component_class_destroy_listener listener;
+
+       BT_ASSERT(comp_cls);
+       BT_ASSERT(func);
+       listener.func = func;
+       listener.data = data;
+       g_array_append_val(comp_cls->destroy_listeners, listener);
+       BT_LIB_LOGV("Added destroy listener to component class: "
+               "%![cc-]+C, listener-func-addr=%p", comp_cls, func);
+}
+
+BT_HIDDEN
+void _bt_component_class_freeze(const struct bt_component_class *comp_cls)
+{
+       BT_ASSERT(comp_cls);
+       BT_LIB_LOGD("Freezing component class: %!+C", comp_cls);
+       ((struct bt_component_class *) comp_cls)->frozen = true;
+}
+
+void bt_component_class_get_ref(
+               const struct bt_component_class *component_class)
+{
+       bt_object_get_ref(component_class);
+}
+
+void bt_component_class_put_ref(
+               const struct bt_component_class *component_class)
+{
+       bt_object_put_ref(component_class);
+}
+
+void bt_component_class_source_get_ref(
+               const struct bt_component_class_source *component_class_source)
+{
+       bt_object_get_ref(component_class_source);
+}
+
+void bt_component_class_source_put_ref(
+               const struct bt_component_class_source *component_class_source)
+{
+       bt_object_put_ref(component_class_source);
+}
+
+void bt_component_class_filter_get_ref(
+               const struct bt_component_class_filter *component_class_filter)
+{
+       bt_object_get_ref(component_class_filter);
+}
+
+void bt_component_class_filter_put_ref(
+               const struct bt_component_class_filter *component_class_filter)
+{
+       bt_object_put_ref(component_class_filter);
+}
+
+void bt_component_class_sink_get_ref(
+               const struct bt_component_class_sink *component_class_sink)
+{
+       bt_object_get_ref(component_class_sink);
+}
+
+void bt_component_class_sink_put_ref(
+               const struct bt_component_class_sink *component_class_sink)
+{
+       bt_object_put_ref(component_class_sink);
+}
diff --git a/src/lib/graph/component-class.h b/src/lib/graph/component-class.h
new file mode 100644 (file)
index 0000000..1c49a76
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef BABELTRACE_GRAPH_COMPONENT_CLASS_INTERNAL_H
+#define BABELTRACE_GRAPH_COMPONENT_CLASS_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/graph/component-const.h>
+#include <babeltrace2/graph/component-class.h>
+#include <babeltrace2/graph/component-class-source.h>
+#include <babeltrace2/graph/component-class-filter.h>
+#include <babeltrace2/graph/component-class-sink.h>
+#include "common/babeltrace.h"
+#include "lib/object.h"
+#include "common/list.h"
+#include <babeltrace2/types.h>
+#include <glib.h>
+
+struct bt_component_class;
+struct bt_plugin_so_shared_lib_handle;
+
+typedef void (*bt_component_class_destroy_listener_func)(
+               struct bt_component_class *class, void *data);
+
+struct bt_component_class_destroy_listener {
+       bt_component_class_destroy_listener_func func;
+       void *data;
+};
+
+struct bt_component_class {
+       struct bt_object base;
+       enum bt_component_class_type type;
+       GString *name;
+       GString *description;
+       GString *help;
+
+       /* Array of struct bt_component_class_destroy_listener */
+       GArray *destroy_listeners;
+       bool frozen;
+       struct bt_list_head node;
+       struct bt_plugin_so_shared_lib_handle *so_handle;
+};
+
+struct bt_component_class_source {
+       struct bt_component_class parent;
+       struct {
+               bt_component_class_source_init_method init;
+               bt_component_class_source_finalize_method finalize;
+               bt_component_class_source_message_iterator_init_method msg_iter_init;
+               bt_component_class_source_message_iterator_finalize_method msg_iter_finalize;
+               bt_component_class_source_message_iterator_next_method msg_iter_next;
+               bt_component_class_source_message_iterator_seek_ns_from_origin_method msg_iter_seek_ns_from_origin;
+               bt_component_class_source_message_iterator_seek_beginning_method msg_iter_seek_beginning;
+               bt_component_class_source_message_iterator_can_seek_ns_from_origin_method msg_iter_can_seek_ns_from_origin;
+               bt_component_class_source_message_iterator_can_seek_beginning_method msg_iter_can_seek_beginning;
+               bt_component_class_source_query_method query;
+               bt_component_class_source_accept_output_port_connection_method accept_output_port_connection;
+               bt_component_class_source_output_port_connected_method output_port_connected;
+       } methods;
+};
+
+struct bt_component_class_sink {
+       struct bt_component_class parent;
+       struct {
+               bt_component_class_sink_init_method init;
+               bt_component_class_sink_finalize_method finalize;
+               bt_component_class_sink_query_method query;
+               bt_component_class_sink_accept_input_port_connection_method accept_input_port_connection;
+               bt_component_class_sink_input_port_connected_method input_port_connected;
+               bt_component_class_sink_graph_is_configured_method graph_is_configured;
+               bt_component_class_sink_consume_method consume;
+       } methods;
+};
+
+struct bt_component_class_filter {
+       struct bt_component_class parent;
+       struct {
+               bt_component_class_filter_init_method init;
+               bt_component_class_filter_finalize_method finalize;
+               bt_component_class_filter_message_iterator_init_method msg_iter_init;
+               bt_component_class_filter_message_iterator_finalize_method msg_iter_finalize;
+               bt_component_class_filter_message_iterator_next_method msg_iter_next;
+               bt_component_class_filter_message_iterator_seek_ns_from_origin_method msg_iter_seek_ns_from_origin;
+               bt_component_class_filter_message_iterator_seek_beginning_method msg_iter_seek_beginning;
+               bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method msg_iter_can_seek_ns_from_origin;
+               bt_component_class_filter_message_iterator_can_seek_beginning_method msg_iter_can_seek_beginning;
+               bt_component_class_filter_query_method query;
+               bt_component_class_filter_accept_input_port_connection_method accept_input_port_connection;
+               bt_component_class_filter_accept_output_port_connection_method accept_output_port_connection;
+               bt_component_class_filter_input_port_connected_method input_port_connected;
+               bt_component_class_filter_output_port_connected_method output_port_connected;
+       } methods;
+};
+
+BT_HIDDEN
+void bt_component_class_add_destroy_listener(struct bt_component_class *class,
+               bt_component_class_destroy_listener_func func, void *data);
+
+BT_HIDDEN
+void _bt_component_class_freeze(
+               const struct bt_component_class *component_class);
+
+#ifdef BT_DEV_MODE
+# define bt_component_class_freeze     _bt_component_class_freeze
+#else
+# define bt_component_class_freeze(_cc)
+#endif
+
+static inline
+const char *bt_component_class_type_string(enum bt_component_class_type type)
+{
+       switch (type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+               return "BT_COMPONENT_CLASS_TYPE_SOURCE";
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+               return "BT_COMPONENT_CLASS_TYPE_SINK";
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+               return "BT_COMPONENT_CLASS_TYPE_FILTER";
+       default:
+               return "(unknown)";
+       }
+}
+
+#endif /* BABELTRACE_GRAPH_COMPONENT_CLASS_INTERNAL_H */
diff --git a/src/lib/graph/component-filter.c b/src/lib/graph/component-filter.c
new file mode 100644 (file)
index 0000000..ab48fb7
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COMP-FILTER"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "compat/compiler.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/graph/self-component-filter.h>
+#include <babeltrace2/graph/component-filter-const.h>
+#include <babeltrace2/graph/graph.h>
+
+#include "component-filter.h"
+#include "component.h"
+#include "component-class.h"
+
+BT_HIDDEN
+void bt_component_filter_destroy(struct bt_component *component)
+{
+}
+
+BT_HIDDEN
+struct bt_component *bt_component_filter_create(
+               const struct bt_component_class *class)
+{
+       struct bt_component_filter *filter = NULL;
+
+       filter = g_new0(struct bt_component_filter, 1);
+       if (!filter) {
+               BT_LOGE_STR("Failed to allocate one filter component.");
+               goto end;
+       }
+
+end:
+       return (void *) filter;
+}
+
+const bt_component_class_filter *
+bt_component_filter_borrow_class_const(
+               const bt_component_filter *component)
+{
+       struct bt_component_class *cls;
+
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+
+       cls = component->parent.class;
+
+       BT_ASSERT(cls);
+       BT_ASSERT(cls->type == BT_COMPONENT_CLASS_TYPE_FILTER);
+
+       return (bt_component_class_filter *) cls;
+}
+
+uint64_t bt_component_filter_get_output_port_count(
+               const struct bt_component_filter *comp)
+{
+       return bt_component_get_output_port_count((void *) comp);
+}
+
+const struct bt_port_output *
+bt_component_filter_borrow_output_port_by_name_const(
+               const struct bt_component_filter *comp, const char *name)
+{
+       return bt_component_borrow_output_port_by_name(
+               (void *) comp, name);
+}
+
+struct bt_self_component_port_output *
+bt_self_component_filter_borrow_output_port_by_name(
+               struct bt_self_component_filter *comp, const char *name)
+{
+       return (void *) bt_component_borrow_output_port_by_name(
+               (void *) comp, name);
+}
+
+const struct bt_port_output *
+bt_component_filter_borrow_output_port_by_index_const(
+               const struct bt_component_filter *comp, uint64_t index)
+{
+       return bt_component_borrow_output_port_by_index(
+               (void *) comp, index);
+}
+
+struct bt_self_component_port_output *
+bt_self_component_filter_borrow_output_port_by_index(
+               struct bt_self_component_filter *comp, uint64_t index)
+{
+       return (void *) bt_component_borrow_output_port_by_index(
+               (void *) comp, index);
+}
+
+enum bt_self_component_status bt_self_component_filter_add_output_port(
+               struct bt_self_component_filter *self_comp,
+               const char *name, void *user_data,
+               struct bt_self_component_port_output **self_port)
+{
+       struct bt_component *comp = (void *) self_comp;
+       enum bt_self_component_status status;
+       struct bt_port *port = NULL;
+
+       /* bt_component_add_output_port() logs details and errors */
+       status = bt_component_add_output_port(comp, name, user_data, &port);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto end;
+       }
+
+       if (self_port) {
+               /* Move reference to user */
+               *self_port = (void *) port;
+               port = NULL;
+       }
+
+end:
+       bt_object_put_ref(port);
+       return status;
+}
+
+uint64_t bt_component_filter_get_input_port_count(
+               const struct bt_component_filter *component)
+{
+       /* bt_component_get_input_port_count() logs details/errors */
+       return bt_component_get_input_port_count((void *) component);
+}
+
+const struct bt_port_input *bt_component_filter_borrow_input_port_by_name_const(
+               const struct bt_component_filter *component, const char *name)
+{
+       /* bt_component_borrow_input_port_by_name() logs details/errors */
+       return bt_component_borrow_input_port_by_name(
+               (void *) component, name);
+}
+
+struct bt_self_component_port_input *
+bt_self_component_filter_borrow_input_port_by_name(
+               struct bt_self_component_filter *component, const char *name)
+{
+       /* bt_component_borrow_input_port_by_name() logs details/errors */
+       return (void *) bt_component_borrow_input_port_by_name(
+               (void *) component, name);
+}
+
+const struct bt_port_input *
+bt_component_filter_borrow_input_port_by_index_const(
+               const struct bt_component_filter *component, uint64_t index)
+{
+       /* bt_component_borrow_input_port_by_index() logs details/errors */
+       return bt_component_borrow_input_port_by_index(
+               (void *) component, index);
+}
+
+struct bt_self_component_port_input *
+bt_self_component_filter_borrow_input_port_by_index(
+               struct bt_self_component_filter *component, uint64_t index)
+{
+       /* bt_component_borrow_input_port_by_index() logs details/errors */
+       return (void *) bt_component_borrow_input_port_by_index(
+               (void *) component, index);
+}
+
+enum bt_self_component_status bt_self_component_filter_add_input_port(
+               struct bt_self_component_filter *self_comp,
+               const char *name, void *user_data,
+               struct bt_self_component_port_input **self_port)
+{
+       enum bt_self_component_status status;
+       struct bt_port *port = NULL;
+       struct bt_component *comp = (void *) self_comp;
+
+       /* bt_component_add_input_port() logs details/errors */
+       status = bt_component_add_input_port(comp, name, user_data, &port);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto end;
+       }
+
+       if (self_port) {
+               /* Move reference to user */
+               *self_port = (void *) port;
+               port = NULL;
+       }
+
+end:
+       bt_object_put_ref(port);
+       return status;
+}
+
+void bt_component_filter_get_ref(
+               const struct bt_component_filter *component_filter)
+{
+       bt_object_get_ref(component_filter);
+}
+
+void bt_component_filter_put_ref(
+               const struct bt_component_filter *component_filter)
+{
+       bt_object_put_ref(component_filter);
+}
diff --git a/src/lib/graph/component-filter.h b/src/lib/graph/component-filter.h
new file mode 100644 (file)
index 0000000..7d5a792
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef BABELTRACE_GRAPH_COMPONENT_FILTER_INTERNAL_H
+#define BABELTRACE_GRAPH_COMPONENT_FILTER_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/graph/component-filter-const.h>
+
+#include "component-class.h"
+#include "component.h"
+
+struct bt_component_filter {
+       struct bt_component parent;
+};
+
+BT_HIDDEN
+struct bt_component *bt_component_filter_create(
+               const struct bt_component_class *class);
+
+BT_HIDDEN
+void bt_component_filter_destroy(struct bt_component *component);
+
+#endif /* BABELTRACE_GRAPH_COMPONENT_FILTER_INTERNAL_H */
diff --git a/src/lib/graph/component-sink.c b/src/lib/graph/component-sink.c
new file mode 100644 (file)
index 0000000..5983924
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COMP-SINK"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "compat/compiler.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/graph/self-component-sink.h>
+#include <babeltrace2/graph/component-sink-const.h>
+#include <babeltrace2/graph/graph.h>
+
+#include "component-sink.h"
+#include "component.h"
+
+BT_HIDDEN
+void bt_component_sink_destroy(struct bt_component *component)
+{
+}
+
+BT_HIDDEN
+struct bt_component *bt_component_sink_create(
+               const struct bt_component_class *class)
+{
+       struct bt_component_sink *sink = NULL;
+
+       sink = g_new0(struct bt_component_sink, 1);
+       if (!sink) {
+               BT_LOGE_STR("Failed to allocate one sink component.");
+               goto end;
+       }
+
+end:
+       return (void *) sink;
+}
+
+const bt_component_class_sink *
+bt_component_sink_borrow_class_const(
+               const bt_component_sink *component)
+{
+       struct bt_component_class *cls;
+
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+
+       cls = component->parent.class;
+
+       BT_ASSERT(cls);
+       BT_ASSERT(cls->type == BT_COMPONENT_CLASS_TYPE_SINK);
+
+       return (bt_component_class_sink *) cls;
+}
+
+uint64_t bt_component_sink_get_input_port_count(
+               const struct bt_component_sink *component)
+{
+       /* bt_component_get_input_port_count() logs details/errors */
+       return bt_component_get_input_port_count((void *) component);
+}
+
+const struct bt_port_input *
+bt_component_sink_borrow_input_port_by_name_const(
+               const struct bt_component_sink *component, const char *name)
+{
+       /* bt_component_borrow_input_port_by_name() logs details/errors */
+       return bt_component_borrow_input_port_by_name((void *) component, name);
+}
+
+struct bt_self_component_port_input *
+bt_self_component_sink_borrow_input_port_by_name(
+               struct bt_self_component_sink *component, const char *name)
+{
+       /* bt_component_borrow_input_port_by_name() logs details/errors */
+       return (void *) bt_component_borrow_input_port_by_name(
+               (void *) component, name);
+}
+
+const struct bt_port_input *bt_component_sink_borrow_input_port_by_index_const(
+               const struct bt_component_sink *component, uint64_t index)
+{
+       /* bt_component_borrow_input_port_by_index() logs details/errors */
+       return bt_component_borrow_input_port_by_index(
+               (void *) component, index);
+}
+
+struct bt_self_component_port_input *
+bt_self_component_sink_borrow_input_port_by_index(
+               struct bt_self_component_sink *component, uint64_t index)
+{
+       /* bt_component_borrow_input_port_by_index() logs details/errors */
+       return (void *) bt_component_borrow_input_port_by_index(
+               (void *) component, index);
+}
+
+enum bt_self_component_status bt_self_component_sink_add_input_port(
+               struct bt_self_component_sink *self_comp,
+               const char *name, void *user_data,
+               struct bt_self_component_port_input **self_port)
+{
+       enum bt_self_component_status status;
+       struct bt_port *port = NULL;
+       struct bt_component *comp = (void *) self_comp;
+
+       /* bt_component_add_input_port() logs details/errors */
+       status = bt_component_add_input_port(comp, name, user_data, &port);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto end;
+       }
+
+       if (self_port) {
+               /* Move reference to user */
+               *self_port = (void *) port;
+               port = NULL;
+       }
+
+end:
+       bt_object_put_ref(port);
+       return status;
+}
+
+void bt_component_sink_get_ref(
+               const struct bt_component_sink *component_sink)
+{
+       bt_object_get_ref(component_sink);
+}
+
+void bt_component_sink_put_ref(
+               const struct bt_component_sink *component_sink)
+{
+       bt_object_put_ref(component_sink);
+}
diff --git a/src/lib/graph/component-sink.h b/src/lib/graph/component-sink.h
new file mode 100644 (file)
index 0000000..a670635
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef BABELTRACE_GRAPH_COMPONENT_SINK_INTERNAL_H
+#define BABELTRACE_GRAPH_COMPONENT_SINK_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "compat/compiler.h"
+#include <babeltrace2/graph/component-sink-const.h>
+
+#include "component-class.h"
+#include "component.h"
+
+struct bt_component_sink {
+       struct bt_component parent;
+       bool graph_is_configured_method_called;
+};
+
+BT_HIDDEN
+struct bt_component *bt_component_sink_create(
+               const struct bt_component_class *class);
+
+BT_HIDDEN
+void bt_component_sink_destroy(struct bt_component *component);
+
+#endif /* BABELTRACE_GRAPH_COMPONENT_SINK_INTERNAL_H */
diff --git a/src/lib/graph/component-source.c b/src/lib/graph/component-source.c
new file mode 100644 (file)
index 0000000..c7c01ab
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COMP-SOURCE"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "compat/compiler.h"
+#include <babeltrace2/graph/self-component-source.h>
+#include <babeltrace2/graph/component-source-const.h>
+#include <babeltrace2/graph/message-iterator-const.h>
+#include <babeltrace2/graph/graph.h>
+
+#include "component-source.h"
+#include "component.h"
+#include "port.h"
+#include "message/iterator.h"
+
+BT_HIDDEN
+void bt_component_source_destroy(struct bt_component *component)
+{
+}
+
+BT_HIDDEN
+struct bt_component *bt_component_source_create(
+               const struct bt_component_class *class)
+{
+       struct bt_component_source *source = NULL;
+
+       source = g_new0(struct bt_component_source, 1);
+       if (!source) {
+               BT_LOGE_STR("Failed to allocate one source component.");
+               goto end;
+       }
+
+end:
+       return (void *) source;
+}
+
+const bt_component_class_source *
+bt_component_source_borrow_class_const(
+               const bt_component_source *component)
+{
+       struct bt_component_class *cls;
+
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+
+       cls = component->parent.class;
+
+       BT_ASSERT(cls);
+       BT_ASSERT(cls->type == BT_COMPONENT_CLASS_TYPE_SOURCE);
+
+       return (bt_component_class_source *) cls;
+}
+
+uint64_t bt_component_source_get_output_port_count(
+               const struct bt_component_source *comp)
+{
+       return bt_component_get_output_port_count((void *) comp);
+}
+
+const struct bt_port_output *
+bt_component_source_borrow_output_port_by_name_const(
+               const struct bt_component_source *comp, const char *name)
+{
+       return bt_component_borrow_output_port_by_name((void *) comp, name);
+}
+
+struct bt_self_component_port_output *
+bt_self_component_source_borrow_output_port_by_name(
+               struct bt_self_component_source *comp, const char *name)
+{
+       return (void *) bt_component_borrow_output_port_by_name(
+               (void *) comp, name);
+}
+
+const struct bt_port_output *
+bt_component_source_borrow_output_port_by_index_const(
+               const struct bt_component_source *comp, uint64_t index)
+{
+       return bt_component_borrow_output_port_by_index((void *) comp, index);
+}
+
+struct bt_self_component_port_output *
+bt_self_component_source_borrow_output_port_by_index(
+               struct bt_self_component_source *comp, uint64_t index)
+{
+       return (void *) bt_component_borrow_output_port_by_index(
+               (void *) comp, index);
+}
+
+enum bt_self_component_status bt_self_component_source_add_output_port(
+               struct bt_self_component_source *self_comp,
+               const char *name, void *user_data,
+               struct bt_self_component_port_output **self_port)
+{
+       struct bt_component *comp = (void *) self_comp;
+       enum bt_self_component_status status;
+       struct bt_port *port = NULL;
+
+       /* bt_component_add_output_port() logs details and errors */
+       status = bt_component_add_output_port(comp, name, user_data, &port);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto end;
+       }
+
+       if (self_port) {
+               /* Move reference to user */
+               *self_port = (void *) port;
+               port = NULL;
+       }
+
+end:
+       bt_object_put_ref(port);
+       return status;
+}
+
+void bt_component_source_get_ref(
+               const struct bt_component_source *component_source)
+{
+       bt_object_get_ref(component_source);
+}
+
+void bt_component_source_put_ref(
+               const struct bt_component_source *component_source)
+{
+       bt_object_put_ref(component_source);
+}
diff --git a/src/lib/graph/component-source.h b/src/lib/graph/component-source.h
new file mode 100644 (file)
index 0000000..747d760
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef BABELTRACE_GRAPH_COMPONENT_SOURCE_INTERNAL_H
+#define BABELTRACE_GRAPH_COMPONENT_SOURCE_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+
+#include "component-class.h"
+#include "component.h"
+
+struct bt_component_source {
+       struct bt_component parent;
+};
+
+BT_HIDDEN
+struct bt_component *bt_component_source_create(
+               const struct bt_component_class *class);
+
+BT_HIDDEN
+void bt_component_source_destroy(struct bt_component *component);
+
+#endif /* BABELTRACE_GRAPH_COMPONENT_SOURCE_INTERNAL_H */
diff --git a/src/lib/graph/component.c b/src/lib/graph/component.c
new file mode 100644 (file)
index 0000000..f4e4be1
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "COMP"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include <babeltrace2/graph/self-component.h>
+#include <babeltrace2/graph/component-const.h>
+#include <babeltrace2/graph/component-source-const.h>
+#include <babeltrace2/graph/component-filter-const.h>
+#include <babeltrace2/graph/component-sink-const.h>
+#include "common/babeltrace.h"
+#include "compat/compiler.h"
+#include <babeltrace2/types.h>
+#include <babeltrace2/value.h>
+#include "lib/value.h"
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "component.h"
+#include "component-class.h"
+#include "component-source.h"
+#include "component-filter.h"
+#include "component-sink.h"
+#include "connection.h"
+#include "graph.h"
+#include "message/iterator.h"
+#include "port.h"
+
+static
+struct bt_component * (* const component_create_funcs[])(
+               const struct bt_component_class *) = {
+       [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_create,
+       [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_create,
+       [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_create,
+};
+
+static
+void (*component_destroy_funcs[])(struct bt_component *) = {
+       [BT_COMPONENT_CLASS_TYPE_SOURCE] = bt_component_source_destroy,
+       [BT_COMPONENT_CLASS_TYPE_SINK] = bt_component_sink_destroy,
+       [BT_COMPONENT_CLASS_TYPE_FILTER] = bt_component_filter_destroy,
+};
+
+static
+void finalize_component(struct bt_component *comp)
+{
+       typedef void (*method_t)(void *);
+
+       method_t method = NULL;
+
+       BT_ASSERT(comp);
+
+       switch (comp->class->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               struct bt_component_class_source *src_cc = (void *) comp->class;
+
+               method = (method_t) src_cc->methods.finalize;
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               struct bt_component_class_filter *flt_cc = (void *) comp->class;
+
+               method = (method_t) flt_cc->methods.finalize;
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+       {
+               struct bt_component_class_sink *sink_cc = (void *) comp->class;
+
+               method = (method_t) sink_cc->methods.finalize;
+               break;
+       }
+       default:
+               abort();
+       }
+
+       if (method) {
+               BT_LIB_LOGD("Calling user's finalization method: "
+                       "%![comp-]+c", comp);
+               method(comp);
+       }
+}
+
+static
+void destroy_component(struct bt_object *obj)
+{
+       struct bt_component *component = NULL;
+       int i;
+
+       if (!obj) {
+               return;
+       }
+
+       /*
+        * The component's reference count is 0 if we're here. Increment
+        * it to avoid a double-destroy (possibly infinitely recursive).
+        * This could happen for example if the component's finalization
+        * function does bt_object_get_ref() (or anything that causes
+        * bt_object_get_ref() to be called) on itself (ref. count goes
+        * from 0 to 1), and then bt_object_put_ref(): the reference
+        * count would go from 1 to 0 again and this function would be
+        * called again.
+        */
+       obj->ref_count++;
+       component = container_of(obj, struct bt_component, base);
+       BT_LIB_LOGD("Destroying component: %![comp-]+c, %![graph-]+g",
+               component, bt_component_borrow_graph(component));
+
+       /* Call destroy listeners in reverse registration order */
+       BT_LOGD_STR("Calling destroy listeners.");
+
+       for (i = component->destroy_listeners->len - 1; i >= 0; i--) {
+               struct bt_component_destroy_listener *listener =
+                       &g_array_index(component->destroy_listeners,
+                               struct bt_component_destroy_listener, i);
+
+               listener->func(component, listener->data);
+       }
+
+       /*
+        * User data is destroyed first, followed by the concrete
+        * component instance. Do not finalize if the component's user
+        * initialization method failed in the first place.
+        */
+       if (component->initialized) {
+               finalize_component(component);
+       }
+
+       if (component->destroy) {
+               BT_LOGD_STR("Destroying type-specific data.");
+               component->destroy(component);
+       }
+
+       if (component->input_ports) {
+               BT_LOGD_STR("Destroying input ports.");
+               g_ptr_array_free(component->input_ports, TRUE);
+               component->input_ports = NULL;
+       }
+
+       if (component->output_ports) {
+               BT_LOGD_STR("Destroying output ports.");
+               g_ptr_array_free(component->output_ports, TRUE);
+               component->output_ports = NULL;
+       }
+
+       if (component->destroy_listeners) {
+               g_array_free(component->destroy_listeners, TRUE);
+               component->destroy_listeners = NULL;
+       }
+
+       if (component->name) {
+               g_string_free(component->name, TRUE);
+               component->name = NULL;
+       }
+
+       BT_LOGD_STR("Putting component class.");
+       BT_OBJECT_PUT_REF_AND_RESET(component->class);
+       g_free(component);
+}
+
+enum bt_component_class_type bt_component_get_class_type(
+               const struct bt_component *component)
+{
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+       return component->class->type;
+}
+
+static
+enum bt_self_component_status add_port(
+               struct bt_component *component, GPtrArray *ports,
+               enum bt_port_type port_type, const char *name, void *user_data,
+               struct bt_port **port)
+{
+       struct bt_port *new_port = NULL;
+       struct bt_graph *graph = NULL;
+       enum bt_self_component_status status;
+
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE(strlen(name) > 0, "Name is empty");
+       graph = bt_component_borrow_graph(component);
+       BT_ASSERT_PRE(graph && !bt_graph_is_canceled(graph),
+               "Component's graph is canceled: %![comp-]+c, %![graph-]+g",
+               component, graph);
+       BT_ASSERT_PRE(
+               graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Component's graph is already configured: "
+               "%![comp-]+c, %![graph-]+g", component, graph);
+
+       // TODO: Validate that the name is not already used.
+
+       BT_LIB_LOGD("Adding port to component: %![comp-]+c, "
+               "port-type=%s, port-name=\"%s\"", component,
+               bt_port_type_string(port_type), name);
+
+       new_port = bt_port_create(component, port_type, name, user_data);
+       if (!new_port) {
+               BT_LOGE_STR("Cannot create port object.");
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto error;
+       }
+
+       /*
+        * No name clash, add the port.
+        * The component is now the port's parent; it should _not_
+        * hold a reference to the port since the port's lifetime
+        * is now protected by the component's own lifetime.
+        */
+       g_ptr_array_add(ports, new_port);
+
+       /*
+        * Notify the graph's creator that a new port was added.
+        */
+       graph = bt_component_borrow_graph(component);
+       if (graph) {
+               enum bt_graph_listener_status listener_status;
+
+               listener_status = bt_graph_notify_port_added(graph, new_port);
+               if (listener_status != BT_GRAPH_LISTENER_STATUS_OK) {
+                       bt_graph_make_faulty(graph);
+                       status = listener_status;
+                       goto error;
+               }
+       }
+
+       BT_LIB_LOGD("Created and added port to component: "
+               "%![comp-]+c, %![port-]+p", component, new_port);
+
+       *port = new_port;
+       status = BT_SELF_COMPONENT_STATUS_OK;
+
+       goto end;
+error:
+       /*
+        * We need to release the reference that we would otherwise have
+        * returned to the caller.
+        */
+       BT_PORT_PUT_REF_AND_RESET(new_port);
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+uint64_t bt_component_get_input_port_count(const struct bt_component *comp)
+{
+       BT_ASSERT_PRE_NON_NULL(comp, "Component");
+       return (uint64_t) comp->input_ports->len;
+}
+
+BT_HIDDEN
+uint64_t bt_component_get_output_port_count(const struct bt_component *comp)
+{
+       BT_ASSERT_PRE_NON_NULL(comp, "Component");
+       return (uint64_t) comp->output_ports->len;
+}
+
+BT_HIDDEN
+int bt_component_create(struct bt_component_class *component_class,
+               const char *name, struct bt_component **user_component)
+{
+       int ret = 0;
+       struct bt_component *component = NULL;
+       enum bt_component_class_type type;
+
+       BT_ASSERT(user_component);
+       BT_ASSERT(component_class);
+       BT_ASSERT(name);
+       type = bt_component_class_get_type(component_class);
+       BT_LIB_LOGD("Creating empty component from component class: %![cc-]+C, "
+               "comp-name=\"%s\"", component_class, name);
+       component = component_create_funcs[type](component_class);
+       if (!component) {
+               BT_LOGE_STR("Cannot create specific component object.");
+               ret = -1;
+               goto end;
+       }
+
+       bt_object_init_shared_with_parent(&component->base, destroy_component);
+       component->class = component_class;
+       bt_object_get_no_null_check(component->class);
+       component->destroy = component_destroy_funcs[type];
+       component->name = g_string_new(name);
+       if (!component->name) {
+               BT_LOGE_STR("Failed to allocate one GString.");
+               ret = -1;
+               goto end;
+       }
+
+       component->input_ports = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!component->input_ports) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               ret = -1;
+               goto end;
+       }
+
+       component->output_ports = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!component->output_ports) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               ret = -1;
+               goto end;
+       }
+
+       component->destroy_listeners = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_component_destroy_listener));
+       if (!component->destroy_listeners) {
+               BT_LOGE_STR("Failed to allocate one GArray.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LIB_LOGD("Created empty component from component class: "
+               "%![cc-]+C, %![comp-]+c", component_class, component);
+       BT_OBJECT_MOVE_REF(*user_component, component);
+
+end:
+       bt_object_put_ref(component);
+       return ret;
+}
+
+const char *bt_component_get_name(const struct bt_component *component)
+{
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+       return component->name->str;
+}
+
+const struct bt_component_class *bt_component_borrow_class_const(
+               const struct bt_component *component)
+{
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+       return component->class;
+}
+
+void *bt_self_component_get_data(const struct bt_self_component *self_comp)
+{
+       struct bt_component *component = (void *) self_comp;
+
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+       return component->user_data;
+}
+
+void bt_self_component_set_data(struct bt_self_component *self_comp,
+               void *data)
+{
+       struct bt_component *component = (void *) self_comp;
+
+       BT_ASSERT_PRE_NON_NULL(component, "Component");
+       component->user_data = data;
+       BT_LIB_LOGV("Set component's user data: %!+c", component);
+}
+
+BT_HIDDEN
+void bt_component_set_graph(struct bt_component *component,
+               struct bt_graph *graph)
+{
+       bt_object_set_parent(&component->base,
+               graph ? &graph->base : NULL);
+}
+
+bt_bool bt_component_graph_is_canceled(const struct bt_component *component)
+{
+       return bt_graph_is_canceled(
+               (void *) bt_object_borrow_parent(&component->base));
+}
+
+static
+struct bt_port *borrow_port_by_name(GPtrArray *ports,
+               const char *name)
+{
+       uint64_t i;
+       struct bt_port *ret_port = NULL;
+
+       BT_ASSERT(name);
+
+       for (i = 0; i < ports->len; i++) {
+               struct bt_port *port = g_ptr_array_index(ports, i);
+
+               if (!strcmp(name, port->name->str)) {
+                       ret_port = port;
+                       break;
+               }
+       }
+
+       return ret_port;
+}
+
+BT_HIDDEN
+struct bt_port_input *bt_component_borrow_input_port_by_name(
+               struct bt_component *comp, const char *name)
+{
+       BT_ASSERT(comp);
+       return (void *) borrow_port_by_name(comp->input_ports, name);
+}
+
+BT_HIDDEN
+struct bt_port_output *bt_component_borrow_output_port_by_name(
+               struct bt_component *comp, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(comp, "Component");
+       return (void *)
+               borrow_port_by_name(comp->output_ports, name);
+}
+
+static
+struct bt_port *borrow_port_by_index(GPtrArray *ports, uint64_t index)
+{
+       BT_ASSERT(index < ports->len);
+       return g_ptr_array_index(ports, index);
+}
+
+BT_HIDDEN
+struct bt_port_input *bt_component_borrow_input_port_by_index(
+               struct bt_component *comp, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(comp, "Component");
+       BT_ASSERT_PRE_VALID_INDEX(index, comp->input_ports->len);
+       return (void *)
+               borrow_port_by_index(comp->input_ports, index);
+}
+
+BT_HIDDEN
+struct bt_port_output *bt_component_borrow_output_port_by_index(
+               struct bt_component *comp, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(comp, "Component");
+       BT_ASSERT_PRE_VALID_INDEX(index, comp->output_ports->len);
+       return (void *)
+               borrow_port_by_index(comp->output_ports, index);
+}
+
+BT_HIDDEN
+enum bt_self_component_status bt_component_add_input_port(
+               struct bt_component *component, const char *name,
+               void *user_data, struct bt_port **port)
+{
+       /* add_port() logs details */
+       return add_port(component, component->input_ports,
+               BT_PORT_TYPE_INPUT, name, user_data, port);
+}
+
+BT_HIDDEN
+enum bt_self_component_status bt_component_add_output_port(
+               struct bt_component *component, const char *name,
+               void *user_data, struct bt_port **port)
+{
+       /* add_port() logs details */
+       return add_port(component, component->output_ports,
+               BT_PORT_TYPE_OUTPUT, name, user_data, port);
+}
+
+BT_HIDDEN
+enum bt_self_component_status bt_component_accept_port_connection(
+               struct bt_component *comp, struct bt_port *self_port,
+               struct bt_port *other_port)
+{
+       typedef enum bt_self_component_status (*method_t)(
+               void *, void *, const void *);
+
+       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       method_t method = NULL;
+
+       BT_ASSERT(comp);
+       BT_ASSERT(self_port);
+       BT_ASSERT(other_port);
+
+       switch (comp->class->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               struct bt_component_class_source *src_cc = (void *) comp->class;
+
+               switch (self_port->type) {
+               case BT_PORT_TYPE_OUTPUT:
+                       method = (method_t) src_cc->methods.accept_output_port_connection;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               struct bt_component_class_filter *flt_cc = (void *) comp->class;
+
+               switch (self_port->type) {
+               case BT_PORT_TYPE_INPUT:
+                       method = (method_t) flt_cc->methods.accept_input_port_connection;
+                       break;
+               case BT_PORT_TYPE_OUTPUT:
+                       method = (method_t) flt_cc->methods.accept_output_port_connection;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+       {
+               struct bt_component_class_sink *sink_cc = (void *) comp->class;
+
+               switch (self_port->type) {
+               case BT_PORT_TYPE_INPUT:
+                       method = (method_t) sink_cc->methods.accept_input_port_connection;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+
+       if (method) {
+               BT_LIB_LOGD("Calling user's \"accept port connection\" method: "
+                       "%![comp-]+c, %![self-port-]+p, %![other-port-]+p",
+                       comp, self_port, other_port);
+               status = method(comp, self_port, (void *) other_port);
+               BT_LOGD("User method returned: status=%s",
+                       bt_self_component_status_string(status));
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+enum bt_self_component_status bt_component_port_connected(
+               struct bt_component *comp, struct bt_port *self_port,
+               struct bt_port *other_port)
+{
+       typedef enum bt_self_component_status (*method_t)(
+               void *, void *, const void *);
+
+       enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       method_t method = NULL;
+
+       BT_ASSERT(comp);
+       BT_ASSERT(self_port);
+       BT_ASSERT(other_port);
+
+       switch (comp->class->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               struct bt_component_class_source *src_cc = (void *) comp->class;
+
+               switch (self_port->type) {
+               case BT_PORT_TYPE_OUTPUT:
+                       method = (method_t) src_cc->methods.output_port_connected;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               struct bt_component_class_filter *flt_cc = (void *) comp->class;
+
+               switch (self_port->type) {
+               case BT_PORT_TYPE_INPUT:
+                       method = (method_t) flt_cc->methods.input_port_connected;
+                       break;
+               case BT_PORT_TYPE_OUTPUT:
+                       method = (method_t) flt_cc->methods.output_port_connected;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+       {
+               struct bt_component_class_sink *sink_cc = (void *) comp->class;
+
+               switch (self_port->type) {
+               case BT_PORT_TYPE_INPUT:
+                       method = (method_t) sink_cc->methods.input_port_connected;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+
+       if (method) {
+               BT_LIB_LOGD("Calling user's \"port connected\" method: "
+                       "%![comp-]+c, %![self-port-]+p, %![other-port-]+p",
+                       comp, self_port, other_port);
+               status = method(comp, self_port, (void *) other_port);
+               BT_LOGD("User method returned: status=%s",
+                       bt_self_component_status_string(status));
+               BT_ASSERT_PRE(status == BT_SELF_COMPONENT_STATUS_OK ||
+                       status == BT_SELF_COMPONENT_STATUS_ERROR ||
+                       status == BT_SELF_COMPONENT_STATUS_NOMEM,
+                       "Unexpected returned component status: status=%s",
+                       bt_self_component_status_string(status));
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+void bt_component_add_destroy_listener(struct bt_component *component,
+               bt_component_destroy_listener_func func, void *data)
+{
+       struct bt_component_destroy_listener listener;
+
+       BT_ASSERT(component);
+       BT_ASSERT(func);
+       listener.func = func;
+       listener.data = data;
+       g_array_append_val(component->destroy_listeners, listener);
+       BT_LIB_LOGV("Added destroy listener: %![comp-]+c, "
+               "func-addr=%p, data-addr=%p",
+               component, func, data);
+}
+
+BT_HIDDEN
+void bt_component_remove_destroy_listener(struct bt_component *component,
+               bt_component_destroy_listener_func func, void *data)
+{
+       uint64_t i;
+
+       BT_ASSERT(component);
+       BT_ASSERT(func);
+
+       for (i = 0; i < component->destroy_listeners->len; i++) {
+               struct bt_component_destroy_listener *listener =
+                       &g_array_index(component->destroy_listeners,
+                               struct bt_component_destroy_listener, i);
+
+               if (listener->func == func && listener->data == data) {
+                       g_array_remove_index(component->destroy_listeners, i);
+                       i--;
+                       BT_LIB_LOGV("Removed destroy listener: %![comp-]+c, "
+                               "func-addr=%p, data-addr=%p",
+                               component, func, data);
+               }
+       }
+}
+
+void bt_component_get_ref(const struct bt_component *component)
+{
+       bt_object_get_ref(component);
+}
+
+void bt_component_put_ref(const struct bt_component *component)
+{
+       bt_object_put_ref(component);
+}
diff --git a/src/lib/graph/component.h b/src/lib/graph/component.h
new file mode 100644 (file)
index 0000000..2753cfe
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef BABELTRACE_GRAPH_COMPONENT_INTERNAL_H
+#define BABELTRACE_GRAPH_COMPONENT_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/graph/component-const.h>
+#include "lib/object.h"
+#include <babeltrace2/types.h>
+#include "common/assert.h"
+#include <glib.h>
+#include <stdio.h>
+
+#include "component-class.h"
+#include "port.h"
+
+typedef void (*bt_component_destroy_listener_func)(
+               struct bt_component *class, void *data);
+
+struct bt_component_destroy_listener {
+       bt_component_destroy_listener_func func;
+       void *data;
+};
+
+struct bt_graph;
+
+struct bt_component {
+       struct bt_object base;
+       struct bt_component_class *class;
+       GString *name;
+
+       /*
+        * Internal destroy function specific to a source, filter, or
+        * sink component object.
+        */
+       void (*destroy)(struct bt_component *);
+
+       /* User-defined data */
+       void *user_data;
+
+       /* Input and output ports (weak references) */
+       GPtrArray *input_ports;
+       GPtrArray *output_ports;
+
+       /* Array of struct bt_component_destroy_listener */
+       GArray *destroy_listeners;
+
+       bool initialized;
+};
+
+static inline
+struct bt_graph *bt_component_borrow_graph(struct bt_component *comp)
+{
+       BT_ASSERT(comp);
+       return (void *) bt_object_borrow_parent(&comp->base);
+}
+
+BT_HIDDEN
+int bt_component_create(struct bt_component_class *component_class,
+               const char *name, struct bt_component **component);
+
+BT_HIDDEN
+enum bt_self_component_status bt_component_accept_port_connection(
+               struct bt_component *component, struct bt_port *self_port,
+               struct bt_port *other_port);
+
+BT_HIDDEN
+enum bt_self_component_status bt_component_port_connected(
+               struct bt_component *comp,
+               struct bt_port *self_port, struct bt_port *other_port);
+
+BT_HIDDEN
+void bt_component_set_graph(struct bt_component *component,
+               struct bt_graph *graph);
+
+BT_HIDDEN
+uint64_t bt_component_get_input_port_count(const struct bt_component *comp);
+
+BT_HIDDEN
+uint64_t bt_component_get_output_port_count(const struct bt_component *comp);
+
+BT_HIDDEN
+struct bt_port_input *bt_component_borrow_input_port_by_index(
+               struct bt_component *comp, uint64_t index);
+
+BT_HIDDEN
+struct bt_port_output *bt_component_borrow_output_port_by_index(
+               struct bt_component *comp, uint64_t index);
+
+BT_HIDDEN
+struct bt_port_input *bt_component_borrow_input_port_by_name(
+               struct bt_component *comp, const char *name);
+
+BT_HIDDEN
+struct bt_port_output *bt_component_borrow_output_port_by_name(
+               struct bt_component *comp, const char *name);
+
+BT_HIDDEN
+enum bt_self_component_status bt_component_add_input_port(
+               struct bt_component *component, const char *name,
+               void *user_data, struct bt_port **port);
+
+BT_HIDDEN
+enum bt_self_component_status bt_component_add_output_port(
+               struct bt_component *component, const char *name,
+               void *user_data, struct bt_port **port);
+
+BT_HIDDEN
+void bt_component_remove_port(struct bt_component *component,
+               struct bt_port *port);
+
+BT_HIDDEN
+void bt_component_add_destroy_listener(struct bt_component *component,
+               bt_component_destroy_listener_func func, void *data);
+
+BT_HIDDEN
+void bt_component_remove_destroy_listener(struct bt_component *component,
+               bt_component_destroy_listener_func func, void *data);
+
+static inline
+const char *bt_self_component_status_string(
+               enum bt_self_component_status status)
+{
+       switch (status) {
+       case BT_SELF_COMPONENT_STATUS_OK:
+               return "BT_SELF_COMPONENT_STATUS_OK";
+       case BT_SELF_COMPONENT_STATUS_END:
+               return "BT_SELF_COMPONENT_STATUS_END";
+       case BT_SELF_COMPONENT_STATUS_AGAIN:
+               return "BT_SELF_COMPONENT_STATUS_AGAIN";
+       case BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION:
+               return "BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION";
+       case BT_SELF_COMPONENT_STATUS_ERROR:
+               return "BT_SELF_COMPONENT_STATUS_ERROR";
+       case BT_SELF_COMPONENT_STATUS_NOMEM:
+               return "BT_SELF_COMPONENT_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+}
+
+#endif /* BABELTRACE_GRAPH_COMPONENT_INTERNAL_H */
diff --git a/src/lib/graph/connection.c b/src/lib/graph/connection.c
new file mode 100644 (file)
index 0000000..f76d715
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CONNECTION"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include <babeltrace2/graph/connection-const.h>
+#include "lib/object.h"
+#include "compat/compiler.h"
+#include <stdlib.h>
+#include <glib.h>
+
+#include "component.h"
+#include "connection.h"
+#include "graph.h"
+#include "message/iterator.h"
+#include "port.h"
+
+static
+void destroy_connection(struct bt_object *obj)
+{
+       struct bt_connection *connection = container_of(obj,
+                       struct bt_connection, base);
+
+       BT_LIB_LOGD("Destroying connection: %!+x", connection);
+
+       /*
+        * Make sure that each message iterator which was created for
+        * this connection is finalized before we destroy it. Once a
+        * message iterator is finalized, all its method return NULL or
+        * the BT_MESSAGE_ITERATOR_STATUS_CANCELED status.
+        *
+        * Because connections are destroyed before components within a
+        * graph, this ensures that message iterators are always
+        * finalized before their upstream component.
+        *
+        * Ending the connection does exactly this. We pass `false` to
+        * bt_connection_end() here to avoid removing this connection
+        * from the graph: if we're here, we're already in the graph's
+        * destructor.
+        */
+       bt_connection_end(connection, false);
+       g_ptr_array_free(connection->iterators, TRUE);
+       connection->iterators = NULL;
+
+       /*
+        * No bt_object_put_ref on ports as a connection only holds _weak_
+        * references to them.
+        */
+       g_free(connection);
+}
+
+static
+void try_remove_connection_from_graph(struct bt_connection *connection)
+{
+       void *graph = (void *) bt_object_borrow_parent(&connection->base);
+
+       if (connection->base.ref_count > 0 ||
+                       connection->downstream_port ||
+                       connection->upstream_port ||
+                       connection->iterators->len > 0) {
+               return;
+       }
+
+       /*
+        * At this point we know that:
+        *
+        * 1. The connection is ended (ports were disconnected).
+        * 2. All the message iterators that this connection
+        *    created, if any, are finalized.
+        * 3. The connection's reference count is 0, so only the
+        *    parent (graph) owns this connection after this call.
+        *
+        * In other words, no other object than the graph knows this
+        * connection.
+        *
+        * It is safe to remove the connection from the graph, therefore
+        * destroying it.
+        */
+       BT_LIB_LOGD("Removing self from graph's connections: "
+               "%![graph-]+g, %![conn-]+x", graph, connection);
+       bt_graph_remove_connection(graph, connection);
+}
+
+static
+void parent_is_owner(struct bt_object *obj)
+{
+       struct bt_connection *connection = container_of(obj,
+                       struct bt_connection, base);
+
+       try_remove_connection_from_graph(connection);
+}
+
+BT_HIDDEN
+struct bt_connection *bt_connection_create(struct bt_graph *graph,
+               struct bt_port *upstream_port,
+               struct bt_port *downstream_port)
+{
+       struct bt_connection *connection = NULL;
+
+       BT_LIB_LOGD("Creating connection: "
+               "%![graph-]+g, %![up-port-]+p, %![down-port-]+p",
+               graph, upstream_port, downstream_port);
+       connection = g_new0(struct bt_connection, 1);
+       if (!connection) {
+               BT_LOGE_STR("Failed to allocate one connection.");
+               goto end;
+       }
+
+       bt_object_init_shared_with_parent(&connection->base,
+               destroy_connection);
+       bt_object_set_parent_is_owner_listener_func(&connection->base,
+               parent_is_owner);
+       connection->iterators = g_ptr_array_new();
+       if (!connection->iterators) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               BT_OBJECT_PUT_REF_AND_RESET(connection);
+               goto end;
+       }
+
+       /* Weak references are taken, see comment in header. */
+       connection->upstream_port = upstream_port;
+       connection->downstream_port = downstream_port;
+       BT_LIB_LOGD("Setting upstream port's connection: %!+p", upstream_port);
+       bt_port_set_connection(upstream_port, connection);
+       BT_LIB_LOGD("Setting downstream port's connection: %!+p",
+               downstream_port);
+       bt_port_set_connection(downstream_port, connection);
+       bt_object_set_parent(&connection->base, &graph->base);
+       BT_LIB_LOGD("Created connection: %!+x", connection);
+
+end:
+       return connection;
+}
+
+BT_HIDDEN
+void bt_connection_end(struct bt_connection *conn, bool try_remove_from_graph)
+{
+       struct bt_port *downstream_port = conn->downstream_port;
+       struct bt_port *upstream_port = conn->upstream_port;
+       size_t i;
+
+       BT_LIB_LOGD("Ending connection: %!+x, try-remove-from-graph=%d",
+               conn, try_remove_from_graph);
+
+       /*
+        * Any of the following message callback functions could
+        * remove one of the connection's ports from its component. To
+        * make sure that at least logging in called functions works
+        * with existing objects, get a local reference on both ports.
+        */
+       bt_object_get_ref(downstream_port);
+       bt_object_get_ref(upstream_port);
+
+       if (downstream_port) {
+               BT_LIB_LOGD("Disconnecting connection's downstream port: %!+p",
+                       downstream_port);
+               bt_port_set_connection(downstream_port, NULL);
+               conn->downstream_port = NULL;
+       }
+
+       if (upstream_port) {
+               BT_LIB_LOGD("Disconnecting connection's upstream port: %!+p",
+                       upstream_port);
+               bt_port_set_connection(upstream_port, NULL);
+               conn->upstream_port = NULL;
+       }
+
+       /*
+        * It is safe to put the local port references now that we don't
+        * need them anymore. This could indeed destroy them.
+        */
+       bt_object_put_ref(downstream_port);
+       bt_object_put_ref(upstream_port);
+
+       /*
+        * Because this connection is ended, finalize each message
+        * iterator created from it.
+        *
+        * In practice, this only happens when the connection is
+        * destroyed and not all its message iterators were finalized,
+        * which is on graph destruction.
+        */
+       for (i = 0; i < conn->iterators->len; i++) {
+               struct bt_self_component_port_input_message_iterator *iterator =
+                       g_ptr_array_index(conn->iterators, i);
+
+               BT_LIB_LOGD("Finalizing message iterator created by "
+                       "this ended connection: %![iter-]+i", iterator);
+               bt_self_component_port_input_message_iterator_try_finalize(
+                       iterator);
+
+               /*
+                * Make sure this iterator does not try to remove itself
+                * from this connection's iterators on destruction
+                * because this connection won't exist anymore.
+                */
+               bt_self_component_port_input_message_iterator_set_connection(
+                       iterator, NULL);
+       }
+
+       g_ptr_array_set_size(conn->iterators, 0);
+
+       if (try_remove_from_graph) {
+               try_remove_connection_from_graph(conn);
+       }
+}
+
+const struct bt_port_output *bt_connection_borrow_upstream_port_const(
+               const struct bt_connection *connection)
+{
+       BT_ASSERT_PRE_NON_NULL(connection, "Connection");
+       return (void *) connection->upstream_port;
+}
+
+const struct bt_port_input *bt_connection_borrow_downstream_port_const(
+               const struct bt_connection *connection)
+{
+       BT_ASSERT_PRE_NON_NULL(connection, "Connection");
+       return (void *) connection->downstream_port;
+}
+
+BT_HIDDEN
+void bt_connection_remove_iterator(struct bt_connection *conn,
+               struct bt_self_component_port_input_message_iterator *iterator)
+{
+       g_ptr_array_remove(conn->iterators, iterator);
+       BT_LIB_LOGV("Removed message iterator from connection: "
+               "%![conn-]+x, %![iter-]+i", conn, iterator);
+       try_remove_connection_from_graph(conn);
+}
+
+void bt_connection_get_ref(const struct bt_connection *connection)
+{
+       bt_object_get_ref(connection);
+}
+
+void bt_connection_put_ref(const struct bt_connection *connection)
+{
+       bt_object_put_ref(connection);
+}
diff --git a/src/lib/graph/connection.h b/src/lib/graph/connection.h
new file mode 100644 (file)
index 0000000..e6190fa
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef BABELTRACE_GRAPH_CONNECTION_INTERNAL_H
+#define BABELTRACE_GRAPH_CONNECTION_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/graph/connection-const.h>
+#include <babeltrace2/graph/message-iterator-const.h>
+#include "lib/object.h"
+#include "common/assert.h"
+#include <stdbool.h>
+
+#include "message/iterator.h"
+
+struct bt_graph;
+
+struct bt_connection {
+       /*
+        * The graph is a connection's parent and the connection is the parent
+        * of all iterators it has created.
+        */
+       struct bt_object base;
+       /*
+        * Weak references are held to both ports. Their existence is guaranteed
+        * by the existence of the graph and thus, of their respective
+        * components.
+        */
+       /* Downstream port. */
+       struct bt_port *downstream_port;
+       /* Upstream port. */
+       struct bt_port *upstream_port;
+
+       /*
+        * Weak references to all the message iterators that were
+        * created on this connection.
+        */
+       GPtrArray *iterators;
+
+       bool notified_upstream_port_connected;
+       bool notified_downstream_port_connected;
+       bool notified_graph_ports_connected;
+};
+
+BT_HIDDEN
+struct bt_connection *bt_connection_create(struct bt_graph *graph,
+               struct bt_port *upstream_port,
+               struct bt_port *downstream_port);
+
+BT_HIDDEN
+void bt_connection_end(struct bt_connection *conn, bool try_remove_from_graph);
+
+BT_HIDDEN
+void bt_connection_remove_iterator(struct bt_connection *conn,
+               struct bt_self_component_port_input_message_iterator *iterator);
+
+static inline
+struct bt_graph *bt_connection_borrow_graph(struct bt_connection *conn)
+{
+       BT_ASSERT(conn);
+       return (void *) conn->base.parent;
+}
+
+#endif /* BABELTRACE_GRAPH_CONNECTION_INTERNAL_H */
diff --git a/src/lib/graph/graph.c b/src/lib/graph/graph.c
new file mode 100644 (file)
index 0000000..4b87d73
--- /dev/null
@@ -0,0 +1,1557 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "GRAPH"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include <babeltrace2/graph/graph.h>
+#include <babeltrace2/graph/graph-const.h>
+#include <babeltrace2/graph/component-source-const.h>
+#include <babeltrace2/graph/component-filter-const.h>
+#include <babeltrace2/graph/port-const.h>
+#include "lib/graph/message/message.h"
+#include "compat/compiler.h"
+#include "common/common.h"
+#include <babeltrace2/types.h>
+#include <babeltrace2/value.h>
+#include <babeltrace2/value-const.h>
+#include "lib/value.h"
+#include <unistd.h>
+#include <glib.h>
+
+#include "component.h"
+#include "component-sink.h"
+#include "connection.h"
+#include "graph.h"
+#include "message/event.h"
+#include "message/packet.h"
+
+typedef enum bt_graph_listener_status (*port_added_func_t)(
+               const void *, const void *, void *);
+
+typedef enum bt_graph_listener_status (*ports_connected_func_t)(
+               const void *, const void *, const void *, const void *, void *);
+
+typedef enum bt_self_component_status (*comp_init_method_t)(const void *,
+               const void *, void *);
+
+struct bt_graph_listener {
+       bt_graph_listener_removed_func removed;
+       void *data;
+};
+
+struct bt_graph_listener_port_added {
+       struct bt_graph_listener base;
+       port_added_func_t func;
+};
+
+struct bt_graph_listener_ports_connected {
+       struct bt_graph_listener base;
+       ports_connected_func_t func;
+};
+
+#define INIT_LISTENERS_ARRAY(_type, _listeners)                                \
+       do {                                                            \
+               _listeners = g_array_new(FALSE, TRUE, sizeof(_type));   \
+               if (!(_listeners)) {                                    \
+                       BT_LOGE_STR("Failed to allocate one GArray.");  \
+               }                                                       \
+       } while (0)
+
+#define CALL_REMOVE_LISTENERS(_type, _listeners)                       \
+       do {                                                            \
+               size_t i;                                               \
+                                                                       \
+               if (!_listeners) {                                      \
+                       break;                                          \
+               }                                                       \
+               for (i = 0; i < (_listeners)->len; i++) {               \
+                       _type *listener =                               \
+                               &g_array_index((_listeners), _type, i); \
+                                                                       \
+                       if (listener->base.removed) {                   \
+                               listener->base.removed(listener->base.data); \
+                       }                                               \
+               }                                                       \
+       } while (0)
+
+static
+void destroy_graph(struct bt_object *obj)
+{
+       struct bt_graph *graph = container_of(obj, struct bt_graph, base);
+
+       /*
+        * The graph's reference count is 0 if we're here. Increment
+        * it to avoid a double-destroy (possibly infinitely recursive)
+        * in this situation:
+        *
+        * 1. We put and destroy a connection.
+        * 2. This connection's destructor finalizes its active message
+        *    iterators.
+        * 3. A message iterator's finalization function gets a new
+        *    reference on its component (reference count goes from 0 to
+        *    1).
+        * 4. Since this component's reference count goes to 1, it takes
+        *    a reference on its parent (this graph). This graph's
+        *    reference count goes from 0 to 1.
+        * 5. The message iterator's finalization function puts its
+        *    component reference (reference count goes from 1 to 0).
+        * 6. Since this component's reference count goes from 1 to 0,
+        *    it puts its parent (this graph). This graph's reference
+        *    count goes from 1 to 0.
+        * 7. Since this graph's reference count goes from 1 to 0, its
+        *    destructor is called (this function).
+        *
+        * With the incrementation below, the graph's reference count at
+        * step 4 goes from 1 to 2, and from 2 to 1 at step 6. This
+        * ensures that this function is not called two times.
+        */
+       BT_LIB_LOGD("Destroying graph: %!+g", graph);
+       obj->ref_count++;
+
+       /*
+        * Cancel the graph to disallow some operations, like creating
+        * message iterators and adding ports to components.
+        */
+       (void) bt_graph_cancel((void *) graph);
+
+       /* Call all remove listeners */
+       CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
+               graph->listeners.source_output_port_added);
+       CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
+               graph->listeners.filter_output_port_added);
+       CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
+               graph->listeners.filter_input_port_added);
+       CALL_REMOVE_LISTENERS(struct bt_graph_listener_port_added,
+               graph->listeners.sink_input_port_added);
+       CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
+               graph->listeners.source_filter_ports_connected);
+       CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
+               graph->listeners.filter_filter_ports_connected);
+       CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
+               graph->listeners.source_sink_ports_connected);
+       CALL_REMOVE_LISTENERS(struct bt_graph_listener_ports_connected,
+               graph->listeners.filter_sink_ports_connected);
+
+       if (graph->messages) {
+               g_ptr_array_free(graph->messages, TRUE);
+               graph->messages = NULL;
+       }
+
+       if (graph->connections) {
+               BT_LOGD_STR("Destroying connections.");
+               g_ptr_array_free(graph->connections, TRUE);
+               graph->connections = NULL;
+       }
+
+       if (graph->components) {
+               BT_LOGD_STR("Destroying components.");
+               g_ptr_array_free(graph->components, TRUE);
+               graph->components = NULL;
+       }
+
+       if (graph->sinks_to_consume) {
+               g_queue_free(graph->sinks_to_consume);
+               graph->sinks_to_consume = NULL;
+       }
+
+       if (graph->listeners.source_output_port_added) {
+               g_array_free(graph->listeners.source_output_port_added, TRUE);
+               graph->listeners.source_output_port_added = NULL;
+       }
+
+       if (graph->listeners.filter_output_port_added) {
+               g_array_free(graph->listeners.filter_output_port_added, TRUE);
+               graph->listeners.filter_output_port_added = NULL;
+       }
+
+       if (graph->listeners.filter_input_port_added) {
+               g_array_free(graph->listeners.filter_input_port_added, TRUE);
+               graph->listeners.filter_input_port_added = NULL;
+       }
+
+       if (graph->listeners.sink_input_port_added) {
+               g_array_free(graph->listeners.sink_input_port_added, TRUE);
+               graph->listeners.sink_input_port_added = NULL;
+       }
+
+       if (graph->listeners.source_filter_ports_connected) {
+               g_array_free(graph->listeners.source_filter_ports_connected,
+                       TRUE);
+               graph->listeners.source_filter_ports_connected = NULL;
+       }
+
+       if (graph->listeners.filter_filter_ports_connected) {
+               g_array_free(graph->listeners.filter_filter_ports_connected,
+                       TRUE);
+               graph->listeners.filter_filter_ports_connected = NULL;
+       }
+
+       if (graph->listeners.source_sink_ports_connected) {
+               g_array_free(graph->listeners.source_sink_ports_connected,
+                       TRUE);
+               graph->listeners.source_sink_ports_connected = NULL;
+       }
+
+       if (graph->listeners.filter_sink_ports_connected) {
+               g_array_free(graph->listeners.filter_sink_ports_connected,
+                       TRUE);
+               graph->listeners.filter_sink_ports_connected = NULL;
+       }
+
+       bt_object_pool_finalize(&graph->event_msg_pool);
+       bt_object_pool_finalize(&graph->packet_begin_msg_pool);
+       bt_object_pool_finalize(&graph->packet_end_msg_pool);
+       g_free(graph);
+}
+
+static
+void destroy_message_event(struct bt_message *msg,
+               struct bt_graph *graph)
+{
+       bt_message_event_destroy(msg);
+}
+
+static
+void destroy_message_packet_begin(struct bt_message *msg,
+               struct bt_graph *graph)
+{
+       bt_message_packet_destroy(msg);
+}
+
+static
+void destroy_message_packet_end(struct bt_message *msg,
+               struct bt_graph *graph)
+{
+       bt_message_packet_destroy(msg);
+}
+
+static
+void notify_message_graph_is_destroyed(struct bt_message *msg)
+{
+       bt_message_unlink_graph(msg);
+}
+
+struct bt_graph *bt_graph_create(void)
+{
+       struct bt_graph *graph;
+       int ret;
+
+       BT_LOGD_STR("Creating graph object.");
+       graph = g_new0(struct bt_graph, 1);
+       if (!graph) {
+               BT_LOGE_STR("Failed to allocate one graph.");
+               goto end;
+       }
+
+       bt_object_init_shared(&graph->base, destroy_graph);
+       graph->connections = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!graph->connections) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+       graph->components = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!graph->components) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+       graph->sinks_to_consume = g_queue_new();
+       if (!graph->sinks_to_consume) {
+               BT_LOGE_STR("Failed to allocate one GQueue.");
+               goto error;
+       }
+
+       bt_graph_set_can_consume(graph, true);
+       INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
+               graph->listeners.source_output_port_added);
+
+       if (!graph->listeners.source_output_port_added) {
+               ret = -1;
+               goto error;
+       }
+
+       INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
+               graph->listeners.filter_output_port_added);
+
+       if (!graph->listeners.filter_output_port_added) {
+               ret = -1;
+               goto error;
+       }
+
+       INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
+               graph->listeners.filter_input_port_added);
+
+       if (!graph->listeners.filter_input_port_added) {
+               ret = -1;
+               goto error;
+       }
+
+       INIT_LISTENERS_ARRAY(struct bt_graph_listener_port_added,
+               graph->listeners.sink_input_port_added);
+
+       if (!graph->listeners.sink_input_port_added) {
+               ret = -1;
+               goto error;
+       }
+
+       INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
+               graph->listeners.source_filter_ports_connected);
+
+       if (!graph->listeners.source_filter_ports_connected) {
+               ret = -1;
+               goto error;
+       }
+
+       INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
+               graph->listeners.source_sink_ports_connected);
+
+       if (!graph->listeners.source_sink_ports_connected) {
+               ret = -1;
+               goto error;
+       }
+
+       INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
+               graph->listeners.filter_filter_ports_connected);
+
+       if (!graph->listeners.filter_filter_ports_connected) {
+               ret = -1;
+               goto error;
+       }
+
+       INIT_LISTENERS_ARRAY(struct bt_graph_listener_ports_connected,
+               graph->listeners.filter_sink_ports_connected);
+
+       if (!graph->listeners.filter_sink_ports_connected) {
+               ret = -1;
+               goto error;
+       }
+
+       ret = bt_object_pool_initialize(&graph->event_msg_pool,
+               (bt_object_pool_new_object_func) bt_message_event_new,
+               (bt_object_pool_destroy_object_func) destroy_message_event,
+               graph);
+       if (ret) {
+               BT_LOGE("Failed to initialize event message pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
+       ret = bt_object_pool_initialize(&graph->packet_begin_msg_pool,
+               (bt_object_pool_new_object_func) bt_message_packet_beginning_new,
+               (bt_object_pool_destroy_object_func) destroy_message_packet_begin,
+               graph);
+       if (ret) {
+               BT_LOGE("Failed to initialize packet beginning message pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
+       ret = bt_object_pool_initialize(&graph->packet_end_msg_pool,
+               (bt_object_pool_new_object_func) bt_message_packet_end_new,
+               (bt_object_pool_destroy_object_func) destroy_message_packet_end,
+               graph);
+       if (ret) {
+               BT_LOGE("Failed to initialize packet end message pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
+       graph->messages = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) notify_message_graph_is_destroyed);
+       BT_LIB_LOGD("Created graph object: %!+g", graph);
+
+end:
+       return (void *) graph;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(graph);
+       goto end;
+}
+
+enum bt_graph_status bt_graph_connect_ports(
+               struct bt_graph *graph,
+               const struct bt_port_output *upstream_port_out,
+               const struct bt_port_input *downstream_port_in,
+               const struct bt_connection **user_connection)
+{
+       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
+       enum bt_graph_listener_status listener_status;
+       struct bt_connection *connection = NULL;
+       struct bt_port *upstream_port = (void *) upstream_port_out;
+       struct bt_port *downstream_port = (void *) downstream_port_in;
+       struct bt_component *upstream_component = NULL;
+       struct bt_component *downstream_component = NULL;
+       enum bt_self_component_status component_status;
+       bool init_can_consume;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(upstream_port, "Upstream port");
+       BT_ASSERT_PRE_NON_NULL(downstream_port, "Downstream port port");
+       BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
+       BT_ASSERT_PRE(
+               graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Graph is not in the \"configuring\" state: %!+g", graph);
+       BT_ASSERT_PRE(!bt_port_is_connected(upstream_port),
+               "Upstream port is already connected: %!+p", upstream_port);
+       BT_ASSERT_PRE(!bt_port_is_connected(downstream_port),
+               "Downstream port is already connected: %!+p", downstream_port);
+       BT_ASSERT_PRE(bt_port_borrow_component_inline((void *) upstream_port),
+               "Upstream port does not belong to a component: %!+p",
+               upstream_port);
+       BT_ASSERT_PRE(bt_port_borrow_component_inline((void *) downstream_port),
+               "Downstream port does not belong to a component: %!+p",
+               downstream_port);
+       init_can_consume = graph->can_consume;
+       BT_LIB_LOGD("Connecting component ports within graph: "
+               "%![graph-]+g, %![up-port-]+p, %![down-port-]+p",
+               graph, upstream_port, downstream_port);
+       bt_graph_set_can_consume(graph, false);
+       upstream_component = bt_port_borrow_component_inline(
+               (void *) upstream_port);
+       downstream_component = bt_port_borrow_component_inline(
+               (void *) downstream_port);
+
+       /*
+        * At this point the ports are not connected yet. Both
+        * components need to accept an eventual connection to their
+        * port by the other port before we continue.
+        */
+       BT_LIB_LOGD("Asking upstream component to accept the connection: "
+               "%![comp-]+c", upstream_component);
+       component_status = bt_component_accept_port_connection(
+               upstream_component, (void *) upstream_port,
+               (void *) downstream_port);
+       if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
+               if (component_status == BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
+                       BT_LOGD_STR("Upstream component refused the connection.");
+               } else {
+                       BT_LOGW("Cannot ask upstream component to accept the connection: "
+                               "status=%s", bt_self_component_status_string(component_status));
+               }
+
+               status = (int) component_status;
+               goto end;
+       }
+
+       BT_LIB_LOGD("Asking downstream component to accept the connection: "
+               "%![comp-]+c", downstream_component);
+       component_status = bt_component_accept_port_connection(
+               downstream_component, (void *) downstream_port,
+               (void *) upstream_port);
+       if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
+               if (component_status == BT_SELF_COMPONENT_STATUS_REFUSE_PORT_CONNECTION) {
+                       BT_LOGD_STR("Downstream component refused the connection.");
+               } else {
+                       BT_LOGW("Cannot ask downstream component to accept the connection: "
+                               "status=%s", bt_self_component_status_string(component_status));
+               }
+
+               status = (int) component_status;
+               goto end;
+       }
+
+       BT_LOGD_STR("Creating connection.");
+       connection = bt_connection_create(graph, (void *) upstream_port,
+               (void *) downstream_port);
+       if (!connection) {
+               BT_LOGW("Cannot create connection object.");
+               status = BT_GRAPH_STATUS_NOMEM;
+               goto end;
+       }
+
+       BT_LIB_LOGD("Connection object created: %!+x", connection);
+
+       /*
+        * Ownership of upstream_component/downstream_component and of
+        * the connection object is transferred to the graph.
+        */
+       g_ptr_array_add(graph->connections, connection);
+
+       /*
+        * Notify both components that their port is connected.
+        */
+       BT_LIB_LOGD("Notifying upstream component that its port is connected: "
+               "%![comp-]+c, %![port-]+p", upstream_component, upstream_port);
+       component_status = bt_component_port_connected(upstream_component,
+               (void *) upstream_port, (void *) downstream_port);
+       if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
+               BT_LIB_LOGW("Error while notifying upstream component that its port is connected: "
+                       "status=%s, %![graph-]+g, %![up-comp-]+c, "
+                       "%![down-comp-]+c, %![up-port-]+p, %![down-port-]+p",
+                       bt_self_component_status_string(component_status),
+                       graph, upstream_component, downstream_component,
+                       upstream_port, downstream_port);
+               bt_connection_end(connection, true);
+               status = (int) component_status;
+               goto end;
+       }
+
+       connection->notified_upstream_port_connected = true;
+       BT_LIB_LOGD("Notifying downstream component that its port is connected: "
+               "%![comp-]+c, %![port-]+p", downstream_component,
+               downstream_port);
+       component_status = bt_component_port_connected(downstream_component,
+               (void *) downstream_port, (void *) upstream_port);
+       if (component_status != BT_SELF_COMPONENT_STATUS_OK) {
+               BT_LIB_LOGW("Error while notifying downstream component that its port is connected: "
+                       "status=%s, %![graph-]+g, %![up-comp-]+c, "
+                       "%![down-comp-]+c, %![up-port-]+p, %![down-port-]+p",
+                       bt_self_component_status_string(component_status),
+                       graph, upstream_component, downstream_component,
+                       upstream_port, downstream_port);
+               bt_connection_end(connection, true);
+               status = (int) component_status;
+               goto end;
+       }
+
+       connection->notified_downstream_port_connected = true;
+
+       /*
+        * Notify the graph's creator that both ports are connected.
+        */
+       BT_LOGD_STR("Notifying graph's user that new component ports are connected.");
+       listener_status = bt_graph_notify_ports_connected(graph, upstream_port, downstream_port);
+       if (listener_status != BT_GRAPH_LISTENER_STATUS_OK) {
+               status = (int) listener_status;
+               goto end;
+       }
+
+       connection->notified_graph_ports_connected = true;
+       BT_LIB_LOGD("Connected component ports within graph: "
+               "%![graph-]+g, %![up-comp-]+c, %![down-comp-]+c, "
+               "%![up-port-]+p, %![down-port-]+p",
+               graph, upstream_component, downstream_component,
+               upstream_port, downstream_port);
+
+       if (user_connection) {
+               /* Move reference to user */
+               *user_connection = connection;
+               connection = NULL;
+       }
+
+end:
+       if (status != BT_GRAPH_STATUS_OK) {
+               bt_graph_make_faulty(graph);
+       }
+
+       bt_object_put_ref(connection);
+       (void) init_can_consume;
+       bt_graph_set_can_consume(graph, init_can_consume);
+       return status;
+}
+
+static inline
+enum bt_graph_status consume_graph_sink(struct bt_component_sink *comp)
+{
+       enum bt_self_component_status comp_status;
+       struct bt_component_class_sink *sink_class = NULL;
+
+       BT_ASSERT(comp);
+       sink_class = (void *) comp->parent.class;
+       BT_ASSERT(sink_class->methods.consume);
+       BT_LIB_LOGD("Calling user's consume method: %!+c", comp);
+       comp_status = sink_class->methods.consume((void *) comp);
+       BT_LOGD("User method returned: status=%s",
+               bt_self_component_status_string(comp_status));
+       BT_ASSERT_PRE(comp_status == BT_SELF_COMPONENT_STATUS_OK ||
+               comp_status == BT_SELF_COMPONENT_STATUS_END ||
+               comp_status == BT_SELF_COMPONENT_STATUS_AGAIN ||
+               comp_status == BT_SELF_COMPONENT_STATUS_ERROR ||
+               comp_status == BT_SELF_COMPONENT_STATUS_NOMEM,
+               "Invalid component status returned by consuming method: "
+               "status=%s", bt_self_component_status_string(comp_status));
+       if (comp_status < 0) {
+               BT_LOGW_STR("Consume method failed.");
+               goto end;
+       }
+
+       BT_LIB_LOGV("Consumed from sink: %![comp-]+c, status=%s",
+               comp, bt_self_component_status_string(comp_status));
+
+end:
+       return (int) comp_status;
+}
+
+/*
+ * `node` is removed from the queue of sinks to consume when passed to
+ * this function. This function adds it back to the queue if there's
+ * still something to consume afterwards.
+ */
+static inline
+enum bt_graph_status consume_sink_node(struct bt_graph *graph, GList *node)
+{
+       enum bt_graph_status status;
+       struct bt_component_sink *sink;
+
+       sink = node->data;
+       status = consume_graph_sink(sink);
+       if (unlikely(status != BT_GRAPH_STATUS_END)) {
+               g_queue_push_tail_link(graph->sinks_to_consume, node);
+               goto end;
+       }
+
+       /* End reached, the node is not added back to the queue and free'd. */
+       g_queue_delete_link(graph->sinks_to_consume, node);
+
+       /* Don't forward an END status if there are sinks left to consume. */
+       if (!g_queue_is_empty(graph->sinks_to_consume)) {
+               status = BT_GRAPH_STATUS_OK;
+               goto end;
+       }
+
+end:
+       BT_LIB_LOGV("Consumed sink node: %![comp-]+c, status=%s",
+               sink, bt_graph_status_string(status));
+       return status;
+}
+
+BT_HIDDEN
+enum bt_graph_status bt_graph_consume_sink_no_check(struct bt_graph *graph,
+               struct bt_component_sink *sink)
+{
+       enum bt_graph_status status;
+       GList *sink_node;
+       int index;
+
+       BT_LIB_LOGV("Making specific sink consume: %![comp-]+c", sink);
+       BT_ASSERT(bt_component_borrow_graph((void *) sink) == graph);
+
+       if (g_queue_is_empty(graph->sinks_to_consume)) {
+               BT_LOGV_STR("Graph's sink queue is empty: end of graph.");
+               status = BT_GRAPH_STATUS_END;
+               goto end;
+       }
+
+       index = g_queue_index(graph->sinks_to_consume, sink);
+       if (index < 0) {
+               BT_LOGV_STR("Sink is not marked as consumable: sink is ended.");
+               status = BT_GRAPH_STATUS_END;
+               goto end;
+       }
+
+       sink_node = g_queue_pop_nth_link(graph->sinks_to_consume, index);
+       BT_ASSERT(sink_node);
+       status = consume_sink_node(graph, sink_node);
+
+end:
+       return status;
+}
+
+static inline
+enum bt_graph_status consume_no_check(struct bt_graph *graph)
+{
+       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
+       struct bt_component *sink;
+       GList *current_node;
+
+       BT_ASSERT_PRE(graph->has_sink,
+               "Graph has no sink component: %!+g", graph);
+       BT_LIB_LOGV("Making next sink consume: %![graph-]+g", graph);
+
+       if (unlikely(g_queue_is_empty(graph->sinks_to_consume))) {
+               BT_LOGV_STR("Graph's sink queue is empty: end of graph.");
+               status = BT_GRAPH_STATUS_END;
+               goto end;
+       }
+
+       current_node = g_queue_pop_head_link(graph->sinks_to_consume);
+       sink = current_node->data;
+       BT_LIB_LOGV("Chose next sink to consume: %!+c", sink);
+       status = consume_sink_node(graph, current_node);
+
+end:
+       return status;
+}
+
+enum bt_graph_status bt_graph_consume(struct bt_graph *graph)
+{
+       enum bt_graph_status status;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
+       BT_ASSERT_PRE(graph->can_consume,
+               "Cannot consume graph in its current state: %!+g", graph);
+       BT_ASSERT_PRE(graph->config_state != BT_GRAPH_CONFIGURATION_STATE_FAULTY,
+               "Graph is in a faulty state: %!+g", graph);
+       bt_graph_set_can_consume(graph, false);
+       status = bt_graph_configure(graph);
+       if (unlikely(status)) {
+               /* bt_graph_configure() logs errors */
+               goto end;
+       }
+
+       status = consume_no_check(graph);
+       bt_graph_set_can_consume(graph, true);
+
+end:
+       return status;
+}
+
+enum bt_graph_status bt_graph_run(struct bt_graph *graph)
+{
+       enum bt_graph_status status;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
+       BT_ASSERT_PRE(graph->can_consume,
+               "Cannot consume graph in its current state: %!+g", graph);
+       BT_ASSERT_PRE(graph->config_state != BT_GRAPH_CONFIGURATION_STATE_FAULTY,
+               "Graph is in a faulty state: %!+g", graph);
+       bt_graph_set_can_consume(graph, false);
+       status = bt_graph_configure(graph);
+       if (unlikely(status)) {
+               /* bt_graph_configure() logs errors */
+               goto end;
+       }
+
+       BT_LIB_LOGV("Running graph: %!+g", graph);
+
+       do {
+               /*
+                * Check if the graph is canceled at each iteration. If
+                * the graph was canceled by another thread or by a
+                * signal handler, this is not a warning nor an error,
+                * it was intentional: log with a DEBUG level only.
+                */
+               if (unlikely(graph->canceled)) {
+                       BT_LIB_LOGD("Stopping the graph: graph is canceled: "
+                               "%!+g", graph);
+                       status = BT_GRAPH_STATUS_CANCELED;
+                       goto end;
+               }
+
+               status = consume_no_check(graph);
+               if (unlikely(status == BT_GRAPH_STATUS_AGAIN)) {
+                       /*
+                        * If AGAIN is received and there are multiple
+                        * sinks, go ahead and consume from the next
+                        * sink.
+                        *
+                        * However, in the case where a single sink is
+                        * left, the caller can decide to busy-wait and
+                        * call bt_graph_run() continuously
+                        * until the source is ready or it can decide to
+                        * sleep for an arbitrary amount of time.
+                        */
+                       if (graph->sinks_to_consume->length > 1) {
+                               status = BT_GRAPH_STATUS_OK;
+                       }
+               }
+       } while (status == BT_GRAPH_STATUS_OK);
+
+       if (g_queue_is_empty(graph->sinks_to_consume)) {
+               status = BT_GRAPH_STATUS_END;
+       }
+
+end:
+       BT_LIB_LOGV("Graph ran: %![graph-]+g, status=%s", graph,
+               bt_graph_status_string(status));
+       bt_graph_set_can_consume(graph, true);
+       return status;
+}
+
+enum bt_graph_status
+bt_graph_add_source_component_output_port_added_listener(
+               struct bt_graph *graph,
+               bt_graph_source_component_output_port_added_listener_func func,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *out_listener_id)
+{
+       struct bt_graph_listener_port_added listener = {
+               .base = {
+                       .removed = listener_removed,
+                       .data = data,
+               },
+               .func = (port_added_func_t) func,
+       };
+       int listener_id;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(func, "Listener");
+       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
+       BT_ASSERT_PRE(!graph->in_remove_listener,
+               "Graph currently executing a \"listener removed\" listener: "
+               "%!+g", graph);
+       g_array_append_val(graph->listeners.source_output_port_added, listener);
+       listener_id = graph->listeners.source_output_port_added->len - 1;
+       BT_LIB_LOGV("Added \"source component output port added\" listener to graph: "
+               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
+               listener_id);
+
+       if (listener_id) {
+               *out_listener_id = listener_id;
+       }
+
+       return BT_GRAPH_STATUS_OK;
+}
+
+enum bt_graph_status
+bt_graph_add_filter_component_output_port_added_listener(
+               struct bt_graph *graph,
+               bt_graph_filter_component_output_port_added_listener_func func,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *out_listener_id)
+{
+       struct bt_graph_listener_port_added listener = {
+               .base = {
+                       .removed = listener_removed,
+                       .data = data,
+               },
+               .func = (port_added_func_t) func,
+       };
+       int listener_id;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(func, "Listener");
+       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
+       BT_ASSERT_PRE(!graph->in_remove_listener,
+               "Graph currently executing a \"listener removed\" listener: "
+               "%!+g", graph);
+       g_array_append_val(graph->listeners.filter_output_port_added, listener);
+       listener_id = graph->listeners.filter_output_port_added->len - 1;
+       BT_LIB_LOGV("Added \"filter component output port added\" listener to graph: "
+               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
+               listener_id);
+
+       if (listener_id) {
+               *out_listener_id = listener_id;
+       }
+
+       return BT_GRAPH_STATUS_OK;
+}
+
+enum bt_graph_status
+bt_graph_add_filter_component_input_port_added_listener(
+               struct bt_graph *graph,
+               bt_graph_filter_component_input_port_added_listener_func func,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *out_listener_id)
+{
+       struct bt_graph_listener_port_added listener = {
+               .base = {
+                       .removed = listener_removed,
+                       .data = data,
+               },
+               .func = (port_added_func_t) func,
+       };
+       int listener_id;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(func, "Listener");
+       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
+       BT_ASSERT_PRE(!graph->in_remove_listener,
+               "Graph currently executing a \"listener removed\" listener: "
+               "%!+g", graph);
+       g_array_append_val(graph->listeners.filter_input_port_added, listener);
+       listener_id = graph->listeners.filter_input_port_added->len - 1;
+       BT_LIB_LOGV("Added \"filter component input port added\" listener to graph: "
+               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
+               listener_id);
+
+       if (listener_id) {
+               *out_listener_id = listener_id;
+       }
+
+       return BT_GRAPH_STATUS_OK;
+}
+
+enum bt_graph_status
+bt_graph_add_sink_component_input_port_added_listener(
+               struct bt_graph *graph,
+               bt_graph_sink_component_input_port_added_listener_func func,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *out_listener_id)
+{
+       struct bt_graph_listener_port_added listener = {
+               .base = {
+                       .removed = listener_removed,
+                       .data = data,
+               },
+               .func = (port_added_func_t) func,
+       };
+       int listener_id;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(func, "Listener");
+       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
+       BT_ASSERT_PRE(!graph->in_remove_listener,
+               "Graph currently executing a \"listener removed\" listener: "
+               "%!+g", graph);
+       g_array_append_val(graph->listeners.sink_input_port_added, listener);
+       listener_id = graph->listeners.sink_input_port_added->len - 1;
+       BT_LIB_LOGV("Added \"sink component input port added\" listener to graph: "
+               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
+               listener_id);
+
+       if (listener_id) {
+               *out_listener_id = listener_id;
+       }
+
+       return BT_GRAPH_STATUS_OK;
+}
+
+enum bt_graph_status
+bt_graph_add_source_filter_component_ports_connected_listener(
+               struct bt_graph *graph,
+               bt_graph_source_filter_component_ports_connected_listener_func func,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *out_listener_id)
+{
+       struct bt_graph_listener_ports_connected listener = {
+               .base = {
+                       .removed = listener_removed,
+                       .data = data,
+               },
+               .func = (ports_connected_func_t) func,
+       };
+       int listener_id;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(func, "Listener");
+       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
+       BT_ASSERT_PRE(!graph->in_remove_listener,
+               "Graph currently executing a \"listener removed\" listener: "
+               "%!+g", graph);
+       g_array_append_val(graph->listeners.source_filter_ports_connected,
+               listener);
+       listener_id = graph->listeners.source_filter_ports_connected->len - 1;
+       BT_LIB_LOGV("Added \"source to filter component ports connected\" listener to graph: "
+               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
+               listener_id);
+
+       if (listener_id) {
+               *out_listener_id = listener_id;
+       }
+
+       return BT_GRAPH_STATUS_OK;
+}
+
+enum bt_graph_status
+bt_graph_add_source_sink_component_ports_connected_listener(
+               struct bt_graph *graph,
+               bt_graph_source_sink_component_ports_connected_listener_func func,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *out_listener_id)
+{
+       struct bt_graph_listener_ports_connected listener = {
+               .base = {
+                       .removed = listener_removed,
+                       .data = data,
+               },
+               .func = (ports_connected_func_t) func,
+       };
+       int listener_id;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(func, "Listener");
+       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
+       BT_ASSERT_PRE(!graph->in_remove_listener,
+               "Graph currently executing a \"listener removed\" listener: "
+               "%!+g", graph);
+       g_array_append_val(graph->listeners.source_sink_ports_connected,
+               listener);
+       listener_id = graph->listeners.source_sink_ports_connected->len - 1;
+       BT_LIB_LOGV("Added \"source to sink component ports connected\" listener to graph: "
+               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
+               listener_id);
+
+       if (listener_id) {
+               *out_listener_id = listener_id;
+       }
+
+       return BT_GRAPH_STATUS_OK;
+}
+
+enum bt_graph_status
+bt_graph_add_filter_filter_component_ports_connected_listener(
+               struct bt_graph *graph,
+               bt_graph_filter_filter_component_ports_connected_listener_func func,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *out_listener_id)
+{
+       struct bt_graph_listener_ports_connected listener = {
+               .base = {
+                       .removed = listener_removed,
+                       .data = data,
+               },
+               .func = (ports_connected_func_t) func,
+       };
+       int listener_id;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(func, "Listener");
+       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
+       BT_ASSERT_PRE(!graph->in_remove_listener,
+               "Graph currently executing a \"listener removed\" listener: "
+               "%!+g", graph);
+       g_array_append_val(graph->listeners.filter_filter_ports_connected,
+               listener);
+       listener_id = graph->listeners.filter_filter_ports_connected->len - 1;
+       BT_LIB_LOGV("Added \"filter to filter component ports connected\" listener to graph: "
+               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
+               listener_id);
+
+       if (listener_id) {
+               *out_listener_id = listener_id;
+       }
+
+       return BT_GRAPH_STATUS_OK;
+}
+
+enum bt_graph_status
+bt_graph_add_filter_sink_component_ports_connected_listener(
+               struct bt_graph *graph,
+               bt_graph_filter_sink_component_ports_connected_listener_func func,
+               bt_graph_listener_removed_func listener_removed, void *data,
+               int *out_listener_id)
+{
+       struct bt_graph_listener_ports_connected listener = {
+               .base = {
+                       .removed = listener_removed,
+                       .data = data,
+               },
+               .func = (ports_connected_func_t) func,
+       };
+       int listener_id;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(func, "Listener");
+       BT_ASSERT_PRE_NON_NULL(func, "\"Listener removed\" listener");
+       BT_ASSERT_PRE(!graph->in_remove_listener,
+               "Graph currently executing a \"listener removed\" listener: "
+               "%!+g", graph);
+       g_array_append_val(graph->listeners.filter_sink_ports_connected,
+               listener);
+       listener_id = graph->listeners.filter_sink_ports_connected->len - 1;
+       BT_LIB_LOGV("Added \"filter to sink component ports connected\" listener to graph: "
+               "%![graph-]+g, listener-addr=%p, id=%d", graph, listener,
+               listener_id);
+
+       if (listener_id) {
+               *out_listener_id = listener_id;
+       }
+
+       return BT_GRAPH_STATUS_OK;
+}
+
+BT_HIDDEN
+enum bt_graph_listener_status bt_graph_notify_port_added(
+               struct bt_graph *graph, struct bt_port *port)
+{
+       uint64_t i;
+       GArray *listeners;
+       struct bt_component *comp;
+       enum bt_graph_listener_status status = BT_GRAPH_LISTENER_STATUS_OK;
+
+       BT_ASSERT(graph);
+       BT_ASSERT(port);
+       BT_LIB_LOGV("Notifying graph listeners that a port was added: "
+               "%![graph-]+g, %![port-]+p", graph, port);
+       comp = bt_port_borrow_component_inline(port);
+       BT_ASSERT(comp);
+
+       switch (comp->class->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               switch (port->type) {
+               case BT_PORT_TYPE_OUTPUT:
+                       listeners = graph->listeners.source_output_port_added;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               switch (port->type) {
+               case BT_PORT_TYPE_INPUT:
+                       listeners = graph->listeners.filter_input_port_added;
+                       break;
+               case BT_PORT_TYPE_OUTPUT:
+                       listeners = graph->listeners.filter_output_port_added;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+       {
+               switch (port->type) {
+               case BT_PORT_TYPE_INPUT:
+                       listeners = graph->listeners.sink_input_port_added;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+
+       for (i = 0; i < listeners->len; i++) {
+               struct bt_graph_listener_port_added *listener =
+                       &g_array_index(listeners,
+                               struct bt_graph_listener_port_added, i);
+
+
+               BT_ASSERT(listener->func);
+               status = listener->func(comp, port, listener->base.data);
+               if (status != BT_GRAPH_LISTENER_STATUS_OK) {
+                       goto end;
+               }
+       }
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+enum bt_graph_listener_status bt_graph_notify_ports_connected(
+               struct bt_graph *graph, struct bt_port *upstream_port,
+               struct bt_port *downstream_port)
+{
+       uint64_t i;
+       GArray *listeners;
+       struct bt_component *upstream_comp;
+       struct bt_component *downstream_comp;
+       enum bt_graph_listener_status status = BT_GRAPH_LISTENER_STATUS_OK;
+
+       BT_ASSERT(graph);
+       BT_ASSERT(upstream_port);
+       BT_ASSERT(downstream_port);
+       BT_LIB_LOGV("Notifying graph listeners that ports were connected: "
+               "%![graph-]+g, %![up-port-]+p, %![down-port-]+p",
+               graph, upstream_port, downstream_port);
+       upstream_comp = bt_port_borrow_component_inline(upstream_port);
+       BT_ASSERT(upstream_comp);
+       downstream_comp = bt_port_borrow_component_inline(downstream_port);
+       BT_ASSERT(downstream_comp);
+
+       switch (upstream_comp->class->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               switch (downstream_comp->class->type) {
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       listeners =
+                               graph->listeners.source_filter_ports_connected;
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       listeners =
+                               graph->listeners.source_sink_ports_connected;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               switch (downstream_comp->class->type) {
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       listeners =
+                               graph->listeners.filter_filter_ports_connected;
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       listeners =
+                               graph->listeners.filter_sink_ports_connected;
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       default:
+               abort();
+       }
+
+       for (i = 0; i < listeners->len; i++) {
+               struct bt_graph_listener_ports_connected *listener =
+                       &g_array_index(listeners,
+                               struct bt_graph_listener_ports_connected, i);
+
+               BT_ASSERT(listener->func);
+               status = listener->func(upstream_comp, downstream_comp,
+                       upstream_port, downstream_port, listener->base.data);
+               if (status != BT_GRAPH_LISTENER_STATUS_OK) {
+                       goto end;
+               }
+       }
+
+end:
+       return status;
+}
+
+enum bt_graph_status bt_graph_cancel(struct bt_graph *graph)
+{
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       graph->canceled = true;
+       BT_LIB_LOGV("Canceled graph: %!+i", graph);
+       return BT_GRAPH_STATUS_OK;
+}
+
+bt_bool bt_graph_is_canceled(const struct bt_graph *graph)
+{
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       return graph->canceled ? BT_TRUE : BT_FALSE;
+}
+
+BT_HIDDEN
+void bt_graph_remove_connection(struct bt_graph *graph,
+               struct bt_connection *connection)
+{
+       BT_ASSERT(graph);
+       BT_ASSERT(connection);
+       BT_LIB_LOGV("Removing graph's connection: %![graph-]+g, %![conn-]+x",
+               graph, connection);
+       g_ptr_array_remove(graph->connections, connection);
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool component_name_exists(struct bt_graph *graph, const char *name)
+{
+       bool exists = false;
+       uint64_t i;
+
+       for (i = 0; i < graph->components->len; i++) {
+               struct bt_component *other_comp = graph->components->pdata[i];
+
+               if (strcmp(name, bt_component_get_name(other_comp)) == 0) {
+                       BT_ASSERT_PRE_MSG("Another component with the same name already exists in the graph: "
+                               "%![other-comp-]+c, name=\"%s\"",
+                               other_comp, name);
+                       exists = true;
+                       goto end;
+               }
+       }
+
+end:
+       return exists;
+}
+
+static
+enum bt_graph_status add_component_with_init_method_data(
+               struct bt_graph *graph,
+               struct bt_component_class *comp_cls,
+               comp_init_method_t init_method,
+               const char *name, const struct bt_value *params,
+               void *init_method_data, struct bt_component **user_component)
+{
+       enum bt_graph_status graph_status = BT_GRAPH_STATUS_OK;
+       enum bt_self_component_status comp_status;
+       struct bt_component *component = NULL;
+       int ret;
+       bool init_can_consume;
+       struct bt_value *new_params = NULL;
+
+       BT_ASSERT(comp_cls);
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE(!graph->canceled, "Graph is canceled: %!+g", graph);
+       BT_ASSERT_PRE(
+               graph->config_state == BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Graph is not in the \"configuring\" state: %!+g", graph);
+       BT_ASSERT_PRE(!component_name_exists(graph, name),
+               "Duplicate component name: %!+g, name=\"%s\"", graph, name);
+       BT_ASSERT_PRE(!params || bt_value_is_map(params),
+               "Parameter value is not a map value: %!+v", params);
+       init_can_consume = graph->can_consume;
+       bt_graph_set_can_consume(graph, false);
+       BT_LIB_LOGD("Adding component to graph: "
+               "%![graph-]+g, %![cc-]+C, name=\"%s\", %![params-]+v, "
+               "init-method-data-addr=%p",
+               graph, comp_cls, name, params, init_method_data);
+
+       if (!params) {
+               new_params = bt_value_map_create();
+               if (!new_params) {
+                       BT_LOGE_STR("Cannot create map value object.");
+                       graph_status = BT_GRAPH_STATUS_NOMEM;
+                       goto end;
+               }
+
+               params = new_params;
+       }
+
+       ret = bt_component_create(comp_cls, name, &component);
+       if (ret) {
+               BT_LOGE("Cannot create empty component object: ret=%d",
+                       ret);
+               graph_status = BT_GRAPH_STATUS_NOMEM;
+               goto end;
+       }
+
+       /*
+        * The user's initialization method needs to see that this
+        * component is part of the graph. If the user method fails, we
+        * immediately remove the component from the graph's components.
+        */
+       g_ptr_array_add(graph->components, component);
+       bt_component_set_graph(component, graph);
+       bt_value_freeze(params);
+
+       if (init_method) {
+               BT_LOGD_STR("Calling user's initialization method.");
+               comp_status = init_method(component, params, init_method_data);
+               BT_LOGD("User method returned: status=%s",
+                       bt_self_component_status_string(comp_status));
+               if (comp_status != BT_SELF_COMPONENT_STATUS_OK) {
+                       BT_LOGW_STR("Initialization method failed.");
+                       graph_status = (int) comp_status;
+                       bt_component_set_graph(component, NULL);
+                       g_ptr_array_remove_fast(graph->components, component);
+                       goto end;
+               }
+       }
+
+       /*
+        * Mark the component as initialized so that its finalization
+        * method is called when it is destroyed.
+        */
+       component->initialized = true;
+
+       /*
+        * If it's a sink component, it needs to be part of the graph's
+        * sink queue to be consumed by bt_graph_consume().
+        */
+       if (bt_component_is_sink(component)) {
+               graph->has_sink = true;
+               g_queue_push_tail(graph->sinks_to_consume, component);
+       }
+
+       /*
+        * Freeze the component class now that it's instantiated at
+        * least once.
+        */
+       BT_LOGD_STR("Freezing component class.");
+       bt_component_class_freeze(comp_cls);
+       BT_LIB_LOGD("Added component to graph: "
+               "%![graph-]+g, %![cc-]+C, name=\"%s\", %![params-]+v, "
+               "init-method-data-addr=%p, %![comp-]+c",
+               graph, comp_cls, name, params, init_method_data, component);
+
+       if (user_component) {
+               /* Move reference to user */
+               *user_component = component;
+               component = NULL;
+       }
+
+end:
+       if (graph_status != BT_GRAPH_STATUS_OK) {
+               bt_graph_make_faulty(graph);
+       }
+
+       bt_object_put_ref(component);
+       bt_object_put_ref(new_params);
+       (void) init_can_consume;
+       bt_graph_set_can_consume(graph, init_can_consume);
+       return graph_status;
+}
+
+enum bt_graph_status
+bt_graph_add_source_component_with_init_method_data(
+               struct bt_graph *graph,
+               const struct bt_component_class_source *comp_cls,
+               const char *name, const struct bt_value *params,
+               void *init_method_data,
+               const struct bt_component_source **component)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       return add_component_with_init_method_data(graph,
+               (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
+               name, params, init_method_data, (void *) component);
+}
+
+enum bt_graph_status bt_graph_add_source_component(
+               struct bt_graph *graph,
+               const struct bt_component_class_source *comp_cls,
+               const char *name, const struct bt_value *params,
+               const struct bt_component_source **component)
+{
+       return bt_graph_add_source_component_with_init_method_data(
+               graph, comp_cls, name, params, NULL, component);
+}
+
+enum bt_graph_status
+bt_graph_add_filter_component_with_init_method_data(
+               struct bt_graph *graph,
+               const struct bt_component_class_filter *comp_cls,
+               const char *name, const struct bt_value *params,
+               void *init_method_data,
+               const struct bt_component_filter **component)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       return add_component_with_init_method_data(graph,
+               (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
+               name, params, init_method_data, (void *) component);
+}
+
+enum bt_graph_status bt_graph_add_filter_component(
+               struct bt_graph *graph,
+               const struct bt_component_class_filter *comp_cls,
+               const char *name, const struct bt_value *params,
+               const struct bt_component_filter **component)
+{
+       return bt_graph_add_filter_component_with_init_method_data(
+               graph, comp_cls, name, params, NULL, component);
+}
+
+enum bt_graph_status
+bt_graph_add_sink_component_with_init_method_data(
+               struct bt_graph *graph,
+               const struct bt_component_class_sink *comp_cls,
+               const char *name, const struct bt_value *params,
+               void *init_method_data,
+               const struct bt_component_sink **component)
+{
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       return add_component_with_init_method_data(graph,
+               (void *) comp_cls, (comp_init_method_t) comp_cls->methods.init,
+               name, params, init_method_data, (void *) component);
+}
+
+enum bt_graph_status bt_graph_add_sink_component(
+               struct bt_graph *graph,
+               const struct bt_component_class_sink *comp_cls,
+               const char *name, const struct bt_value *params,
+               const struct bt_component_sink **component)
+{
+       return bt_graph_add_sink_component_with_init_method_data(
+               graph, comp_cls, name, params, NULL, component);
+}
+
+BT_HIDDEN
+int bt_graph_remove_unconnected_component(struct bt_graph *graph,
+               struct bt_component *component)
+{
+       bool init_can_consume;
+       uint64_t count;
+       uint64_t i;
+       int ret = 0;
+
+       BT_ASSERT(graph);
+       BT_ASSERT(component);
+       BT_ASSERT(component->base.ref_count == 0);
+       BT_ASSERT(bt_component_borrow_graph(component) == graph);
+
+       init_can_consume = graph->can_consume;
+       count = bt_component_get_input_port_count(component);
+
+       for (i = 0; i < count; i++) {
+               struct bt_port *port = (void *)
+                       bt_component_borrow_input_port_by_index(component, i);
+
+               BT_ASSERT(port);
+
+               if (bt_port_is_connected(port)) {
+                       BT_LIB_LOGW("Cannot remove component from graph: "
+                               "an input port is connected: "
+                               "%![graph-]+g, %![comp-]+c, %![port-]+p",
+                               graph, component, port);
+                       goto error;
+               }
+       }
+
+       count = bt_component_get_output_port_count(component);
+
+       for (i = 0; i < count; i++) {
+               struct bt_port *port = (void *)
+                       bt_component_borrow_output_port_by_index(component, i);
+
+               BT_ASSERT(port);
+
+               if (bt_port_is_connected(port)) {
+                       BT_LIB_LOGW("Cannot remove component from graph: "
+                               "an output port is connected: "
+                               "%![graph-]+g, %![comp-]+c, %![port-]+p",
+                               graph, component, port);
+                       goto error;
+               }
+       }
+
+       bt_graph_set_can_consume(graph, false);
+
+       /* Possibly remove from sinks to consume */
+       (void) g_queue_remove(graph->sinks_to_consume, component);
+
+       if (graph->sinks_to_consume->length == 0) {
+               graph->has_sink = false;
+       }
+
+       /*
+        * This calls bt_object_try_spec_release() on the component, and
+        * since its reference count is 0, its destructor is called. Its
+        * destructor calls the user's finalization method (if set).
+        */
+       g_ptr_array_remove(graph->components, component);
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       (void) init_can_consume;
+       bt_graph_set_can_consume(graph, init_can_consume);
+       return ret;
+}
+
+BT_HIDDEN
+void bt_graph_add_message(struct bt_graph *graph,
+               struct bt_message *msg)
+{
+       BT_ASSERT(graph);
+       BT_ASSERT(msg);
+
+       /*
+        * It's okay not to take a reference because, when a
+        * message's reference count drops to 0, either:
+        *
+        * * It is recycled back to one of this graph's pool.
+        * * It is destroyed because it doesn't have any link to any
+        *   graph, which means the original graph is already destroyed.
+        */
+       g_ptr_array_add(graph->messages, msg);
+}
+
+void bt_graph_get_ref(const struct bt_graph *graph)
+{
+       bt_object_get_ref(graph);
+}
+
+void bt_graph_put_ref(const struct bt_graph *graph)
+{
+       bt_object_put_ref(graph);
+}
diff --git a/src/lib/graph/graph.h b/src/lib/graph/graph.h
new file mode 100644 (file)
index 0000000..c41d131
--- /dev/null
@@ -0,0 +1,300 @@
+#ifndef BABELTRACE_GRAPH_GRAPH_INTERNAL_H
+#define BABELTRACE_GRAPH_GRAPH_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/graph/graph.h>
+#include <babeltrace2/graph/message-const.h>
+#include "common/babeltrace.h"
+#include "lib/object.h"
+#include "lib/object-pool.h"
+#include "common/assert.h"
+#include <stdlib.h>
+#include <glib.h>
+
+#include "component.h"
+#include "component-sink.h"
+#include "connection.h"
+
+struct bt_component;
+struct bt_port;
+
+enum bt_graph_configuration_state {
+       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+       BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED,
+       BT_GRAPH_CONFIGURATION_STATE_CONFIGURED,
+       BT_GRAPH_CONFIGURATION_STATE_FAULTY,
+};
+
+struct bt_graph {
+       /**
+        * A component graph contains components and point-to-point connection
+        * between these components.
+        *
+        * In terms of ownership:
+        * 1) The graph is the components' parent,
+        * 2) The graph is the connnections' parent,
+        * 3) Components share the ownership of their connections,
+        * 4) A connection holds weak references to its two component endpoints.
+        */
+       struct bt_object base;
+
+       /* Array of pointers to bt_connection. */
+       GPtrArray *connections;
+       /* Array of pointers to bt_component. */
+       GPtrArray *components;
+       /* Queue of pointers (weak references) to sink bt_components. */
+       GQueue *sinks_to_consume;
+
+       bool canceled;
+       bool in_remove_listener;
+       bool has_sink;
+
+       /*
+        * If this is false, then the public API's consuming
+        * functions (bt_graph_consume() and bt_graph_run()) return
+        * BT_GRAPH_STATUS_CANNOT_CONSUME. The internal "no check"
+        * functions always work.
+        *
+        * In bt_port_output_message_iterator_create(), on success,
+        * this flag is cleared so that the iterator remains the only
+        * consumer for the graph's lifetime.
+        */
+       bool can_consume;
+
+       enum bt_graph_configuration_state config_state;
+
+       struct {
+               GArray *source_output_port_added;
+               GArray *filter_output_port_added;
+               GArray *filter_input_port_added;
+               GArray *sink_input_port_added;
+               GArray *source_filter_ports_connected;
+               GArray *source_sink_ports_connected;
+               GArray *filter_filter_ports_connected;
+               GArray *filter_sink_ports_connected;
+       } listeners;
+
+       /* Pool of `struct bt_message_event *` */
+       struct bt_object_pool event_msg_pool;
+
+       /* Pool of `struct bt_message_packet_beginning *` */
+       struct bt_object_pool packet_begin_msg_pool;
+
+       /* Pool of `struct bt_message_packet_end *` */
+       struct bt_object_pool packet_end_msg_pool;
+
+       /*
+        * Array of `struct bt_message *` (weak).
+        *
+        * This is an array of all the messages ever created from
+        * this graph. Some of them can be in one of the pools above,
+        * some of them can be at large. Because each message has a
+        * weak pointer to the graph containing its pool, we need to
+        * notify each message that the graph is gone on graph
+        * destruction.
+        *
+        * TODO: When we support a maximum size for object pools,
+        * add a way for a message to remove itself from this
+        * array (on destruction).
+        */
+       GPtrArray *messages;
+};
+
+static inline
+void _bt_graph_set_can_consume(struct bt_graph *graph, bool can_consume)
+{
+       BT_ASSERT(graph);
+       graph->can_consume = can_consume;
+}
+
+#ifdef BT_DEV_MODE
+# define bt_graph_set_can_consume      _bt_graph_set_can_consume
+#else
+# define bt_graph_set_can_consume(_graph, _can_consume)
+#endif
+
+BT_HIDDEN
+enum bt_graph_status bt_graph_consume_sink_no_check(struct bt_graph *graph,
+               struct bt_component_sink *sink);
+
+BT_HIDDEN
+enum bt_graph_listener_status bt_graph_notify_port_added(struct bt_graph *graph,
+               struct bt_port *port);
+
+BT_HIDDEN
+enum bt_graph_listener_status bt_graph_notify_ports_connected(
+               struct bt_graph *graph, struct bt_port *upstream_port,
+               struct bt_port *downstream_port);
+
+BT_HIDDEN
+void bt_graph_remove_connection(struct bt_graph *graph,
+               struct bt_connection *connection);
+
+/*
+ * This only works with a component which is not connected at this
+ * point.
+ *
+ * Also the reference count of `component` should be 0 when you call
+ * this function, which means only `graph` owns the component, so it
+ * is safe to destroy.
+ */
+BT_HIDDEN
+int bt_graph_remove_unconnected_component(struct bt_graph *graph,
+               struct bt_component *component);
+
+BT_HIDDEN
+void bt_graph_add_message(struct bt_graph *graph,
+               struct bt_message *msg);
+
+static inline
+const char *bt_graph_status_string(enum bt_graph_status status)
+{
+       switch (status) {
+       case BT_GRAPH_STATUS_CANCELED:
+               return "BT_GRAPH_STATUS_CANCELED";
+       case BT_GRAPH_STATUS_AGAIN:
+               return "BT_GRAPH_STATUS_AGAIN";
+       case BT_GRAPH_STATUS_END:
+               return "BT_GRAPH_STATUS_END";
+       case BT_GRAPH_STATUS_OK:
+               return "BT_GRAPH_STATUS_OK";
+       case BT_GRAPH_STATUS_ERROR:
+               return "BT_GRAPH_STATUS_ERROR";
+       case BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION:
+               return "BT_GRAPH_STATUS_COMPONENT_REFUSES_PORT_CONNECTION";
+       case BT_GRAPH_STATUS_NOMEM:
+               return "BT_GRAPH_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+const char *bt_graph_configuration_state_string(
+               enum bt_graph_configuration_state state)
+{
+       switch (state) {
+       case BT_GRAPH_CONFIGURATION_STATE_CONFIGURING:
+               return "BT_GRAPH_CONFIGURATION_STATE_CONFIGURING";
+       case BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED:
+               return "BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED";
+       case BT_GRAPH_CONFIGURATION_STATE_CONFIGURED:
+               return "BT_GRAPH_CONFIGURATION_STATE_CONFIGURED";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+enum bt_graph_status bt_graph_configure(struct bt_graph *graph)
+{
+       enum bt_graph_status status = BT_GRAPH_STATUS_OK;
+       uint64_t i;
+
+       BT_ASSERT(graph->config_state != BT_GRAPH_CONFIGURATION_STATE_FAULTY);
+
+       if (likely(graph->config_state ==
+                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURED)) {
+               goto end;
+       }
+
+#ifdef BT_ASSERT_PRE
+       BT_ASSERT_PRE(graph->has_sink, "Graph has no sink component: %!+g", graph);
+#endif
+
+       graph->config_state = BT_GRAPH_CONFIGURATION_STATE_PARTIALLY_CONFIGURED;
+
+       for (i = 0; i < graph->components->len; i++) {
+               struct bt_component *comp = graph->components->pdata[i];
+               struct bt_component_sink *comp_sink = (void *) comp;
+               struct bt_component_class_sink *comp_cls_sink =
+                       (void *) comp->class;
+
+               if (comp->class->type != BT_COMPONENT_CLASS_TYPE_SINK) {
+                       continue;
+               }
+
+               if (comp_sink->graph_is_configured_method_called) {
+                       continue;
+               }
+
+               if (comp_cls_sink->methods.graph_is_configured) {
+                       enum bt_self_component_status comp_status;
+
+#ifdef BT_LIB_LOGD
+                       BT_LIB_LOGD("Calling user's \"graph is configured\" method: "
+                               "%![graph-]+g, %![comp-]+c",
+                               graph, comp);
+#endif
+
+                       comp_status = comp_cls_sink->methods.graph_is_configured(
+                               (void *) comp_sink);
+
+#ifdef BT_LIB_LOGD
+                       BT_LIB_LOGD("User method returned: status=%s",
+                               bt_self_component_status_string(comp_status));
+#endif
+
+#ifdef BT_ASSERT_PRE
+                       BT_ASSERT_PRE(comp_status == BT_SELF_COMPONENT_STATUS_OK ||
+                               comp_status == BT_SELF_COMPONENT_STATUS_ERROR ||
+                               comp_status == BT_SELF_COMPONENT_STATUS_NOMEM,
+                               "Unexpected returned status: status=%s",
+                               bt_self_component_status_string(comp_status));
+#endif
+
+                       if (comp_status != BT_SELF_COMPONENT_STATUS_OK) {
+                               status = BT_GRAPH_STATUS_ERROR;
+#ifdef BT_LIB_LOGW
+                               BT_LIB_LOGW("User's \"graph is configured\" method failed: "
+                                       "%![comp-]+c, status=%s",
+                                       comp,
+                                       bt_self_component_status_string(
+                                               comp_status));
+#endif
+
+                               goto end;
+                       }
+               }
+
+               comp_sink->graph_is_configured_method_called = true;
+       }
+
+       graph->config_state = BT_GRAPH_CONFIGURATION_STATE_CONFIGURED;
+
+end:
+       return status;
+}
+
+static inline
+void bt_graph_make_faulty(struct bt_graph *graph)
+{
+       graph->config_state = BT_GRAPH_CONFIGURATION_STATE_FAULTY;
+#ifdef BT_LIB_LOGD
+       BT_LIB_LOGD("Set graph's state to faulty: %![graph-]+g", graph);
+#endif
+}
+
+#endif /* BABELTRACE_GRAPH_GRAPH_INTERNAL_H */
diff --git a/src/lib/graph/iterator.c b/src/lib/graph/iterator.c
new file mode 100644 (file)
index 0000000..4b87699
--- /dev/null
@@ -0,0 +1,1473 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "MSG-ITER"
+#include "lib/lib-logging.h"
+
+#include "compat/compiler.h"
+#include "lib/trace-ir/clock-class.h"
+#include "lib/trace-ir/clock-snapshot.h"
+#include <babeltrace2/trace-ir/field.h>
+#include <babeltrace2/trace-ir/event-const.h>
+#include "lib/trace-ir/event.h"
+#include <babeltrace2/trace-ir/packet-const.h>
+#include "lib/trace-ir/packet.h"
+#include "lib/trace-ir/stream.h"
+#include <babeltrace2/graph/connection-const.h>
+#include <babeltrace2/graph/component-const.h>
+#include <babeltrace2/graph/component-sink-const.h>
+#include <babeltrace2/graph/message-const.h>
+#include <babeltrace2/graph/message-iterator-const.h>
+#include <babeltrace2/graph/self-component-port-input-message-iterator.h>
+#include <babeltrace2/graph/port-output-message-iterator.h>
+#include <babeltrace2/graph/message-event-const.h>
+#include <babeltrace2/graph/message-packet-beginning-const.h>
+#include <babeltrace2/graph/message-packet-end-const.h>
+#include <babeltrace2/graph/message-stream-beginning-const.h>
+#include <babeltrace2/graph/message-stream-end-const.h>
+#include <babeltrace2/graph/port-const.h>
+#include <babeltrace2/graph/graph.h>
+#include <babeltrace2/graph/graph-const.h>
+#include <babeltrace2/types.h>
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "component-class.h"
+#include "component-class-sink-colander.h"
+#include "component.h"
+#include "component-sink.h"
+#include "component-source.h"
+#include "connection.h"
+#include "graph.h"
+#include "message/discarded-items.h"
+#include "message/event.h"
+#include "message/iterator.h"
+#include "message/message.h"
+#include "message/message-iterator-inactivity.h"
+#include "message/stream.h"
+#include "message/packet.h"
+#include "message/stream-activity.h"
+
+/*
+ * TODO: Use graph's state (number of active iterators, etc.) and
+ * possibly system specifications to make a better guess than this.
+ */
+#define MSG_BATCH_SIZE 15
+
+#define BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(_iter)                    \
+       BT_ASSERT_PRE((_iter)->state == BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE || \
+               (_iter)->state == BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED || \
+               (_iter)->state == BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN || \
+               (_iter)->state == BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR, \
+               "Message iterator is in the wrong state: %!+i", _iter)
+
+static inline
+void set_self_comp_port_input_msg_iterator_state(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               enum bt_self_component_port_input_message_iterator_state state)
+{
+       BT_ASSERT(iterator);
+       BT_LIB_LOGD("Updating message iterator's state: new-state=%s",
+               bt_self_component_port_input_message_iterator_state_string(state));
+       iterator->state = state;
+}
+
+static
+void destroy_base_message_iterator(struct bt_object *obj)
+{
+       struct bt_message_iterator *iterator = (void *) obj;
+
+       BT_ASSERT(iterator);
+
+       if (iterator->msgs) {
+               g_ptr_array_free(iterator->msgs, TRUE);
+               iterator->msgs = NULL;
+       }
+
+       g_free(iterator);
+}
+
+static
+void bt_self_component_port_input_message_iterator_destroy(struct bt_object *obj)
+{
+       struct bt_self_component_port_input_message_iterator *iterator;
+
+       BT_ASSERT(obj);
+
+       /*
+        * The message iterator's reference count is 0 if we're
+        * here. Increment it to avoid a double-destroy (possibly
+        * infinitely recursive). This could happen for example if the
+        * message iterator's finalization function does
+        * bt_object_get_ref() (or anything that causes
+        * bt_object_get_ref() to be called) on itself (ref. count goes
+        * from 0 to 1), and then bt_object_put_ref(): the reference
+        * count would go from 1 to 0 again and this function would be
+        * called again.
+        */
+       obj->ref_count++;
+       iterator = (void *) obj;
+       BT_LIB_LOGD("Destroying self component input port message iterator object: "
+               "%!+i", iterator);
+       bt_self_component_port_input_message_iterator_try_finalize(iterator);
+
+       if (iterator->connection) {
+               /*
+                * Remove ourself from the originating connection so
+                * that it does not try to finalize a dangling pointer
+                * later.
+                */
+               bt_connection_remove_iterator(iterator->connection, iterator);
+               iterator->connection = NULL;
+       }
+
+       if (iterator->auto_seek_msgs) {
+               while (!g_queue_is_empty(iterator->auto_seek_msgs)) {
+                       bt_object_put_no_null_check(
+                               g_queue_pop_tail(iterator->auto_seek_msgs));
+               }
+
+               g_queue_free(iterator->auto_seek_msgs);
+               iterator->auto_seek_msgs = NULL;
+       }
+
+       destroy_base_message_iterator(obj);
+}
+
+BT_HIDDEN
+void bt_self_component_port_input_message_iterator_try_finalize(
+               struct bt_self_component_port_input_message_iterator *iterator)
+{
+       typedef void (*method_t)(void *);
+
+       struct bt_component_class *comp_class = NULL;
+       method_t method = NULL;
+
+       BT_ASSERT(iterator);
+
+       switch (iterator->state) {
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_NON_INITIALIZED:
+               /* Skip user finalization if user initialization failed */
+               BT_LIB_LOGD("Not finalizing non-initialized message iterator: "
+                       "%!+i", iterator);
+               goto end;
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED:
+               /* Already finalized */
+               BT_LIB_LOGD("Not finalizing message iterator: already finalized: "
+                       "%!+i", iterator);
+               goto end;
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING:
+               /* Already finalized */
+               BT_LIB_LOGF("Message iterator is already being finalized: "
+                       "%!+i", iterator);
+               abort();
+       default:
+               break;
+       }
+
+       BT_LIB_LOGD("Finalizing message iterator: %!+i", iterator);
+       set_self_comp_port_input_msg_iterator_state(iterator,
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING);
+       BT_ASSERT(iterator->upstream_component);
+       comp_class = iterator->upstream_component->class;
+
+       /* Call user-defined destroy method */
+       switch (comp_class->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               struct bt_component_class_source *src_comp_cls =
+                       (void *) comp_class;
+
+               method = (method_t) src_comp_cls->methods.msg_iter_finalize;
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               struct bt_component_class_filter *flt_comp_cls =
+                       (void *) comp_class;
+
+               method = (method_t) flt_comp_cls->methods.msg_iter_finalize;
+               break;
+       }
+       default:
+               /* Unreachable */
+               abort();
+       }
+
+       if (method) {
+               BT_LIB_LOGD("Calling user's finalization method: %!+i",
+                       iterator);
+               method(iterator);
+       }
+
+       iterator->upstream_component = NULL;
+       iterator->upstream_port = NULL;
+       set_self_comp_port_input_msg_iterator_state(iterator,
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED);
+       BT_LIB_LOGD("Finalized message iterator: %!+i", iterator);
+
+end:
+       return;
+}
+
+BT_HIDDEN
+void bt_self_component_port_input_message_iterator_set_connection(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               struct bt_connection *connection)
+{
+       BT_ASSERT(iterator);
+       iterator->connection = connection;
+       BT_LIB_LOGV("Set message iterator's connection: "
+               "%![iter-]+i, %![conn-]+x", iterator, connection);
+}
+
+static
+int init_message_iterator(struct bt_message_iterator *iterator,
+               enum bt_message_iterator_type type,
+               bt_object_release_func destroy)
+{
+       int ret = 0;
+
+       bt_object_init_shared(&iterator->base, destroy);
+       iterator->type = type;
+       iterator->msgs = g_ptr_array_new();
+       if (!iterator->msgs) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_set_size(iterator->msgs, MSG_BATCH_SIZE);
+
+end:
+       return ret;
+}
+
+static
+bt_bool can_seek_ns_from_origin_true(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin)
+{
+       return BT_TRUE;
+}
+
+static
+bt_bool can_seek_beginning_true(
+               struct bt_self_component_port_input_message_iterator *iterator)
+{
+       return BT_TRUE;
+}
+
+static
+struct bt_self_component_port_input_message_iterator *
+bt_self_component_port_input_message_iterator_create_initial(
+               struct bt_component *upstream_comp,
+               struct bt_port *upstream_port)
+{
+       int ret;
+       struct bt_self_component_port_input_message_iterator *iterator = NULL;
+
+       BT_ASSERT(upstream_comp);
+       BT_ASSERT(upstream_port);
+       BT_ASSERT(bt_port_is_connected(upstream_port));
+       BT_LIB_LOGD("Creating initial message iterator on self component input port: "
+               "%![up-comp-]+c, %![up-port-]+p", upstream_comp, upstream_port);
+       BT_ASSERT(bt_component_get_class_type(upstream_comp) ==
+               BT_COMPONENT_CLASS_TYPE_SOURCE ||
+               bt_component_get_class_type(upstream_comp) ==
+               BT_COMPONENT_CLASS_TYPE_FILTER);
+       iterator = g_new0(
+               struct bt_self_component_port_input_message_iterator, 1);
+       if (!iterator) {
+               BT_LOGE_STR("Failed to allocate one self component input port "
+                       "message iterator.");
+               goto end;
+       }
+
+       ret = init_message_iterator((void *) iterator,
+               BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT,
+               bt_self_component_port_input_message_iterator_destroy);
+       if (ret) {
+               /* init_message_iterator() logs errors */
+               BT_OBJECT_PUT_REF_AND_RESET(iterator);
+               goto end;
+       }
+
+       iterator->auto_seek_msgs = g_queue_new();
+       if (!iterator->auto_seek_msgs) {
+               BT_LOGE_STR("Failed to allocate a GQueue.");
+               ret = -1;
+               goto end;
+       }
+
+       iterator->upstream_component = upstream_comp;
+       iterator->upstream_port = upstream_port;
+       iterator->connection = iterator->upstream_port->connection;
+       iterator->graph = bt_component_borrow_graph(upstream_comp);
+       set_self_comp_port_input_msg_iterator_state(iterator,
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_NON_INITIALIZED);
+
+       switch (iterator->upstream_component->class->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               struct bt_component_class_source *src_comp_cls =
+                       (void *) iterator->upstream_component->class;
+
+               iterator->methods.next =
+                       (bt_self_component_port_input_message_iterator_next_method)
+                               src_comp_cls->methods.msg_iter_next;
+               iterator->methods.seek_ns_from_origin =
+                       (bt_self_component_port_input_message_iterator_seek_ns_from_origin_method)
+                               src_comp_cls->methods.msg_iter_seek_ns_from_origin;
+               iterator->methods.seek_beginning =
+                       (bt_self_component_port_input_message_iterator_seek_beginning_method)
+                               src_comp_cls->methods.msg_iter_seek_beginning;
+               iterator->methods.can_seek_ns_from_origin =
+                       (bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method)
+                               src_comp_cls->methods.msg_iter_can_seek_ns_from_origin;
+               iterator->methods.can_seek_beginning =
+                       (bt_self_component_port_input_message_iterator_can_seek_beginning_method)
+                               src_comp_cls->methods.msg_iter_can_seek_beginning;
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               struct bt_component_class_filter *flt_comp_cls =
+                       (void *) iterator->upstream_component->class;
+
+               iterator->methods.next =
+                       (bt_self_component_port_input_message_iterator_next_method)
+                               flt_comp_cls->methods.msg_iter_next;
+               iterator->methods.seek_ns_from_origin =
+                       (bt_self_component_port_input_message_iterator_seek_ns_from_origin_method)
+                               flt_comp_cls->methods.msg_iter_seek_ns_from_origin;
+               iterator->methods.seek_beginning =
+                       (bt_self_component_port_input_message_iterator_seek_beginning_method)
+                               flt_comp_cls->methods.msg_iter_seek_beginning;
+               iterator->methods.can_seek_ns_from_origin =
+                       (bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method)
+                               flt_comp_cls->methods.msg_iter_can_seek_ns_from_origin;
+               iterator->methods.can_seek_beginning =
+                       (bt_self_component_port_input_message_iterator_can_seek_beginning_method)
+                               flt_comp_cls->methods.msg_iter_can_seek_beginning;
+               break;
+       }
+       default:
+               abort();
+       }
+
+       if (iterator->methods.seek_ns_from_origin &&
+                       !iterator->methods.can_seek_ns_from_origin) {
+               iterator->methods.can_seek_ns_from_origin =
+                       (bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method)
+                               can_seek_ns_from_origin_true;
+       }
+
+       if (iterator->methods.seek_beginning &&
+                       !iterator->methods.can_seek_beginning) {
+               iterator->methods.can_seek_beginning =
+                       (bt_self_component_port_input_message_iterator_seek_beginning_method)
+                               can_seek_beginning_true;
+       }
+
+       BT_LIB_LOGD("Created initial message iterator on self component input port: "
+               "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
+               upstream_port, upstream_comp, iterator);
+
+end:
+       return iterator;
+}
+
+struct bt_self_component_port_input_message_iterator *
+bt_self_component_port_input_message_iterator_create(
+               struct bt_self_component_port_input *self_port)
+{
+       typedef enum bt_self_message_iterator_status (*init_method_t)(
+                       void *, void *, void *);
+
+       init_method_t init_method = NULL;
+       struct bt_self_component_port_input_message_iterator *iterator =
+               NULL;
+       struct bt_port *port = (void *) self_port;
+       struct bt_port *upstream_port;
+       struct bt_component *comp;
+       struct bt_component *upstream_comp;
+       struct bt_component_class *upstream_comp_cls;
+
+       BT_ASSERT_PRE_NON_NULL(port, "Port");
+       comp = bt_port_borrow_component_inline(port);
+       BT_ASSERT_PRE(bt_port_is_connected(port),
+               "Port is not connected: %![port-]+p", port);
+       BT_ASSERT_PRE(comp, "Port is not part of a component: %![port-]+p",
+               port);
+       BT_ASSERT_PRE(!bt_component_graph_is_canceled(comp),
+               "Port's component's graph is canceled: "
+               "%![port-]+p, %![comp-]+c", port, comp);
+       BT_ASSERT(port->connection);
+       upstream_port = port->connection->upstream_port;
+       BT_ASSERT(upstream_port);
+       upstream_comp = bt_port_borrow_component_inline(upstream_port);
+       BT_ASSERT(upstream_comp);
+       BT_ASSERT_PRE(
+               bt_component_borrow_graph(upstream_comp)->config_state !=
+                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Graph is not configured: %!+g",
+               bt_component_borrow_graph(upstream_comp));
+       upstream_comp_cls = upstream_comp->class;
+       BT_ASSERT(upstream_comp->class->type ==
+               BT_COMPONENT_CLASS_TYPE_SOURCE ||
+               upstream_comp->class->type ==
+               BT_COMPONENT_CLASS_TYPE_FILTER);
+       iterator = bt_self_component_port_input_message_iterator_create_initial(
+               upstream_comp, upstream_port);
+       if (!iterator) {
+               BT_LOGW_STR("Cannot create self component input port "
+                       "message iterator.");
+               goto end;
+       }
+
+       switch (upstream_comp_cls->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               struct bt_component_class_source *src_comp_cls =
+                       (void *) upstream_comp_cls;
+
+               init_method =
+                       (init_method_t) src_comp_cls->methods.msg_iter_init;
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               struct bt_component_class_filter *flt_comp_cls =
+                       (void *) upstream_comp_cls;
+
+               init_method =
+                       (init_method_t) flt_comp_cls->methods.msg_iter_init;
+               break;
+       }
+       default:
+               /* Unreachable */
+               abort();
+       }
+
+       if (init_method) {
+               int iter_status;
+
+               BT_LIB_LOGD("Calling user's initialization method: %!+i", iterator);
+               iter_status = init_method(iterator, upstream_comp,
+                       upstream_port);
+               BT_LOGD("User method returned: status=%s",
+                       bt_message_iterator_status_string(iter_status));
+               if (iter_status != BT_MESSAGE_ITERATOR_STATUS_OK) {
+                       BT_LOGW_STR("Initialization method failed.");
+                       BT_OBJECT_PUT_REF_AND_RESET(iterator);
+                       goto end;
+               }
+       }
+
+       set_self_comp_port_input_msg_iterator_state(iterator,
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE);
+       g_ptr_array_add(port->connection->iterators, iterator);
+       BT_LIB_LOGD("Created message iterator on self component input port: "
+               "%![up-port-]+p, %![up-comp-]+c, %![iter-]+i",
+               upstream_port, upstream_comp, iterator);
+
+end:
+       return iterator;
+}
+
+void *bt_self_message_iterator_get_data(
+               const struct bt_self_message_iterator *self_iterator)
+{
+       struct bt_self_component_port_input_message_iterator *iterator =
+               (void *) self_iterator;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return iterator->user_data;
+}
+
+void bt_self_message_iterator_set_data(
+               struct bt_self_message_iterator *self_iterator, void *data)
+{
+       struct bt_self_component_port_input_message_iterator *iterator =
+               (void *) self_iterator;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       iterator->user_data = data;
+       BT_LIB_LOGV("Set message iterator's user data: "
+               "%!+i, user-data-addr=%p", iterator, data);
+}
+
+enum bt_message_iterator_status
+bt_self_component_port_input_message_iterator_next(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               bt_message_array_const *msgs, uint64_t *user_count)
+{
+       int status = BT_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(msgs, "Message array (output)");
+       BT_ASSERT_PRE_NON_NULL(user_count, "Message count (output)");
+       BT_ASSERT_PRE(iterator->state ==
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE,
+               "Message iterator's \"next\" called, but "
+               "message iterator is in the wrong state: %!+i", iterator);
+       BT_ASSERT(iterator->upstream_component);
+       BT_ASSERT(iterator->upstream_component->class);
+       BT_ASSERT_PRE(
+               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
+                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Graph is not configured: %!+g",
+               bt_component_borrow_graph(iterator->upstream_component));
+       BT_LIB_LOGD("Getting next self component input port "
+               "message iterator's messages: %!+i", iterator);
+
+       /*
+        * Call the user's "next" method to get the next messages
+        * and status.
+        */
+       BT_ASSERT(iterator->methods.next);
+       BT_LOGD_STR("Calling user's \"next\" method.");
+       status = iterator->methods.next(iterator,
+               (void *) iterator->base.msgs->pdata, MSG_BATCH_SIZE,
+               user_count);
+       BT_LOGD("User method returned: status=%s",
+               bt_message_iterator_status_string(status));
+       if (status < 0) {
+               BT_LOGW_STR("User method failed.");
+               goto end;
+       }
+
+       /*
+        * There is no way that this iterator could have been finalized
+        * during its "next" method, as the only way to do this is to
+        * put the last iterator's reference, and this can only be done
+        * by its downstream owner.
+        *
+        * For the same reason, there is no way that this iterator could
+        * have seeked (cannot seek a self message iterator).
+        */
+       BT_ASSERT(iterator->state ==
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE);
+
+       switch (status) {
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+               BT_ASSERT_PRE(*user_count <= MSG_BATCH_SIZE,
+                       "Invalid returned message count: greater than "
+                       "batch size: count=%" PRIu64 ", batch-size=%u",
+                       *user_count, MSG_BATCH_SIZE);
+               *msgs = (void *) iterator->base.msgs->pdata;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_END:
+               set_self_comp_port_input_msg_iterator_state(iterator,
+                       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED);
+               goto end;
+       default:
+               /* Unknown non-error status */
+               abort();
+       }
+
+end:
+       return status;
+}
+
+enum bt_message_iterator_status bt_port_output_message_iterator_next(
+               struct bt_port_output_message_iterator *iterator,
+               bt_message_array_const *msgs_to_user,
+               uint64_t *count_to_user)
+{
+       enum bt_message_iterator_status status;
+       enum bt_graph_status graph_status;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(msgs_to_user, "Message array (output)");
+       BT_ASSERT_PRE_NON_NULL(count_to_user, "Message count (output)");
+       BT_LIB_LOGD("Getting next output port message iterator's messages: "
+               "%!+i", iterator);
+       graph_status = bt_graph_consume_sink_no_check(iterator->graph,
+               iterator->colander);
+       switch (graph_status) {
+       case BT_GRAPH_STATUS_CANCELED:
+       case BT_GRAPH_STATUS_AGAIN:
+       case BT_GRAPH_STATUS_END:
+       case BT_GRAPH_STATUS_NOMEM:
+               status = (int) graph_status;
+               break;
+       case BT_GRAPH_STATUS_OK:
+               status = BT_MESSAGE_ITERATOR_STATUS_OK;
+
+               /*
+                * On success, the colander sink moves the messages
+                * to this iterator's array and sets this iterator's
+                * message count: move them to the user.
+                */
+               *msgs_to_user = (void *) iterator->base.msgs->pdata;
+               *count_to_user = iterator->count;
+               break;
+       default:
+               /* Other errors */
+               status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
+       }
+
+       return status;
+}
+
+struct bt_component *
+bt_self_component_port_input_message_iterator_borrow_component(
+               struct bt_self_component_port_input_message_iterator *iterator)
+{
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return iterator->upstream_component;
+}
+
+const struct bt_component *
+bt_self_component_port_input_message_iterator_borrow_component_const(
+               const struct bt_self_component_port_input_message_iterator *iterator)
+{
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return iterator->upstream_component;
+}
+
+struct bt_self_component *bt_self_message_iterator_borrow_component(
+               struct bt_self_message_iterator *self_iterator)
+{
+       struct bt_self_component_port_input_message_iterator *iterator =
+               (void *) self_iterator;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return (void *) iterator->upstream_component;
+}
+
+struct bt_self_port_output *bt_self_message_iterator_borrow_port(
+               struct bt_self_message_iterator *self_iterator)
+{
+       struct bt_self_component_port_input_message_iterator *iterator =
+               (void *) self_iterator;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return (void *) iterator->upstream_port;
+}
+
+static
+void bt_port_output_message_iterator_destroy(struct bt_object *obj)
+{
+       struct bt_port_output_message_iterator *iterator = (void *) obj;
+
+       BT_LIB_LOGD("Destroying output port message iterator object: %!+i",
+               iterator);
+       BT_LOGD_STR("Putting graph.");
+       BT_OBJECT_PUT_REF_AND_RESET(iterator->graph);
+       BT_LOGD_STR("Putting colander sink component.");
+       BT_OBJECT_PUT_REF_AND_RESET(iterator->colander);
+       destroy_base_message_iterator(obj);
+}
+
+struct bt_port_output_message_iterator *
+bt_port_output_message_iterator_create(struct bt_graph *graph,
+               const struct bt_port_output *output_port)
+{
+       struct bt_port_output_message_iterator *iterator = NULL;
+       struct bt_component_class_sink *colander_comp_cls = NULL;
+       struct bt_component *output_port_comp = NULL;
+       struct bt_component_sink *colander_comp;
+       enum bt_graph_status graph_status;
+       struct bt_port_input *colander_in_port = NULL;
+       struct bt_component_class_sink_colander_data colander_data;
+       int ret;
+
+       BT_ASSERT_PRE_NON_NULL(graph, "Graph");
+       BT_ASSERT_PRE_NON_NULL(output_port, "Output port");
+       output_port_comp = bt_port_borrow_component_inline(
+               (const void *) output_port);
+       BT_ASSERT_PRE(output_port_comp,
+               "Output port has no component: %!+p", output_port);
+       BT_ASSERT_PRE(bt_component_borrow_graph(output_port_comp) ==
+               (void *) graph,
+               "Output port is not part of graph: %![graph-]+g, %![port-]+p",
+               graph, output_port);
+       BT_ASSERT_PRE(!graph->has_sink,
+               "Graph already has a sink component: %![graph-]+g");
+
+       /* Create message iterator */
+       BT_LIB_LOGD("Creating message iterator on output port: "
+               "%![port-]+p, %![comp-]+c", output_port, output_port_comp);
+       iterator = g_new0(struct bt_port_output_message_iterator, 1);
+       if (!iterator) {
+               BT_LOGE_STR("Failed to allocate one output port message iterator.");
+               goto error;
+       }
+
+       ret = init_message_iterator((void *) iterator,
+               BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT,
+               bt_port_output_message_iterator_destroy);
+       if (ret) {
+               /* init_message_iterator() logs errors */
+               BT_OBJECT_PUT_REF_AND_RESET(iterator);
+               goto end;
+       }
+
+       /* Create colander component */
+       colander_comp_cls = bt_component_class_sink_colander_get();
+       if (!colander_comp_cls) {
+               BT_LOGW("Cannot get colander sink component class.");
+               goto error;
+       }
+
+       iterator->graph = graph;
+       bt_object_get_no_null_check(iterator->graph);
+       colander_data.msgs = (void *) iterator->base.msgs->pdata;
+       colander_data.count_addr = &iterator->count;
+
+       /* Hope that nobody uses this very unique name */
+       graph_status =
+               bt_graph_add_sink_component_with_init_method_data(
+                       (void *) graph, colander_comp_cls,
+                       "colander-36ac3409-b1a8-4d60-ab1f-4fdf341a8fb1",
+                       NULL, &colander_data, (void *) &iterator->colander);
+       if (graph_status != BT_GRAPH_STATUS_OK) {
+               BT_LIB_LOGW("Cannot add colander sink component to graph: "
+                       "%1[graph-]+g, status=%s", graph,
+                       bt_graph_status_string(graph_status));
+               goto error;
+       }
+
+       /*
+        * Connect provided output port to the colander component's
+        * input port.
+        */
+       colander_in_port =
+               (void *) bt_component_sink_borrow_input_port_by_index_const(
+                       (void *) iterator->colander, 0);
+       BT_ASSERT(colander_in_port);
+       graph_status = bt_graph_connect_ports(graph,
+               output_port, colander_in_port, NULL);
+       if (graph_status != BT_GRAPH_STATUS_OK) {
+               BT_LIB_LOGW("Cannot add colander sink component to graph: "
+                       "%![graph-]+g, %![comp-]+c, status=%s", graph,
+                       iterator->colander,
+                       bt_graph_status_string(graph_status));
+               goto error;
+       }
+
+       /*
+        * At this point everything went fine. Make the graph
+        * nonconsumable forever so that only this message iterator
+        * can consume (thanks to bt_graph_consume_sink_no_check()).
+        * This avoids leaking the message created by the colander
+        * sink and moved to the message iterator's message
+        * member.
+        */
+       bt_graph_set_can_consume(iterator->graph, false);
+
+       /* Also set the graph as being configured. */
+       graph_status = bt_graph_configure(graph);
+       if (graph_status != BT_GRAPH_STATUS_OK) {
+               BT_LIB_LOGW("Cannot configure graph after having added colander: "
+                       "%![graph-]+g, status=%s", graph,
+                       bt_graph_status_string(graph_status));
+               goto error;
+       }
+       goto end;
+
+error:
+       if (iterator && iterator->graph && iterator->colander) {
+               int ret;
+
+               /* Remove created colander component from graph if any */
+               colander_comp = iterator->colander;
+               BT_OBJECT_PUT_REF_AND_RESET(iterator->colander);
+
+               /*
+                * At this point the colander component's reference
+                * count is 0 because iterator->colander was the only
+                * owner. We also know that it is not connected because
+                * this is the last operation before this function
+                * succeeds.
+                *
+                * Since we honor the preconditions here,
+                * bt_graph_remove_unconnected_component() always
+                * succeeds.
+                */
+               ret = bt_graph_remove_unconnected_component(iterator->graph,
+                       (void *) colander_comp);
+               BT_ASSERT(ret == 0);
+       }
+
+       BT_OBJECT_PUT_REF_AND_RESET(iterator);
+
+end:
+       bt_object_put_ref(colander_comp_cls);
+       return (void *) iterator;
+}
+
+bt_bool bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin)
+{
+       bt_bool can = BT_FALSE;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
+       BT_ASSERT_PRE(
+               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
+                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Graph is not configured: %!+g",
+               bt_component_borrow_graph(iterator->upstream_component));
+
+       if (iterator->methods.can_seek_ns_from_origin) {
+               can = iterator->methods.can_seek_ns_from_origin(iterator,
+                       ns_from_origin);
+               goto end;
+       }
+
+       /*
+        * Automatic seeking fall back: if we can seek to the beginning,
+        * then we can automatically seek to any message.
+        */
+       if (iterator->methods.can_seek_beginning) {
+               can = iterator->methods.can_seek_beginning(iterator);
+       }
+
+end:
+       return can;
+}
+
+bt_bool bt_self_component_port_input_message_iterator_can_seek_beginning(
+               struct bt_self_component_port_input_message_iterator *iterator)
+{
+       bt_bool can = BT_FALSE;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
+       BT_ASSERT_PRE(
+               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
+                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Graph is not configured: %!+g",
+               bt_component_borrow_graph(iterator->upstream_component));
+
+       if (iterator->methods.can_seek_beginning) {
+               can = iterator->methods.can_seek_beginning(iterator);
+       }
+
+       return can;
+}
+
+static inline
+void set_iterator_state_after_seeking(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               enum bt_message_iterator_status status)
+{
+       enum bt_self_component_port_input_message_iterator_state new_state = 0;
+
+       /* Set iterator's state depending on seeking status */
+       switch (status) {
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+               new_state = BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               new_state = BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_ERROR:
+       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               new_state = BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_END:
+               new_state = BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED;
+               break;
+       default:
+               abort();
+       }
+
+       set_self_comp_port_input_msg_iterator_state(iterator, new_state);
+}
+
+enum bt_message_iterator_status
+bt_self_component_port_input_message_iterator_seek_beginning(
+               struct bt_self_component_port_input_message_iterator *iterator)
+{
+       int status;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
+       BT_ASSERT_PRE(
+               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
+                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Graph is not configured: %!+g",
+               bt_component_borrow_graph(iterator->upstream_component));
+       BT_ASSERT_PRE(
+               bt_self_component_port_input_message_iterator_can_seek_beginning(
+                       iterator),
+               "Message iterator cannot seek beginning: %!+i", iterator);
+       BT_LIB_LOGD("Calling user's \"seek beginning\" method: %!+i", iterator);
+       set_self_comp_port_input_msg_iterator_state(iterator,
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING);
+       status = iterator->methods.seek_beginning(iterator);
+       BT_LOGD("User method returned: status=%s",
+               bt_message_iterator_status_string(status));
+       BT_ASSERT_PRE(status == BT_MESSAGE_ITERATOR_STATUS_OK ||
+               status == BT_MESSAGE_ITERATOR_STATUS_ERROR ||
+               status == BT_MESSAGE_ITERATOR_STATUS_NOMEM ||
+               status == BT_MESSAGE_ITERATOR_STATUS_AGAIN,
+               "Unexpected status: %![iter-]+i, status=%s",
+               iterator, bt_common_self_message_iterator_status_string(status));
+       set_iterator_state_after_seeking(iterator, status);
+       return status;
+}
+
+static inline
+enum bt_message_iterator_status auto_seek_handle_message(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin, const struct bt_message *msg,
+               bool *got_first)
+{
+       enum bt_message_iterator_status status = BT_MESSAGE_ITERATOR_STATUS_OK;
+       int64_t msg_ns_from_origin;
+       const struct bt_clock_snapshot *clk_snapshot = NULL;
+       int ret;
+
+       BT_ASSERT(msg);
+       BT_ASSERT(got_first);
+
+       switch (msg->type) {
+       case BT_MESSAGE_TYPE_EVENT:
+       {
+               const struct bt_message_event *event_msg =
+                       (const void *) msg;
+
+               clk_snapshot = event_msg->default_cs;
+               BT_ASSERT_PRE(clk_snapshot,
+                       "Event message has no default clock snapshot: %!+n",
+                       event_msg);
+               break;
+       }
+       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+       {
+               const struct bt_message_message_iterator_inactivity *inactivity_msg =
+                       (const void *) msg;
+
+               clk_snapshot = inactivity_msg->default_cs;
+               BT_ASSERT(clk_snapshot);
+               break;
+       }
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+       case BT_MESSAGE_TYPE_PACKET_END:
+       {
+               const struct bt_message_packet *packet_msg =
+                       (const void *) msg;
+
+               clk_snapshot = packet_msg->default_cs;
+               BT_ASSERT_PRE(clk_snapshot,
+                       "Packet message has no default clock snapshot: %!+n",
+                       packet_msg);
+               break;
+       }
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+       {
+               struct bt_message_discarded_items *msg_disc_items =
+                       (void *) msg;
+
+               BT_ASSERT_PRE(msg_disc_items->default_begin_cs &&
+                       msg_disc_items->default_end_cs,
+                       "Discarded events/packets message has no default clock snapshots: %!+n",
+                       msg_disc_items);
+               ret = bt_clock_snapshot_get_ns_from_origin(
+                       msg_disc_items->default_begin_cs,
+                       &msg_ns_from_origin);
+               if (ret) {
+                       status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
+                       goto end;
+               }
+
+               if (msg_ns_from_origin >= ns_from_origin) {
+                       *got_first = true;
+                       goto push_msg;
+               }
+
+               ret = bt_clock_snapshot_get_ns_from_origin(
+                       msg_disc_items->default_end_cs,
+                       &msg_ns_from_origin);
+               if (ret) {
+                       status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
+                       goto end;
+               }
+
+               if (msg_ns_from_origin >= ns_from_origin) {
+                       /*
+                        * The discarded items message's beginning time
+                        * is before the requested seeking time, but its
+                        * end time is after. Modify the message so as
+                        * to set its beginning time to the requested
+                        * seeking time, and make its item count unknown
+                        * as we don't know if items were really
+                        * discarded within the new time range.
+                        */
+                       uint64_t new_begin_raw_value;
+
+                       ret = bt_clock_class_clock_value_from_ns_from_origin(
+                               msg_disc_items->default_end_cs->clock_class,
+                               ns_from_origin, &new_begin_raw_value);
+                       if (ret) {
+                               status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       bt_clock_snapshot_set_raw_value(
+                               msg_disc_items->default_begin_cs,
+                               new_begin_raw_value);
+                       msg_disc_items->count.base.avail =
+                               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
+
+                       /*
+                        * It is safe to push it because its beginning
+                        * time is exactly the requested seeking time.
+                        */
+                       goto push_msg;
+               } else {
+                       goto skip_msg;
+               }
+       }
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+       {
+               const struct bt_message_stream_activity *stream_act_msg =
+                       (const void *) msg;
+
+               switch (stream_act_msg->default_cs_state) {
+               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
+               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
+                       /*
+                        * -inf is always less than any requested time,
+                        * and we can't assume any specific time for an
+                        * unknown clock snapshot, so skip this.
+                        */
+                       goto skip_msg;
+               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
+                       clk_snapshot = stream_act_msg->default_cs;
+                       BT_ASSERT(clk_snapshot);
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+       {
+               const struct bt_message_stream_activity *stream_act_msg =
+                       (const void *) msg;
+
+               switch (stream_act_msg->default_cs_state) {
+               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
+                       /*
+                        * We can't assume any specific time for an
+                        * unknown clock snapshot, so skip this.
+                        */
+                       goto skip_msg;
+               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
+                       /*
+                        * +inf is always greater than any requested
+                        * time.
+                        */
+                       *got_first = true;
+                       goto push_msg;
+               case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
+                       clk_snapshot = stream_act_msg->default_cs;
+                       BT_ASSERT(clk_snapshot);
+                       break;
+               default:
+                       abort();
+               }
+
+               break;
+       }
+       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
+       case BT_MESSAGE_TYPE_STREAM_END:
+               /* Ignore */
+               goto skip_msg;
+       default:
+               abort();
+       }
+
+       BT_ASSERT(clk_snapshot);
+       ret = bt_clock_snapshot_get_ns_from_origin(clk_snapshot,
+               &msg_ns_from_origin);
+       if (ret) {
+               status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       if (msg_ns_from_origin >= ns_from_origin) {
+               *got_first = true;
+               goto push_msg;
+       }
+
+skip_msg:
+       bt_object_put_no_null_check(msg);
+       msg = NULL;
+       goto end;
+
+push_msg:
+       g_queue_push_head(iterator->auto_seek_msgs, (void *) msg);
+       msg = NULL;
+
+end:
+       BT_ASSERT(!msg || status != BT_MESSAGE_ITERATOR_STATUS_OK);
+       return status;
+}
+
+static
+enum bt_message_iterator_status find_message_ge_ns_from_origin(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin)
+{
+       int status;
+       enum bt_self_component_port_input_message_iterator_state init_state =
+               iterator->state;
+       const struct bt_message *messages[MSG_BATCH_SIZE];
+       uint64_t user_count = 0;
+       uint64_t i;
+       bool got_first = false;
+
+       BT_ASSERT(iterator);
+       memset(&messages[0], 0, sizeof(messages[0]) * MSG_BATCH_SIZE);
+
+       /*
+        * Make this iterator temporarily active (not seeking) to call
+        * the "next" method.
+        */
+       set_self_comp_port_input_msg_iterator_state(iterator,
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE);
+
+       BT_ASSERT(iterator->methods.next);
+
+       while (!got_first) {
+               /*
+                * Call the user's "next" method to get the next
+                * messages and status.
+                */
+               BT_LOGD_STR("Calling user's \"next\" method.");
+               status = iterator->methods.next(iterator,
+                       &messages[0], MSG_BATCH_SIZE, &user_count);
+               BT_LOGD("User method returned: status=%s",
+                       bt_message_iterator_status_string(status));
+
+               /*
+                * The user's "next" method must not do any action which
+                * would change the iterator's state.
+                */
+               BT_ASSERT(iterator->state ==
+                       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE);
+
+               switch (status) {
+               case BT_MESSAGE_ITERATOR_STATUS_OK:
+                       BT_ASSERT_PRE(user_count <= MSG_BATCH_SIZE,
+                               "Invalid returned message count: greater than "
+                               "batch size: count=%" PRIu64 ", batch-size=%u",
+                               user_count, MSG_BATCH_SIZE);
+                       break;
+               case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               case BT_MESSAGE_ITERATOR_STATUS_ERROR:
+               case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               case BT_MESSAGE_ITERATOR_STATUS_END:
+                       goto end;
+               default:
+                       abort();
+               }
+
+               for (i = 0; i < user_count; i++) {
+                       if (got_first) {
+                               g_queue_push_head(iterator->auto_seek_msgs,
+                                       (void *) messages[i]);
+                               messages[i] = NULL;
+                               continue;
+                       }
+
+                       status = auto_seek_handle_message(iterator,
+                               ns_from_origin, messages[i], &got_first);
+                       if (status == BT_MESSAGE_ITERATOR_STATUS_OK) {
+                               /* Message was either pushed or moved */
+                               messages[i] = NULL;
+                       } else {
+                               goto end;
+                       }
+               }
+       }
+
+end:
+       for (i = 0; i < user_count; i++) {
+               if (messages[i]) {
+                       bt_object_put_no_null_check(messages[i]);
+               }
+       }
+
+       set_self_comp_port_input_msg_iterator_state(iterator, init_state);
+       return status;
+}
+
+static
+enum bt_self_message_iterator_status post_auto_seek_next(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       BT_ASSERT(!g_queue_is_empty(iterator->auto_seek_msgs));
+       *count = 0;
+
+       /*
+        * Move auto-seek messages to the output array (which is this
+        * iterator's base message array).
+        */
+       while (capacity > 0 && !g_queue_is_empty(iterator->auto_seek_msgs)) {
+               msgs[*count] = g_queue_pop_tail(iterator->auto_seek_msgs);
+               capacity--;
+               (*count)++;
+       }
+
+       BT_ASSERT(*count > 0);
+
+       if (g_queue_is_empty(iterator->auto_seek_msgs)) {
+               /* No more auto-seek messages */
+               switch (iterator->upstream_component->class->type) {
+               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+               {
+                       struct bt_component_class_source *src_comp_cls =
+                               (void *) iterator->upstream_component->class;
+
+                       iterator->methods.next =
+                               (bt_self_component_port_input_message_iterator_next_method)
+                                       src_comp_cls->methods.msg_iter_next;
+                       break;
+               }
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+               {
+                       struct bt_component_class_filter *flt_comp_cls =
+                               (void *) iterator->upstream_component->class;
+
+                       iterator->methods.next =
+                               (bt_self_component_port_input_message_iterator_next_method)
+                                       flt_comp_cls->methods.msg_iter_next;
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+
+       return BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+}
+
+enum bt_message_iterator_status
+bt_self_component_port_input_message_iterator_seek_ns_from_origin(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               int64_t ns_from_origin)
+{
+       int status;
+
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       BT_ASSERT_PRE_ITER_HAS_STATE_TO_SEEK(iterator);
+       BT_ASSERT_PRE(
+               bt_component_borrow_graph(iterator->upstream_component)->config_state !=
+                       BT_GRAPH_CONFIGURATION_STATE_CONFIGURING,
+               "Graph is not configured: %!+g",
+               bt_component_borrow_graph(iterator->upstream_component));
+       BT_ASSERT_PRE(
+               bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
+                       iterator, ns_from_origin),
+               "Message iterator cannot seek nanoseconds from origin: %!+i, "
+               "ns-from-origin=%" PRId64, iterator, ns_from_origin);
+       set_self_comp_port_input_msg_iterator_state(iterator,
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING);
+
+       if (iterator->methods.seek_ns_from_origin) {
+               BT_LIB_LOGD("Calling user's \"seek nanoseconds from origin\" method: "
+                       "%![iter-]+i, ns=%" PRId64, iterator, ns_from_origin);
+               status = iterator->methods.seek_ns_from_origin(iterator,
+                       ns_from_origin);
+               BT_LOGD("User method returned: status=%s",
+                       bt_message_iterator_status_string(status));
+               BT_ASSERT_PRE(status == BT_MESSAGE_ITERATOR_STATUS_OK ||
+                       status == BT_MESSAGE_ITERATOR_STATUS_ERROR ||
+                       status == BT_MESSAGE_ITERATOR_STATUS_NOMEM ||
+                       status == BT_MESSAGE_ITERATOR_STATUS_AGAIN,
+                       "Unexpected status: %![iter-]+i, status=%s",
+                       iterator,
+                       bt_common_self_message_iterator_status_string(status));
+       } else {
+               /* Start automatic seeking: seek beginning first */
+               BT_ASSERT(iterator->methods.can_seek_beginning(iterator));
+               BT_ASSERT(iterator->methods.seek_beginning);
+               BT_LIB_LOGD("Calling user's \"seek beginning\" method: %!+i",
+                       iterator);
+               status = iterator->methods.seek_beginning(iterator);
+               BT_LOGD("User method returned: status=%s",
+                       bt_message_iterator_status_string(status));
+               BT_ASSERT_PRE(status == BT_MESSAGE_ITERATOR_STATUS_OK ||
+                       status == BT_MESSAGE_ITERATOR_STATUS_ERROR ||
+                       status == BT_MESSAGE_ITERATOR_STATUS_NOMEM ||
+                       status == BT_MESSAGE_ITERATOR_STATUS_AGAIN,
+                       "Unexpected status: %![iter-]+i, status=%s",
+                       iterator,
+                       bt_common_self_message_iterator_status_string(status));
+               switch (status) {
+               case BT_MESSAGE_ITERATOR_STATUS_OK:
+                       break;
+               case BT_MESSAGE_ITERATOR_STATUS_ERROR:
+               case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+                       goto end;
+               default:
+                       abort();
+               }
+
+               /*
+                * Find the first message which has a default clock
+                * snapshot greater than or equal to the requested
+                * seeking time, and move the received messages from
+                * this point in the batch to this iterator's auto-seek
+                * message queue.
+                */
+               while (!g_queue_is_empty(iterator->auto_seek_msgs)) {
+                       bt_object_put_no_null_check(
+                               g_queue_pop_tail(iterator->auto_seek_msgs));
+               }
+
+               status = find_message_ge_ns_from_origin(iterator,
+                       ns_from_origin);
+               switch (status) {
+               case BT_MESSAGE_ITERATOR_STATUS_OK:
+               case BT_MESSAGE_ITERATOR_STATUS_END:
+                       /*
+                        * If there are messages in the auto-seek
+                        * message queue, replace the user's "next"
+                        * method with a custom, temporary "next" method
+                        * which returns them.
+                        */
+                       if (!g_queue_is_empty(iterator->auto_seek_msgs)) {
+                               iterator->methods.next =
+                                       (bt_self_component_port_input_message_iterator_next_method)
+                                               post_auto_seek_next;
+                       }
+
+                       /*
+                        * `BT_MESSAGE_ITERATOR_STATUS_END` becomes
+                        * `BT_MESSAGE_ITERATOR_STATUS_OK`: the next
+                        * time this iterator's "next" method is called,
+                        * it will return
+                        * `BT_MESSAGE_ITERATOR_STATUS_END`.
+                        */
+                       status = BT_MESSAGE_ITERATOR_STATUS_OK;
+                       break;
+               case BT_MESSAGE_ITERATOR_STATUS_ERROR:
+               case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+                       goto end;
+               default:
+                       abort();
+               }
+       }
+
+end:
+       set_iterator_state_after_seeking(iterator, status);
+       return status;
+}
+
+static inline
+bt_self_component_port_input_message_iterator *
+borrow_output_port_message_iterator_upstream_iterator(
+               struct bt_port_output_message_iterator *iterator)
+{
+       struct bt_component_class_sink_colander_priv_data *colander_data;
+
+       BT_ASSERT(iterator);
+       colander_data = (void *) iterator->colander->parent.user_data;
+       BT_ASSERT(colander_data);
+       BT_ASSERT(colander_data->msg_iter);
+       return colander_data->msg_iter;
+}
+
+bt_bool bt_port_output_message_iterator_can_seek_ns_from_origin(
+               struct bt_port_output_message_iterator *iterator,
+               int64_t ns_from_origin)
+{
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
+               borrow_output_port_message_iterator_upstream_iterator(
+                       iterator), ns_from_origin);
+}
+
+bt_bool bt_port_output_message_iterator_can_seek_beginning(
+               struct bt_port_output_message_iterator *iterator)
+{
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return bt_self_component_port_input_message_iterator_can_seek_beginning(
+               borrow_output_port_message_iterator_upstream_iterator(
+                       iterator));
+}
+
+enum bt_message_iterator_status bt_port_output_message_iterator_seek_ns_from_origin(
+               struct bt_port_output_message_iterator *iterator,
+               int64_t ns_from_origin)
+{
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return bt_self_component_port_input_message_iterator_seek_ns_from_origin(
+               borrow_output_port_message_iterator_upstream_iterator(iterator),
+               ns_from_origin);
+}
+
+enum bt_message_iterator_status bt_port_output_message_iterator_seek_beginning(
+               struct bt_port_output_message_iterator *iterator)
+{
+       BT_ASSERT_PRE_NON_NULL(iterator, "Message iterator");
+       return bt_self_component_port_input_message_iterator_seek_beginning(
+               borrow_output_port_message_iterator_upstream_iterator(
+                       iterator));
+}
+
+void bt_port_output_message_iterator_get_ref(
+               const struct bt_port_output_message_iterator *iterator)
+{
+       bt_object_get_ref(iterator);
+}
+
+void bt_port_output_message_iterator_put_ref(
+               const struct bt_port_output_message_iterator *iterator)
+{
+       bt_object_put_ref(iterator);
+}
+
+void bt_self_component_port_input_message_iterator_get_ref(
+               const struct bt_self_component_port_input_message_iterator *iterator)
+{
+       bt_object_get_ref(iterator);
+}
+
+void bt_self_component_port_input_message_iterator_put_ref(
+               const struct bt_self_component_port_input_message_iterator *iterator)
+{
+       bt_object_put_ref(iterator);
+}
diff --git a/src/lib/graph/message/Makefile.am b/src/lib/graph/message/Makefile.am
new file mode 100644 (file)
index 0000000..b0053ce
--- /dev/null
@@ -0,0 +1,18 @@
+noinst_LTLIBRARIES = libgraph-message.la
+
+libgraph_message_la_SOURCES = \
+       discarded-items.c \
+       discarded-items.h \
+       event.c \
+       event.h \
+       iterator.h \
+       message.c \
+       message.h \
+       message-iterator-inactivity.c \
+       message-iterator-inactivity.h \
+       packet.c \
+       packet.h \
+       stream-activity.c \
+       stream-activity.h \
+       stream.c \
+       stream.h
diff --git a/src/lib/graph/message/discarded-items.c b/src/lib/graph/message/discarded-items.c
new file mode 100644 (file)
index 0000000..646a7e4
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "MSG-DISCARDED-ITEMS"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include "lib/object.h"
+#include "compat/compiler.h"
+#include <babeltrace2/trace-ir/clock-class.h>
+#include "lib/trace-ir/clock-snapshot.h"
+#include "lib/trace-ir/stream-class.h"
+#include "lib/trace-ir/stream.h"
+#include "lib/property.h"
+#include "lib/graph/message/message.h"
+#include <babeltrace2/graph/message-discarded-events.h>
+#include <babeltrace2/graph/message-discarded-events-const.h>
+#include <babeltrace2/graph/message-discarded-packets.h>
+#include <babeltrace2/graph/message-discarded-packets-const.h>
+
+#include "discarded-items.h"
+
+static
+void destroy_discarded_items_message(struct bt_object *obj)
+{
+       struct bt_message_discarded_items *message = (void *) obj;
+
+       BT_LIB_LOGD("Destroying discarded items message: %!+n", message);
+       BT_LIB_LOGD("Putting stream: %!+s", message->stream);
+       BT_OBJECT_PUT_REF_AND_RESET(message->stream);
+
+       if (message->default_begin_cs) {
+               bt_clock_snapshot_recycle(message->default_begin_cs);
+               message->default_begin_cs = NULL;
+       }
+
+       if (message->default_end_cs) {
+               bt_clock_snapshot_recycle(message->default_end_cs);
+               message->default_end_cs = NULL;
+       }
+
+       g_free(message);
+}
+
+static inline
+struct bt_message *create_discarded_items_message(
+               struct bt_self_message_iterator *self_msg_iter,
+               enum bt_message_type type, struct bt_stream *stream,
+               bool with_cs,
+               uint64_t beginning_raw_value, uint64_t end_raw_value)
+{
+       struct bt_message_discarded_items *message;
+       struct bt_stream_class *stream_class;
+       bool has_support;
+       bool need_cs;
+
+       BT_ASSERT_PRE_NON_NULL(self_msg_iter, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       stream_class = bt_stream_borrow_class(stream);
+       BT_ASSERT(stream_class);
+
+       if (type == BT_MESSAGE_TYPE_DISCARDED_EVENTS) {
+               has_support = stream_class->supports_discarded_events;
+               need_cs = stream_class->discarded_events_have_default_clock_snapshots;
+       } else {
+               has_support = stream_class->supports_discarded_packets;
+               need_cs = stream_class->discarded_packets_have_default_clock_snapshots;
+       }
+
+       BT_ASSERT_PRE(has_support,
+               "Stream class does not support discarded events or packets: "
+               "type=%s, %![stream-]+s, %![sc-]+S",
+               bt_message_type_string(type), stream, stream_class);
+       BT_ASSERT_PRE(need_cs ? with_cs : true,
+               "Unexpected stream class configuration when creating "
+               "a discarded events or discarded packets message: "
+               "default clock snapshots are needed, but none was provided: "
+               "type=%s, %![stream-]+s, %![sc-]+S, with-cs=%d, "
+               "cs-begin-val=%" PRIu64 ", cs-end-val=%" PRIu64,
+               bt_message_type_string(type), stream, stream_class,
+               with_cs, beginning_raw_value, end_raw_value);
+       BT_ASSERT_PRE(!need_cs ? !with_cs : true,
+               "Unexpected stream class configuration when creating "
+               "a discarded events or discarded packets message: "
+               "no default clock snapshots are needed, but two were provided: "
+               "type=%s, %![stream-]+s, %![sc-]+S, with-cs=%d, "
+               "cs-begin-val=%" PRIu64 ", cs-end-val=%" PRIu64,
+               bt_message_type_string(type), stream, stream_class,
+               with_cs, beginning_raw_value, end_raw_value);
+       BT_LIB_LOGD("Creating discarded items message object: "
+               "type=%s, %![stream-]+s, %![sc-]+S, with-cs=%d, "
+               "cs-begin-val=%" PRIu64 ", cs-end-val=%" PRIu64,
+               bt_message_type_string(type), stream, stream_class,
+               with_cs, beginning_raw_value, end_raw_value);
+       message = g_new0(struct bt_message_discarded_items, 1);
+       if (!message) {
+               BT_LOGE_STR("Failed to allocate one discarded items message.");
+               goto error;
+       }
+
+       bt_message_init(&message->parent, type,
+               destroy_discarded_items_message, NULL);
+       message->stream = stream;
+       bt_object_get_no_null_check(message->stream);
+
+       if (with_cs) {
+               BT_ASSERT(stream_class->default_clock_class);
+               message->default_begin_cs = bt_clock_snapshot_create(
+                       stream_class->default_clock_class);
+               if (!message->default_begin_cs) {
+                       goto error;
+               }
+
+               bt_clock_snapshot_set_raw_value(message->default_begin_cs,
+                       beginning_raw_value);
+
+               message->default_end_cs = bt_clock_snapshot_create(
+                       stream_class->default_clock_class);
+               if (!message->default_end_cs) {
+                       goto error;
+               }
+
+               bt_clock_snapshot_set_raw_value(message->default_end_cs,
+                       end_raw_value);
+       }
+
+       bt_property_uint_init(&message->count,
+               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE, 0);
+       BT_LIB_LOGD("Created discarded items message object: "
+               "%![msg-]+n, %![stream-]+s, %![sc-]+S", message,
+               stream, stream_class);
+
+       return (void *) &message->parent;
+
+error:
+       return NULL;
+}
+
+static inline
+struct bt_stream *borrow_discarded_items_message_stream(
+               struct bt_message *message)
+{
+       struct bt_message_discarded_items *disc_items_msg = (void *) message;
+
+       BT_ASSERT(message);
+       return disc_items_msg->stream;
+}
+
+static inline
+void set_discarded_items_message_count(struct bt_message *message,
+               uint64_t count)
+{
+       struct bt_message_discarded_items *disc_items_msg = (void *) message;
+
+       BT_ASSERT(message);
+       BT_ASSERT_PRE_HOT(message, "Message", ": %!+n", message);
+       bt_property_uint_set(&disc_items_msg->count, count);
+}
+
+static inline
+enum bt_property_availability get_discarded_items_message_count(
+               const struct bt_message *message, uint64_t *count)
+{
+       struct bt_message_discarded_items *disc_items_msg = (void *) message;
+
+       BT_ASSERT_PRE_NON_NULL(count, "Count (output)");
+       BT_ASSERT(message);
+       *count = disc_items_msg->count.value;
+       return disc_items_msg->count.base.avail;
+}
+
+static inline
+const struct bt_clock_snapshot *
+borrow_discarded_items_message_beginning_default_clock_snapshot_const(
+               const struct bt_message *message)
+{
+       struct bt_message_discarded_items *disc_items_msg = (void *) message;
+
+       BT_ASSERT(message);
+       BT_ASSERT_PRE(disc_items_msg->stream->class->default_clock_class,
+               "Message's stream's class has no default clock class: "
+               "%![msg-]+n, %![sc-]+S",
+               message, disc_items_msg->stream->class);
+       return disc_items_msg->default_begin_cs;
+}
+
+static inline
+const struct bt_clock_snapshot *
+borrow_discarded_items_message_end_default_clock_snapshot_const(
+               const struct bt_message *message)
+{
+       struct bt_message_discarded_items *disc_items_msg = (void *) message;
+
+       BT_ASSERT(message);
+       BT_ASSERT_PRE(disc_items_msg->stream->class->default_clock_class,
+               "Message's stream's class has no default clock class: "
+               "%![msg-]+n, %![sc-]+S",
+               message, disc_items_msg->stream->class);
+       return disc_items_msg->default_end_cs;
+}
+
+struct bt_message *bt_message_discarded_events_create(
+               struct bt_self_message_iterator *message_iterator,
+               const struct bt_stream *stream)
+{
+       return create_discarded_items_message(message_iterator,
+               BT_MESSAGE_TYPE_DISCARDED_EVENTS, (void *) stream,
+               false, 0, 0);
+}
+
+struct bt_message *bt_message_discarded_events_create_with_default_clock_snapshots(
+               struct bt_self_message_iterator *message_iterator,
+               const struct bt_stream *stream, uint64_t beginning_raw_value,
+               uint64_t end_raw_value)
+{
+       return create_discarded_items_message(message_iterator,
+               BT_MESSAGE_TYPE_DISCARDED_EVENTS, (void *) stream,
+               true, beginning_raw_value, end_raw_value);
+}
+
+struct bt_stream *bt_message_discarded_events_borrow_stream(
+               struct bt_message *message)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
+       return borrow_discarded_items_message_stream(message);
+}
+
+void bt_message_discarded_events_set_count(struct bt_message *message,
+               uint64_t count)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
+       set_discarded_items_message_count(message, count);
+}
+
+const struct bt_clock_snapshot *
+bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
+       return borrow_discarded_items_message_beginning_default_clock_snapshot_const(
+               msg);
+}
+
+const struct bt_clock_snapshot *
+bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
+       return borrow_discarded_items_message_end_default_clock_snapshot_const(
+               msg);
+}
+
+const struct bt_stream *
+bt_message_discarded_events_borrow_stream_const(const struct bt_message *message)
+{
+       return (void *) bt_message_discarded_events_borrow_stream(
+               (void *) message);
+}
+
+enum bt_property_availability bt_message_discarded_events_get_count(
+               const struct bt_message *message, uint64_t *count)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
+       return get_discarded_items_message_count(message, count);
+}
+
+struct bt_message *bt_message_discarded_packets_create(
+               struct bt_self_message_iterator *message_iterator,
+               const struct bt_stream *stream)
+{
+       return create_discarded_items_message(message_iterator,
+               BT_MESSAGE_TYPE_DISCARDED_PACKETS, (void *) stream,
+               false, 0, 0);
+}
+
+struct bt_message *bt_message_discarded_packets_create_with_default_clock_snapshots(
+               struct bt_self_message_iterator *message_iterator,
+               const struct bt_stream *stream, uint64_t beginning_raw_value,
+               uint64_t end_raw_value)
+{
+       return create_discarded_items_message(message_iterator,
+               BT_MESSAGE_TYPE_DISCARDED_PACKETS, (void *) stream,
+               true, beginning_raw_value, end_raw_value);
+}
+
+struct bt_stream *bt_message_discarded_packets_borrow_stream(
+               struct bt_message *message)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
+       return borrow_discarded_items_message_stream(message);
+}
+
+void bt_message_discarded_packets_set_count(struct bt_message *message,
+               uint64_t count)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
+       set_discarded_items_message_count(message, count);
+}
+
+const struct bt_clock_snapshot *
+bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
+       return borrow_discarded_items_message_beginning_default_clock_snapshot_const(
+               msg);
+}
+
+const struct bt_clock_snapshot *
+bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
+       return borrow_discarded_items_message_end_default_clock_snapshot_const(
+               msg);
+}
+
+const struct bt_stream *
+bt_message_discarded_packets_borrow_stream_const(const struct bt_message *message)
+{
+       return (void *) bt_message_discarded_packets_borrow_stream(
+               (void *) message);
+}
+
+enum bt_property_availability bt_message_discarded_packets_get_count(
+               const struct bt_message *message, uint64_t *count)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
+       return get_discarded_items_message_count(message, count);
+}
+
+static inline
+const struct bt_clock_class *
+borrow_discarded_items_message_stream_class_default_clock_class(
+               const struct bt_message *msg)
+{
+       struct bt_message_discarded_items *disc_items_msg = (void *) msg;
+
+       BT_ASSERT(msg);
+       return disc_items_msg->stream->class->default_clock_class;
+}
+
+const struct bt_clock_class *
+bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_EVENTS);
+       return borrow_discarded_items_message_stream_class_default_clock_class(
+               msg);
+}
+
+const struct bt_clock_class *
+bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_DISCARDED_PACKETS);
+       return borrow_discarded_items_message_stream_class_default_clock_class(
+               msg);
+}
diff --git a/src/lib/graph/message/discarded-items.h b/src/lib/graph/message/discarded-items.h
new file mode 100644 (file)
index 0000000..d9f3fb6
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef BABELTRACE_GRAPH_MESSAGE_DISCARDED_ITEMS_INTERNAL_H
+#define BABELTRACE_GRAPH_MESSAGE_DISCARDED_ITEMS_INTERNAL_H
+
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include "lib/trace-ir/clock-snapshot.h"
+#include "lib/trace-ir/stream.h"
+#include "lib/property.h"
+#include <babeltrace2/graph/message-const.h>
+
+#include "message.h"
+
+struct bt_message_discarded_items {
+       struct bt_message parent;
+       struct bt_stream *stream;
+       struct bt_clock_snapshot *default_begin_cs;
+       struct bt_clock_snapshot *default_end_cs;
+       struct bt_property_uint count;
+};
+
+#endif /* BABELTRACE_GRAPH_MESSAGE_DISCARDED_ITEMS_INTERNAL_H */
diff --git a/src/lib/graph/message/event.c b/src/lib/graph/message/event.c
new file mode 100644 (file)
index 0000000..00b428c
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "MSG-EVENT"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "compat/compiler.h"
+#include "lib/object.h"
+#include <babeltrace2/trace-ir/event.h>
+#include "lib/trace-ir/event.h"
+#include "lib/trace-ir/event-class.h"
+#include "lib/trace-ir/stream-class.h"
+#include <babeltrace2/trace-ir/trace.h>
+#include "lib/trace-ir/clock-snapshot.h"
+#include "lib/graph/graph.h"
+#include <babeltrace2/graph/message-event-const.h>
+#include <babeltrace2/graph/message-event.h>
+#include <babeltrace2/types.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include "event.h"
+
+BT_ASSERT_PRE_FUNC
+static inline bool event_class_has_trace(struct bt_event_class *event_class)
+{
+       struct bt_stream_class *stream_class;
+
+       stream_class = bt_event_class_borrow_stream_class_inline(event_class);
+       BT_ASSERT(stream_class);
+       return bt_stream_class_borrow_trace_class(stream_class) != NULL;
+}
+
+BT_HIDDEN
+struct bt_message *bt_message_event_new(
+               struct bt_graph *graph)
+{
+       struct bt_message_event *message = NULL;
+
+       message = g_new0(struct bt_message_event, 1);
+       if (!message) {
+               BT_LOGE_STR("Failed to allocate one event message.");
+               goto error;
+       }
+
+       bt_message_init(&message->parent, BT_MESSAGE_TYPE_EVENT,
+               (bt_object_release_func) bt_message_event_recycle, graph);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(message);
+
+end:
+       return (void *) message;
+}
+
+static inline
+struct bt_message *create_event_message(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_event_class *c_event_class,
+               const struct bt_packet *c_packet, bool with_cs,
+               uint64_t raw_value)
+{
+       struct bt_self_component_port_input_message_iterator *msg_iter =
+               (void *) self_msg_iter;
+       struct bt_message_event *message = NULL;
+       struct bt_event_class *event_class = (void *) c_event_class;
+       struct bt_stream_class *stream_class;
+       struct bt_packet *packet = (void *) c_packet;
+       struct bt_event *event;
+
+       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
+       BT_ASSERT_PRE(event_class_has_trace(event_class),
+               "Event class is not part of a trace: %!+E", event_class);
+       stream_class = bt_event_class_borrow_stream_class_inline(event_class);
+       BT_ASSERT(stream_class);
+       BT_ASSERT_PRE((with_cs && stream_class->default_clock_class) ||
+               (!with_cs && !stream_class->default_clock_class),
+               "Creating an event message with a default clock snapshot, but without "
+               "a default clock class, or without a default clock snapshot, "
+               "but with a default clock class: ",
+               "%![ec-]+E, %![sc-]+S, with-cs=%d, "
+               "cs-val=%" PRIu64,
+               event_class, stream_class, with_cs, raw_value);
+       BT_LIB_LOGD("Creating event message object: %![ec-]+E", event_class);
+       event = bt_event_create(event_class, packet);
+       if (unlikely(!event)) {
+               BT_LIB_LOGE("Cannot create event from event class: "
+                       "%![ec-]+E", event_class);
+               goto error;
+       }
+
+       /*
+        * Create message from pool _after_ we have everything
+        * (in this case, a valid event object) so that we never have an
+        * error condition with a non-NULL message object.
+        * Otherwise:
+        *
+        * * We cannot recycle the message on error because
+        *   bt_message_event_recycle() expects a complete
+        *   message (and the event or clock class priority map
+        *   object could be unset).
+        *
+        * * We cannot destroy the message because we would need
+        *   to notify the graph (pool owner) so that it removes the
+        *   message from its message array.
+        */
+       message = (void *) bt_message_create_from_pool(
+               &msg_iter->graph->event_msg_pool, msg_iter->graph);
+       if (unlikely(!message)) {
+               /* bt_message_create_from_pool() logs errors */
+               goto error;
+       }
+
+       if (with_cs) {
+               BT_ASSERT(stream_class->default_clock_class);
+               message->default_cs = bt_clock_snapshot_create(
+                       stream_class->default_clock_class);
+               if (!message->default_cs) {
+                       goto error;
+               }
+
+               bt_clock_snapshot_set_raw_value(message->default_cs, raw_value);
+       }
+
+       BT_ASSERT(!message->event);
+       message->event = event;
+       bt_packet_set_is_frozen(packet, true);
+       bt_event_class_freeze(event_class);
+       BT_LIB_LOGD("Created event message object: "
+               "%![msg-]+n, %![event-]+e", message, event);
+       goto end;
+
+error:
+       BT_ASSERT(!message);
+       bt_event_destroy(event);
+
+end:
+       return (void *) message;
+}
+
+struct bt_message *bt_message_event_create(
+               struct bt_self_message_iterator *msg_iter,
+               const struct bt_event_class *event_class,
+               const struct bt_packet *packet)
+{
+       return create_event_message(msg_iter, event_class, packet, false, 0);
+}
+
+struct bt_message *bt_message_event_create_with_default_clock_snapshot(
+               struct bt_self_message_iterator *msg_iter,
+               const struct bt_event_class *event_class,
+               const struct bt_packet *packet,
+               uint64_t raw_value)
+{
+       return create_event_message(msg_iter, event_class, packet,
+               true, raw_value);
+}
+
+BT_HIDDEN
+void bt_message_event_destroy(struct bt_message *msg)
+{
+       struct bt_message_event *event_msg = (void *) msg;
+
+       BT_LIB_LOGD("Destroying event message: %!+n", msg);
+
+       if (event_msg->event) {
+               BT_LIB_LOGD("Recycling event: %!+e", event_msg->event);
+               bt_event_recycle(event_msg->event);
+               event_msg->event = NULL;
+       }
+
+       if (event_msg->default_cs) {
+               bt_clock_snapshot_recycle(event_msg->default_cs);
+               event_msg->default_cs = NULL;
+       }
+
+       g_free(msg);
+}
+
+BT_HIDDEN
+void bt_message_event_recycle(struct bt_message *msg)
+{
+       struct bt_message_event *event_msg = (void *) msg;
+       struct bt_graph *graph;
+
+       BT_ASSERT(event_msg);
+
+       if (unlikely(!msg->graph)) {
+               bt_message_event_destroy(msg);
+               return;
+       }
+
+       BT_LIB_LOGD("Recycling event message: %![msg-]+n, %![event-]+e",
+               msg, event_msg->event);
+       bt_message_reset(msg);
+       BT_ASSERT(event_msg->event);
+       bt_event_recycle(event_msg->event);
+       event_msg->event = NULL;
+
+       if (event_msg->default_cs) {
+               bt_clock_snapshot_recycle(event_msg->default_cs);
+               event_msg->default_cs = NULL;
+       }
+
+       graph = msg->graph;
+       msg->graph = NULL;
+       bt_object_pool_recycle_object(&graph->event_msg_pool, msg);
+}
+
+static inline
+struct bt_event *borrow_event(struct bt_message *message)
+{
+       struct bt_message_event *event_message;
+
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_EVENT);
+       event_message = container_of(message,
+                       struct bt_message_event, parent);
+       return event_message->event;
+}
+
+struct bt_event *bt_message_event_borrow_event(
+               struct bt_message *message)
+{
+       return borrow_event(message);
+}
+
+const struct bt_event *bt_message_event_borrow_event_const(
+               const struct bt_message *message)
+{
+       return borrow_event((void *) message);
+}
+
+const struct bt_clock_snapshot *
+bt_message_event_borrow_default_clock_snapshot_const(
+               const struct bt_message *msg)
+{
+       struct bt_message_event *event_msg = (void *) msg;
+       struct bt_stream_class *stream_class;
+
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_EVENT);
+       stream_class = bt_event_class_borrow_stream_class_inline(
+               event_msg->event->class);
+       BT_ASSERT(stream_class);
+       BT_ASSERT_PRE(stream_class->default_clock_class,
+               "Message's stream's class has no default clock class: "
+               "%![msg-]+n, %![sc-]+S", msg, stream_class);
+       return event_msg->default_cs;
+}
+
+const bt_clock_class *
+bt_message_event_borrow_stream_class_default_clock_class_const(
+               const bt_message *msg)
+{
+       struct bt_message_event *event_msg = (void *) msg;
+       struct bt_stream_class *stream_class;
+
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_EVENT);
+       stream_class = bt_event_class_borrow_stream_class_inline(
+               event_msg->event->class);
+       BT_ASSERT(stream_class);
+       return stream_class->default_clock_class;
+}
diff --git a/src/lib/graph/message/event.h b/src/lib/graph/message/event.h
new file mode 100644 (file)
index 0000000..b53b6e2
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef BABELTRACE_GRAPH_MESSAGE_EVENT_INTERNAL_H
+#define BABELTRACE_GRAPH_MESSAGE_EVENT_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "compat/compiler.h"
+#include <babeltrace2/trace-ir/event-class.h>
+#include <babeltrace2/trace-ir/event.h>
+#include "common/assert.h"
+
+#include "message.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bt_message_event {
+       struct bt_message parent;
+       struct bt_event *event;
+       struct bt_clock_snapshot *default_cs;
+};
+
+BT_HIDDEN
+struct bt_message *bt_message_event_new(struct bt_graph *graph);
+
+BT_HIDDEN
+void bt_message_event_recycle(struct bt_message *msg);
+
+BT_HIDDEN
+void bt_message_event_destroy(struct bt_message *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_GRAPH_MESSAGE_EVENT_INTERNAL_H */
diff --git a/src/lib/graph/message/iterator.h b/src/lib/graph/message/iterator.h
new file mode 100644 (file)
index 0000000..bae41b1
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef BABELTRACE_GRAPH_MESSAGE_ITERATOR_INTERNAL_H
+#define BABELTRACE_GRAPH_MESSAGE_ITERATOR_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "lib/object.h"
+#include <babeltrace2/graph/connection-const.h>
+#include <babeltrace2/graph/message-const.h>
+#include <babeltrace2/graph/message-iterator-const.h>
+#include <babeltrace2/types.h>
+#include "common/assert.h"
+#include <stdbool.h>
+
+struct bt_port;
+struct bt_graph;
+
+enum bt_message_iterator_type {
+       BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT,
+       BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT,
+};
+
+enum bt_self_component_port_input_message_iterator_state {
+       /* Iterator is not initialized */
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_NON_INITIALIZED,
+
+       /* Iterator is active, not at the end yet, and not finalized */
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE,
+
+       /*
+        * Iterator is ended, not finalized yet: the "next" method
+        * returns BT_MESSAGE_ITERATOR_STATUS_END.
+        */
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED,
+
+       /* Iterator is currently being finalized */
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING,
+
+       /* Iterator is finalized */
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED,
+
+       /* Iterator is seeking */
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING,
+
+       /* Iterator did seek, but returned `BT_MESSAGE_ITERATOR_STATUS_AGAIN` */
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN,
+
+       /* Iterator did seek, but returned error status */
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR,
+};
+
+struct bt_message_iterator {
+       struct bt_object base;
+       enum bt_message_iterator_type type;
+       GPtrArray *msgs;
+};
+
+typedef enum bt_self_message_iterator_status
+(*bt_self_component_port_input_message_iterator_next_method)(
+               void *, bt_message_array_const, uint64_t, uint64_t *);
+
+typedef enum bt_self_message_iterator_status
+(*bt_self_component_port_input_message_iterator_seek_ns_from_origin_method)(
+               void *, int64_t);
+
+typedef enum bt_self_message_iterator_status
+(*bt_self_component_port_input_message_iterator_seek_beginning_method)(
+               void *);
+
+typedef bt_bool
+(*bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method)(
+               void *, int64_t);
+
+typedef bt_bool
+(*bt_self_component_port_input_message_iterator_can_seek_beginning_method)(
+               void *);
+
+struct bt_self_component_port_input_message_iterator {
+       struct bt_message_iterator base;
+       struct bt_component *upstream_component; /* Weak */
+       struct bt_port *upstream_port; /* Weak */
+       struct bt_connection *connection; /* Weak */
+       struct bt_graph *graph; /* Weak */
+
+       struct {
+               bt_self_component_port_input_message_iterator_next_method next;
+               bt_self_component_port_input_message_iterator_seek_ns_from_origin_method seek_ns_from_origin;
+               bt_self_component_port_input_message_iterator_seek_beginning_method seek_beginning;
+               bt_self_component_port_input_message_iterator_can_seek_ns_from_origin_method can_seek_ns_from_origin;
+               bt_self_component_port_input_message_iterator_can_seek_beginning_method can_seek_beginning;
+       } methods;
+
+       enum bt_self_component_port_input_message_iterator_state state;
+       GQueue *auto_seek_msgs;
+       void *user_data;
+};
+
+struct bt_port_output_message_iterator {
+       struct bt_message_iterator base;
+       struct bt_graph *graph; /* Owned by this */
+       struct bt_component_sink *colander; /* Owned by this */
+
+       /*
+        * Only used temporarily as a bridge between a colander sink and
+        * the user.
+        */
+       uint64_t count;
+};
+
+BT_HIDDEN
+void bt_self_component_port_input_message_iterator_try_finalize(
+               struct bt_self_component_port_input_message_iterator *iterator);
+
+BT_HIDDEN
+void bt_self_component_port_input_message_iterator_set_connection(
+               struct bt_self_component_port_input_message_iterator *iterator,
+               struct bt_connection *connection);
+
+static inline
+const char *bt_message_iterator_status_string(
+               enum bt_message_iterator_status status)
+{
+       switch (status) {
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               return "BT_MESSAGE_ITERATOR_STATUS_AGAIN";
+       case BT_MESSAGE_ITERATOR_STATUS_END:
+               return "BT_MESSAGE_ITERATOR_STATUS_END";
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+               return "BT_MESSAGE_ITERATOR_STATUS_OK";
+       case BT_MESSAGE_ITERATOR_STATUS_ERROR:
+               return "BT_MESSAGE_ITERATOR_STATUS_ERROR";
+       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               return "BT_MESSAGE_ITERATOR_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline
+const char *bt_self_component_port_input_message_iterator_state_string(
+               enum bt_self_component_port_input_message_iterator_state state)
+{
+       switch (state) {
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE:
+               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ACTIVE";
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED:
+               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_ENDED";
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING:
+               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZING";
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED:
+               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_FINALIZED";
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING:
+               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_SEEKING";
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN:
+               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_AGAIN";
+       case BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR:
+               return "BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR";
+       default:
+               return "(unknown)";
+       }
+};
+
+#endif /* BABELTRACE_GRAPH_MESSAGE_ITERATOR_INTERNAL_H */
diff --git a/src/lib/graph/message/message-iterator-inactivity.c b/src/lib/graph/message/message-iterator-inactivity.c
new file mode 100644 (file)
index 0000000..cfec17e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "MSG-MESSAGE-ITERATOR-INACTIVITY"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include "lib/object.h"
+#include "compat/compiler.h"
+#include <babeltrace2/trace-ir/clock-class.h>
+#include "lib/trace-ir/clock-snapshot.h"
+#include "lib/graph/message/message.h"
+#include <babeltrace2/graph/message-message-iterator-inactivity-const.h>
+#include <babeltrace2/graph/message-message-iterator-inactivity.h>
+
+#include "message-iterator-inactivity.h"
+
+static
+void bt_message_message_iterator_inactivity_destroy(struct bt_object *obj)
+{
+       struct bt_message_message_iterator_inactivity *message =
+                       (struct bt_message_message_iterator_inactivity *) obj;
+
+       BT_LIB_LOGD("Destroying message iterator inactivity message: %!+n",
+                       message);
+
+       if (message->default_cs) {
+               bt_clock_snapshot_recycle(message->default_cs);
+               message->default_cs = NULL;
+       }
+
+       g_free(message);
+}
+
+struct bt_message *bt_message_message_iterator_inactivity_create(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_clock_class *default_clock_class,
+               uint64_t value_cycles)
+{
+       struct bt_self_component_port_input_message_iterator *msg_iter =
+               (void *) self_msg_iter;
+       struct bt_message_message_iterator_inactivity *message;
+       struct bt_message *ret_msg = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(default_clock_class, "Default clock class");
+       BT_LIB_LOGD("Creating message iterator inactivity message object: "
+               "%![iter-]+i, %![default-cc-]+K, value=%" PRIu64, msg_iter,
+               default_clock_class, value_cycles);
+       message = g_new0(struct bt_message_message_iterator_inactivity, 1);
+       if (!message) {
+               BT_LOGE_STR("Failed to allocate one message iterator "
+                               "inactivity message.");
+               goto error;
+       }
+       bt_message_init(&message->parent,
+               BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY,
+               bt_message_message_iterator_inactivity_destroy, NULL);
+       ret_msg = &message->parent;
+       message->default_cs = bt_clock_snapshot_create(
+               (void *) default_clock_class);
+       if (!message->default_cs) {
+               goto error;
+       }
+       bt_clock_snapshot_set_raw_value(message->default_cs, value_cycles);
+
+       BT_LIB_LOGD("Created message iterator inactivity message object: %!+n",
+                       ret_msg);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(ret_msg);
+
+end:
+       return (void *) ret_msg;
+}
+
+extern const struct bt_clock_snapshot *
+bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
+               const bt_message *msg)
+{
+       struct bt_message_message_iterator_inactivity *inactivity = (void *) msg;
+
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY);
+       return inactivity->default_cs;
+}
diff --git a/src/lib/graph/message/message-iterator-inactivity.h b/src/lib/graph/message/message-iterator-inactivity.h
new file mode 100644 (file)
index 0000000..12806bf
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef BABELTRACE_GRAPH_MESSAGE_MESSAGE_ITERATOR_INACTIVITY_INTERNAL_H
+#define BABELTRACE_GRAPH_MESSAGE_MESSAGE_ITERATOR_INACTIVITY_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include "lib/trace-ir/clock-snapshot.h"
+#include <babeltrace2/graph/message-const.h>
+
+struct bt_message_message_iterator_inactivity {
+       struct bt_message parent;
+       struct bt_clock_snapshot *default_cs;
+};
+
+#endif /* BABELTRACE_GRAPH_MESSAGE_MESSAGE_ITERATOR_INACTIVITY_INTERNAL_H */
diff --git a/src/lib/graph/message/message.c b/src/lib/graph/message/message.c
new file mode 100644 (file)
index 0000000..0a65b3b
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "MSG"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include <babeltrace2/graph/message-const.h>
+#include "lib/graph/message/message.h"
+#include "lib/graph/graph.h"
+
+BT_HIDDEN
+void bt_message_init(struct bt_message *message,
+               enum bt_message_type type,
+               bt_object_release_func release,
+               struct bt_graph *graph)
+{
+       BT_ASSERT(type >= 0 && type <= BT_MESSAGE_TYPE_DISCARDED_PACKETS);
+       message->type = type;
+       bt_object_init_shared(&message->base, release);
+       message->graph = graph;
+
+       if (graph) {
+               bt_graph_add_message(graph, message);
+       }
+}
+
+enum bt_message_type bt_message_get_type(
+               const struct bt_message *message)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       return message->type;
+}
+
+BT_HIDDEN
+void bt_message_unlink_graph(struct bt_message *msg)
+{
+       BT_ASSERT(msg);
+       msg->graph = NULL;
+}
+
+void bt_message_get_ref(const struct bt_message *message)
+{
+       bt_object_get_ref(message);
+}
+
+void bt_message_put_ref(const struct bt_message *message)
+{
+       bt_object_put_ref(message);
+}
diff --git a/src/lib/graph/message/message.h b/src/lib/graph/message/message.h
new file mode 100644 (file)
index 0000000..9843770
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef BABELTRACE_GRAPH_MESSAGE_MESSAGE_INTERNAL_H
+#define BABELTRACE_GRAPH_MESSAGE_MESSAGE_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "lib/object.h"
+#include "common/assert.h"
+#include <babeltrace2/graph/graph.h>
+#include <babeltrace2/graph/message-const.h>
+#include <babeltrace2/trace-ir/stream.h>
+#include "lib/object-pool.h"
+#include <babeltrace2/types.h>
+
+typedef struct bt_stream *(*get_stream_func)(
+               struct bt_message *message);
+
+struct bt_message {
+       struct bt_object base;
+       enum bt_message_type type;
+       bt_bool frozen;
+
+       /* Owned by this; keeps the graph alive while the msg. is alive */
+       struct bt_graph *graph;
+};
+
+#define BT_ASSERT_PRE_MSG_IS_TYPE(_msg, _type)                 \
+       BT_ASSERT_PRE(((struct bt_message *) (_msg))->type == (_type), \
+               "Message has the wrong type: expected-type=%s, "        \
+               "%![msg-]+n", bt_message_type_string(_type),    \
+               (_msg))
+
+BT_HIDDEN
+void bt_message_init(struct bt_message *message,
+               enum bt_message_type type,
+               bt_object_release_func release,
+               struct bt_graph *graph);
+
+static inline
+void bt_message_reset(struct bt_message *message)
+{
+       BT_ASSERT(message);
+
+#ifdef BT_DEV_MODE
+       message->frozen = BT_FALSE;
+#endif
+}
+
+static inline
+struct bt_message *bt_message_create_from_pool(
+               struct bt_object_pool *pool, struct bt_graph *graph)
+{
+       struct bt_message *msg = bt_object_pool_create_object(pool);
+
+       if (unlikely(!msg)) {
+#ifdef BT_LIB_LOGE
+               BT_LIB_LOGE("Cannot allocate one message from message pool: "
+                       "%![pool-]+o, %![graph-]+g", pool, graph);
+#endif
+               goto error;
+       }
+
+       if (likely(!msg->graph)) {
+               msg->graph = graph;
+       }
+
+       goto end;
+
+error:
+       BT_ASSERT(!msg);
+
+end:
+       return msg;
+}
+
+static inline void _bt_message_freeze(struct bt_message *message)
+{
+       message->frozen = BT_TRUE;
+}
+
+BT_HIDDEN
+void bt_message_unlink_graph(struct bt_message *msg);
+
+#ifdef BT_DEV_MODE
+# define bt_message_freeze             _bt_message_freeze
+#else
+# define bt_message_freeze(_x)
+#endif /* BT_DEV_MODE */
+
+static inline
+const char *bt_message_type_string(enum bt_message_type type)
+{
+       switch (type) {
+       case BT_MESSAGE_TYPE_EVENT:
+               return "BT_MESSAGE_TYPE_EVENT";
+       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+               return "BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY";
+       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
+               return "BT_MESSAGE_TYPE_STREAM_BEGINNING";
+       case BT_MESSAGE_TYPE_STREAM_END:
+               return "BT_MESSAGE_TYPE_STREAM_END";
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+               return "BT_MESSAGE_TYPE_PACKET_BEGINNING";
+       case BT_MESSAGE_TYPE_PACKET_END:
+               return "BT_MESSAGE_TYPE_PACKET_END";
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+               return "BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING";
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+               return "BT_MESSAGE_TYPE_STREAM_ACTIVITY_END";
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+               return "BT_MESSAGE_TYPE_DISCARDED_EVENTS";
+       default:
+               return "(unknown)";
+       }
+}
+
+#endif /* BABELTRACE_GRAPH_MESSAGE_MESSAGE_INTERNAL_H */
diff --git a/src/lib/graph/message/packet.c b/src/lib/graph/message/packet.c
new file mode 100644 (file)
index 0000000..6bce712
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "MSG-PACKET"
+#include "lib/lib-logging.h"
+
+#include "compat/compiler.h"
+#include <babeltrace2/trace-ir/packet.h>
+#include "lib/trace-ir/packet.h"
+#include <babeltrace2/trace-ir/stream-class.h>
+#include <babeltrace2/trace-ir/stream.h>
+#include "lib/trace-ir/stream.h"
+#include "lib/trace-ir/stream-class.h"
+#include "lib/graph/graph.h"
+#include <babeltrace2/graph/message-packet-beginning-const.h>
+#include <babeltrace2/graph/message-packet-end-const.h>
+#include <babeltrace2/graph/message-packet-beginning.h>
+#include <babeltrace2/graph/message-packet-end.h>
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "lib/object.h"
+#include <inttypes.h>
+
+#include "packet.h"
+
+static inline
+struct bt_message *new_packet_message(struct bt_graph *graph,
+               enum bt_message_type type, bt_object_release_func recycle_func)
+{
+       struct bt_message_packet *message;
+
+       message = g_new0(struct bt_message_packet, 1);
+       if (!message) {
+               BT_LOGE_STR("Failed to allocate one packet message.");
+               goto error;
+       }
+
+       bt_message_init(&message->parent, type, recycle_func, graph);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(message);
+
+end:
+       return (void *) message;
+}
+
+BT_HIDDEN
+struct bt_message *bt_message_packet_beginning_new(struct bt_graph *graph)
+{
+       return new_packet_message(graph, BT_MESSAGE_TYPE_PACKET_BEGINNING,
+               (bt_object_release_func) bt_message_packet_beginning_recycle);
+}
+
+BT_HIDDEN
+struct bt_message *bt_message_packet_end_new(struct bt_graph *graph)
+{
+       return new_packet_message(graph, BT_MESSAGE_TYPE_PACKET_END,
+               (bt_object_release_func) bt_message_packet_end_recycle);
+}
+
+static inline
+struct bt_message *create_packet_message(
+               struct bt_self_component_port_input_message_iterator *msg_iter,
+               struct bt_packet *packet, struct bt_object_pool *pool,
+               bool with_cs, uint64_t raw_value)
+{
+       struct bt_message_packet *message = NULL;
+       struct bt_stream *stream;
+       struct bt_stream_class *stream_class;
+       bool need_cs;
+
+       BT_ASSERT(msg_iter);
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
+       stream = bt_packet_borrow_stream(packet);
+       BT_ASSERT(stream);
+       stream_class = bt_stream_borrow_class(stream);
+       BT_ASSERT(stream_class);
+
+       if (pool == &msg_iter->graph->packet_begin_msg_pool) {
+               need_cs = stream_class->packets_have_beginning_default_clock_snapshot;
+       } else {
+               need_cs = stream_class->packets_have_end_default_clock_snapshot;
+       }
+
+       /*
+        * `packet_has_default_clock_snapshot` implies that the stream
+        * class has a default clock class (precondition).
+        */
+       BT_ASSERT_PRE(need_cs ? with_cs : true,
+               "Unexpected stream class configuration when creating "
+               "a packet beginning or end message: "
+               "a default clock snapshot is needed, but none was provided: "
+               "%![stream-]+s, %![sc-]+S, with-cs=%d, "
+               "cs-val=%" PRIu64,
+               stream, stream_class, with_cs, raw_value);
+       BT_ASSERT_PRE(!need_cs ? !with_cs : true,
+               "Unexpected stream class configuration when creating "
+               "a packet beginning or end message: "
+               "no default clock snapshot is needed, but one was provided: "
+               "%![stream-]+s, %![sc-]+S, with-cs=%d, "
+               "cs-val=%" PRIu64,
+               stream, stream_class, with_cs, raw_value);
+       BT_LIB_LOGD("Creating packet message object: "
+               "%![packet-]+a, %![stream-]+s, %![sc-]+S",
+               packet, stream, stream_class);
+       message = (void *) bt_message_create_from_pool(pool, msg_iter->graph);
+       if (!message) {
+               /* bt_message_create_from_pool() logs errors */
+               goto end;
+       }
+
+       if (with_cs) {
+               BT_ASSERT(stream_class->default_clock_class);
+               message->default_cs = bt_clock_snapshot_create(
+                       stream_class->default_clock_class);
+               if (!message->default_cs) {
+                       bt_object_put_no_null_check(message);
+                       message = NULL;
+                       goto end;
+               }
+
+               bt_clock_snapshot_set_raw_value(message->default_cs, raw_value);
+       }
+
+       BT_ASSERT(!message->packet);
+       message->packet = packet;
+       bt_object_get_no_null_check_no_parent_check(
+               &message->packet->base);
+       bt_packet_set_is_frozen(packet, true);
+       BT_LIB_LOGD("Created packet message object: "
+               "%![msg-]+n, %![packet-]+a, %![stream-]+s, %![sc-]+S",
+               message, packet, stream, stream_class);
+       goto end;
+
+end:
+       return (void *) message;
+}
+
+struct bt_message *bt_message_packet_beginning_create(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_packet *packet)
+{
+       struct bt_self_component_port_input_message_iterator *msg_iter =
+               (void *) self_msg_iter;
+
+       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
+       return create_packet_message(msg_iter, (void *) packet,
+               &msg_iter->graph->packet_begin_msg_pool, false, 0);
+}
+
+struct bt_message *bt_message_packet_beginning_create_with_default_clock_snapshot(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_packet *packet, uint64_t raw_value)
+{
+       struct bt_self_component_port_input_message_iterator *msg_iter =
+               (void *) self_msg_iter;
+
+       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
+       return create_packet_message(msg_iter, (void *) packet,
+               &msg_iter->graph->packet_begin_msg_pool, true, raw_value);
+}
+
+struct bt_message *bt_message_packet_end_create(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_packet *packet)
+{
+       struct bt_self_component_port_input_message_iterator *msg_iter =
+               (void *) self_msg_iter;
+
+       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
+       return create_packet_message(msg_iter, (void *) packet,
+               &msg_iter->graph->packet_end_msg_pool, false, 0);
+}
+
+struct bt_message *bt_message_packet_end_create_with_default_clock_snapshot(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_packet *packet, uint64_t raw_value)
+{
+       struct bt_self_component_port_input_message_iterator *msg_iter =
+               (void *) self_msg_iter;
+
+       BT_ASSERT_PRE_NON_NULL(msg_iter, "Message iterator");
+       return create_packet_message(msg_iter, (void *) packet,
+               &msg_iter->graph->packet_end_msg_pool, true, raw_value);
+}
+
+BT_HIDDEN
+void bt_message_packet_destroy(struct bt_message *msg)
+{
+       struct bt_message_packet *packet_msg = (void *) msg;
+
+       BT_LIB_LOGD("Destroying packet message: %!+n", msg);
+       BT_LIB_LOGD("Putting packet: %!+a", packet_msg->packet);
+       BT_OBJECT_PUT_REF_AND_RESET(packet_msg->packet);
+
+       if (packet_msg->default_cs) {
+               bt_clock_snapshot_recycle(packet_msg->default_cs);
+               packet_msg->default_cs = NULL;
+       }
+
+       g_free(msg);
+}
+
+static inline
+void recycle_packet_message(struct bt_message *msg, struct bt_object_pool *pool)
+{
+       struct bt_message_packet *packet_msg = (void *) msg;
+
+       BT_LIB_LOGD("Recycling packet message: %!+n", msg);
+       bt_message_reset(msg);
+       bt_object_put_no_null_check(&packet_msg->packet->base);
+
+       if (packet_msg->default_cs) {
+               bt_clock_snapshot_recycle(packet_msg->default_cs);
+               packet_msg->default_cs = NULL;
+       }
+
+       packet_msg->packet = NULL;
+       msg->graph = NULL;
+       bt_object_pool_recycle_object(pool, msg);
+}
+
+BT_HIDDEN
+void bt_message_packet_beginning_recycle(struct bt_message *msg)
+{
+       BT_ASSERT(msg);
+
+       if (unlikely(!msg->graph)) {
+               bt_message_packet_destroy(msg);
+               return;
+       }
+
+       recycle_packet_message(msg, &msg->graph->packet_begin_msg_pool);
+}
+
+BT_HIDDEN
+void bt_message_packet_end_recycle(struct bt_message *msg)
+{
+       BT_ASSERT(msg);
+
+       if (unlikely(!msg->graph)) {
+               bt_message_packet_destroy(msg);
+               return;
+       }
+
+       recycle_packet_message(msg, &msg->graph->packet_end_msg_pool);
+}
+
+struct bt_packet *bt_message_packet_beginning_borrow_packet(
+               struct bt_message *message)
+{
+       struct bt_message_packet *packet_msg = (void *) message;
+
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message,
+               BT_MESSAGE_TYPE_PACKET_BEGINNING);
+       return packet_msg->packet;
+}
+
+const struct bt_packet *bt_message_packet_beginning_borrow_packet_const(
+               const struct bt_message *message)
+{
+       return bt_message_packet_beginning_borrow_packet(
+               (void *) message);
+}
+
+struct bt_packet *bt_message_packet_end_borrow_packet(
+               struct bt_message *message)
+{
+       struct bt_message_packet *packet_msg = (void *) message;
+
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message,
+               BT_MESSAGE_TYPE_PACKET_END);
+       return packet_msg->packet;
+}
+
+const struct bt_packet *bt_message_packet_end_borrow_packet_const(
+               const struct bt_message *message)
+{
+       return bt_message_packet_end_borrow_packet(
+               (void *) message);
+}
+
+static inline
+const struct bt_clock_snapshot *
+borrow_packet_message_default_clock_snapshot_const(
+               const struct bt_message *message)
+{
+       struct bt_message_packet *packet_msg = (void *) message;
+
+       BT_ASSERT(message);
+       BT_ASSERT_PRE(packet_msg->packet->stream->class->default_clock_class,
+               "Message's stream's class has no default clock class: "
+               "%![msg-]+n, %![sc-]+S",
+               message, packet_msg->packet->stream->class);
+       return packet_msg->default_cs;
+}
+
+const struct bt_clock_snapshot *
+bt_message_packet_beginning_borrow_default_clock_snapshot_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_PACKET_BEGINNING);
+       return borrow_packet_message_default_clock_snapshot_const(msg);
+}
+
+const struct bt_clock_snapshot *
+bt_message_packet_end_borrow_default_clock_snapshot_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_PACKET_END);
+       return borrow_packet_message_default_clock_snapshot_const(msg);
+}
+
+static inline
+const struct bt_clock_class *
+borrow_packet_message_stream_class_default_clock_class(
+               const struct bt_message *msg)
+{
+       struct bt_message_packet *packet_msg = (void *) msg;
+
+       BT_ASSERT(msg);
+       return packet_msg->packet->stream->class->default_clock_class;
+}
+
+const struct bt_clock_class *
+bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_PACKET_BEGINNING);
+       return borrow_packet_message_stream_class_default_clock_class(msg);
+}
+
+const struct bt_clock_class *
+bt_message_packet_end_borrow_stream_class_default_clock_class_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_PACKET_END);
+       return borrow_packet_message_stream_class_default_clock_class(msg);
+}
diff --git a/src/lib/graph/message/packet.h b/src/lib/graph/message/packet.h
new file mode 100644 (file)
index 0000000..7738788
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef BABELTRACE_GRAPH_MESSAGE_PACKET_INTERNAL_H
+#define BABELTRACE_GRAPH_MESSAGE_PACKET_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "compat/compiler.h"
+#include <babeltrace2/trace-ir/packet.h>
+#include "lib/trace-ir/clock-snapshot.h"
+#include "common/assert.h"
+
+#include "message.h"
+
+struct bt_message_packet {
+       struct bt_message parent;
+       struct bt_packet *packet;
+       struct bt_clock_snapshot *default_cs;
+};
+
+BT_HIDDEN
+void bt_message_packet_destroy(struct bt_message *msg);
+
+BT_HIDDEN
+struct bt_message *bt_message_packet_beginning_new(
+               struct bt_graph *graph);
+BT_HIDDEN
+void bt_message_packet_beginning_recycle(struct bt_message *msg);
+
+BT_HIDDEN
+struct bt_message *bt_message_packet_end_new(struct bt_graph *graph);
+
+BT_HIDDEN
+void bt_message_packet_end_recycle(struct bt_message *msg);
+
+#endif /* BABELTRACE_GRAPH_MESSAGE_PACKET_INTERNAL_H */
diff --git a/src/lib/graph/message/stream-activity.c b/src/lib/graph/message/stream-activity.c
new file mode 100644 (file)
index 0000000..dc840be
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "MSG-STREAM-ACTIVITY"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include "lib/object.h"
+#include "compat/compiler.h"
+#include <babeltrace2/trace-ir/clock-class.h>
+#include "lib/trace-ir/clock-snapshot.h"
+#include "lib/trace-ir/stream-class.h"
+#include "lib/trace-ir/stream.h"
+#include "lib/graph/message/message.h"
+#include <babeltrace2/graph/message-stream-activity-beginning-const.h>
+#include <babeltrace2/graph/message-stream-activity-end-const.h>
+#include <babeltrace2/graph/message-stream-activity-beginning.h>
+#include <babeltrace2/graph/message-stream-activity-end.h>
+
+#include "stream-activity.h"
+
+static
+void destroy_stream_activity_message(struct bt_object *obj)
+{
+       struct bt_message_stream_activity *message = (void *) obj;
+
+       BT_LIB_LOGD("Destroying stream activity message: %!+n", message);
+       BT_LIB_LOGD("Putting stream: %!+s", message->stream);
+       BT_OBJECT_PUT_REF_AND_RESET(message->stream);
+
+       if (message->default_cs) {
+               bt_clock_snapshot_recycle(message->default_cs);
+               message->default_cs = NULL;
+       }
+
+       g_free(message);
+}
+
+static inline
+struct bt_message *create_stream_activity_message(
+               struct bt_self_message_iterator *self_msg_iter,
+               struct bt_stream *stream, enum bt_message_type type)
+{
+       struct bt_message_stream_activity *message;
+       struct bt_stream_class *stream_class;
+
+       BT_ASSERT_PRE_NON_NULL(self_msg_iter, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       stream_class = bt_stream_borrow_class(stream);
+       BT_ASSERT(stream_class);
+       BT_LIB_LOGD("Creating stream activity message object: "
+               "type=%s, %![stream-]+s, %![sc-]+S",
+               bt_message_type_string(type), stream, stream_class);
+       message = g_new0(struct bt_message_stream_activity, 1);
+       if (!message) {
+               BT_LOGE_STR("Failed to allocate one stream activity message.");
+               goto error;
+       }
+
+       bt_message_init(&message->parent, type,
+               destroy_stream_activity_message, NULL);
+       message->stream = stream;
+       bt_object_get_no_null_check(message->stream);
+
+       if (stream_class->default_clock_class) {
+               message->default_cs = bt_clock_snapshot_create(
+                       stream_class->default_clock_class);
+               if (!message->default_cs) {
+                       goto error;
+               }
+       }
+
+       message->default_cs_state =
+               BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN;
+       BT_LIB_LOGD("Created stream activity message object: "
+               "%![msg-]+n, %![stream-]+s, %![sc-]+S", message,
+               stream, stream_class);
+
+       return (void *) &message->parent;
+
+error:
+       return NULL;
+}
+
+struct bt_message *bt_message_stream_activity_beginning_create(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_stream *stream)
+{
+       return create_stream_activity_message(self_msg_iter, (void *) stream,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
+}
+
+struct bt_message *bt_message_stream_activity_end_create(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_stream *stream)
+{
+       return create_stream_activity_message(self_msg_iter, (void *) stream,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
+}
+
+static inline
+struct bt_stream *borrow_stream_activity_message_stream(
+               struct bt_message *message)
+{
+       struct bt_message_stream_activity *stream_act_msg = (void *) message;
+
+       BT_ASSERT(message);
+       return stream_act_msg->stream;
+}
+
+struct bt_stream *bt_message_stream_activity_beginning_borrow_stream(
+               struct bt_message *message)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
+       return borrow_stream_activity_message_stream(message);
+}
+
+struct bt_stream *bt_message_stream_activity_end_borrow_stream(
+               struct bt_message *message)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
+       return borrow_stream_activity_message_stream(message);
+}
+
+const struct bt_stream *bt_message_stream_activity_beginning_borrow_stream_const(
+               const struct bt_message *message)
+{
+       return bt_message_stream_activity_beginning_borrow_stream(
+               (void *) message);
+}
+
+const struct bt_stream *bt_message_stream_activity_end_borrow_stream_const(
+               const struct bt_message *message)
+{
+       return bt_message_stream_activity_end_borrow_stream((void *) message);
+}
+
+static inline
+void set_stream_activity_message_default_clock_snapshot(
+               struct bt_message *msg, uint64_t value_cycles)
+{
+       struct bt_message_stream_activity *stream_act_msg = (void *) msg;
+       struct bt_stream_class *sc;
+
+       BT_ASSERT(msg);
+       BT_ASSERT_PRE_HOT(msg, "Message", ": %!+n", msg);
+       sc = stream_act_msg->stream->class;
+       BT_ASSERT(sc);
+       BT_ASSERT_PRE(sc->default_clock_class,
+               "Message's stream's class has no default clock class: "
+               "%![msg-]+n, %![sc-]+S", msg, sc);
+       bt_clock_snapshot_set_raw_value(stream_act_msg->default_cs,
+               value_cycles);
+       stream_act_msg->default_cs_state =
+               BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN;
+       BT_LIB_LOGV("Set stream activity message's default clock snapshot: "
+               "%![msg-]+n, value=%" PRIu64, msg, value_cycles);
+}
+
+void bt_message_stream_activity_beginning_set_default_clock_snapshot(
+               struct bt_message *msg, uint64_t raw_value)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
+       set_stream_activity_message_default_clock_snapshot(msg, raw_value);
+}
+
+void bt_message_stream_activity_end_set_default_clock_snapshot(
+               struct bt_message *msg, uint64_t raw_value)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
+       set_stream_activity_message_default_clock_snapshot(msg, raw_value);
+}
+
+static inline
+enum bt_message_stream_activity_clock_snapshot_state
+borrow_stream_activity_message_default_clock_snapshot_const(
+               const bt_message *msg, const bt_clock_snapshot **snapshot)
+{
+       const struct bt_message_stream_activity *stream_act_msg =
+               (const void *) msg;
+
+       BT_ASSERT_PRE_NON_NULL(snapshot, "Clock snapshot (output)");
+       *snapshot = stream_act_msg->default_cs;
+       return stream_act_msg->default_cs_state;
+}
+
+enum bt_message_stream_activity_clock_snapshot_state
+bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
+               const bt_message *msg, const bt_clock_snapshot **snapshot)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
+       return borrow_stream_activity_message_default_clock_snapshot_const(msg,
+               snapshot);
+}
+
+enum bt_message_stream_activity_clock_snapshot_state
+bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
+               const bt_message *msg, const bt_clock_snapshot **snapshot)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
+       return borrow_stream_activity_message_default_clock_snapshot_const(msg,
+               snapshot);
+}
+
+static inline
+void set_stream_activity_message_default_clock_snapshot_state(
+               struct bt_message *msg,
+               enum bt_message_stream_activity_clock_snapshot_state state)
+{
+       struct bt_message_stream_activity *stream_act_msg = (void *) msg;
+
+       BT_ASSERT(msg);
+       BT_ASSERT_PRE_HOT(msg, "Message", ": %!+n", msg);
+       BT_ASSERT_PRE(state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN,
+               "Invalid clock snapshot state: %![msg-]+n, state=%s",
+               msg,
+               bt_message_stream_activity_clock_snapshot_state_string(state));
+       stream_act_msg->default_cs_state = state;
+       BT_LIB_LOGV("Set stream activity message's default clock snapshot state: "
+               "%![msg-]+n, state=%s", msg,
+               bt_message_stream_activity_clock_snapshot_state_string(state));
+}
+
+void bt_message_stream_activity_beginning_set_default_clock_snapshot_state(
+               struct bt_message *msg,
+               enum bt_message_stream_activity_clock_snapshot_state state)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
+       set_stream_activity_message_default_clock_snapshot_state(msg, state);
+}
+
+void bt_message_stream_activity_end_set_default_clock_snapshot_state(
+               struct bt_message *msg,
+               enum bt_message_stream_activity_clock_snapshot_state state)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
+       set_stream_activity_message_default_clock_snapshot_state(msg, state);
+}
+
+static inline
+const struct bt_clock_class *
+borrow_stream_activity_message_stream_class_default_clock_class(
+               const struct bt_message *msg)
+{
+       struct bt_message_stream_activity *stream_act_msg = (void *) msg;
+
+       BT_ASSERT(msg);
+       return stream_act_msg->stream->class->default_clock_class;
+}
+
+const struct bt_clock_class *
+bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg,
+               BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING);
+       return borrow_stream_activity_message_stream_class_default_clock_class(
+               msg);
+}
+
+const struct bt_clock_class *
+bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
+               const struct bt_message *msg)
+{
+       BT_ASSERT_PRE_NON_NULL(msg, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(msg, BT_MESSAGE_TYPE_STREAM_ACTIVITY_END);
+       return borrow_stream_activity_message_stream_class_default_clock_class(
+               msg);
+}
diff --git a/src/lib/graph/message/stream-activity.h b/src/lib/graph/message/stream-activity.h
new file mode 100644 (file)
index 0000000..9199d43
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef BABELTRACE_GRAPH_MESSAGE_STREAM_ACTIVITY_INTERNAL_H
+#define BABELTRACE_GRAPH_MESSAGE_STREAM_ACTIVITY_INTERNAL_H
+
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include "lib/trace-ir/clock-snapshot.h"
+#include "lib/trace-ir/stream.h"
+#include <babeltrace2/graph/message-const.h>
+#include <babeltrace2/graph/message-stream-activity-const.h>
+
+struct bt_message_stream_activity {
+       struct bt_message parent;
+       struct bt_stream *stream;
+       struct bt_clock_snapshot *default_cs;
+       enum bt_message_stream_activity_clock_snapshot_state default_cs_state;
+};
+
+static inline
+const char *bt_message_stream_activity_clock_snapshot_state_string(
+               enum bt_message_stream_activity_clock_snapshot_state state)
+{
+       switch (state) {
+       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN:
+               return "BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN";
+       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN:
+               return "BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN";
+       case BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE:
+               return "BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE";
+       default:
+               return "(unknown)";
+       }
+}
+
+#endif /* BABELTRACE_GRAPH_MESSAGE_STREAM_ACTIVITY_INTERNAL_H */
diff --git a/src/lib/graph/message/stream.c b/src/lib/graph/message/stream.c
new file mode 100644 (file)
index 0000000..f691d72
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "MSG-STREAM"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include "compat/compiler.h"
+#include <babeltrace2/trace-ir/clock-snapshot-const.h>
+#include "lib/trace-ir/stream.h"
+#include <babeltrace2/trace-ir/stream-class.h>
+#include "lib/trace-ir/stream-class.h"
+#include <babeltrace2/graph/message-stream-beginning.h>
+#include <babeltrace2/graph/message-stream-end.h>
+#include <babeltrace2/graph/message-stream-beginning-const.h>
+#include <babeltrace2/graph/message-stream-end-const.h>
+#include "common/assert.h"
+#include <inttypes.h>
+
+#include "stream.h"
+
+static
+void destroy_stream_message(struct bt_object *obj)
+{
+       struct bt_message_stream *message = (void *) obj;
+
+       BT_LIB_LOGD("Destroying stream message: %!+n", message);
+       BT_LIB_LOGD("Putting stream: %!+s", message->stream);
+       BT_OBJECT_PUT_REF_AND_RESET(message->stream);
+       g_free(message);
+}
+
+static inline
+struct bt_message *create_stream_message(
+               struct bt_self_message_iterator *self_msg_iter,
+               struct bt_stream *stream, enum bt_message_type type)
+{
+       struct bt_message_stream *message;
+       struct bt_stream_class *stream_class;
+
+       BT_ASSERT_PRE_NON_NULL(self_msg_iter, "Message iterator");
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       stream_class = bt_stream_borrow_class(stream);
+       BT_ASSERT(stream_class);
+       BT_LIB_LOGD("Creating stream message object: "
+               "type=%s, %![stream-]+s, %![sc-]+S",
+               bt_message_type_string(type), stream, stream_class);
+       message = g_new0(struct bt_message_stream, 1);
+       if (!message) {
+               BT_LOGE_STR("Failed to allocate one stream message.");
+               goto error;
+       }
+
+       bt_message_init(&message->parent, type,
+               destroy_stream_message, NULL);
+       message->stream = stream;
+       bt_object_get_no_null_check(message->stream);
+       BT_LIB_LOGD("Created stream message object: "
+               "%![msg-]+n, %![stream-]+s, %![sc-]+S", message,
+               stream, stream_class);
+
+       return (void *) &message->parent;
+
+error:
+       return NULL;
+}
+
+struct bt_message *bt_message_stream_beginning_create(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_stream *stream)
+{
+       return create_stream_message(self_msg_iter, (void *) stream,
+               BT_MESSAGE_TYPE_STREAM_BEGINNING);
+}
+
+struct bt_message *bt_message_stream_end_create(
+               struct bt_self_message_iterator *self_msg_iter,
+               const struct bt_stream *stream)
+{
+       return create_stream_message(self_msg_iter, (void *) stream,
+               BT_MESSAGE_TYPE_STREAM_END);
+}
+
+static inline
+struct bt_stream *borrow_stream_message_stream(struct bt_message *message)
+{
+       struct bt_message_stream *stream_msg;
+
+       BT_ASSERT(message);
+       stream_msg = (void *) message;
+       return stream_msg->stream;
+}
+
+struct bt_stream *bt_message_stream_beginning_borrow_stream(
+               struct bt_message *message)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_STREAM_BEGINNING);
+       return borrow_stream_message_stream(message);
+}
+
+struct bt_stream *bt_message_stream_end_borrow_stream(
+               struct bt_message *message)
+{
+       BT_ASSERT_PRE_NON_NULL(message, "Message");
+       BT_ASSERT_PRE_MSG_IS_TYPE(message, BT_MESSAGE_TYPE_STREAM_END);
+       return borrow_stream_message_stream(message);
+}
+
+const struct bt_stream *bt_message_stream_beginning_borrow_stream_const(
+               const struct bt_message *message)
+{
+       return bt_message_stream_beginning_borrow_stream(
+               (void *) message);
+}
+
+const struct bt_stream *bt_message_stream_end_borrow_stream_const(
+               const struct bt_message *message)
+{
+       return bt_message_stream_end_borrow_stream(
+               (void *) message);
+}
diff --git a/src/lib/graph/message/stream.h b/src/lib/graph/message/stream.h
new file mode 100644 (file)
index 0000000..7cca4bc
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef BABELTRACE_GRAPH_MESSAGE_STREAM_INTERNAL_H
+#define BABELTRACE_GRAPH_MESSAGE_STREAM_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "compat/compiler.h"
+#include "lib/trace-ir/stream.h"
+#include "lib/trace-ir/clock-snapshot.h"
+#include "common/assert.h"
+
+#include "message.h"
+
+struct bt_message_stream {
+       struct bt_message parent;
+       struct bt_stream *stream;
+};
+
+#endif /* BABELTRACE_GRAPH_MESSAGE_STREAM_INTERNAL_H */
diff --git a/src/lib/graph/port.c b/src/lib/graph/port.c
new file mode 100644 (file)
index 0000000..ff4e443
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PORT"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include <babeltrace2/graph/port-const.h>
+#include <babeltrace2/graph/port-input-const.h>
+#include <babeltrace2/graph/port-output-const.h>
+#include <babeltrace2/graph/self-component-port.h>
+#include <babeltrace2/graph/self-component-port-input.h>
+#include <babeltrace2/graph/self-component-port-output.h>
+#include "lib/object.h"
+#include "compat/compiler.h"
+
+#include "component.h"
+#include "connection.h"
+#include "port.h"
+
+static
+void destroy_port(struct bt_object *obj)
+{
+       struct bt_port *port = (void *) obj;
+
+       BT_LIB_LOGD("Destroying port: %!+p", port);
+
+       if (port->name) {
+               g_string_free(port->name, TRUE);
+               port->name = NULL;
+       }
+
+       g_free(port);
+}
+
+BT_HIDDEN
+struct bt_port *bt_port_create(struct bt_component *parent_component,
+               enum bt_port_type type, const char *name, void *user_data)
+{
+       struct bt_port *port = NULL;
+
+       BT_ASSERT(name);
+       BT_ASSERT(parent_component);
+       BT_ASSERT(type == BT_PORT_TYPE_INPUT || type == BT_PORT_TYPE_OUTPUT);
+       BT_ASSERT(strlen(name) > 0);
+       port = g_new0(struct bt_port, 1);
+       if (!port) {
+               BT_LOGE_STR("Failed to allocate one port.");
+               goto end;
+       }
+
+       BT_LIB_LOGD("Creating port for component: %![comp-]+c, port-type=%s, "
+               "port-name=\"%s\"", parent_component, bt_port_type_string(type),
+               name);
+       bt_object_init_shared_with_parent(&port->base, destroy_port);
+       port->name = g_string_new(name);
+       if (!port->name) {
+               BT_LOGE_STR("Failed to allocate one GString.");
+               BT_OBJECT_PUT_REF_AND_RESET(port);
+               goto end;
+       }
+
+       port->type = type;
+       port->user_data = user_data;
+       bt_object_set_parent(&port->base, &parent_component->base);
+       BT_LIB_LOGD("Created port for component: "
+               "%![comp-]+c, %![port-]+p", parent_component, port);
+
+end:
+       return port;
+}
+
+const char *bt_port_get_name(const struct bt_port *port)
+{
+       BT_ASSERT_PRE_NON_NULL(port, "Port");
+       return port->name->str;
+}
+
+enum bt_port_type bt_port_get_type(const struct bt_port *port)
+{
+       BT_ASSERT_PRE_NON_NULL(port, "Port");
+       return port->type;
+}
+
+const struct bt_connection *bt_port_borrow_connection_const(
+               const struct bt_port *port)
+{
+       BT_ASSERT_PRE_NON_NULL(port, "Port");
+       return port->connection;
+}
+
+const struct bt_component *bt_port_borrow_component_const(
+               const struct bt_port *port)
+{
+       BT_ASSERT_PRE_NON_NULL(port, "Port");
+       return bt_port_borrow_component_inline(port);
+}
+
+struct bt_self_component *bt_self_component_port_borrow_component(
+               struct bt_self_component_port *port)
+{
+       BT_ASSERT_PRE_NON_NULL(port, "Port");
+       return (void *) bt_object_borrow_parent((void *) port);
+}
+
+BT_HIDDEN
+void bt_port_set_connection(struct bt_port *port,
+               struct bt_connection *connection)
+{
+       /*
+        * Don't take a reference on connection as its existence is
+        * guaranteed by the existence of the graph in which the
+        * connection exists.
+        */
+       port->connection = connection;
+       BT_LIB_LOGV("Set port's connection: %![port-]+p, %![conn-]+x", port,
+               connection);
+}
+
+bt_bool bt_port_is_connected(const struct bt_port *port)
+{
+       BT_ASSERT_PRE_NON_NULL(port, "Port");
+       return port->connection ? BT_TRUE : BT_FALSE;
+}
+
+void *bt_self_component_port_get_data(const struct bt_self_component_port *port)
+{
+       BT_ASSERT_PRE_NON_NULL(port, "Port");
+       return ((struct bt_port *) port)->user_data;
+}
+
+void bt_port_get_ref(const struct bt_port *port)
+{
+       bt_object_get_ref(port);
+}
+
+void bt_port_put_ref(const struct bt_port *port)
+{
+       bt_object_put_ref(port);
+}
+
+void bt_port_input_get_ref(const struct bt_port_input *port_input)
+{
+       bt_object_get_ref(port_input);
+}
+
+void bt_port_input_put_ref(const struct bt_port_input *port_input)
+{
+       bt_object_put_ref(port_input);
+}
+
+void bt_port_output_get_ref(const struct bt_port_output *port_output)
+{
+       bt_object_get_ref(port_output);
+}
+
+void bt_port_output_put_ref(const struct bt_port_output *port_output)
+{
+       bt_object_put_ref(port_output);
+}
diff --git a/src/lib/graph/port.h b/src/lib/graph/port.h
new file mode 100644 (file)
index 0000000..c1be31a
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef BABELTRACE_GRAPH_PORT_INTERNAL_H
+#define BABELTRACE_GRAPH_PORT_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/graph/port-const.h>
+
+struct bt_port {
+       struct bt_object base;
+       enum bt_port_type type;
+       GString *name;
+       struct bt_connection *connection;
+       void *user_data;
+};
+
+struct bt_component;
+
+BT_HIDDEN
+struct bt_port *bt_port_create(struct bt_component *parent_component,
+               enum bt_port_type type, const char *name, void *user_data);
+
+BT_HIDDEN
+void bt_port_set_connection(struct bt_port *port,
+               struct bt_connection *connection);
+
+static inline
+struct bt_component *bt_port_borrow_component_inline(const struct bt_port *port)
+{
+       BT_ASSERT(port);
+       return (void *) bt_object_borrow_parent(&port->base);
+}
+
+static inline
+const char *bt_port_type_string(enum bt_port_type port_type)
+{
+       switch (port_type) {
+       case BT_PORT_TYPE_INPUT:
+               return "BT_PORT_TYPE_INPUT";
+       case BT_PORT_TYPE_OUTPUT:
+               return "BT_PORT_TYPE_OUTPUT";
+       default:
+               return "(unknown)";
+       }
+}
+
+#endif /* BABELTRACE_GRAPH_PORT_INTERNAL_H */
diff --git a/src/lib/graph/query-executor.c b/src/lib/graph/query-executor.c
new file mode 100644 (file)
index 0000000..b26455d
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "QUERY-EXECUTOR"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include <babeltrace2/graph/query-executor-const.h>
+#include <babeltrace2/graph/query-executor.h>
+#include <babeltrace2/graph/component-class.h>
+#include <babeltrace2/value.h>
+#include <babeltrace2/value-const.h>
+#include "lib/object.h"
+#include "compat/compiler.h"
+
+#include "component-class.h"
+#include "query-executor.h"
+
+static
+void bt_query_executor_destroy(struct bt_object *obj)
+{
+       struct bt_query_executor *query_exec =
+               container_of(obj, struct bt_query_executor, base);
+
+       BT_LOGD("Destroying query executor: addr=%p", query_exec);
+       g_free(query_exec);
+}
+
+struct bt_query_executor *bt_query_executor_create(void)
+{
+       struct bt_query_executor *query_exec;
+
+       BT_LOGD_STR("Creating query executor.");
+       query_exec = g_new0(struct bt_query_executor, 1);
+       if (!query_exec) {
+               BT_LOGE_STR("Failed to allocate one query executor.");
+               goto end;
+       }
+
+       bt_object_init_shared(&query_exec->base,
+               bt_query_executor_destroy);
+       BT_LOGD("Created query executor: addr=%p", query_exec);
+
+end:
+       return (void *) query_exec;
+}
+
+enum bt_query_executor_status bt_query_executor_query(
+               struct bt_query_executor *query_exec,
+               const struct bt_component_class *comp_cls,
+               const char *object, const struct bt_value *params,
+               const struct bt_value **user_result)
+{
+       typedef enum bt_query_status (*method_t)(void *, const void *,
+               const void *, const void *, const void *);
+
+       enum bt_query_status status;
+       enum bt_query_executor_status exec_status;
+       method_t method = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(query_exec, "Query executor");
+       BT_ASSERT_PRE_NON_NULL(comp_cls, "Component class");
+       BT_ASSERT_PRE_NON_NULL(object, "Object");
+       BT_ASSERT_PRE_NON_NULL(user_result, "Result (output)");
+       BT_ASSERT_PRE(!query_exec->canceled, "Query executor is canceled.");
+
+       if (!params) {
+               params = bt_value_null;
+       }
+
+       switch (comp_cls->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+       {
+               struct bt_component_class_source *src_cc = (void *) comp_cls;
+
+               method = (method_t) src_cc->methods.query;
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+       {
+               struct bt_component_class_filter *flt_cc = (void *) comp_cls;
+
+               method = (method_t) flt_cc->methods.query;
+               break;
+       }
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+       {
+               struct bt_component_class_sink *sink_cc = (void *) comp_cls;
+
+               method = (method_t) sink_cc->methods.query;
+               break;
+       }
+       default:
+               abort();
+       }
+
+       if (!method) {
+               /* Not an error: nothing to query */
+               BT_LIB_LOGD("Component class has no registered query method: "
+                       "%!+C", comp_cls);
+               exec_status = BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED;
+               goto end;
+       }
+
+       BT_LIB_LOGD("Calling user's query method: "
+               "query-exec-addr=%p, %![cc-]+C, object=\"%s\", %![params-]+v",
+               query_exec, comp_cls, object, params);
+       *user_result = NULL;
+       status = method((void *) comp_cls, query_exec, object, params,
+               user_result);
+       BT_LIB_LOGD("User method returned: status=%s, %![res-]+v",
+               bt_query_status_string(status), *user_result);
+       BT_ASSERT_PRE(status != BT_QUERY_STATUS_OK || *user_result,
+               "User method returned `BT_QUERY_STATUS_OK` without a result.");
+       exec_status = (int) status;
+       if (query_exec->canceled) {
+               BT_OBJECT_PUT_REF_AND_RESET(*user_result);
+               exec_status = BT_QUERY_EXECUTOR_STATUS_CANCELED;
+               goto end;
+       }
+
+end:
+       return exec_status;
+}
+
+enum bt_query_executor_status bt_query_executor_cancel(
+               struct bt_query_executor *query_exec)
+{
+       BT_ASSERT_PRE_NON_NULL(query_exec, "Query executor");
+       query_exec->canceled = BT_TRUE;
+       BT_LOGV("Canceled query executor: addr=%p", query_exec);
+       return BT_QUERY_EXECUTOR_STATUS_OK;
+}
+
+bt_bool bt_query_executor_is_canceled(const struct bt_query_executor *query_exec)
+{
+       BT_ASSERT_PRE_NON_NULL(query_exec, "Query executor");
+       return query_exec->canceled;
+}
+
+void bt_query_executor_get_ref(const struct bt_query_executor *query_executor)
+{
+       bt_object_get_ref(query_executor);
+}
+
+void bt_query_executor_put_ref(const struct bt_query_executor *query_executor)
+{
+       bt_object_put_ref(query_executor);
+}
diff --git a/src/lib/graph/query-executor.h b/src/lib/graph/query-executor.h
new file mode 100644 (file)
index 0000000..57951b7
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H
+#define BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/types.h>
+#include "lib/object.h"
+#include <babeltrace2/graph/query-executor.h>
+#include <babeltrace2/graph/component-class.h>
+
+struct bt_query_executor {
+       struct bt_object base;
+       bool canceled;
+};
+
+static inline const char *bt_query_status_string(enum bt_query_status status)
+{
+       switch (status) {
+       case BT_QUERY_STATUS_OK:
+               return "BT_QUERY_STATUS_OK";
+       case BT_QUERY_STATUS_AGAIN:
+               return "BT_QUERY_STATUS_AGAIN";
+       case BT_QUERY_STATUS_ERROR:
+               return "BT_QUERY_STATUS_ERROR";
+       case BT_QUERY_STATUS_INVALID_OBJECT:
+               return "BT_QUERY_STATUS_INVALID_OBJECT";
+       case BT_QUERY_STATUS_INVALID_PARAMS:
+               return "BT_QUERY_STATUS_INVALID_PARAMS";
+       case BT_QUERY_STATUS_NOMEM:
+               return "BT_QUERY_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+};
+
+static inline const char *bt_query_executor_status_string(
+               enum bt_query_executor_status status)
+{
+       switch (status) {
+       case BT_QUERY_EXECUTOR_STATUS_OK:
+               return "BT_QUERY_EXECUTOR_STATUS_OK";
+       case BT_QUERY_EXECUTOR_STATUS_AGAIN:
+               return "BT_QUERY_EXECUTOR_STATUS_AGAIN";
+       case BT_QUERY_EXECUTOR_STATUS_CANCELED:
+               return "BT_QUERY_EXECUTOR_STATUS_CANCELED";
+       case BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED:
+               return "BT_QUERY_EXECUTOR_STATUS_UNSUPPORTED";
+       case BT_QUERY_EXECUTOR_STATUS_ERROR:
+               return "BT_QUERY_EXECUTOR_STATUS_ERROR";
+       case BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT:
+               return "BT_QUERY_EXECUTOR_STATUS_INVALID_OBJECT";
+       case BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS:
+               return "BT_QUERY_EXECUTOR_STATUS_INVALID_PARAMS";
+       case BT_QUERY_EXECUTOR_STATUS_NOMEM:
+               return "BT_QUERY_EXECUTOR_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+};
+
+#endif /* BABELTRACE_GRAPH_QUERY_EXECUTOR_INTERNAL_H */
diff --git a/src/lib/lib-logging.c b/src/lib/lib-logging.c
new file mode 100644 (file)
index 0000000..d6d75e0
--- /dev/null
@@ -0,0 +1,1420 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "LIB-LOGGING"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <wchar.h>
+#include <glib.h>
+#include "common/common.h"
+#include "lib/value.h"
+#include "lib/value.h"
+#include "lib/object-pool.h"
+#include <babeltrace2/trace-ir/event-const.h>
+#include <babeltrace2/trace-ir/packet-const.h>
+#include <babeltrace2/trace-ir/stream-const.h>
+
+#include "graph/component-class.h"
+#include "graph/component-class-sink-colander.h"
+#include "graph/component-filter.h"
+#include "graph/component.h"
+#include "graph/component-sink.h"
+#include "graph/component-source.h"
+#include "graph/connection.h"
+#include "graph/graph.h"
+#include "graph/message/discarded-items.h"
+#include "graph/message/event.h"
+#include "graph/message/iterator.h"
+#include "graph/message/message.h"
+#include "graph/message/message-iterator-inactivity.h"
+#include "graph/message/packet.h"
+#include "graph/message/stream-activity.h"
+#include "graph/message/stream.h"
+#include "graph/port.h"
+#include "lib-logging.h"
+#include "plugin/plugin.h"
+#include "plugin/plugin-so.h"
+#include "trace-ir/clock-class.h"
+#include "trace-ir/clock-snapshot.h"
+#include "trace-ir/event-class.h"
+#include "trace-ir/event.h"
+#include "trace-ir/field-class.h"
+#include "trace-ir/field.h"
+#include "trace-ir/field-path.h"
+#include "trace-ir/packet.h"
+#include "trace-ir/stream-class.h"
+#include "trace-ir/stream.h"
+#include "trace-ir/trace-class.h"
+#include "trace-ir/trace.h"
+#include "trace-ir/utils.h"
+#include "assert-pre.h"
+
+#define LIB_LOGGING_BUF_SIZE   (4096 * 4)
+
+static __thread char lib_logging_buf[LIB_LOGGING_BUF_SIZE];
+
+#define BUF_APPEND(_fmt, ...)                                          \
+       do {                                                            \
+               int _count;                                             \
+               size_t _size = LIB_LOGGING_BUF_SIZE -                   \
+                               (size_t) (*buf_ch - lib_logging_buf);   \
+               _count = snprintf(*buf_ch, _size, (_fmt), __VA_ARGS__); \
+               BT_ASSERT(_count >= 0);                                 \
+               *buf_ch += MIN(_count, _size);                          \
+               if (*buf_ch >= lib_logging_buf + LIB_LOGGING_BUF_SIZE - 1) { \
+                       return;                                         \
+               }                                                       \
+       } while (0)
+
+#define BUF_APPEND_UUID(_uuid)                                         \
+       do {                                                            \
+               BUF_APPEND(", %suuid=", prefix);                        \
+               format_uuid(buf_ch, (_uuid));                           \
+       } while (0)
+
+#define PRFIELD(_expr) prefix, (_expr)
+
+#define PRFIELD_GSTRING(_expr) PRFIELD((_expr) ? (_expr)->str : NULL)
+
+#define TMP_PREFIX_LEN 64
+#define SET_TMP_PREFIX(_prefix2)                                       \
+       do {                                                            \
+               snprintf(tmp_prefix, TMP_PREFIX_LEN - 1, "%s%s",        \
+                       prefix, (_prefix2));                            \
+               tmp_prefix[TMP_PREFIX_LEN - 1] = '\0';                  \
+       } while (0)
+
+static inline void format_component(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_component *component);
+
+static inline void format_port(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_port *port);
+
+static inline void format_connection(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_connection *connection);
+
+static inline void format_clock_snapshot(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_clock_snapshot *clock_snapshot);
+
+static inline void format_field_path(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_field_path *field_path);
+
+static inline void format_object(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_object *obj)
+{
+       BUF_APPEND(", %sref-count=%llu", prefix, obj->ref_count);
+}
+
+static inline void format_uuid(char **buf_ch, bt_uuid uuid)
+{
+       BUF_APPEND("\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+               (unsigned int) uuid[0],
+               (unsigned int) uuid[1],
+               (unsigned int) uuid[2],
+               (unsigned int) uuid[3],
+               (unsigned int) uuid[4],
+               (unsigned int) uuid[5],
+               (unsigned int) uuid[6],
+               (unsigned int) uuid[7],
+               (unsigned int) uuid[8],
+               (unsigned int) uuid[9],
+               (unsigned int) uuid[10],
+               (unsigned int) uuid[11],
+               (unsigned int) uuid[12],
+               (unsigned int) uuid[13],
+               (unsigned int) uuid[14],
+               (unsigned int) uuid[15]);
+}
+
+static inline void format_object_pool(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_object_pool *pool)
+{
+       BUF_APPEND(", %ssize=%zu", PRFIELD(pool->size));
+
+       if (pool->objects) {
+               BUF_APPEND(", %scap=%u", PRFIELD(pool->objects->len));
+       }
+}
+
+static inline void format_integer_field_class(char **buf_ch,
+               bool extended, const char *prefix,
+               const struct bt_field_class *field_class)
+{
+       const struct bt_field_class_integer *int_fc =
+               (const void *) field_class;
+
+       BUF_APPEND(", %srange-size=%" PRIu64 ", %sbase=%s",
+               PRFIELD(int_fc->range),
+               PRFIELD(bt_common_field_class_integer_preferred_display_base_string(int_fc->base)));
+}
+
+static inline void format_array_field_class(char **buf_ch,
+               bool extended, const char *prefix,
+               const struct bt_field_class *field_class)
+{
+       const struct bt_field_class_array *array_fc =
+               (const void *) field_class;
+
+       BUF_APPEND(", %selement-fc-addr=%p, %selement-fc-type=%s",
+               PRFIELD(array_fc->element_fc),
+               PRFIELD(bt_common_field_class_type_string(array_fc->element_fc->type)));
+}
+
+static inline void format_field_class(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_field_class *field_class)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %stype=%s",
+               PRFIELD(bt_common_field_class_type_string(field_class->type)));
+
+       if (extended) {
+               BUF_APPEND(", %sis-frozen=%d", PRFIELD(field_class->frozen));
+               BUF_APPEND(", %sis-part-of-trace-class=%d",
+                       PRFIELD(field_class->part_of_trace_class));
+       } else {
+               return;
+       }
+
+       switch (field_class->type) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
+       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
+       {
+               format_integer_field_class(buf_ch, extended, prefix, field_class);
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_REAL:
+       {
+               const struct bt_field_class_real *real_fc = (void *) field_class;
+
+               BUF_APPEND(", %sis-single-precision=%d",
+                       PRFIELD(real_fc->is_single_precision));
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+       {
+               const struct bt_field_class_enumeration *enum_fc =
+                       (const void *) field_class;
+
+               format_integer_field_class(buf_ch, extended, prefix, field_class);
+               BUF_APPEND(", %smapping-count=%u",
+                       PRFIELD(enum_fc->mappings->len));
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       {
+               const struct bt_field_class_structure *struct_fc =
+                       (const void *) field_class;
+
+               if (struct_fc->common.named_fcs) {
+                       BUF_APPEND(", %smember-count=%u",
+                               PRFIELD(struct_fc->common.named_fcs->len));
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       {
+               const struct bt_field_class_static_array *array_fc =
+                       (const void *) field_class;
+
+               format_array_field_class(buf_ch, extended, prefix, field_class);
+               BUF_APPEND(", %slength=%" PRIu64, PRFIELD(array_fc->length));
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+       {
+               const struct bt_field_class_dynamic_array *array_fc =
+                       (const void *) field_class;
+
+               format_array_field_class(buf_ch, extended, prefix, field_class);
+
+               if (array_fc->length_fc) {
+                       SET_TMP_PREFIX("length-fc-");
+                       format_field_class(buf_ch, extended, tmp_prefix,
+                               array_fc->length_fc);
+               }
+
+               if (array_fc->length_field_path) {
+                       SET_TMP_PREFIX("length-field-path-");
+                       format_field_path(buf_ch, extended, tmp_prefix,
+                               array_fc->length_field_path);
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               const struct bt_field_class_variant *var_fc =
+                       (const void *) field_class;
+
+               if (var_fc->common.named_fcs) {
+                       BUF_APPEND(", %soption-count=%u",
+                               PRFIELD(var_fc->common.named_fcs->len));
+               }
+
+               if (var_fc->selector_fc) {
+                       SET_TMP_PREFIX("selector-fc-");
+                       format_field_class(buf_ch, extended, tmp_prefix,
+                               var_fc->selector_fc);
+               }
+
+               if (var_fc->selector_field_path) {
+                       SET_TMP_PREFIX("selector-field-path-");
+                       format_field_path(buf_ch, extended, tmp_prefix,
+                               var_fc->selector_field_path);
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static inline void format_field_integer_extended(char **buf_ch,
+               const char *prefix, const struct bt_field *field)
+{
+       const struct bt_field_integer *integer = (void *) field;
+       const struct bt_field_class_integer *field_class =
+               (void *) field->class;
+       const char *fmt = NULL;
+
+       BT_ASSERT(field_class);
+
+       if (field_class->base == BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL) {
+               fmt = ", %svalue=%" PRIo64;
+       } else if (field_class->base == BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL) {
+               fmt = ", %svalue=%" PRIx64;
+       }
+
+       if (field_class->common.type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
+                       field_class->common.type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
+               if (!fmt) {
+                       fmt = ", %svalue=%" PRId64;
+               }
+
+               BUF_APPEND(fmt, PRFIELD(integer->value.i));
+       } else {
+               if (!fmt) {
+                       fmt = ", %svalue=%" PRIu64;
+               }
+
+               BUF_APPEND(fmt, PRFIELD(integer->value.u));
+       }
+}
+
+static inline void format_field(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_field *field)
+{
+       BUF_APPEND(", %sis-set=%d", PRFIELD(field->is_set));
+
+       if (extended) {
+               BUF_APPEND(", %sis-frozen=%d", PRFIELD(field->frozen));
+       }
+
+       BUF_APPEND(", %sclass-addr=%p", PRFIELD(field->class));
+
+       if (!field->class) {
+               return;
+       }
+
+       BUF_APPEND(", %sclass-type=%s",
+               PRFIELD(bt_common_field_class_type_string(field->class->type)));
+
+       if (!extended || !field->is_set) {
+               return;
+       }
+
+       switch (field->class->type) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
+       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+       {
+               format_field_integer_extended(buf_ch, prefix, field);
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_REAL:
+       {
+               const struct bt_field_real *real_field = (const void *) field;
+
+               BUF_APPEND(", %svalue=%f", PRFIELD(real_field->value));
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STRING:
+       {
+               const struct bt_field_string *str = (const void *) field;
+
+               if (str->buf) {
+                       BT_ASSERT(str->buf->data);
+                       BUF_APPEND(", %spartial-value=\"%.32s\"",
+                               PRFIELD(str->buf->data));
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+       {
+               const struct bt_field_array *array_field = (const void *) field;
+
+               BUF_APPEND(", %slength=%" PRIu64, PRFIELD(array_field->length));
+
+               if (array_field->fields) {
+                       BUF_APPEND(", %sallocated-length=%u",
+                               PRFIELD(array_field->fields->len));
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               const struct bt_field_variant *var_field = (const void *) field;
+
+               BUF_APPEND(", %sselected-field-index=%" PRIu64,
+                       PRFIELD(var_field->selected_index));
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static inline void format_field_path(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_field_path *field_path)
+{
+       uint64_t i;
+
+       if (field_path->items) {
+               BT_ASSERT(field_path->items);
+               BUF_APPEND(", %sitem-count=%u",
+                       PRFIELD(field_path->items->len));
+       }
+
+       if (!extended || !field_path->items) {
+               return;
+       }
+
+       BUF_APPEND(", %spath=[%s",
+               PRFIELD(bt_common_scope_string(field_path->root)));
+
+       for (i = 0; i < bt_field_path_get_item_count(field_path); i++) {
+               const struct bt_field_path_item *fp_item =
+                       bt_field_path_borrow_item_by_index_const(field_path, i);
+
+               switch (bt_field_path_item_get_type(fp_item)) {
+               case BT_FIELD_PATH_ITEM_TYPE_INDEX:
+                       BUF_APPEND(", %" PRIu64,
+                               bt_field_path_item_index_get_index(fp_item));
+                       break;
+               case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
+                       BUF_APPEND("%s", ", <CUR>");
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       BUF_APPEND("%s", "]");
+}
+
+static inline void format_trace_class(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_trace_class *trace_class)
+{
+       if (trace_class->name.value) {
+               BUF_APPEND(", %sname=\"%s\"",
+                       PRFIELD(trace_class->name.value));
+       }
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-frozen=%d", PRFIELD(trace_class->frozen));
+
+       if (trace_class->uuid.value) {
+               BUF_APPEND_UUID(trace_class->uuid.value);
+       }
+
+       if (trace_class->stream_classes) {
+               BUF_APPEND(", %sstream-class-count=%u",
+                       PRFIELD(trace_class->stream_classes->len));
+       }
+
+       BUF_APPEND(", %sassigns-auto-sc-id=%d",
+               PRFIELD(trace_class->assigns_automatic_stream_class_id));
+}
+
+static inline void format_trace(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_trace *trace)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       if (trace->name.value) {
+               BUF_APPEND(", %sname=\"%s\"", PRFIELD(trace->name.value));
+       }
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-frozen=%d", PRFIELD(trace->frozen));
+
+       if (trace->streams) {
+               BUF_APPEND(", %sstream-count=%u",
+                       PRFIELD(trace->streams->len));
+       }
+
+       if (!trace->class) {
+               return;
+       }
+
+       BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace->class));
+       SET_TMP_PREFIX("trace-class-");
+       format_trace_class(buf_ch, false, tmp_prefix, trace->class);
+}
+
+static inline void format_stream_class(char **buf_ch, bool extended,
+               const char *prefix,
+               const struct bt_stream_class *stream_class)
+{
+       const struct bt_trace_class *trace_class;
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(stream_class->id));
+
+       if (stream_class->name.value) {
+               BUF_APPEND(", %sname=\"%s\"",
+                       PRFIELD(stream_class->name.value));
+       }
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-frozen=%d", PRFIELD(stream_class->frozen));
+
+       if (stream_class->event_classes) {
+               BUF_APPEND(", %sevent-class-count=%u",
+                       PRFIELD(stream_class->event_classes->len));
+       }
+
+       BUF_APPEND(", %spacket-context-fc-addr=%p, "
+               "%sevent-common-context-fc-addr=%p",
+               PRFIELD(stream_class->packet_context_fc),
+               PRFIELD(stream_class->event_common_context_fc));
+       trace_class = bt_stream_class_borrow_trace_class_inline(stream_class);
+       if (!trace_class) {
+               return;
+       }
+
+       BUF_APPEND(", %sassigns-auto-ec-id=%d, %sassigns-auto-stream-id=%d, "
+               "%spackets-have-default-beginning-cs=%d, "
+               "%spackets-have-default-end-cs=%d, "
+               "%ssupports-discarded-events=%d, "
+               "%sdiscarded-events-have-default-cs=%d, "
+               "%ssupports-discarded-packets=%d, "
+               "%sdiscarded-packets-have-default-cs=%d",
+               PRFIELD(stream_class->assigns_automatic_event_class_id),
+               PRFIELD(stream_class->assigns_automatic_stream_id),
+               PRFIELD(stream_class->packets_have_beginning_default_clock_snapshot),
+               PRFIELD(stream_class->packets_have_end_default_clock_snapshot),
+               PRFIELD(stream_class->supports_discarded_events),
+               PRFIELD(stream_class->discarded_events_have_default_clock_snapshots),
+               PRFIELD(stream_class->supports_discarded_packets),
+               PRFIELD(stream_class->discarded_packets_have_default_clock_snapshots));
+       BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace_class));
+       SET_TMP_PREFIX("trace-class-");
+       format_trace_class(buf_ch, false, tmp_prefix, trace_class);
+       SET_TMP_PREFIX("pcf-pool-");
+       format_object_pool(buf_ch, extended, tmp_prefix,
+               &stream_class->packet_context_field_pool);
+}
+
+static inline void format_event_class(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_event_class *event_class)
+{
+       const struct bt_stream_class *stream_class;
+       const struct bt_trace_class *trace_class;
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(event_class->id));
+
+       if (event_class->name.value) {
+               BUF_APPEND(", %sname=\"%s\"",
+                       PRFIELD(event_class->name.value));
+       }
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-frozen=%d", PRFIELD(event_class->frozen));
+
+       if (event_class->log_level.base.avail) {
+               BUF_APPEND(", %slog-level=%s",
+                       PRFIELD(bt_common_event_class_log_level_string(
+                               (int) event_class->log_level.value)));
+       }
+
+       if (event_class->emf_uri.value) {
+               BUF_APPEND(", %semf-uri=\"%s\"",
+                       PRFIELD(event_class->emf_uri.value));
+       }
+
+       BUF_APPEND(", %sspecific-context-fc-addr=%p, %spayload-fc-addr=%p",
+               PRFIELD(event_class->specific_context_fc),
+               PRFIELD(event_class->payload_fc));
+
+       stream_class = bt_event_class_borrow_stream_class_const(event_class);
+       if (!stream_class) {
+               return;
+       }
+
+       BUF_APPEND(", %sstream-class-addr=%p", PRFIELD(stream_class));
+       SET_TMP_PREFIX("stream-class-");
+       format_stream_class(buf_ch, false, tmp_prefix, stream_class);
+       trace_class = bt_stream_class_borrow_trace_class_inline(stream_class);
+       if (!trace_class) {
+               return;
+       }
+
+       BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace_class));
+       SET_TMP_PREFIX("trace-class-");
+       format_trace_class(buf_ch, false, tmp_prefix, trace_class);
+       SET_TMP_PREFIX("event-pool-");
+       format_object_pool(buf_ch, extended, tmp_prefix,
+               &event_class->event_pool);
+}
+
+static inline void format_stream(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_stream *stream)
+{
+       const struct bt_stream_class *stream_class;
+       const struct bt_trace_class *trace_class = NULL;
+       const struct bt_trace *trace = NULL;
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %sid=%" PRIu64, PRFIELD(stream->id));
+
+       if (stream->name.value) {
+               BUF_APPEND(", %sname=\"%s\"", PRFIELD(stream->name.value));
+       }
+
+       if (!extended) {
+               return;
+       }
+
+       stream_class = bt_stream_borrow_class_const(stream);
+       if (stream_class) {
+               BUF_APPEND(", %sstream-class-addr=%p", PRFIELD(stream_class));
+               SET_TMP_PREFIX("stream-class-");
+               format_stream_class(buf_ch, false, tmp_prefix, stream_class);
+               trace_class = bt_stream_class_borrow_trace_class_inline(stream_class);
+       }
+
+       if (trace_class) {
+               BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace_class));
+               SET_TMP_PREFIX("trace-class-");
+               format_trace_class(buf_ch, false, tmp_prefix, trace_class);
+       }
+
+       trace = bt_stream_borrow_trace_inline(stream);
+       if (trace) {
+               BUF_APPEND(", %strace-addr=%p", PRFIELD(trace));
+               SET_TMP_PREFIX("trace-");
+               format_trace(buf_ch, false, tmp_prefix, trace);
+       }
+
+       SET_TMP_PREFIX("packet-pool-");
+       format_object_pool(buf_ch, extended, tmp_prefix, &stream->packet_pool);
+}
+
+static inline void format_packet(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_packet *packet)
+{
+       const struct bt_stream *stream;
+       const struct bt_trace_class *trace_class;
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-frozen=%d, %scontext-field-addr=%p",
+               PRFIELD(packet->frozen),
+               PRFIELD(packet->context_field ? packet->context_field->field : NULL));
+       stream = bt_packet_borrow_stream_const(packet);
+       if (!stream) {
+               return;
+       }
+
+       BUF_APPEND(", %sstream-addr=%p", PRFIELD(stream));
+       SET_TMP_PREFIX("stream-");
+       format_stream(buf_ch, false, tmp_prefix, stream);
+       trace_class = (const struct bt_trace_class *) bt_object_borrow_parent(&stream->base);
+       if (!trace_class) {
+               return;
+       }
+
+       BUF_APPEND(", %strace-class-addr=%p", PRFIELD(trace_class));
+       SET_TMP_PREFIX("trace-class-");
+       format_trace_class(buf_ch, false, tmp_prefix, trace_class);
+}
+
+static inline void format_event(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_event *event)
+{
+       const struct bt_packet *packet;
+       const struct bt_stream *stream;
+       const struct bt_trace_class *trace_class;
+       const struct bt_stream_class *stream_class;
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-frozen=%d, "
+               "%scommon-context-field-addr=%p, "
+               "%sspecific-context-field-addr=%p, "
+               "%spayload-field-addr=%p, ",
+               PRFIELD(event->frozen),
+               PRFIELD(event->common_context_field),
+               PRFIELD(event->specific_context_field),
+               PRFIELD(event->payload_field));
+       BUF_APPEND(", %sevent-class-addr=%p", PRFIELD(event->class));
+
+       if (!event->class) {
+               return;
+       }
+
+       SET_TMP_PREFIX("event-class-");
+       format_event_class(buf_ch, false, tmp_prefix, event->class);
+       stream_class = bt_event_class_borrow_stream_class(event->class);
+       if (stream_class) {
+               BUF_APPEND(", %sstream-class-addr=%p", PRFIELD(stream_class));
+               SET_TMP_PREFIX("stream-class-");
+               format_stream_class(buf_ch, false, tmp_prefix,
+                       stream_class);
+
+               trace_class = bt_stream_class_borrow_trace_class_inline(
+                       stream_class);
+               if (trace_class) {
+                       BUF_APPEND(", %strace-class-addr=%p",
+                               PRFIELD(trace_class));
+                       SET_TMP_PREFIX("trace-class-");
+                       format_trace_class(buf_ch, false, tmp_prefix,
+                               trace_class);
+               }
+       }
+
+       packet = bt_event_borrow_packet_const(event);
+       if (!packet) {
+               return;
+       }
+
+       BUF_APPEND(", %spacket-addr=%p", PRFIELD(packet));
+       SET_TMP_PREFIX("packet-");
+       format_packet(buf_ch, false, tmp_prefix, packet);
+       stream = bt_packet_borrow_stream_const(packet);
+       if (!stream) {
+               return;
+       }
+
+       BUF_APPEND(", %sstream-addr=%p", PRFIELD(stream));
+       SET_TMP_PREFIX("stream-");
+       format_stream(buf_ch, false, tmp_prefix, stream);
+}
+
+static inline void format_clock_class(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_clock_class *clock_class)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       if (clock_class->name.value) {
+               BUF_APPEND(", %sname=\"%s\"", PRFIELD(clock_class->name.value));
+       }
+
+       BUF_APPEND(", %sfreq=%" PRIu64, PRFIELD(clock_class->frequency));
+
+       if (!extended) {
+               return;
+       }
+
+       if (clock_class->description.value) {
+               BUF_APPEND(", %spartial-descr=\"%.32s\"",
+                       PRFIELD(clock_class->description.value));
+       }
+
+       if (clock_class->uuid.value) {
+               BUF_APPEND_UUID(clock_class->uuid.value);
+       }
+
+       BUF_APPEND(", %sis-frozen=%d, %sprecision=%" PRIu64 ", "
+               "%soffset-s=%" PRId64 ", "
+               "%soffset-cycles=%" PRIu64 ", %sorigin-is-unix-epoch=%d, "
+               "%sbase-offset-ns=%" PRId64,
+               PRFIELD(clock_class->frozen), PRFIELD(clock_class->precision),
+               PRFIELD(clock_class->offset_seconds),
+               PRFIELD(clock_class->offset_cycles),
+               PRFIELD(clock_class->origin_is_unix_epoch),
+               PRFIELD(clock_class->base_offset.value_ns));
+
+       SET_TMP_PREFIX("cs-pool-");
+       format_object_pool(buf_ch, extended, tmp_prefix,
+               &clock_class->cs_pool);
+}
+
+static inline void format_clock_snapshot(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_clock_snapshot *clock_snapshot)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+       BUF_APPEND(", %svalue=%" PRIu64 ", %sns-from-origin=%" PRId64,
+               PRFIELD(clock_snapshot->value_cycles),
+               PRFIELD(clock_snapshot->ns_from_origin));
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-set=%d", PRFIELD(clock_snapshot->is_set));
+
+       if (clock_snapshot->clock_class) {
+               BUF_APPEND(", %sclock-class-addr=%p",
+                       PRFIELD(clock_snapshot->clock_class));
+               SET_TMP_PREFIX("clock-class-");
+               format_clock_class(buf_ch, false, tmp_prefix,
+                       clock_snapshot->clock_class);
+       }
+}
+
+static inline void format_value(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_value *value)
+{
+       BUF_APPEND(", %stype=%s",
+               PRFIELD(bt_common_value_type_string(bt_value_get_type(value))));
+
+       if (!extended) {
+               return;
+       }
+
+       switch (bt_value_get_type(value)) {
+       case BT_VALUE_TYPE_BOOL:
+       {
+               bt_bool val = bt_value_bool_get(value);
+
+               BUF_APPEND(", %svalue=%d", PRFIELD(val));
+               break;
+       }
+       case BT_VALUE_TYPE_UNSIGNED_INTEGER:
+       {
+               BUF_APPEND(", %svalue=%" PRIu64,
+                       PRFIELD(bt_value_unsigned_integer_get(value)));
+               break;
+       }
+       case BT_VALUE_TYPE_SIGNED_INTEGER:
+       {
+               BUF_APPEND(", %svalue=%" PRId64,
+                       PRFIELD(bt_value_signed_integer_get(value)));
+               break;
+       }
+       case BT_VALUE_TYPE_REAL:
+       {
+               double val = bt_value_real_get(value);
+
+               BUF_APPEND(", %svalue=%f", PRFIELD(val));
+               break;
+       }
+       case BT_VALUE_TYPE_STRING:
+       {
+               const char *val = bt_value_string_get(value);
+
+               BUF_APPEND(", %spartial-value=\"%.32s\"", PRFIELD(val));
+               break;
+       }
+       case BT_VALUE_TYPE_ARRAY:
+       {
+               int64_t count = bt_value_array_get_size(value);
+
+               BT_ASSERT(count >= 0);
+               BUF_APPEND(", %selement-count=%" PRId64, PRFIELD(count));
+               break;
+       }
+       case BT_VALUE_TYPE_MAP:
+       {
+               int64_t count = bt_value_map_get_size(value);
+
+               BT_ASSERT(count >= 0);
+               BUF_APPEND(", %selement-count=%" PRId64, PRFIELD(count));
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static inline void format_message(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_message *msg)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %stype=%s",
+               PRFIELD(bt_message_type_string(msg->type)));
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-frozen=%d, %sgraph-addr=%p",
+               PRFIELD(msg->frozen), PRFIELD(msg->graph));
+
+       switch (msg->type) {
+       case BT_MESSAGE_TYPE_EVENT:
+       {
+               const struct bt_message_event *msg_event =
+                       (const void *) msg;
+
+               if (msg_event->event) {
+                       SET_TMP_PREFIX("event-");
+                       format_event(buf_ch, true, tmp_prefix,
+                               msg_event->event);
+               }
+
+               if (msg_event->default_cs) {
+                       SET_TMP_PREFIX("default-cs-");
+                       format_clock_snapshot(buf_ch, true, tmp_prefix,
+                               msg_event->default_cs);
+               }
+
+               break;
+       }
+       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
+       case BT_MESSAGE_TYPE_STREAM_END:
+       {
+               const struct bt_message_stream *msg_stream = (const void *) msg;
+
+               if (msg_stream->stream) {
+                       SET_TMP_PREFIX("stream-");
+                       format_stream(buf_ch, true, tmp_prefix,
+                               msg_stream->stream);
+               }
+
+               break;
+       }
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+       {
+               const struct bt_message_stream_activity *msg_stream_activity =
+                       (const void *) msg;
+
+               if (msg_stream_activity->stream) {
+                       SET_TMP_PREFIX("stream-");
+                       format_stream(buf_ch, true, tmp_prefix,
+                               msg_stream_activity->stream);
+               }
+
+               BUF_APPEND(", %sdefault-cs-state=%s",
+                       PRFIELD(bt_message_stream_activity_clock_snapshot_state_string(
+                               msg_stream_activity->default_cs_state)));
+
+               if (msg_stream_activity->default_cs) {
+                       SET_TMP_PREFIX("default-cs-");
+                       format_clock_snapshot(buf_ch, true, tmp_prefix,
+                               msg_stream_activity->default_cs);
+               }
+
+               break;
+       }
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+       case BT_MESSAGE_TYPE_PACKET_END:
+       {
+               const struct bt_message_packet *msg_packet = (const void *) msg;
+
+               if (msg_packet->packet) {
+                       SET_TMP_PREFIX("packet-");
+                       format_packet(buf_ch, true, tmp_prefix,
+                               msg_packet->packet);
+               }
+
+               if (msg_packet->default_cs) {
+                       SET_TMP_PREFIX("default-cs-");
+                       format_clock_snapshot(buf_ch, true, tmp_prefix,
+                               msg_packet->default_cs);
+               }
+
+               break;
+       }
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+       {
+               const struct bt_message_discarded_items *msg_disc_items =
+                       (const void *) msg;
+
+               if (msg_disc_items->stream) {
+                       SET_TMP_PREFIX("stream-");
+                       format_stream(buf_ch, true, tmp_prefix,
+                               msg_disc_items->stream);
+               }
+
+               if (msg_disc_items->default_begin_cs) {
+                       SET_TMP_PREFIX("default-begin-cs-");
+                       format_clock_snapshot(buf_ch, true, tmp_prefix,
+                               msg_disc_items->default_begin_cs);
+               }
+
+               if (msg_disc_items->default_end_cs) {
+                       SET_TMP_PREFIX("default-end-cs-");
+                       format_clock_snapshot(buf_ch, true, tmp_prefix,
+                               msg_disc_items->default_end_cs);
+               }
+
+               if (msg_disc_items->count.base.avail) {
+                       BUF_APPEND(", %scount=%" PRIu64,
+                               PRFIELD(msg_disc_items->count.value));
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static inline void format_plugin_so_shared_lib_handle(char **buf_ch,
+               const char *prefix,
+               const struct bt_plugin_so_shared_lib_handle *handle)
+{
+       BUF_APPEND(", %saddr=%p", PRFIELD(handle));
+
+       if (handle->path) {
+               BUF_APPEND(", %spath=\"%s\"", PRFIELD_GSTRING(handle->path));
+       }
+}
+
+static inline void format_component_class(char **buf_ch, bool extended,
+               const char *prefix,
+               const struct bt_component_class *comp_class)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %stype=%s, %sname=\"%s\"",
+               PRFIELD(bt_component_class_type_string(comp_class->type)),
+               PRFIELD_GSTRING(comp_class->name));
+
+       if (comp_class->description) {
+               BUF_APPEND(", %spartial-descr=\"%.32s\"",
+                       PRFIELD_GSTRING(comp_class->description));
+       }
+
+       if (!extended) {
+               return;
+       }
+
+       BUF_APPEND(", %sis-frozen=%d", PRFIELD(comp_class->frozen));
+
+       if (comp_class->so_handle) {
+               SET_TMP_PREFIX("so-handle-");
+               format_plugin_so_shared_lib_handle(buf_ch, tmp_prefix,
+                       comp_class->so_handle);
+       }
+}
+
+static inline void format_component(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_component *component)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %sname=\"%s\"",
+               PRFIELD_GSTRING(component->name));
+
+       if (component->class) {
+               SET_TMP_PREFIX("class-");
+               format_component_class(buf_ch, extended, tmp_prefix,
+                       component->class);
+       }
+
+       if (!extended) {
+               return;
+       }
+
+       if (component->input_ports) {
+               BUF_APPEND(", %sinput-port-count=%u",
+                       PRFIELD(component->input_ports->len));
+       }
+
+       if (component->output_ports) {
+               BUF_APPEND(", %soutput-port-count=%u",
+                       PRFIELD(component->output_ports->len));
+       }
+}
+
+static inline void format_port(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_port *port)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %stype=%s, %sname=\"%s\"",
+               PRFIELD(bt_port_type_string(port->type)),
+               PRFIELD_GSTRING(port->name));
+
+       if (!extended) {
+               return;
+       }
+
+       if (port->connection) {
+               SET_TMP_PREFIX("conn-");
+               format_connection(buf_ch, false, tmp_prefix, port->connection);
+       }
+}
+
+static inline void format_connection(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_connection *connection)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       if (!extended) {
+               return;
+       }
+
+       if (connection->upstream_port) {
+               SET_TMP_PREFIX("upstream-port-");
+               format_port(buf_ch, false, tmp_prefix,
+                       connection->upstream_port);
+       }
+
+       if (connection->downstream_port) {
+               SET_TMP_PREFIX("downstream-port-");
+               format_port(buf_ch, false, tmp_prefix,
+                       connection->downstream_port);
+       }
+}
+
+static inline void format_graph(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_graph *graph)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %sis-canceled=%d, %scan-consume=%d, "
+               "%sconfig-state=%s",
+               PRFIELD(graph->canceled),
+               PRFIELD(graph->can_consume),
+               PRFIELD(bt_graph_configuration_state_string(graph->config_state)));
+
+       if (!extended) {
+               return;
+       }
+
+       if (graph->components) {
+               BUF_APPEND(", %scomp-count=%u",
+                       PRFIELD(graph->components->len));
+       }
+
+       if (graph->connections) {
+               BUF_APPEND(", %sconn-count=%u",
+                       PRFIELD(graph->connections->len));
+       }
+
+       SET_TMP_PREFIX("en-pool-");
+       format_object_pool(buf_ch, extended, tmp_prefix,
+               &graph->event_msg_pool);
+       SET_TMP_PREFIX("pbn-pool-");
+       format_object_pool(buf_ch, extended, tmp_prefix,
+               &graph->packet_begin_msg_pool);
+       SET_TMP_PREFIX("pen-pool-");
+       format_object_pool(buf_ch, extended, tmp_prefix,
+               &graph->packet_end_msg_pool);
+}
+
+static inline void format_message_iterator(char **buf_ch,
+               bool extended, const char *prefix,
+               const struct bt_message_iterator *iterator)
+{
+       const char *type;
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       if (iterator->type == BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT) {
+               type = "BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT";
+       } else if (iterator->type == BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT) {
+               type = "BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT";
+       } else {
+               type = "(unknown)";
+       }
+
+       BUF_APPEND(", %stype=%s", PRFIELD(type));
+
+       switch (iterator->type) {
+       case BT_MESSAGE_ITERATOR_TYPE_SELF_COMPONENT_PORT_INPUT:
+       {
+               const struct bt_self_component_port_input_message_iterator *
+                       port_in_iter = (const void *) iterator;
+
+               if (port_in_iter->upstream_component) {
+                       SET_TMP_PREFIX("upstream-comp-");
+                       format_component(buf_ch, false, tmp_prefix,
+                               port_in_iter->upstream_component);
+               }
+
+               if (port_in_iter->upstream_port) {
+                       SET_TMP_PREFIX("upstream-port-");
+                       format_port(buf_ch, false, tmp_prefix,
+                               port_in_iter->upstream_port);
+               }
+
+               if (port_in_iter->connection) {
+                       SET_TMP_PREFIX("upstream-conn-");
+                       format_connection(buf_ch, false, tmp_prefix,
+                               port_in_iter->connection);
+               }
+               break;
+       }
+       case BT_MESSAGE_ITERATOR_TYPE_PORT_OUTPUT:
+       {
+               const struct bt_port_output_message_iterator *port_out_iter =
+                       (const void *) iterator;
+
+               if (port_out_iter->graph) {
+                       SET_TMP_PREFIX("graph-");
+                       format_graph(buf_ch, false, tmp_prefix,
+                               port_out_iter->graph);
+               }
+
+               if (port_out_iter->colander) {
+                       SET_TMP_PREFIX("colander-comp-");
+                       format_component(buf_ch, false, tmp_prefix,
+                               (void *) port_out_iter->colander);
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static inline void format_plugin(char **buf_ch, bool extended,
+               const char *prefix, const struct bt_plugin *plugin)
+{
+       char tmp_prefix[TMP_PREFIX_LEN];
+
+       BUF_APPEND(", %stype=%s", PRFIELD(bt_plugin_type_string(plugin->type)));
+
+       if (plugin->info.path_set) {
+               BUF_APPEND(", %spath=\"%s\"",
+                       PRFIELD_GSTRING(plugin->info.path));
+       }
+
+       if (plugin->info.name_set) {
+               BUF_APPEND(", %sname=\"%s\"",
+                       PRFIELD_GSTRING(plugin->info.name));
+       }
+
+       if (!extended) {
+               return;
+       }
+
+       if (plugin->info.author_set) {
+               BUF_APPEND(", %sauthor=\"%s\"",
+                       PRFIELD_GSTRING(plugin->info.author));
+       }
+
+       if (plugin->info.license_set) {
+               BUF_APPEND(", %slicense=\"%s\"",
+                       PRFIELD_GSTRING(plugin->info.license));
+       }
+
+       if (plugin->info.version_set) {
+               BUF_APPEND(", %sversion=%u.%u.%u%s",
+                       PRFIELD(plugin->info.version.major),
+                       plugin->info.version.minor,
+                       plugin->info.version.patch,
+                       plugin->info.version.extra ?
+                               plugin->info.version.extra->str : "");
+       }
+
+       BUF_APPEND(", %ssrc-comp-class-count=%u, %sflt-comp-class-count=%u, "
+               "%ssink-comp-class-count=%u",
+               PRFIELD(plugin->src_comp_classes->len),
+               PRFIELD(plugin->flt_comp_classes->len),
+               PRFIELD(plugin->sink_comp_classes->len));
+
+       if (plugin->spec_data) {
+               const struct bt_plugin_so_spec_data *spec_data =
+                       (const void *) plugin->spec_data;
+
+               if (spec_data->shared_lib_handle) {
+                       SET_TMP_PREFIX("so-handle-");
+                       format_plugin_so_shared_lib_handle(buf_ch, tmp_prefix,
+                               spec_data->shared_lib_handle);
+               }
+       }
+}
+
+static inline void handle_conversion_specifier_bt(void *priv_data,
+               char **buf_ch, size_t avail_size,
+               const char **out_fmt_ch, va_list *args)
+{
+       const char *fmt_ch = *out_fmt_ch;
+       bool extended = false;
+       char prefix[64];
+       char *prefix_ch = prefix;
+       const void *obj;
+
+       /* skip "%!" */
+       fmt_ch += 2;
+
+       if (*fmt_ch == 'u') {
+               /* UUID */
+               obj = va_arg(*args, void *);
+               format_uuid(buf_ch, obj);
+               goto update_fmt;
+       }
+
+       if (*fmt_ch == '[') {
+               /* local prefix */
+               fmt_ch++;
+
+               while (true) {
+                       if (*fmt_ch == ']') {
+                               *prefix_ch = '\0';
+                               fmt_ch++;
+                               break;
+                       }
+
+                       *prefix_ch = *fmt_ch;
+                       prefix_ch++;
+                       fmt_ch++;
+               }
+       }
+
+       *prefix_ch = '\0';
+
+       if (*fmt_ch == '+') {
+               extended = true;
+               fmt_ch++;
+       }
+
+       obj = va_arg(*args, void *);
+       BUF_APPEND("%saddr=%p", prefix, obj);
+
+       if (!obj) {
+               goto update_fmt;
+       }
+
+       switch (*fmt_ch) {
+       case 'F':
+               format_field_class(buf_ch, extended, prefix, obj);
+               break;
+       case 'f':
+               format_field(buf_ch, extended, prefix, obj);
+               break;
+       case 'P':
+               format_field_path(buf_ch, extended, prefix, obj);
+               break;
+       case 'E':
+               format_event_class(buf_ch, extended, prefix, obj);
+               break;
+       case 'e':
+               format_event(buf_ch, extended, prefix, obj);
+               break;
+       case 'S':
+               format_stream_class(buf_ch, extended, prefix, obj);
+               break;
+       case 's':
+               format_stream(buf_ch, extended, prefix, obj);
+               break;
+       case 'a':
+               format_packet(buf_ch, extended, prefix, obj);
+               break;
+       case 't':
+               format_trace(buf_ch, extended, prefix, obj);
+               break;
+       case 'T':
+               format_trace_class(buf_ch, extended, prefix, obj);
+               break;
+       case 'K':
+               format_clock_class(buf_ch, extended, prefix, obj);
+               break;
+       case 'k':
+               format_clock_snapshot(buf_ch, extended, prefix, obj);
+               break;
+       case 'v':
+               format_value(buf_ch, extended, prefix, obj);
+               break;
+       case 'n':
+               format_message(buf_ch, extended, prefix, obj);
+               break;
+       case 'i':
+               format_message_iterator(buf_ch, extended, prefix, obj);
+               break;
+       case 'C':
+               format_component_class(buf_ch, extended, prefix, obj);
+               break;
+       case 'c':
+               format_component(buf_ch, extended, prefix, obj);
+               break;
+       case 'p':
+               format_port(buf_ch, extended, prefix, obj);
+               break;
+       case 'x':
+               format_connection(buf_ch, extended, prefix, obj);
+               break;
+       case 'l':
+               format_plugin(buf_ch, extended, prefix, obj);
+               break;
+       case 'g':
+               format_graph(buf_ch, extended, prefix, obj);
+               break;
+       case 'o':
+               format_object_pool(buf_ch, extended, prefix, obj);
+               break;
+       case 'O':
+               format_object(buf_ch, extended, prefix, obj);
+               break;
+       default:
+               abort();
+       }
+
+update_fmt:
+       fmt_ch++;
+       *out_fmt_ch = fmt_ch;
+}
+
+void bt_lib_log(const char *func, const char *file, unsigned line,
+               int lvl, const char *tag, const char *fmt, ...)
+{
+       va_list args;
+
+       BT_ASSERT(fmt);
+       va_start(args, fmt);
+       bt_common_custom_vsnprintf(lib_logging_buf, LIB_LOGGING_BUF_SIZE, '!',
+               handle_conversion_specifier_bt, NULL, fmt, &args);
+       va_end(args);
+       _bt_log_write_d(func, file, line, lvl, tag, "%s", lib_logging_buf);
+}
diff --git a/src/lib/lib-logging.h b/src/lib/lib-logging.h
new file mode 100644 (file)
index 0000000..59e8559
--- /dev/null
@@ -0,0 +1,193 @@
+#ifndef BABELTRACE_LIB_LOGGING_INTERNAL_H
+#define BABELTRACE_LIB_LOGGING_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <stdarg.h>
+
+#ifndef BT_LOG_TAG
+# error Please define a tag with BT_LOG_TAG before including this file.
+#endif
+
+#define BT_LOG_OUTPUT_LEVEL bt_lib_log_level
+
+#include "logging/log.h"
+
+extern
+int bt_lib_log_level;
+
+#define BT_LIB_LOG(_lvl, _fmt, ...)                                    \
+       do {                                                            \
+               if (BT_LOG_ON(_lvl)) {                                  \
+                       bt_lib_log(_BT_LOG_SRCLOC_FUNCTION, __FILE__,   \
+                               __LINE__, _lvl, _BT_LOG_TAG,            \
+                               (_fmt), ##__VA_ARGS__);                 \
+               }                                                       \
+       } while (0)
+
+/*
+ * The six macros below are logging statements which are specialized
+ * for the Babeltrace library.
+ *
+ * `_fmt` is a typical printf()-style format string, with the following
+ * limitations:
+ *
+ * * The `*` width specifier is not accepted.
+ * * The `*` precision specifier is not accepted.
+ * * The `j` and `t` length modifiers are not accepted.
+ * * The `n` format specifier is not accepted.
+ * * The format specifiers defined in <inttypes.h> are not accepted
+ *   except for `PRId64`, `PRIu64`, `PRIx64`, `PRIX64`, `PRIo64`, and
+ *   `PRIi64`.
+ *
+ * The Babeltrace extension conversion specifier is accepted. Its syntax
+ * is either `%!u` to format a UUID (`bt_uuid` type) or:
+ *
+ * 1. Introductory `%!` sequence.
+ *
+ * 2. Optional: `[` followed by a custom prefix for the printed fields
+ *    of this specifier, followed by `]`. The standard form is to end
+ *    this prefix with `-` so that, for example, with the prefix
+ *    `prefix-`, the complete field name is `prefix-addr`.
+ *
+ * 3. Optional: `+` to print extended fields. This depends on the
+ *    provided format specifier.
+ *
+ * 4. Format specifier (see below).
+ *
+ * The available format specifiers are:
+ *
+ *   `F`:
+ *       Trace IR field class. The parameter type is
+ *      `struct bt_field_class *`.
+ *
+ *   `f`:
+ *       Trace IR field. The parameter type is `struct bt_field *`.
+ *
+ *   `P`:
+ *       Field path. The parameter type is `struct bt_field_path *`.
+ *
+ *   `E`:
+ *       Trace IR event class. The parameter type is
+ *      `struct bt_event_class *`.
+ *
+ *   `e`:
+ *       Trace IR event. The parameter type is `struct bt_event *`.
+ *
+ *   `S`:
+ *       Trace IR stream class. The parameter type is
+ *      `struct bt_stream_class *`.
+ *
+ *   `s`:
+ *       Trace IR stream. The parameter type is `struct bt_stream *`.
+ *
+ *   `a`:
+ *       Packet. The parameter type is `struct bt_packet *`.
+ *
+ *   `T`:
+ *       Trace IR trace class. The parameter type is `struct bt_trace_class *`.
+ *
+ *   `t`:
+ *       Trace IR trace. The parameter type is `struct bt_trace *`.
+ *
+ *   `K`:
+ *       Clock class. The parameter type is `struct bt_clock_class *`.
+ *
+ *   `k`:
+ *       Clock snapshot. The parameter type is `struct bt_clock_snapshot *`.
+ *
+ *   `v`:
+ *       Value. The parameter type is `struct bt_value *`.
+ *
+ *   `n`:
+ *       Message. The parameter type is `struct bt_message *`.
+ *
+ *   `i`:
+ *       Message iterator. The parameter type is
+ *       `struct bt_message_iterator *`.
+ *
+ *   `C`:
+ *       Component class. The parameter type is
+ *      `struct bt_component_class *`.
+ *
+ *   `c`:
+ *       Component. The parameter type is `struct bt_component *`.
+ *
+ *   `p`:
+ *       Port. The parameter type is `struct bt_port *`.
+ *
+ *   `x`:
+ *       Connection. The parameter type is `struct bt_connection *`.
+ *
+ *   `g`:
+ *       Graph. The parameter type is `struct bt_graph *`.
+ *
+ *   `l`:
+ *       Plugin. The parameter type is `const struct bt_plugin *`.
+ *
+ *   `o`:
+ *       Object pool. The parameter type is `struct bt_object_pool *`.
+ *
+ *   `O`:
+ *       Object. The parameter type is `struct bt_object *`.
+ *
+ * Conversion specifier examples:
+ *
+ *     %!f
+ *     %![my-event-]+e
+ *     %!t
+ *     %!+F
+ *
+ * The string `, ` is printed between individual fields, but not after
+ * the last one. Therefore you must put this separator in the format
+ * string between two conversion specifiers, e.g.:
+ *
+ *     BT_LIB_LOGW("Message: count=%u, %!E, %!+K", count, event_class,
+ *                 clock_class);
+ *
+ * Example with a custom prefix:
+ *
+ *     BT_LIB_LOGI("Some message: %![ec-a-]e, %![ec-b-]+e", ec_a, ec_b);
+ *
+ * It is safe to pass NULL as any Babeltrace object parameter: the
+ * macros only print its null address.
+ */
+#define BT_LIB_LOGF(_fmt, ...) BT_LIB_LOG(BT_LOG_FATAL, _fmt, ##__VA_ARGS__)
+#define BT_LIB_LOGE(_fmt, ...) BT_LIB_LOG(BT_LOG_ERROR, _fmt, ##__VA_ARGS__)
+#define BT_LIB_LOGW(_fmt, ...) BT_LIB_LOG(BT_LOG_WARN, _fmt, ##__VA_ARGS__)
+#define BT_LIB_LOGI(_fmt, ...) BT_LIB_LOG(BT_LOG_INFO, _fmt, ##__VA_ARGS__)
+#define BT_LIB_LOGD(_fmt, ...) BT_LIB_LOG(BT_LOG_DEBUG, _fmt, ##__VA_ARGS__)
+#define BT_LIB_LOGV(_fmt, ...) BT_LIB_LOG(BT_LOG_VERBOSE, _fmt, ##__VA_ARGS__)
+
+/*
+ * Log statement, specialized for the Babeltrace library.
+ *
+ * Use one of the BT_LIB_LOGF*() macros above instead of calling this
+ * function directly.
+ */
+
+void bt_lib_log(const char *func, const char *file, unsigned line,
+               int lvl, const char *tag, const char *fmt, ...);
+
+#endif /* BABELTRACE_LIB_LOGGING_INTERNAL_H */
diff --git a/src/lib/logging.c b/src/lib/logging.c
new file mode 100644 (file)
index 0000000..3c0178c
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <babeltrace2/logging.h>
+#include <babeltrace2/version.h>
+
+#define BT_LOG_TAG "LIB"
+#include "lib/lib-logging.h"
+
+#ifdef BT_DEV_MODE
+/*
+ * Default log level is FATAL in developer mode because fatal logging is
+ * our way to communicate an unsatisfied precondition and the details.
+ */
+# define DEFAULT_LOG_LEVEL     BT_LOG_FATAL
+#else
+/*
+ * In non-developer mode, use NONE by default: we don't to print logging
+ * statements for any executable which links with the library. The
+ * executable should call bt_logging_set_global_level() or the
+ * executable's user should set the BABELTRACE_LOGGING_GLOBAL_LEVEL
+ * environment variable.
+ */
+# define DEFAULT_LOG_LEVEL     BT_LOG_NONE
+#endif /* BT_DEV_MODE */
+
+int bt_lib_log_level = DEFAULT_LOG_LEVEL;
+
+enum bt_logging_level bt_logging_get_minimal_level(void)
+{
+       return BT_LOG_LEVEL;
+}
+
+enum bt_logging_level bt_logging_get_global_level(void)
+{
+       return bt_lib_log_level;
+}
+
+void bt_logging_set_global_level(enum bt_logging_level log_level)
+{
+#ifdef BT_DEV_MODE
+       /*
+        * Do not allow the library's log level to fall to NONE when in
+        * developer mode because fatal logging is our way to
+        * communicate an unsatisfied precondition and the details.
+        */
+       if (log_level == BT_LOG_NONE) {
+               log_level = BT_LOG_FATAL;
+       }
+#endif
+
+       bt_lib_log_level = log_level;
+}
+
+static
+void __attribute__((constructor)) bt_logging_ctor(void)
+{
+       const char *v_extra = bt_version_get_extra() ? bt_version_get_extra() :
+               "";
+
+       bt_logging_set_global_level(
+               bt_log_get_level_from_env("BABELTRACE_LOGGING_GLOBAL_LEVEL"));
+       BT_LOGI("Babeltrace %d.%d.%d%s library loaded: "
+               "major=%d, minor=%d, patch=%d, extra=\"%s\"",
+               bt_version_get_major(), bt_version_get_minor(),
+               bt_version_get_patch(), v_extra,
+               bt_version_get_major(), bt_version_get_minor(),
+               bt_version_get_patch(), v_extra);
+}
diff --git a/src/lib/object-pool.c b/src/lib/object-pool.c
new file mode 100644 (file)
index 0000000..2542047
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "OBJECT-POOL"
+#include "lib/lib-logging.h"
+
+#include <stdint.h>
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "lib/object-pool.h"
+
+int bt_object_pool_initialize(struct bt_object_pool *pool,
+               bt_object_pool_new_object_func new_object_func,
+               bt_object_pool_destroy_object_func destroy_object_func,
+               void *data)
+{
+       int ret = 0;
+
+       BT_ASSERT(new_object_func);
+       BT_ASSERT(destroy_object_func);
+       BT_LOGD("Initializing object pool: addr=%p, data-addr=%p",
+               pool, data);
+       pool->objects = g_ptr_array_new();
+       if (!pool->objects) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       pool->funcs.new_object = new_object_func;
+       pool->funcs.destroy_object = destroy_object_func;
+       pool->data = data;
+       pool->size = 0;
+       BT_LIB_LOGD("Initialized object pool: %!+o", pool);
+       goto end;
+
+error:
+       if (pool) {
+               bt_object_pool_finalize(pool);
+       }
+
+       ret = -1;
+
+end:
+       return ret;
+}
+
+void bt_object_pool_finalize(struct bt_object_pool *pool)
+{
+       uint64_t i;
+
+       BT_ASSERT(pool);
+       BT_LIB_LOGD("Finalizing object pool: %!+o", pool);
+
+       if (pool->objects) {
+               for (i = 0; i < pool->size; i++) {
+                       void *obj = pool->objects->pdata[i];
+
+                       if (obj) {
+                               pool->funcs.destroy_object(obj, pool->data);
+                       }
+               }
+
+               g_ptr_array_free(pool->objects, TRUE);
+               pool->objects = NULL;
+       }
+}
diff --git a/src/lib/object-pool.h b/src/lib/object-pool.h
new file mode 100644 (file)
index 0000000..eb7833f
--- /dev/null
@@ -0,0 +1,182 @@
+#ifndef BABELTRACE_OBJECT_POOL_INTERNAL_H
+#define BABELTRACE_OBJECT_POOL_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This is a generic object pool to avoid memory allocation/deallocation
+ * for objects of which the lifespan is typically short, but which are
+ * created a lot.
+ *
+ * The object pool, thanks to two user functions, knows how to allocate
+ * a brand new object in memory when the pool is empty and how to
+ * destroy an object when we destroy the pool.
+ *
+ * The object pool's user is responsible for:
+ *
+ * * Setting whatever references the object needs to keep and reset some
+ *   properties _after_ calling bt_object_pool_create_object(). This is
+ *   typically done in the bt_*_create() function which calls
+ *   bt_object_pool_create_object() (which could call the user-provided
+ *   allocation function if the pool is empty) and then sets the
+ *   appropriate properties on the possibly recycled object.
+ *
+ * * Releasing whatever references the object keeps _before_ calling
+ *   bt_object_pool_recycle_object(). This is typically done in a custom
+ *   bt_*_recycle() function which does the necessary before calling
+ *   bt_object_pool_recycle_object() with an object ready to be reused
+ *   at any time.
+ */
+
+#include <glib.h>
+#include "lib/object.h"
+
+typedef void *(*bt_object_pool_new_object_func)(void *data);
+typedef void *(*bt_object_pool_destroy_object_func)(void *obj, void *data);
+
+struct bt_object_pool {
+       /*
+        * Container of recycled objects, owned by this. The array's size
+        * is the pool's capacity.
+        */
+       GPtrArray *objects;
+
+       /*
+        * Pool's size, that is, number of elements in the array above,
+        * starting at index 0, which exist as recycled objects.
+        */
+       size_t size;
+
+       /* User functions */
+       struct {
+               /* Allocate a new object in memory */
+               bt_object_pool_new_object_func new_object;
+
+               /* Free direct and indirect memory occupied by object */
+               bt_object_pool_destroy_object_func destroy_object;
+       } funcs;
+
+       /* User data passed to user functions */
+       void *data;
+};
+
+/*
+ * Initializes an object pool which is already allocated.
+ */
+int bt_object_pool_initialize(struct bt_object_pool *pool,
+               bt_object_pool_new_object_func new_object_func,
+               bt_object_pool_destroy_object_func destroy_object_func,
+               void *data);
+
+/*
+ * Finalizes an object pool without deallocating it.
+ */
+void bt_object_pool_finalize(struct bt_object_pool *pool);
+
+/*
+ * Creates an object from an object pool. If the pool is empty, this
+ * function calls the "new" user function to allocate a new object
+ * before returning it. Otherwise this function returns a recycled
+ * object, removing it from the pool.
+ *
+ * The returned object is owned by the caller.
+ */
+static inline
+void *bt_object_pool_create_object(struct bt_object_pool *pool)
+{
+       struct bt_object *obj;
+
+       BT_ASSERT(pool);
+
+#ifdef BT_LOGV
+       BT_LOGV("Creating object from pool: pool-addr=%p, pool-size=%zu, pool-cap=%u",
+               pool, pool->size, pool->objects->len);
+#endif
+
+       if (pool->size > 0) {
+               /* Pick one from the pool */
+               pool->size--;
+               obj = pool->objects->pdata[pool->size];
+               pool->objects->pdata[pool->size] = NULL;
+               goto end;
+       }
+
+       /* Pool is empty: create a brand new object */
+#ifdef BT_LOGV
+       BT_LOGV("Pool is empty: allocating new object: pool-addr=%p",
+               pool);
+#endif
+
+       obj = pool->funcs.new_object(pool->data);
+
+end:
+#ifdef BT_LOGV
+       BT_LOGV("Created one object from pool: pool-addr=%p, obj-addr=%p",
+               pool, obj);
+#endif
+
+       return obj;
+}
+
+/*
+ * Recycles an object, that is, puts it back into the pool.
+ *
+ * The pool becomes the sole owner of the object to recycle.
+ */
+static inline
+void bt_object_pool_recycle_object(struct bt_object_pool *pool, void *obj)
+{
+       struct bt_object *bt_obj = obj;
+
+       BT_ASSERT(pool);
+       BT_ASSERT(obj);
+
+#ifdef BT_LOGV
+       BT_LOGV("Recycling object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
+               pool, pool->size, pool->objects->len, obj);
+#endif
+
+       if (pool->size == pool->objects->len) {
+               /* Backing array is full: make place for recycled object */
+#ifdef BT_LOGV
+               BT_LOGV("Object pool is full: increasing object pool capacity: "
+                       "pool-addr=%p, old-pool-cap=%u, new-pool-cap=%u",
+                       pool, pool->objects->len, pool->objects->len + 1);
+#endif
+               g_ptr_array_set_size(pool->objects, pool->size + 1);
+       }
+
+       /* Reset reference count to 1 since it could be 0 now */
+       bt_obj->ref_count = 1;
+
+       /* Back to the pool */
+       pool->objects->pdata[pool->size] = obj;
+       pool->size++;
+
+#ifdef BT_LOGV
+       BT_LOGV("Recycled object: pool-addr=%p, pool-size=%zu, pool-cap=%u, obj-addr=%p",
+               pool, pool->size, pool->objects->len, obj);
+#endif
+}
+
+#endif /* BABELTRACE_OBJECT_POOL_INTERNAL_H */
diff --git a/src/lib/object.h b/src/lib/object.h
new file mode 100644 (file)
index 0000000..c3afd73
--- /dev/null
@@ -0,0 +1,374 @@
+#ifndef BABELTRACE_OBJECT_INTERNAL_H
+#define BABELTRACE_OBJECT_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <stdbool.h>
+
+struct bt_object;
+
+typedef void (*bt_object_release_func)(struct bt_object *);
+typedef void (*bt_object_parent_is_owner_listener_func)(
+               struct bt_object *);
+
+static inline
+void bt_object_get_no_null_check(const void *obj);
+
+static inline
+void bt_object_put_no_null_check(const void *obj);
+
+/*
+ * Babeltrace object base.
+ *
+ * All objects publicly exposed by Babeltrace APIs must contain this
+ * object as their first member.
+ */
+struct bt_object {
+       /*
+        * True if this object is shared, that is, it has a reference
+        * count.
+        */
+       bool is_shared;
+
+       /*
+        * Current reference count.
+        */
+       unsigned long long ref_count;
+
+       /*
+        * Release function called when the object's reference count
+        * falls to zero. For an object with a parent, this function is
+        * bt_object_with_parent_release_func(), which calls
+        * `spec_release_func` below if there's no current parent.
+        */
+       bt_object_release_func release_func;
+
+       /*
+        * Specific release function called by
+        * bt_object_with_parent_release_func() or directly by a
+        * parent object.
+        */
+       bt_object_release_func spec_release_func;
+
+       /*
+        * Optional callback for an object with a parent, called by
+        * bt_object_with_parent_release_func() to indicate to the
+        * object that its parent is its owner.
+        */
+       bt_object_parent_is_owner_listener_func
+               parent_is_owner_listener_func;
+
+       /*
+        * Optional parent object.
+        */
+       struct bt_object *parent;
+};
+
+static inline
+unsigned long long bt_object_get_ref_count(const struct bt_object *c_obj)
+{
+       struct bt_object *obj = (void *) c_obj;
+
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       return obj->ref_count;
+}
+
+static inline
+struct bt_object *bt_object_borrow_parent(const struct bt_object *c_obj)
+{
+       struct bt_object *obj = (void *) c_obj;
+
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       return obj->parent;
+}
+
+static inline
+struct bt_object *bt_object_get_parent(const struct bt_object *c_obj)
+{
+       struct bt_object *obj = (void *) c_obj;
+       struct bt_object *parent = bt_object_borrow_parent(obj);
+
+       if (parent) {
+               bt_object_get_no_null_check(parent);
+       }
+
+       return parent;
+}
+
+static inline
+void bt_object_set_parent(struct bt_object *child, struct bt_object *parent)
+{
+       BT_ASSERT(child);
+       BT_ASSERT(child->is_shared);
+
+#ifdef BT_LOGV
+       BT_LOGV("Setting object's parent: addr=%p, parent-addr=%p",
+               child, parent);
+#endif
+
+       /*
+        * It is assumed that a "child" having a parent is publicly
+        * reachable. Therefore, a reference to its parent must be
+        * taken. The reference to the parent will be released once the
+        * object's reference count falls to zero.
+        */
+       if (parent) {
+               BT_ASSERT(!child->parent);
+               child->parent = parent;
+               bt_object_get_no_null_check(parent);
+       } else {
+               if (child->parent) {
+                       bt_object_put_no_null_check(child->parent);
+               }
+
+               child->parent = NULL;
+       }
+}
+
+static inline
+void bt_object_try_spec_release(struct bt_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       BT_ASSERT(obj->spec_release_func);
+
+       if (bt_object_get_ref_count(obj) == 0) {
+               obj->spec_release_func(obj);
+       }
+}
+
+static inline
+void bt_object_with_parent_release_func(struct bt_object *obj)
+{
+       if (obj->parent) {
+               /*
+                * Keep our own copy of the parent address because `obj`
+                * could be destroyed in
+                * obj->parent_is_owner_listener_func().
+                */
+               struct bt_object *parent = obj->parent;
+
+#ifdef BT_LOGV
+               BT_LOGV("Releasing parented object: addr=%p, ref-count=%llu, "
+                       "parent-addr=%p, parent-ref-count=%llu",
+                       obj, obj->ref_count,
+                       parent, parent->ref_count);
+#endif
+
+               if (obj->parent_is_owner_listener_func) {
+                       /*
+                        * Object has a chance to destroy itself here
+                        * under certain conditions and notify its
+                        * parent. At this point the parent is
+                        * guaranteed to exist because it's not put yet.
+                        */
+                       obj->parent_is_owner_listener_func(obj);
+               }
+
+               /* The release function will be invoked by the parent. */
+               bt_object_put_no_null_check(parent);
+       } else {
+               bt_object_try_spec_release(obj);
+       }
+}
+
+static inline
+void bt_object_init(struct bt_object *obj, bool is_shared,
+               bt_object_release_func release_func)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(!is_shared || release_func);
+       obj->is_shared = is_shared;
+       obj->release_func = release_func;
+       obj->parent_is_owner_listener_func = NULL;
+       obj->spec_release_func = NULL;
+       obj->parent = NULL;
+       obj->ref_count = 1;
+}
+
+static inline
+void bt_object_init_shared(struct bt_object *obj,
+               bt_object_release_func release_func)
+{
+       bt_object_init(obj, true, release_func);
+}
+
+static inline
+void bt_object_init_unique(struct bt_object *obj)
+{
+       bt_object_init(obj, false, NULL);
+}
+
+static inline
+void bt_object_init_shared_with_parent(struct bt_object *obj,
+               bt_object_release_func spec_release_func)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(spec_release_func);
+       bt_object_init_shared(obj, bt_object_with_parent_release_func);
+       obj->spec_release_func = spec_release_func;
+}
+
+static inline
+void bt_object_set_parent_is_owner_listener_func(struct bt_object *obj,
+               bt_object_parent_is_owner_listener_func func)
+{
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       BT_ASSERT(obj->spec_release_func);
+       ((struct bt_object *) obj)->parent_is_owner_listener_func = func;
+}
+
+static inline
+void bt_object_inc_ref_count(const struct bt_object *c_obj)
+{
+       struct bt_object *obj = (void *) c_obj;
+
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       obj->ref_count++;
+       BT_ASSERT(obj->ref_count != 0);
+}
+
+static inline
+void bt_object_get_no_null_check_no_parent_check(const struct bt_object *c_obj)
+{
+       struct bt_object *obj = (void *) c_obj;
+
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+
+#ifdef BT_LOGV
+       BT_LOGV("Incrementing object's reference count: %llu -> %llu: "
+               "addr=%p, cur-count=%llu, new-count=%llu",
+               obj->ref_count, obj->ref_count + 1,
+               obj, obj->ref_count, obj->ref_count + 1);
+#endif
+
+       bt_object_inc_ref_count(obj);
+}
+
+static inline
+void bt_object_get_no_null_check(const void *c_obj)
+{
+       struct bt_object *obj = (void *) c_obj;
+
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+
+       if (unlikely(obj->parent && bt_object_get_ref_count(obj) == 0)) {
+#ifdef BT_LOGV
+               BT_LOGV("Incrementing object's parent's reference count: "
+                       "addr=%p, parent-addr=%p", obj, obj->parent);
+#endif
+
+               bt_object_get_no_null_check(obj->parent);
+       }
+
+#ifdef BT_LOGV
+       BT_LOGV("Incrementing object's reference count: %llu -> %llu: "
+               "addr=%p, cur-count=%llu, new-count=%llu",
+               obj->ref_count, obj->ref_count + 1,
+               obj, obj->ref_count, obj->ref_count + 1);
+#endif
+
+       bt_object_inc_ref_count(obj);
+}
+
+static inline
+void bt_object_put_no_null_check(const void *c_obj)
+{
+       struct bt_object *obj = (void *) c_obj;
+
+       BT_ASSERT(obj);
+       BT_ASSERT(obj->is_shared);
+       BT_ASSERT(obj->ref_count > 0);
+
+#ifdef BT_LOGV
+       BT_LOGV("Decrementing object's reference count: %llu -> %llu: "
+               "addr=%p, cur-count=%llu, new-count=%llu",
+               obj->ref_count, obj->ref_count - 1,
+               obj, obj->ref_count, obj->ref_count - 1);
+#endif
+
+       obj->ref_count--;
+
+       if (obj->ref_count == 0) {
+               BT_ASSERT(obj->release_func);
+               obj->release_func(obj);
+       }
+}
+
+static inline
+void bt_object_get_ref(const void *ptr)
+{
+       struct bt_object *obj = (void *) ptr;
+
+       if (unlikely(!obj)) {
+               return;
+       }
+
+#ifdef BT_ASSERT_PRE
+       BT_ASSERT_PRE(obj->is_shared, "Object is not shared: %!+O", obj);
+#endif
+
+       bt_object_get_no_null_check(obj);
+}
+
+static inline
+void bt_object_put_ref(const void *ptr)
+{
+       struct bt_object *obj = (void *) ptr;
+
+       if (unlikely(!obj)) {
+               return;
+       }
+
+#ifdef BT_ASSERT_PRE
+       BT_ASSERT_PRE(obj->is_shared, "Object is not shared: %!+O", obj);
+       BT_ASSERT_PRE(bt_object_get_ref_count(obj) > 0,
+               "Decrementing a reference count set to 0: %!+O", ptr);
+#endif
+
+       bt_object_put_no_null_check(obj);
+}
+
+#define BT_OBJECT_PUT_REF_AND_RESET(_var)      \
+       do {                                    \
+               bt_object_put_ref(_var);        \
+               (_var) = NULL;                  \
+       } while (0)
+
+#define BT_OBJECT_MOVE_REF(_var_dst, _var_src) \
+       do {                                    \
+               bt_object_put_ref(_var_dst);    \
+               (_var_dst) = (_var_src);        \
+               (_var_src) = NULL;              \
+       } while (0)
+
+#endif /* BABELTRACE_OBJECT_INTERNAL_H */
diff --git a/src/lib/plugin/Makefile.am b/src/lib/plugin/Makefile.am
new file mode 100644 (file)
index 0000000..d3133dd
--- /dev/null
@@ -0,0 +1,8 @@
+noinst_LTLIBRARIES = libplugin.la
+
+# Plug-in system library
+libplugin_la_SOURCES = \
+       plugin.c \
+       plugin.h \
+       plugin-so.c \
+       plugin-so.h
diff --git a/src/lib/plugin/plugin-so.c b/src/lib/plugin/plugin-so.c
new file mode 100644 (file)
index 0000000..621353c
--- /dev/null
@@ -0,0 +1,1620 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-SO"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "compat/compiler.h"
+#include <babeltrace2/plugin/plugin-dev.h>
+#include "lib/graph/component-class.h"
+#include <babeltrace2/graph/component-class.h>
+#include <babeltrace2/graph/component-class-source.h>
+#include <babeltrace2/graph/component-class-filter.h>
+#include <babeltrace2/graph/component-class-sink.h>
+#include <babeltrace2/types.h>
+#include "common/list.h"
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <gmodule.h>
+
+#include "plugin.h"
+#include "plugin-so.h"
+
+#define NATIVE_PLUGIN_SUFFIX           "." G_MODULE_SUFFIX
+#define NATIVE_PLUGIN_SUFFIX_LEN       sizeof(NATIVE_PLUGIN_SUFFIX)
+#define LIBTOOL_PLUGIN_SUFFIX          ".la"
+#define LIBTOOL_PLUGIN_SUFFIX_LEN      sizeof(LIBTOOL_PLUGIN_SUFFIX)
+
+#define PLUGIN_SUFFIX_LEN      max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
+                                       sizeof(LIBTOOL_PLUGIN_SUFFIX))
+
+BT_PLUGIN_MODULE();
+
+/*
+ * This list, global to the library, keeps all component classes that
+ * have a reference to their shared library handles. It allows iteration
+ * on all component classes still present when the destructor executes
+ * to release the shared library handle references they might still have.
+ *
+ * The list items are the component classes created with
+ * bt_plugin_add_component_class(). They keep the shared library handle
+ * object created by their plugin alive so that the plugin's code is
+ * not discarded when it could still be in use by living components
+ * created from those component classes:
+ *
+ *     [component] --ref-> [component class]-> [shlib handle]
+ *
+ * It allows this use-case:
+ *
+ *        my_plugins = bt_plugin_find_all_from_file("/path/to/my-plugin.so");
+ *        // instantiate components from a plugin's component classes
+ *        // put plugins and free my_plugins here
+ *        // user code of instantiated components still exists
+ *
+ * An entry is removed from this list when a component class is
+ * destroyed thanks to a custom destroy listener. When the entry is
+ * removed, the entry is removed from the list, and we release the
+ * reference on the shlib handle. Assuming the original plugin object
+ * which contained some component classes is put first, when the last
+ * component class is removed from this list, the shared library handle
+ * object's reference count falls to zero and the shared library is
+ * finally closed.
+ */
+
+static
+BT_LIST_HEAD(component_class_list);
+
+__attribute__((destructor)) static
+void fini_comp_class_list(void)
+{
+       struct bt_component_class *comp_class, *tmp;
+
+       bt_list_for_each_entry_safe(comp_class, tmp, &component_class_list, node) {
+               bt_list_del(&comp_class->node);
+               BT_OBJECT_PUT_REF_AND_RESET(comp_class->so_handle);
+       }
+
+       BT_LOGD_STR("Released references from all component classes to shared library handles.");
+}
+
+static inline
+const char *bt_self_plugin_status_string(enum bt_self_plugin_status status)
+{
+       switch (status) {
+       case BT_SELF_PLUGIN_STATUS_OK:
+               return "BT_SELF_PLUGIN_STATUS_OK";
+       case BT_SELF_PLUGIN_STATUS_ERROR:
+               return "BT_SELF_PLUGIN_STATUS_ERROR";
+       case BT_SELF_PLUGIN_STATUS_NOMEM:
+               return "BT_SELF_PLUGIN_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+}
+
+static
+void bt_plugin_so_shared_lib_handle_destroy(struct bt_object *obj)
+{
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle;
+
+       BT_ASSERT(obj);
+       shared_lib_handle = container_of(obj,
+               struct bt_plugin_so_shared_lib_handle, base);
+       const char *path = shared_lib_handle->path ?
+               shared_lib_handle->path->str : NULL;
+
+       BT_LOGD("Destroying shared library handle: addr=%p, path=\"%s\"",
+               shared_lib_handle, path);
+
+       if (shared_lib_handle->init_called && shared_lib_handle->exit) {
+               BT_LOGD_STR("Calling user's plugin exit function.");
+               shared_lib_handle->exit();
+               BT_LOGD_STR("User function returned.");
+       }
+
+       if (shared_lib_handle->module) {
+#ifndef NDEBUG
+               /*
+                * Valgrind shows incomplete stack traces when
+                * dynamically loaded libraries are closed before it
+                * finishes. Use the BABELTRACE_NO_DLCLOSE in a debug
+                * build to avoid this.
+                */
+               const char *var = getenv("BABELTRACE_NO_DLCLOSE");
+
+               if (!var || strcmp(var, "1") != 0) {
+#endif
+                       BT_LOGD("Closing GModule: path=\"%s\"", path);
+
+                       if (!g_module_close(shared_lib_handle->module)) {
+                               BT_LOGE("Cannot close GModule: %s: path=\"%s\"",
+                                       g_module_error(), path);
+                       }
+
+                       shared_lib_handle->module = NULL;
+#ifndef NDEBUG
+               } else {
+                       BT_LOGD("Not closing GModule because `BABELTRACE_NO_DLCLOSE=1`: "
+                               "path=\"%s\"", path);
+               }
+#endif
+       }
+
+       if (shared_lib_handle->path) {
+               g_string_free(shared_lib_handle->path, TRUE);
+               shared_lib_handle->path = NULL;
+       }
+
+       g_free(shared_lib_handle);
+}
+
+static
+struct bt_plugin_so_shared_lib_handle *bt_plugin_so_shared_lib_handle_create(
+               const char *path)
+{
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL;
+
+       BT_LOGD("Creating shared library handle: path=\"%s\"", path);
+       shared_lib_handle = g_new0(struct bt_plugin_so_shared_lib_handle, 1);
+       if (!shared_lib_handle) {
+               BT_LOGE_STR("Failed to allocate one shared library handle.");
+               goto error;
+       }
+
+       bt_object_init_shared(&shared_lib_handle->base,
+               bt_plugin_so_shared_lib_handle_destroy);
+
+       if (!path) {
+               goto end;
+       }
+
+       shared_lib_handle->path = g_string_new(path);
+       if (!shared_lib_handle->path) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       shared_lib_handle->module = g_module_open(path, G_MODULE_BIND_LOCAL);
+       if (!shared_lib_handle->module) {
+               /*
+                * DEBUG-level logging because we're only _trying_ to
+                * open this file as a Babeltrace plugin: if it's not,
+                * it's not an error. And because this can be tried
+                * during bt_plugin_find_all_from_dir(), it's not even
+                * a warning.
+                */
+               BT_LOGD("Cannot open GModule: %s: path=\"%s\"",
+                       g_module_error(), path);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle);
+
+end:
+       if (shared_lib_handle) {
+               BT_LOGD("Created shared library handle: path=\"%s\", addr=%p",
+                       path, shared_lib_handle);
+       }
+
+       return shared_lib_handle;
+}
+
+static
+void bt_plugin_so_destroy_spec_data(struct bt_plugin *plugin)
+{
+       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
+
+       if (!plugin->spec_data) {
+               return;
+       }
+
+       BT_ASSERT(plugin->type == BT_PLUGIN_TYPE_SO);
+       BT_ASSERT(spec);
+       BT_OBJECT_PUT_REF_AND_RESET(spec->shared_lib_handle);
+       g_free(plugin->spec_data);
+       plugin->spec_data = NULL;
+}
+
+/*
+ * This function does the following:
+ *
+ * 1. Iterate on the plugin descriptor attributes section and set the
+ *    plugin's attributes depending on the attribute types. This
+ *    includes the name of the plugin, its description, and its
+ *    initialization function, for example.
+ *
+ * 2. Iterate on the component class descriptors section and create one
+ *    "full descriptor" (temporary structure) for each one that is found
+ *    and attached to our plugin descriptor.
+ *
+ * 3. Iterate on the component class descriptor attributes section and
+ *    set the corresponding full descriptor's attributes depending on
+ *    the attribute types. This includes the description of the
+ *    component class, as well as its initialization and destroy
+ *    methods.
+ *
+ * 4. Call the user's plugin initialization function, if any is
+ *    defined.
+ *
+ * 5. For each full component class descriptor, create a component class
+ *    object, set its optional attributes, and add it to the plugin
+ *    object.
+ *
+ * 6. Freeze the plugin object.
+ */
+static
+enum bt_plugin_status bt_plugin_so_init(
+               struct bt_plugin *plugin,
+               const struct __bt_plugin_descriptor *descriptor,
+               struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
+               struct __bt_plugin_descriptor_attribute const * const *attrs_end,
+               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
+               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
+               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
+               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
+{
+       /*
+        * This structure's members point to the plugin's memory
+        * (do NOT free).
+        */
+       struct comp_class_full_descriptor {
+               const struct __bt_plugin_component_class_descriptor *descriptor;
+               const char *description;
+               const char *help;
+
+               union {
+                       struct {
+                               bt_component_class_source_init_method init;
+                               bt_component_class_source_finalize_method finalize;
+                               bt_component_class_source_query_method query;
+                               bt_component_class_source_accept_output_port_connection_method accept_output_port_connection;
+                               bt_component_class_source_output_port_connected_method output_port_connected;
+                               bt_component_class_source_message_iterator_init_method msg_iter_init;
+                               bt_component_class_source_message_iterator_finalize_method msg_iter_finalize;
+                               bt_component_class_source_message_iterator_seek_ns_from_origin_method msg_iter_seek_ns_from_origin;
+                               bt_component_class_source_message_iterator_seek_beginning_method msg_iter_seek_beginning;
+                               bt_component_class_source_message_iterator_can_seek_ns_from_origin_method msg_iter_can_seek_ns_from_origin;
+                               bt_component_class_source_message_iterator_can_seek_beginning_method msg_iter_can_seek_beginning;
+                       } source;
+
+                       struct {
+                               bt_component_class_filter_init_method init;
+                               bt_component_class_filter_finalize_method finalize;
+                               bt_component_class_filter_query_method query;
+                               bt_component_class_filter_accept_input_port_connection_method accept_input_port_connection;
+                               bt_component_class_filter_accept_output_port_connection_method accept_output_port_connection;
+                               bt_component_class_filter_input_port_connected_method input_port_connected;
+                               bt_component_class_filter_output_port_connected_method output_port_connected;
+                               bt_component_class_filter_message_iterator_init_method msg_iter_init;
+                               bt_component_class_filter_message_iterator_finalize_method msg_iter_finalize;
+                               bt_component_class_filter_message_iterator_seek_ns_from_origin_method msg_iter_seek_ns_from_origin;
+                               bt_component_class_filter_message_iterator_seek_beginning_method msg_iter_seek_beginning;
+                               bt_component_class_filter_message_iterator_can_seek_ns_from_origin_method msg_iter_can_seek_ns_from_origin;
+                               bt_component_class_filter_message_iterator_can_seek_beginning_method msg_iter_can_seek_beginning;
+                       } filter;
+
+                       struct {
+                               bt_component_class_sink_init_method init;
+                               bt_component_class_sink_finalize_method finalize;
+                               bt_component_class_sink_query_method query;
+                               bt_component_class_sink_accept_input_port_connection_method accept_input_port_connection;
+                               bt_component_class_sink_input_port_connected_method input_port_connected;
+                               bt_component_class_sink_graph_is_configured_method graph_is_configured;
+                       } sink;
+               } methods;
+       };
+
+       enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
+       struct __bt_plugin_descriptor_attribute const * const *cur_attr_ptr;
+       struct __bt_plugin_component_class_descriptor const * const *cur_cc_descr_ptr;
+       struct __bt_plugin_component_class_descriptor_attribute const * const *cur_cc_descr_attr_ptr;
+       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
+       GArray *comp_class_full_descriptors;
+       size_t i;
+       int ret;
+
+       BT_LOGD("Initializing plugin object from descriptors found in sections: "
+               "plugin-addr=%p, plugin-path=\"%s\", "
+               "attrs-begin-addr=%p, attrs-end-addr=%p, "
+               "cc-descr-begin-addr=%p, cc-descr-end-addr=%p, "
+               "cc-descr-attrs-begin-addr=%p, cc-descr-attrs-end-addr=%p",
+               plugin,
+               spec->shared_lib_handle->path ?
+                       spec->shared_lib_handle->path->str : NULL,
+               attrs_begin, attrs_end,
+               cc_descriptors_begin, cc_descriptors_end,
+               cc_descr_attrs_begin, cc_descr_attrs_end);
+       comp_class_full_descriptors = g_array_new(FALSE, TRUE,
+               sizeof(struct comp_class_full_descriptor));
+       if (!comp_class_full_descriptors) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               status = BT_PLUGIN_STATUS_ERROR;
+               goto end;
+       }
+
+       /* Set mandatory attributes */
+       spec->descriptor = descriptor;
+       bt_plugin_set_name(plugin, descriptor->name);
+
+       /*
+        * Find and set optional attributes attached to this plugin
+        * descriptor.
+        */
+       for (cur_attr_ptr = attrs_begin; cur_attr_ptr != attrs_end; cur_attr_ptr++) {
+               const struct __bt_plugin_descriptor_attribute *cur_attr =
+                       *cur_attr_ptr;
+
+               if (cur_attr == NULL) {
+                       continue;
+               }
+
+               if (cur_attr->plugin_descriptor != descriptor) {
+                       continue;
+               }
+
+               switch (cur_attr->type) {
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_INIT:
+                       spec->init = cur_attr->value.init;
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_EXIT:
+                       spec->shared_lib_handle->exit = cur_attr->value.exit;
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_AUTHOR:
+                       bt_plugin_set_author(plugin, cur_attr->value.author);
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_LICENSE:
+                       bt_plugin_set_license(plugin, cur_attr->value.license);
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
+                       bt_plugin_set_description(plugin, cur_attr->value.description);
+                       break;
+               case BT_PLUGIN_DESCRIPTOR_ATTRIBUTE_TYPE_VERSION:
+                       bt_plugin_set_version(plugin,
+                               (unsigned int) cur_attr->value.version.major,
+                               (unsigned int) cur_attr->value.version.minor,
+                               (unsigned int) cur_attr->value.version.patch,
+                               cur_attr->value.version.extra);
+                       break;
+               default:
+                       /*
+                        * WARN-level logging because this should not
+                        * happen with the appropriate ABI version. If
+                        * we're here, we know that for the reported
+                        * version of the ABI, this attribute is
+                        * unknown.
+                        */
+                       BT_LOGW("Ignoring unknown plugin descriptor attribute: "
+                               "plugin-path=\"%s\", plugin-name=\"%s\", "
+                               "attr-type-name=\"%s\", attr-type-id=%d",
+                               spec->shared_lib_handle->path ?
+                                       spec->shared_lib_handle->path->str :
+                                       NULL,
+                               descriptor->name, cur_attr->type_name,
+                               cur_attr->type);
+                       break;
+               }
+       }
+
+       /*
+        * Find component class descriptors attached to this plugin
+        * descriptor and initialize corresponding full component class
+        * descriptors in the array.
+        */
+       for (cur_cc_descr_ptr = cc_descriptors_begin; cur_cc_descr_ptr != cc_descriptors_end; cur_cc_descr_ptr++) {
+               const struct __bt_plugin_component_class_descriptor *cur_cc_descr =
+                       *cur_cc_descr_ptr;
+               struct comp_class_full_descriptor full_descriptor = {0};
+
+               if (cur_cc_descr == NULL) {
+                       continue;
+               }
+
+               if (cur_cc_descr->plugin_descriptor != descriptor) {
+                       continue;
+               }
+
+               full_descriptor.descriptor = cur_cc_descr;
+               g_array_append_val(comp_class_full_descriptors,
+                       full_descriptor);
+       }
+
+       /*
+        * Find component class descriptor attributes attached to this
+        * plugin descriptor and update corresponding full component
+        * class descriptors in the array.
+        */
+       for (cur_cc_descr_attr_ptr = cc_descr_attrs_begin; cur_cc_descr_attr_ptr != cc_descr_attrs_end; cur_cc_descr_attr_ptr++) {
+               const struct __bt_plugin_component_class_descriptor_attribute *cur_cc_descr_attr =
+                       *cur_cc_descr_attr_ptr;
+               enum bt_component_class_type cc_type;
+
+               if (cur_cc_descr_attr == NULL) {
+                       continue;
+               }
+
+               if (cur_cc_descr_attr->comp_class_descriptor->plugin_descriptor !=
+                               descriptor) {
+                       continue;
+               }
+
+               cc_type = cur_cc_descr_attr->comp_class_descriptor->type;
+
+               /* Find the corresponding component class descriptor entry */
+               for (i = 0; i < comp_class_full_descriptors->len; i++) {
+                       struct comp_class_full_descriptor *cc_full_descr =
+                               &g_array_index(comp_class_full_descriptors,
+                                       struct comp_class_full_descriptor, i);
+
+                       if (cur_cc_descr_attr->comp_class_descriptor !=
+                                       cc_full_descr->descriptor) {
+                               continue;
+                       }
+
+                       switch (cur_cc_descr_attr->type) {
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_DESCRIPTION:
+                               cc_full_descr->description =
+                                       cur_cc_descr_attr->value.description;
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_HELP:
+                               cc_full_descr->help =
+                                       cur_cc_descr_attr->value.help;
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INIT_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.init =
+                                               cur_cc_descr_attr->value.source_init_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.init =
+                                               cur_cc_descr_attr->value.filter_init_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_SINK:
+                                       cc_full_descr->methods.sink.init =
+                                               cur_cc_descr_attr->value.sink_init_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_FINALIZE_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.finalize =
+                                               cur_cc_descr_attr->value.source_finalize_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.finalize =
+                                               cur_cc_descr_attr->value.filter_finalize_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_SINK:
+                                       cc_full_descr->methods.sink.finalize =
+                                               cur_cc_descr_attr->value.sink_finalize_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_QUERY_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.query =
+                                               cur_cc_descr_attr->value.source_query_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.query =
+                                               cur_cc_descr_attr->value.filter_query_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_SINK:
+                                       cc_full_descr->methods.sink.query =
+                                               cur_cc_descr_attr->value.sink_query_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_ACCEPT_INPUT_PORT_CONNECTION_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.accept_input_port_connection =
+                                               cur_cc_descr_attr->value.filter_accept_input_port_connection_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_SINK:
+                                       cc_full_descr->methods.sink.accept_input_port_connection =
+                                               cur_cc_descr_attr->value.sink_accept_input_port_connection_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_ACCEPT_OUTPUT_PORT_CONNECTION_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.accept_output_port_connection =
+                                               cur_cc_descr_attr->value.source_accept_output_port_connection_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.accept_output_port_connection =
+                                               cur_cc_descr_attr->value.filter_accept_output_port_connection_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_INPUT_PORT_CONNECTED_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.input_port_connected =
+                                               cur_cc_descr_attr->value.filter_input_port_connected_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_SINK:
+                                       cc_full_descr->methods.sink.input_port_connected =
+                                               cur_cc_descr_attr->value.sink_input_port_connected_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_OUTPUT_PORT_CONNECTED_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.output_port_connected =
+                                               cur_cc_descr_attr->value.source_output_port_connected_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.output_port_connected =
+                                               cur_cc_descr_attr->value.filter_output_port_connected_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_GRAPH_IS_CONFIGURED_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SINK:
+                                       cc_full_descr->methods.sink.graph_is_configured =
+                                               cur_cc_descr_attr->value.sink_graph_is_configured_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_INIT_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.msg_iter_init =
+                                               cur_cc_descr_attr->value.source_msg_iter_init_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.msg_iter_init =
+                                               cur_cc_descr_attr->value.filter_msg_iter_init_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_FINALIZE_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.msg_iter_finalize =
+                                               cur_cc_descr_attr->value.source_msg_iter_finalize_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.msg_iter_finalize =
+                                               cur_cc_descr_attr->value.filter_msg_iter_finalize_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_SEEK_NS_FROM_ORIGIN_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.msg_iter_seek_ns_from_origin =
+                                               cur_cc_descr_attr->value.source_msg_iter_seek_ns_from_origin_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.msg_iter_seek_ns_from_origin =
+                                               cur_cc_descr_attr->value.filter_msg_iter_seek_ns_from_origin_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_SEEK_BEGINNING_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.msg_iter_seek_beginning =
+                                               cur_cc_descr_attr->value.source_msg_iter_seek_beginning_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.msg_iter_seek_beginning =
+                                               cur_cc_descr_attr->value.filter_msg_iter_seek_beginning_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_CAN_SEEK_NS_FROM_ORIGIN_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.msg_iter_can_seek_ns_from_origin =
+                                               cur_cc_descr_attr->value.source_msg_iter_can_seek_ns_from_origin_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.msg_iter_can_seek_ns_from_origin =
+                                               cur_cc_descr_attr->value.filter_msg_iter_can_seek_ns_from_origin_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       case BT_PLUGIN_COMPONENT_CLASS_DESCRIPTOR_ATTRIBUTE_TYPE_MSG_ITER_CAN_SEEK_BEGINNING_METHOD:
+                               switch (cc_type) {
+                               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                                       cc_full_descr->methods.source.msg_iter_can_seek_beginning =
+                                               cur_cc_descr_attr->value.source_msg_iter_can_seek_beginning_method;
+                                       break;
+                               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                                       cc_full_descr->methods.filter.msg_iter_can_seek_beginning =
+                                               cur_cc_descr_attr->value.filter_msg_iter_can_seek_beginning_method;
+                                       break;
+                               default:
+                                       abort();
+                               }
+                               break;
+                       default:
+                               /*
+                                * WARN-level logging because this
+                                * should not happen with the
+                                * appropriate ABI version. If we're
+                                * here, we know that for the reported
+                                * version of the ABI, this attribute is
+                                * unknown.
+                                */
+                               BT_LOGW("Ignoring unknown component class descriptor attribute: "
+                                       "plugin-path=\"%s\", "
+                                       "plugin-name=\"%s\", "
+                                       "comp-class-name=\"%s\", "
+                                       "comp-class-type=%s, "
+                                       "attr-type-name=\"%s\", "
+                                       "attr-type-id=%d",
+                                       spec->shared_lib_handle->path ?
+                                               spec->shared_lib_handle->path->str :
+                                               NULL,
+                                       descriptor->name,
+                                       cur_cc_descr_attr->comp_class_descriptor->name,
+                                       bt_component_class_type_string(
+                                               cur_cc_descr_attr->comp_class_descriptor->type),
+                                       cur_cc_descr_attr->type_name,
+                                       cur_cc_descr_attr->type);
+                               break;
+                       }
+               }
+       }
+
+       /* Initialize plugin */
+       if (spec->init) {
+               enum bt_self_plugin_status init_status;
+
+               BT_LOGD_STR("Calling user's plugin initialization function.");
+               init_status = spec->init((void *) plugin);
+               BT_LOGD("User function returned: %s",
+                       bt_self_plugin_status_string(init_status));
+
+               if (init_status < 0) {
+                       BT_LOGW_STR("User's plugin initialization function failed.");
+                       status = BT_PLUGIN_STATUS_ERROR;
+                       goto end;
+               }
+       }
+
+       spec->shared_lib_handle->init_called = BT_TRUE;
+
+       /* Add described component classes to plugin */
+       for (i = 0; i < comp_class_full_descriptors->len; i++) {
+               struct comp_class_full_descriptor *cc_full_descr =
+                       &g_array_index(comp_class_full_descriptors,
+                               struct comp_class_full_descriptor, i);
+               struct bt_component_class *comp_class = NULL;
+               struct bt_component_class_source *src_comp_class = NULL;
+               struct bt_component_class_filter *flt_comp_class = NULL;
+               struct bt_component_class_sink *sink_comp_class = NULL;
+
+               BT_LOGD("Creating and setting properties of plugin's component class: "
+                       "plugin-path=\"%s\", plugin-name=\"%s\", "
+                       "comp-class-name=\"%s\", comp-class-type=%s",
+                       spec->shared_lib_handle->path ?
+                               spec->shared_lib_handle->path->str :
+                               NULL,
+                       descriptor->name,
+                       cc_full_descr->descriptor->name,
+                       bt_component_class_type_string(
+                               cc_full_descr->descriptor->type));
+
+               switch (cc_full_descr->descriptor->type) {
+               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                       src_comp_class = bt_component_class_source_create(
+                               cc_full_descr->descriptor->name,
+                               cc_full_descr->descriptor->methods.source.msg_iter_next);
+                       comp_class = bt_component_class_source_as_component_class(
+                               src_comp_class);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       flt_comp_class = bt_component_class_filter_create(
+                               cc_full_descr->descriptor->name,
+                               cc_full_descr->descriptor->methods.source.msg_iter_next);
+                       comp_class = bt_component_class_filter_as_component_class(
+                               flt_comp_class);
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       sink_comp_class = bt_component_class_sink_create(
+                               cc_full_descr->descriptor->name,
+                               cc_full_descr->descriptor->methods.sink.consume);
+                       comp_class = bt_component_class_sink_as_component_class(
+                               sink_comp_class);
+                       break;
+               default:
+                       /*
+                        * WARN-level logging because this should not
+                        * happen with the appropriate ABI version. If
+                        * we're here, we know that for the reported
+                        * version of the ABI, this component class type
+                        * is unknown.
+                        */
+                       BT_LOGW("Ignoring unknown component class type: "
+                               "plugin-path=\"%s\", plugin-name=\"%s\", "
+                               "comp-class-name=\"%s\", comp-class-type=%d",
+                               spec->shared_lib_handle->path->str ?
+                                       spec->shared_lib_handle->path->str :
+                                       NULL,
+                               descriptor->name,
+                               cc_full_descr->descriptor->name,
+                               cc_full_descr->descriptor->type);
+                       continue;
+               }
+
+               if (!comp_class) {
+                       BT_LOGE_STR("Cannot create component class.");
+                       status = BT_PLUGIN_STATUS_ERROR;
+                       goto end;
+               }
+
+               if (cc_full_descr->description) {
+                       ret = bt_component_class_set_description(
+                               comp_class, cc_full_descr->description);
+                       if (ret) {
+                               BT_LOGE_STR("Cannot set component class's description.");
+                               status = BT_PLUGIN_STATUS_ERROR;
+                               BT_OBJECT_PUT_REF_AND_RESET(comp_class);
+                               goto end;
+                       }
+               }
+
+               if (cc_full_descr->help) {
+                       ret = bt_component_class_set_help(comp_class,
+                               cc_full_descr->help);
+                       if (ret) {
+                               BT_LOGE_STR("Cannot set component class's help string.");
+                               status = BT_PLUGIN_STATUS_ERROR;
+                               BT_OBJECT_PUT_REF_AND_RESET(comp_class);
+                               goto end;
+                       }
+               }
+
+               switch (cc_full_descr->descriptor->type) {
+               case BT_COMPONENT_CLASS_TYPE_SOURCE:
+                       if (cc_full_descr->methods.source.init) {
+                               ret = bt_component_class_source_set_init_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.init);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's initialization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.finalize) {
+                               ret = bt_component_class_source_set_finalize_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.finalize);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's finalization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.query) {
+                               ret = bt_component_class_source_set_query_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.query);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's query method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.accept_output_port_connection) {
+                               ret = bt_component_class_source_set_accept_output_port_connection_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.accept_output_port_connection);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's \"accept input output connection\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.output_port_connected) {
+                               ret = bt_component_class_source_set_output_port_connected_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.output_port_connected);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's \"output port connected\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.msg_iter_init) {
+                               ret = bt_component_class_source_set_message_iterator_init_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.msg_iter_init);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's message iterator initialization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.msg_iter_finalize) {
+                               ret = bt_component_class_source_set_message_iterator_finalize_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.msg_iter_finalize);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's message iterator finalization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.msg_iter_seek_ns_from_origin) {
+                               ret = bt_component_class_source_set_message_iterator_seek_ns_from_origin_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.msg_iter_seek_ns_from_origin);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's message iterator \"seek nanoseconds from origin\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.msg_iter_seek_beginning) {
+                               ret = bt_component_class_source_set_message_iterator_seek_beginning_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.msg_iter_seek_beginning);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's message iterator \"seek beginning\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.msg_iter_can_seek_ns_from_origin) {
+                               ret = bt_component_class_source_set_message_iterator_can_seek_ns_from_origin_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.msg_iter_can_seek_ns_from_origin);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's message iterator \"can seek nanoseconds from origin\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.source.msg_iter_can_seek_beginning) {
+                               ret = bt_component_class_source_set_message_iterator_can_seek_beginning_method(
+                                       src_comp_class,
+                                       cc_full_descr->methods.source.msg_iter_can_seek_beginning);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set source component class's message iterator \"can seek beginning\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(src_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_FILTER:
+                       if (cc_full_descr->methods.filter.init) {
+                               ret = bt_component_class_filter_set_init_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.init);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's initialization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.finalize) {
+                               ret = bt_component_class_filter_set_finalize_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.finalize);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's finalization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.query) {
+                               ret = bt_component_class_filter_set_query_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.query);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's query method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.accept_input_port_connection) {
+                               ret = bt_component_class_filter_set_accept_input_port_connection_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.accept_input_port_connection);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's \"accept input port connection\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.accept_output_port_connection) {
+                               ret = bt_component_class_filter_set_accept_output_port_connection_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.accept_output_port_connection);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's \"accept input output connection\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.input_port_connected) {
+                               ret = bt_component_class_filter_set_input_port_connected_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.input_port_connected);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's \"input port connected\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.output_port_connected) {
+                               ret = bt_component_class_filter_set_output_port_connected_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.output_port_connected);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's \"output port connected\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.msg_iter_init) {
+                               ret = bt_component_class_filter_set_message_iterator_init_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.msg_iter_init);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's message iterator initialization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.msg_iter_finalize) {
+                               ret = bt_component_class_filter_set_message_iterator_finalize_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.msg_iter_finalize);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's message iterator finalization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.msg_iter_seek_ns_from_origin) {
+                               ret = bt_component_class_filter_set_message_iterator_seek_ns_from_origin_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.msg_iter_seek_ns_from_origin);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's message iterator \"seek nanoseconds from origin\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.msg_iter_seek_beginning) {
+                               ret = bt_component_class_filter_set_message_iterator_seek_beginning_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.msg_iter_seek_beginning);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's message iterator \"seek beginning\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.msg_iter_can_seek_ns_from_origin) {
+                               ret = bt_component_class_filter_set_message_iterator_can_seek_ns_from_origin_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.msg_iter_can_seek_ns_from_origin);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's message iterator \"can seek nanoseconds from origin\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.filter.msg_iter_can_seek_beginning) {
+                               ret = bt_component_class_filter_set_message_iterator_can_seek_beginning_method(
+                                       flt_comp_class,
+                                       cc_full_descr->methods.filter.msg_iter_can_seek_beginning);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set filter component class's message iterator \"can seek beginning\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(flt_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       break;
+               case BT_COMPONENT_CLASS_TYPE_SINK:
+                       if (cc_full_descr->methods.sink.init) {
+                               ret = bt_component_class_sink_set_init_method(
+                                       sink_comp_class,
+                                       cc_full_descr->methods.sink.init);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set sink component class's initialization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.sink.finalize) {
+                               ret = bt_component_class_sink_set_finalize_method(
+                                       sink_comp_class,
+                                       cc_full_descr->methods.sink.finalize);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set sink component class's finalization method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.sink.query) {
+                               ret = bt_component_class_sink_set_query_method(
+                                       sink_comp_class,
+                                       cc_full_descr->methods.sink.query);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set sink component class's query method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.sink.accept_input_port_connection) {
+                               ret = bt_component_class_sink_set_accept_input_port_connection_method(
+                                       sink_comp_class,
+                                       cc_full_descr->methods.sink.accept_input_port_connection);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set sink component class's \"accept input port connection\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.sink.input_port_connected) {
+                               ret = bt_component_class_sink_set_input_port_connected_method(
+                                       sink_comp_class,
+                                       cc_full_descr->methods.sink.input_port_connected);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set sink component class's \"input port connected\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       if (cc_full_descr->methods.sink.graph_is_configured) {
+                               ret = bt_component_class_sink_set_graph_is_configured_method(
+                                       sink_comp_class,
+                                       cc_full_descr->methods.sink.graph_is_configured);
+                               if (ret) {
+                                       BT_LOGE_STR("Cannot set sink component class's \"graph is configured\" method.");
+                                       status = BT_PLUGIN_STATUS_ERROR;
+                                       BT_OBJECT_PUT_REF_AND_RESET(sink_comp_class);
+                                       goto end;
+                               }
+                       }
+
+                       break;
+               default:
+                       abort();
+               }
+
+               /*
+                * Add component class to the plugin object.
+                *
+                * This will call back
+                * bt_plugin_so_on_add_component_class() so that we can
+                * add a mapping in the component class list when we
+                * know the component class is successfully added.
+                */
+               status = bt_plugin_add_component_class(plugin,
+                       (void *) comp_class);
+               BT_OBJECT_PUT_REF_AND_RESET(comp_class);
+               if (status < 0) {
+                       BT_LOGE("Cannot add component class to plugin.");
+                       goto end;
+               }
+       }
+
+end:
+       g_array_free(comp_class_full_descriptors, TRUE);
+       return status;
+}
+
+static
+struct bt_plugin *bt_plugin_so_create_empty(
+               struct bt_plugin_so_shared_lib_handle *shared_lib_handle)
+{
+       struct bt_plugin *plugin;
+       struct bt_plugin_so_spec_data *spec;
+
+       plugin = bt_plugin_create_empty(BT_PLUGIN_TYPE_SO);
+       if (!plugin) {
+               goto error;
+       }
+
+       plugin->destroy_spec_data = bt_plugin_so_destroy_spec_data;
+       plugin->spec_data = g_new0(struct bt_plugin_so_spec_data, 1);
+       if (!plugin->spec_data) {
+               BT_LOGE_STR("Failed to allocate one SO plugin specific data structure.");
+               goto error;
+       }
+
+       spec = plugin->spec_data;
+       spec->shared_lib_handle = shared_lib_handle;
+       bt_object_get_no_null_check(spec->shared_lib_handle);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(plugin);
+
+end:
+       return plugin;
+}
+
+static
+size_t count_non_null_items_in_section(const void *begin, const void *end)
+{
+       size_t count = 0;
+       const int * const *begin_int = (const int * const *) begin;
+       const int * const *end_int = (const int * const *) end;
+       const int * const *iter;
+
+       for (iter = begin_int; iter != end_int; iter++) {
+               if (*iter) {
+                       count++;
+               }
+       }
+
+       return count;
+}
+
+static
+struct bt_plugin_set *bt_plugin_so_create_all_from_sections(
+               struct bt_plugin_so_shared_lib_handle *shared_lib_handle,
+               struct __bt_plugin_descriptor const * const *descriptors_begin,
+               struct __bt_plugin_descriptor const * const *descriptors_end,
+               struct __bt_plugin_descriptor_attribute const * const *attrs_begin,
+               struct __bt_plugin_descriptor_attribute const * const *attrs_end,
+               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin,
+               struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end,
+               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin,
+               struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end)
+{
+       size_t descriptor_count;
+       size_t attrs_count;
+       size_t cc_descriptors_count;
+       size_t cc_descr_attrs_count;
+       size_t i;
+       struct bt_plugin_set *plugin_set = NULL;
+
+       descriptor_count = count_non_null_items_in_section(descriptors_begin, descriptors_end);
+       attrs_count = count_non_null_items_in_section(attrs_begin, attrs_end);
+       cc_descriptors_count = count_non_null_items_in_section(cc_descriptors_begin, cc_descriptors_end);
+       cc_descr_attrs_count =  count_non_null_items_in_section(cc_descr_attrs_begin, cc_descr_attrs_end);
+
+       BT_LOGD("Creating all SO plugins from sections: "
+               "plugin-path=\"%s\", "
+               "descr-begin-addr=%p, descr-end-addr=%p, "
+               "attrs-begin-addr=%p, attrs-end-addr=%p, "
+               "cc-descr-begin-addr=%p, cc-descr-end-addr=%p, "
+               "cc-descr-attrs-begin-addr=%p, cc-descr-attrs-end-addr=%p, "
+               "descr-count=%zu, attrs-count=%zu, "
+               "cc-descr-count=%zu, cc-descr-attrs-count=%zu",
+               shared_lib_handle->path ? shared_lib_handle->path->str : NULL,
+               descriptors_begin, descriptors_end,
+               attrs_begin, attrs_end,
+               cc_descriptors_begin, cc_descriptors_end,
+               cc_descr_attrs_begin, cc_descr_attrs_end,
+               descriptor_count, attrs_count,
+               cc_descriptors_count, cc_descr_attrs_count);
+       plugin_set = bt_plugin_set_create();
+       if (!plugin_set) {
+               BT_LOGE_STR("Cannot create empty plugin set.");
+               goto error;
+       }
+
+       for (i = 0; i < descriptors_end - descriptors_begin; i++) {
+               enum bt_plugin_status status;
+               const struct __bt_plugin_descriptor *descriptor =
+                       descriptors_begin[i];
+               struct bt_plugin *plugin;
+
+               if (descriptor == NULL) {
+                       continue;
+               }
+
+               BT_LOGD("Creating plugin object for plugin: "
+                       "name=\"%s\", abi-major=%d, abi-minor=%d",
+                       descriptor->name, descriptor->major, descriptor->minor);
+
+               if (descriptor->major > __BT_PLUGIN_VERSION_MAJOR) {
+                       /*
+                        * DEBUG-level logging because we're only
+                        * _trying_ to open this file as a compatible
+                        * Babeltrace plugin: if it's not, it's not an
+                        * error. And because this can be tried during
+                        * bt_plugin_find_all_from_dir(), it's not
+                        * even a warning.
+                        */
+                       BT_LOGD("Unknown ABI major version: abi-major=%d",
+                               descriptor->major);
+                       goto error;
+               }
+
+               plugin = bt_plugin_so_create_empty(shared_lib_handle);
+               if (!plugin) {
+                       BT_LOGE_STR("Cannot create empty shared library handle.");
+                       goto error;
+               }
+
+               if (shared_lib_handle && shared_lib_handle->path) {
+                       bt_plugin_set_path(plugin, shared_lib_handle->path->str);
+               }
+
+               status = bt_plugin_so_init(plugin, descriptor, attrs_begin,
+                       attrs_end, cc_descriptors_begin, cc_descriptors_end,
+                       cc_descr_attrs_begin, cc_descr_attrs_end);
+               if (status < 0) {
+                       /*
+                        * DEBUG-level logging because we're only
+                        * _trying_ to open this file as a compatible
+                        * Babeltrace plugin: if it's not, it's not an
+                        * error. And because this can be tried during
+                        * bt_plugin_find_all_from_dir(), it's not
+                        * even a warning.
+                        */
+                       BT_LOGD_STR("Cannot initialize SO plugin object from sections.");
+                       BT_OBJECT_PUT_REF_AND_RESET(plugin);
+                       goto error;
+               }
+
+               /* Add to plugin set */
+               bt_plugin_set_add_plugin(plugin_set, plugin);
+               bt_object_put_ref(plugin);
+       }
+
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
+
+end:
+       return plugin_set;
+}
+
+BT_HIDDEN
+struct bt_plugin_set *bt_plugin_so_create_all_from_static(void)
+{
+       struct bt_plugin_set *plugin_set = NULL;
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle =
+               bt_plugin_so_shared_lib_handle_create(NULL);
+
+       if (!shared_lib_handle) {
+               goto end;
+       }
+
+       BT_LOGD_STR("Creating all SO plugins from built-in plugins.");
+       plugin_set = bt_plugin_so_create_all_from_sections(shared_lib_handle,
+               __bt_get_begin_section_plugin_descriptors(),
+               __bt_get_end_section_plugin_descriptors(),
+               __bt_get_begin_section_plugin_descriptor_attributes(),
+               __bt_get_end_section_plugin_descriptor_attributes(),
+               __bt_get_begin_section_component_class_descriptors(),
+               __bt_get_end_section_component_class_descriptors(),
+               __bt_get_begin_section_component_class_descriptor_attributes(),
+               __bt_get_end_section_component_class_descriptor_attributes());
+
+end:
+       BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle);
+
+       return plugin_set;
+}
+
+BT_HIDDEN
+struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path)
+{
+       size_t path_len;
+       struct bt_plugin_set *plugin_set = NULL;
+       struct __bt_plugin_descriptor const * const *descriptors_begin = NULL;
+       struct __bt_plugin_descriptor const * const *descriptors_end = NULL;
+       struct __bt_plugin_descriptor_attribute const * const *attrs_begin = NULL;
+       struct __bt_plugin_descriptor_attribute const * const *attrs_end = NULL;
+       struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_begin = NULL;
+       struct __bt_plugin_component_class_descriptor const * const *cc_descriptors_end = NULL;
+       struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_begin = NULL;
+       struct __bt_plugin_component_class_descriptor_attribute const * const *cc_descr_attrs_end = NULL;
+       struct __bt_plugin_descriptor const * const *(*get_begin_section_plugin_descriptors)(void);
+       struct __bt_plugin_descriptor const * const *(*get_end_section_plugin_descriptors)(void);
+       struct __bt_plugin_descriptor_attribute const * const *(*get_begin_section_plugin_descriptor_attributes)(void);
+       struct __bt_plugin_descriptor_attribute const * const *(*get_end_section_plugin_descriptor_attributes)(void);
+       struct __bt_plugin_component_class_descriptor const * const *(*get_begin_section_component_class_descriptors)(void);
+       struct __bt_plugin_component_class_descriptor const * const *(*get_end_section_component_class_descriptors)(void);
+       struct __bt_plugin_component_class_descriptor_attribute const * const *(*get_begin_section_component_class_descriptor_attributes)(void);
+       struct __bt_plugin_component_class_descriptor_attribute const * const *(*get_end_section_component_class_descriptor_attributes)(void);
+       bt_bool is_libtool_wrapper = BT_FALSE, is_shared_object = BT_FALSE;
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle = NULL;
+
+       if (!path) {
+               BT_LOGW_STR("Invalid parameter: path is NULL.");
+               goto end;
+       }
+
+       BT_LOGD("Creating all SO plugins from file: path=\"%s\"", path);
+       path_len = strlen(path);
+       if (path_len <= PLUGIN_SUFFIX_LEN) {
+               BT_LOGW("Invalid parameter: path length is too short: "
+                       "path-length=%zu", path_len);
+               goto end;
+       }
+
+       path_len++;
+       /*
+        * Check if the file ends with a known plugin file type suffix (i.e. .so
+        * or .la on Linux).
+        */
+       is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
+               path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
+               LIBTOOL_PLUGIN_SUFFIX_LEN);
+       is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
+               path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
+               NATIVE_PLUGIN_SUFFIX_LEN);
+       if (!is_shared_object && !is_libtool_wrapper) {
+               /* Name indicates this is not a plugin file; not an error */
+               BT_LOGV("File is not a SO plugin file: path=\"%s\"", path);
+               goto end;
+       }
+
+       shared_lib_handle = bt_plugin_so_shared_lib_handle_create(path);
+       if (!shared_lib_handle) {
+               BT_LOGD_STR("Cannot create shared library handle.");
+               goto end;
+       }
+
+       if (g_module_symbol(shared_lib_handle->module, "__bt_get_begin_section_plugin_descriptors",
+                       (gpointer *) &get_begin_section_plugin_descriptors)) {
+               descriptors_begin = get_begin_section_plugin_descriptors();
+       } else {
+               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
+                       "symbol=\"%s\"", path,
+                       "__bt_get_begin_section_plugin_descriptors");
+               goto end;
+       }
+
+       if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_plugin_descriptors",
+                       (gpointer *) &get_end_section_plugin_descriptors)) {
+               descriptors_end = get_end_section_plugin_descriptors();
+       } else {
+               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
+                       "symbol=\"%s\"", path,
+                       "__bt_get_end_section_plugin_descriptors");
+               goto end;
+       }
+
+       if (g_module_symbol(shared_lib_handle->module, "__bt_get_begin_section_plugin_descriptor_attributes",
+                       (gpointer *) &get_begin_section_plugin_descriptor_attributes)) {
+                attrs_begin = get_begin_section_plugin_descriptor_attributes();
+       } else {
+               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
+                       "symbol=\"%s\"", path,
+                       "__bt_get_begin_section_plugin_descriptor_attributes");
+       }
+
+       if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_plugin_descriptor_attributes",
+                       (gpointer *) &get_end_section_plugin_descriptor_attributes)) {
+               attrs_end = get_end_section_plugin_descriptor_attributes();
+       } else {
+               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
+                       "symbol=\"%s\"", path,
+                       "__bt_get_end_section_plugin_descriptor_attributes");
+       }
+
+       if ((!!attrs_begin - !!attrs_end) != 0) {
+               BT_LOGD("Found section start or end symbol, but not both: "
+                       "path=\"%s\", symbol-start=\"%s\", "
+                       "symbol-end=\"%s\", symbol-start-addr=%p, "
+                       "symbol-end-addr=%p",
+                       path, "__bt_get_begin_section_plugin_descriptor_attributes",
+                       "__bt_get_end_section_plugin_descriptor_attributes",
+                       attrs_begin, attrs_end);
+               goto end;
+       }
+
+       if (g_module_symbol(shared_lib_handle->module, "__bt_get_begin_section_component_class_descriptors",
+                       (gpointer *) &get_begin_section_component_class_descriptors)) {
+               cc_descriptors_begin = get_begin_section_component_class_descriptors();
+       } else {
+               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
+                       "symbol=\"%s\"", path,
+                       "__bt_get_begin_section_component_class_descriptors");
+       }
+
+       if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_component_class_descriptors",
+                       (gpointer *) &get_end_section_component_class_descriptors)) {
+               cc_descriptors_end = get_end_section_component_class_descriptors();
+       } else {
+               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
+                       "symbol=\"%s\"", path,
+                       "__bt_get_end_section_component_class_descriptors");
+       }
+
+       if ((!!cc_descriptors_begin - !!cc_descriptors_end) != 0) {
+               BT_LOGD("Found section start or end symbol, but not both: "
+                       "path=\"%s\", symbol-start=\"%s\", "
+                       "symbol-end=\"%s\", symbol-start-addr=%p, "
+                       "symbol-end-addr=%p",
+                       path, "__bt_get_begin_section_component_class_descriptors",
+                       "__bt_get_end_section_component_class_descriptors",
+                       cc_descriptors_begin, cc_descriptors_end);
+               goto end;
+       }
+
+       if (g_module_symbol(shared_lib_handle->module, "__bt_get_begin_section_component_class_descriptor_attributes",
+                       (gpointer *) &get_begin_section_component_class_descriptor_attributes)) {
+               cc_descr_attrs_begin = get_begin_section_component_class_descriptor_attributes();
+       } else {
+               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
+                       "symbol=\"%s\"", path,
+                       "__bt_get_begin_section_component_class_descriptor_attributes");
+       }
+
+       if (g_module_symbol(shared_lib_handle->module, "__bt_get_end_section_component_class_descriptor_attributes",
+                       (gpointer *) &get_end_section_component_class_descriptor_attributes)) {
+               cc_descr_attrs_end = get_end_section_component_class_descriptor_attributes();
+       } else {
+               BT_LOGD("Cannot resolve plugin symbol: path=\"%s\", "
+                       "symbol=\"%s\"", path,
+                       "__bt_get_end_section_component_class_descriptor_attributes");
+       }
+
+       if ((!!cc_descr_attrs_begin - !!cc_descr_attrs_end) != 0) {
+               BT_LOGD("Found section start or end symbol, but not both: "
+                       "path=\"%s\", symbol-start=\"%s\", "
+                       "symbol-end=\"%s\", symbol-start-addr=%p, "
+                       "symbol-end-addr=%p",
+                       path, "__bt_get_begin_section_component_class_descriptor_attributes",
+                       "__bt_get_end_section_component_class_descriptor_attributes",
+                       cc_descr_attrs_begin, cc_descr_attrs_end);
+               goto end;
+       }
+
+       /* Initialize plugin */
+       BT_LOGD_STR("Initializing plugin object.");
+       plugin_set = bt_plugin_so_create_all_from_sections(shared_lib_handle,
+               descriptors_begin, descriptors_end, attrs_begin, attrs_end,
+               cc_descriptors_begin, cc_descriptors_end,
+               cc_descr_attrs_begin, cc_descr_attrs_end);
+
+end:
+       BT_OBJECT_PUT_REF_AND_RESET(shared_lib_handle);
+       return plugin_set;
+}
+
+static
+void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class,
+               void *data)
+{
+       bt_list_del(&comp_class->node);
+       BT_OBJECT_PUT_REF_AND_RESET(comp_class->so_handle);
+       BT_LOGV("Component class destroyed: removed entry from list: "
+               "comp-cls-addr=%p", comp_class);
+}
+
+void bt_plugin_so_on_add_component_class(struct bt_plugin *plugin,
+               struct bt_component_class *comp_class)
+{
+       struct bt_plugin_so_spec_data *spec = plugin->spec_data;
+
+       BT_ASSERT(plugin->spec_data);
+       BT_ASSERT(plugin->type == BT_PLUGIN_TYPE_SO);
+
+       bt_list_add(&comp_class->node, &component_class_list);
+       comp_class->so_handle = spec->shared_lib_handle;
+       bt_object_get_no_null_check(comp_class->so_handle);
+
+       /* Add our custom destroy listener */
+       bt_component_class_add_destroy_listener(comp_class,
+               plugin_comp_class_destroy_listener, NULL);
+}
diff --git a/src/lib/plugin/plugin-so.h b/src/lib/plugin/plugin-so.h
new file mode 100644 (file)
index 0000000..094b87a
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H
+#define BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include <gmodule.h>
+#include <babeltrace2/types.h>
+
+struct bt_plugin;
+struct bt_component_class;
+
+struct bt_plugin_so_shared_lib_handle {
+       struct bt_object base;
+       GString *path;
+       GModule *module;
+
+       /* True if initialization function was called */
+       bt_bool init_called;
+       bt_plugin_exit_func exit;
+};
+
+struct bt_plugin_so_spec_data {
+       /* Shared lib. handle: owned by this */
+       struct bt_plugin_so_shared_lib_handle *shared_lib_handle;
+
+       /* Pointers to plugin's memory: do NOT free */
+       const struct __bt_plugin_descriptor *descriptor;
+       bt_plugin_init_func init;
+       const struct __bt_plugin_descriptor_version *version;
+};
+
+BT_HIDDEN
+struct bt_plugin_set *bt_plugin_so_create_all_from_file(const char *path);
+
+BT_HIDDEN
+struct bt_plugin_set *bt_plugin_so_create_all_from_static(void);
+
+void bt_plugin_so_on_add_component_class(struct bt_plugin *plugin,
+               struct bt_component_class *comp_class);
+
+#endif /* BABELTRACE_PLUGIN_PLUGIN_SO_INTERNAL_H */
diff --git a/src/lib/plugin/plugin.c b/src/lib/plugin/plugin.c
new file mode 100644 (file)
index 0000000..53b783f
--- /dev/null
@@ -0,0 +1,635 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN"
+#include "lib/lib-logging.h"
+
+#include "common/assert.h"
+#include "lib/assert-pre.h"
+#include "common/babeltrace.h"
+#include "compat/compiler.h"
+#include "common/common.h"
+#include <babeltrace2/plugin/plugin-const.h>
+#include <babeltrace2/graph/component-class-const.h>
+#include "lib/graph/component-class.h"
+#include <babeltrace2/types.h>
+#include <glib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <ftw.h>
+#include <pthread.h>
+
+#include "plugin.h"
+#include "plugin-so.h"
+
+#define PYTHON_PLUGIN_PROVIDER_FILENAME        "libbabeltrace2-python-plugin-provider." G_MODULE_SUFFIX
+#define PYTHON_PLUGIN_PROVIDER_SYM_NAME        bt_plugin_python_create_all_from_file
+#define PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR    TOSTRING(PYTHON_PLUGIN_PROVIDER_SYM_NAME)
+
+#define APPEND_ALL_FROM_DIR_NFDOPEN_MAX        8
+
+#ifdef BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT
+#include <plugin/python-plugin-provider.h>
+
+static
+struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path) =
+       bt_plugin_python_create_all_from_file;
+
+static
+void init_python_plugin_provider(void) {}
+#else /* BT_BUILT_IN_PYTHON_PLUGIN_SUPPORT */
+static GModule *python_plugin_provider_module;
+static
+struct bt_plugin_set *(*bt_plugin_python_create_all_from_file_sym)(const char *path);
+
+static
+void init_python_plugin_provider(void) {
+       if (bt_plugin_python_create_all_from_file_sym != NULL) {
+               return;
+       }
+
+       BT_LOGD_STR("Loading Python plugin provider module.");
+       python_plugin_provider_module =
+               g_module_open(PYTHON_PLUGIN_PROVIDER_FILENAME, 0);
+       if (!python_plugin_provider_module) {
+               BT_LOGI("Cannot open `%s`: %s: continuing without Python plugin support.",
+                       PYTHON_PLUGIN_PROVIDER_FILENAME, g_module_error());
+               return;
+       }
+
+       if (!g_module_symbol(python_plugin_provider_module,
+                       PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR,
+                       (gpointer) &bt_plugin_python_create_all_from_file_sym)) {
+               BT_LOGI("Cannot find the Python plugin provider loading symbol: continuing without Python plugin support: "
+                       "file=\"%s\", symbol=\"%s\"",
+                       PYTHON_PLUGIN_PROVIDER_FILENAME,
+                       PYTHON_PLUGIN_PROVIDER_SYM_NAME_STR);
+               return;
+       }
+
+       BT_LOGI("Loaded Python plugin provider module: addr=%p",
+               python_plugin_provider_module);
+}
+
+__attribute__((destructor)) static
+void fini_python_plugin_provider(void) {
+       if (python_plugin_provider_module) {
+               BT_LOGD("Unloading Python plugin provider module.");
+
+               if (!g_module_close(python_plugin_provider_module)) {
+                       BT_LOGE("Failed to close the Python plugin provider module: %s.",
+                               g_module_error());
+               }
+
+               python_plugin_provider_module = NULL;
+       }
+}
+#endif
+
+uint64_t bt_plugin_set_get_plugin_count(struct bt_plugin_set *plugin_set)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin_set, "Plugin set");
+       return (uint64_t) plugin_set->plugins->len;
+}
+
+const struct bt_plugin *bt_plugin_set_borrow_plugin_by_index_const(
+               const struct bt_plugin_set *plugin_set, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin_set, "Plugin set");
+       BT_ASSERT_PRE_VALID_INDEX(index, plugin_set->plugins->len);
+       return g_ptr_array_index(plugin_set->plugins, index);
+}
+
+const struct bt_plugin_set *bt_plugin_find_all_from_static(void)
+{
+       /* bt_plugin_so_create_all_from_static() logs errors */
+       return bt_plugin_so_create_all_from_static();
+}
+
+const struct bt_plugin_set *bt_plugin_find_all_from_file(const char *path)
+{
+       struct bt_plugin_set *plugin_set = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(path, "Path");
+       BT_LOGD("Creating plugins from file: path=\"%s\"", path);
+
+       /* Try shared object plugins */
+       plugin_set = bt_plugin_so_create_all_from_file(path);
+       if (plugin_set) {
+               goto end;
+       }
+
+       /* Try Python plugins if support is available */
+       init_python_plugin_provider();
+       if (bt_plugin_python_create_all_from_file_sym) {
+               plugin_set = bt_plugin_python_create_all_from_file_sym(path);
+               if (plugin_set) {
+                       goto end;
+               }
+       }
+
+end:
+       if (plugin_set) {
+               BT_LOGD("Created %u plugins from file: "
+                       "path=\"%s\", count=%u, plugin-set-addr=%p",
+                       plugin_set->plugins->len, path,
+                       plugin_set->plugins->len, plugin_set);
+       } else {
+               BT_LOGD("Found no plugins in file: path=\"%s\"", path);
+       }
+
+       return plugin_set;
+}
+
+static void destroy_gstring(void *data)
+{
+       g_string_free(data, TRUE);
+}
+
+const struct bt_plugin *bt_plugin_find(const char *plugin_name)
+{
+       const char *system_plugin_dir;
+       char *home_plugin_dir = NULL;
+       const char *envvar;
+       const struct bt_plugin *plugin = NULL;
+       const struct bt_plugin_set *plugin_set = NULL;
+       GPtrArray *dirs = NULL;
+       int ret;
+       size_t i, j;
+
+       BT_ASSERT_PRE_NON_NULL(plugin_name, "Name");
+       BT_LOGD("Finding named plugin in standard directories and built-in plugins: "
+               "name=\"%s\"", plugin_name);
+       dirs = g_ptr_array_new_with_free_func((GDestroyNotify) destroy_gstring);
+       if (!dirs) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto end;
+       }
+
+       /*
+        * Search order is:
+        *
+        * 1. BABELTRACE_PLUGIN_PATH environment variable
+        *    (colon-separated list of directories)
+        * 2. ~/.local/lib/babeltrace2/plugins
+        * 3. Default system directory for Babeltrace plugins, usually
+        *    /usr/lib/babeltrace2/plugins or
+        *    /usr/local/lib/babeltrace2/plugins if installed
+        *    locally
+        * 4. Built-in plugins (static)
+        *
+        * Directories are searched non-recursively.
+        */
+       envvar = getenv("BABELTRACE_PLUGIN_PATH");
+       if (envvar) {
+               ret = bt_common_append_plugin_path_dirs(envvar, dirs);
+               if (ret) {
+                       BT_LOGE_STR("Failed to append plugin path to array of directories.");
+                       goto end;
+               }
+       }
+
+       home_plugin_dir = bt_common_get_home_plugin_path();
+       if (home_plugin_dir) {
+               GString *home_plugin_dir_str =
+                       g_string_new(home_plugin_dir);
+
+               if (!home_plugin_dir_str) {
+                       BT_LOGE_STR("Failed to allocate a GString.");
+                       goto end;
+               }
+
+               g_ptr_array_add(dirs, home_plugin_dir_str);
+       }
+
+       system_plugin_dir = bt_common_get_system_plugin_path();
+       if (system_plugin_dir) {
+               GString *system_plugin_dir_str =
+                       g_string_new(system_plugin_dir);
+
+               if (!system_plugin_dir_str) {
+                       BT_LOGE_STR("Failed to allocate a GString.");
+                       goto end;
+               }
+
+               g_ptr_array_add(dirs, system_plugin_dir_str);
+       }
+
+       for (i = 0; i < dirs->len; i++) {
+               GString *dir = g_ptr_array_index(dirs, i);
+
+               BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
+
+               /*
+                * Skip this if the directory does not exist because
+                * bt_plugin_find_all_from_dir() would log a warning.
+                */
+               if (!g_file_test(dir->str, G_FILE_TEST_IS_DIR)) {
+                       BT_LOGV("Skipping nonexistent directory path: "
+                               "path=\"%s\"", dir->str);
+                       continue;
+               }
+
+               /* bt_plugin_find_all_from_dir() logs details/errors */
+               plugin_set = bt_plugin_find_all_from_dir(dir->str, BT_FALSE);
+               if (!plugin_set) {
+                       BT_LOGD("No plugins found in directory: path=\"%s\"",
+                               dir->str);
+                       continue;
+               }
+
+               for (j = 0; j < plugin_set->plugins->len; j++) {
+                       const struct bt_plugin *candidate_plugin =
+                               g_ptr_array_index(plugin_set->plugins, j);
+
+                       if (strcmp(bt_plugin_get_name(candidate_plugin),
+                                       plugin_name) == 0) {
+                               BT_LOGD("Plugin found in directory: name=\"%s\", path=\"%s\"",
+                                       plugin_name, dir->str);
+                               plugin = candidate_plugin;
+                               bt_object_get_no_null_check(plugin);
+                               goto end;
+                       }
+               }
+
+               BT_LOGD("Plugin not found in directory: name=\"%s\", path=\"%s\"",
+                       plugin_name, dir->str);
+       }
+
+       bt_object_put_ref(plugin_set);
+       plugin_set = bt_plugin_find_all_from_static();
+       if (plugin_set) {
+               for (j = 0; j < plugin_set->plugins->len; j++) {
+                       const struct bt_plugin *candidate_plugin =
+                               g_ptr_array_index(plugin_set->plugins, j);
+
+                       if (strcmp(bt_plugin_get_name(candidate_plugin),
+                                       plugin_name) == 0) {
+                               BT_LOGD("Plugin found in built-in plugins: "
+                                       "name=\"%s\"", plugin_name);
+                               plugin = candidate_plugin;
+                               bt_object_get_no_null_check(plugin);
+                               goto end;
+                       }
+               }
+       }
+
+end:
+       free(home_plugin_dir);
+       bt_object_put_ref(plugin_set);
+
+       if (dirs) {
+               g_ptr_array_free(dirs, TRUE);
+       }
+
+       if (plugin) {
+               BT_LIB_LOGD("Found plugin in standard directories and built-in plugins: "
+                       "%!+l", plugin);
+       } else {
+               BT_LOGD("No plugin found in standard directories and built-in plugins: "
+                       "name=\"%s\"", plugin_name);
+       }
+
+       return plugin;
+}
+
+static struct {
+       pthread_mutex_t lock;
+       struct bt_plugin_set *plugin_set;
+       bool recurse;
+} append_all_from_dir_info = {
+       .lock = PTHREAD_MUTEX_INITIALIZER
+};
+
+static
+int nftw_append_all_from_dir(const char *file, const struct stat *sb, int flag,
+               struct FTW *s)
+{
+       int ret = 0;
+       const char *name = file + s->base;
+
+       /* Check for recursion */
+       if (!append_all_from_dir_info.recurse && s->level > 1) {
+               goto end;
+       }
+
+       switch (flag) {
+       case FTW_F:
+       {
+               const struct bt_plugin_set *plugins_from_file;
+
+               if (name[0] == '.') {
+                       /* Skip hidden files */
+                       BT_LOGV("Skipping hidden file: path=\"%s\"", file);
+                       goto end;
+               }
+
+               plugins_from_file = bt_plugin_find_all_from_file(file);
+
+               if (plugins_from_file) {
+                       size_t j;
+
+                       for (j = 0; j < plugins_from_file->plugins->len; j++) {
+                               struct bt_plugin *plugin =
+                                       g_ptr_array_index(plugins_from_file->plugins, j);
+
+                               BT_LIB_LOGD("Adding plugin to plugin set: "
+                                       "plugin-path=\"%s\", %![plugin-]+l",
+                                       file, plugin);
+                               bt_plugin_set_add_plugin(
+                                       append_all_from_dir_info.plugin_set,
+                                       plugin);
+                       }
+
+                       bt_object_put_ref(plugins_from_file);
+               }
+               break;
+       }
+       case FTW_DNR:
+               /* Continue to next file / directory. */
+               BT_LOGW("Cannot enter directory: continuing: path=\"%s\"", file);
+               break;
+       case FTW_NS:
+               /* Continue to next file / directory. */
+               BT_LOGD("Cannot get file information: continuing: path=\"%s\"", file);
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static
+enum bt_plugin_status bt_plugin_create_append_all_from_dir(
+               struct bt_plugin_set *plugin_set, const char *path,
+               bt_bool recurse)
+{
+       int nftw_flags = FTW_PHYS;
+       enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK;
+
+       BT_ASSERT(plugin_set);
+       BT_ASSERT(path);
+       BT_ASSERT(strlen(path) < PATH_MAX);
+       pthread_mutex_lock(&append_all_from_dir_info.lock);
+       append_all_from_dir_info.plugin_set = plugin_set;
+       append_all_from_dir_info.recurse = recurse;
+       ret = nftw(path, nftw_append_all_from_dir,
+               APPEND_ALL_FROM_DIR_NFDOPEN_MAX, nftw_flags);
+       pthread_mutex_unlock(&append_all_from_dir_info.lock);
+       if (ret != 0) {
+               BT_LOGW_ERRNO("Cannot open directory", ": path=\"%s\"", path);
+               ret = BT_PLUGIN_STATUS_ERROR;
+       }
+
+       return ret;
+}
+
+const struct bt_plugin_set *bt_plugin_find_all_from_dir(const char *path,
+               bt_bool recurse)
+{
+       struct bt_plugin_set *plugin_set;
+       enum bt_plugin_status status;
+
+       BT_LOGD("Creating all plugins in directory: path=\"%s\", recurse=%d",
+               path, recurse);
+       plugin_set = bt_plugin_set_create();
+       if (!plugin_set) {
+               BT_LOGE_STR("Cannot create empty plugin set.");
+               goto error;
+       }
+
+       /* Append found plugins to array */
+       status = bt_plugin_create_append_all_from_dir(plugin_set, path,
+               recurse);
+       if (status < 0) {
+               BT_LOGW("Cannot append plugins found in directory: "
+                       "path=\"%s\", status=%s",
+                       path, bt_plugin_status_string(status));
+               goto error;
+       }
+
+       BT_LOGD("Created %u plugins from directory: count=%u, path=\"%s\"",
+               plugin_set->plugins->len, plugin_set->plugins->len, path);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
+
+end:
+       return plugin_set;
+}
+
+const char *bt_plugin_get_name(const struct bt_plugin *plugin)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       return plugin->info.name_set ? plugin->info.name->str : NULL;
+}
+
+const char *bt_plugin_get_author(const struct bt_plugin *plugin)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       return plugin->info.author_set ? plugin->info.author->str : NULL;
+}
+
+const char *bt_plugin_get_license(const struct bt_plugin *plugin)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       return plugin->info.license_set ? plugin->info.license->str : NULL;
+}
+
+const char *bt_plugin_get_path(const struct bt_plugin *plugin)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       return plugin->info.path_set ? plugin->info.path->str : NULL;
+}
+
+const char *bt_plugin_get_description(const struct bt_plugin *plugin)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       return plugin->info.description_set ?
+               plugin->info.description->str : NULL;
+}
+
+enum bt_property_availability bt_plugin_get_version(const struct bt_plugin *plugin,
+               unsigned int *major, unsigned int *minor, unsigned int *patch,
+               const char **extra)
+{
+       enum bt_property_availability avail =
+               BT_PROPERTY_AVAILABILITY_AVAILABLE;
+
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+
+       if (!plugin->info.version_set) {
+               BT_LIB_LOGV("Plugin's version is not set: %!+l", plugin);
+               avail = BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE;
+               goto end;
+       }
+
+       if (major) {
+               *major = plugin->info.version.major;
+       }
+
+       if (minor) {
+               *minor = plugin->info.version.minor;
+       }
+
+       if (patch) {
+               *patch = plugin->info.version.patch;
+       }
+
+       if (extra) {
+               *extra = plugin->info.version.extra->str;
+       }
+
+end:
+       return avail;
+}
+
+uint64_t bt_plugin_get_source_component_class_count(const struct bt_plugin *plugin)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       return (uint64_t) plugin->src_comp_classes->len;
+}
+
+uint64_t bt_plugin_get_filter_component_class_count(const struct bt_plugin *plugin)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       return (uint64_t) plugin->flt_comp_classes->len;
+}
+
+uint64_t bt_plugin_get_sink_component_class_count(const struct bt_plugin *plugin)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       return (uint64_t) plugin->sink_comp_classes->len;
+}
+
+static inline
+struct bt_component_class *borrow_component_class_by_index(
+               const struct bt_plugin *plugin, GPtrArray *comp_classes,
+               uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       BT_ASSERT_PRE_VALID_INDEX(index, comp_classes->len);
+       return g_ptr_array_index(comp_classes, index);
+}
+
+const struct bt_component_class_source *
+bt_plugin_borrow_source_component_class_by_index_const(
+               const struct bt_plugin *plugin, uint64_t index)
+{
+       return (const void *) borrow_component_class_by_index(plugin,
+               plugin->src_comp_classes, index);
+}
+
+const struct bt_component_class_filter *
+bt_plugin_borrow_filter_component_class_by_index_const(
+               const struct bt_plugin *plugin, uint64_t index)
+{
+       return (const void *) borrow_component_class_by_index(plugin,
+               plugin->flt_comp_classes, index);
+}
+
+const struct bt_component_class_sink *
+bt_plugin_borrow_sink_component_class_by_index_const(
+               const struct bt_plugin *plugin, uint64_t index)
+{
+       return (const void *) borrow_component_class_by_index(plugin,
+               plugin->sink_comp_classes, index);
+}
+
+static inline
+struct bt_component_class *borrow_component_class_by_name(
+               const struct bt_plugin *plugin, GPtrArray *comp_classes,
+               const char *name)
+{
+       struct bt_component_class *comp_class = NULL;
+       size_t i;
+
+       BT_ASSERT_PRE_NON_NULL(plugin, "Plugin");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+
+       for (i = 0; i < comp_classes->len; i++) {
+               struct bt_component_class *comp_class_candidate =
+                       g_ptr_array_index(comp_classes, i);
+               const char *comp_class_cand_name =
+                       bt_component_class_get_name(comp_class_candidate);
+
+               BT_ASSERT(comp_class_cand_name);
+
+               if (strcmp(name, comp_class_cand_name) == 0) {
+                       comp_class = comp_class_candidate;
+                       break;
+               }
+       }
+
+       return comp_class;
+}
+
+const struct bt_component_class_source *
+bt_plugin_borrow_source_component_class_by_name_const(
+               const struct bt_plugin *plugin, const char *name)
+{
+       return (const void *) borrow_component_class_by_name(plugin,
+               plugin->src_comp_classes, name);
+}
+
+const struct bt_component_class_filter *
+bt_plugin_borrow_filter_component_class_by_name_const(
+               const struct bt_plugin *plugin, const char *name)
+{
+       return (const void *) borrow_component_class_by_name(plugin,
+               plugin->flt_comp_classes, name);
+}
+
+const struct bt_component_class_sink *
+bt_plugin_borrow_sink_component_class_by_name_const(
+               const struct bt_plugin *plugin, const char *name)
+{
+       return (const void *) borrow_component_class_by_name(plugin,
+               plugin->sink_comp_classes, name);
+}
+
+void bt_plugin_get_ref(const struct bt_plugin *plugin)
+{
+       bt_object_get_ref(plugin);
+}
+
+void bt_plugin_put_ref(const struct bt_plugin *plugin)
+{
+       bt_object_put_ref(plugin);
+}
+
+void bt_plugin_set_get_ref(const struct bt_plugin_set *plugin_set)
+{
+       bt_object_get_ref(plugin_set);
+}
+
+void bt_plugin_set_put_ref(const struct bt_plugin_set *plugin_set)
+{
+       bt_object_put_ref(plugin_set);
+}
diff --git a/src/lib/plugin/plugin.h b/src/lib/plugin/plugin.h
new file mode 100644 (file)
index 0000000..cdd20d6
--- /dev/null
@@ -0,0 +1,443 @@
+#ifndef BABELTRACE_PLUGIN_PLUGIN_INTERNAL_H
+#define BABELTRACE_PLUGIN_PLUGIN_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "lib/graph/component-class.h"
+#include <babeltrace2/plugin/plugin-const.h>
+#include <babeltrace2/plugin/plugin-dev.h>
+#include "lib/object.h"
+#include <babeltrace2/types.h>
+#include "common/assert.h"
+#include "lib/lib-logging.h"
+#include <glib.h>
+
+#include "plugin-so.h"
+
+enum bt_plugin_type {
+       BT_PLUGIN_TYPE_SO = 0,
+       BT_PLUGIN_TYPE_PYTHON = 1,
+};
+
+enum bt_plugin_status {
+       BT_PLUGIN_STATUS_OK = 0,
+       BT_PLUGIN_STATUS_ERROR = -1,
+       BT_PLUGIN_STATUS_NOMEM = -12,
+};
+
+struct bt_plugin {
+       struct bt_object base;
+       enum bt_plugin_type type;
+
+       /* Arrays of `struct bt_component_class *` (owned by this) */
+       GPtrArray *src_comp_classes;
+       GPtrArray *flt_comp_classes;
+       GPtrArray *sink_comp_classes;
+
+       /* Info (owned by this) */
+       struct {
+               GString *path;
+               GString *name;
+               GString *author;
+               GString *license;
+               GString *description;
+               struct {
+                       unsigned int major;
+                       unsigned int minor;
+                       unsigned int patch;
+                       GString *extra;
+               } version;
+               bool path_set;
+               bool name_set;
+               bool author_set;
+               bool license_set;
+               bool description_set;
+               bool version_set;
+       } info;
+
+       /* Value depends on the specific plugin type */
+       void *spec_data;
+       void (*destroy_spec_data)(struct bt_plugin *);
+};
+
+struct bt_plugin_set {
+       struct bt_object base;
+
+       /* Array of struct bt_plugin * */
+       GPtrArray *plugins;
+};
+
+static inline
+const char *bt_plugin_status_string(enum bt_plugin_status status)
+{
+       switch (status) {
+       case BT_PLUGIN_STATUS_OK:
+               return "BT_PLUGIN_STATUS_OK";
+       case BT_PLUGIN_STATUS_ERROR:
+               return "BT_PLUGIN_STATUS_ERROR";
+       case BT_PLUGIN_STATUS_NOMEM:
+               return "BT_PLUGIN_STATUS_NOMEM";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+const char *bt_plugin_type_string(enum bt_plugin_type type)
+{
+       switch (type) {
+       case BT_PLUGIN_TYPE_SO:
+               return "BT_PLUGIN_TYPE_SO";
+       case BT_PLUGIN_TYPE_PYTHON:
+               return "BT_PLUGIN_TYPE_PYTHON";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+void bt_plugin_destroy(struct bt_object *obj)
+{
+       struct bt_plugin *plugin;
+
+       BT_ASSERT(obj);
+       plugin = container_of(obj, struct bt_plugin, base);
+       BT_LIB_LOGD("Destroying plugin object: %!+l", plugin);
+
+       if (plugin->destroy_spec_data) {
+               plugin->destroy_spec_data(plugin);
+       }
+
+       if (plugin->src_comp_classes) {
+               BT_LOGD_STR("Putting source component classes.");
+               g_ptr_array_free(plugin->src_comp_classes, TRUE);
+               plugin->src_comp_classes = NULL;
+       }
+
+       if (plugin->flt_comp_classes) {
+               BT_LOGD_STR("Putting filter component classes.");
+               g_ptr_array_free(plugin->flt_comp_classes, TRUE);
+               plugin->flt_comp_classes = NULL;
+       }
+
+       if (plugin->sink_comp_classes) {
+               BT_LOGD_STR("Putting sink component classes.");
+               g_ptr_array_free(plugin->sink_comp_classes, TRUE);
+               plugin->sink_comp_classes = NULL;
+       }
+
+       if (plugin->info.name) {
+               g_string_free(plugin->info.name, TRUE);
+               plugin->info.name = NULL;
+       }
+
+       if (plugin->info.path) {
+               g_string_free(plugin->info.path, TRUE);
+               plugin->info.path = NULL;
+       }
+
+       if (plugin->info.description) {
+               g_string_free(plugin->info.description, TRUE);
+               plugin->info.description = NULL;
+       }
+
+       if (plugin->info.author) {
+               g_string_free(plugin->info.author, TRUE);
+               plugin->info.author = NULL;
+       }
+
+       if (plugin->info.license) {
+               g_string_free(plugin->info.license, TRUE);
+               plugin->info.license = NULL;
+       }
+
+       if (plugin->info.version.extra) {
+               g_string_free(plugin->info.version.extra, TRUE);
+               plugin->info.version.extra = NULL;
+       }
+
+       g_free(plugin);
+}
+
+static inline
+struct bt_plugin *bt_plugin_create_empty(enum bt_plugin_type type)
+{
+       struct bt_plugin *plugin = NULL;
+
+       BT_LOGD("Creating empty plugin object: type=%s",
+               bt_plugin_type_string(type));
+
+       plugin = g_new0(struct bt_plugin, 1);
+       if (!plugin) {
+               BT_LOGE_STR("Failed to allocate one plugin.");
+               goto error;
+       }
+
+       bt_object_init_shared(&plugin->base, bt_plugin_destroy);
+       plugin->type = type;
+
+       /* Create empty arrays of component classes */
+       plugin->src_comp_classes =
+               g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) bt_object_put_ref);
+       if (!plugin->src_comp_classes) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       plugin->flt_comp_classes =
+               g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) bt_object_put_ref);
+       if (!plugin->flt_comp_classes) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       plugin->sink_comp_classes =
+               g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) bt_object_put_ref);
+       if (!plugin->sink_comp_classes) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       /* Create empty info */
+       plugin->info.name = g_string_new(NULL);
+       if (!plugin->info.name) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       plugin->info.path = g_string_new(NULL);
+       if (!plugin->info.path) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       plugin->info.description = g_string_new(NULL);
+       if (!plugin->info.description) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       plugin->info.author = g_string_new(NULL);
+       if (!plugin->info.author) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       plugin->info.license = g_string_new(NULL);
+       if (!plugin->info.license) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       plugin->info.version.extra = g_string_new(NULL);
+       if (!plugin->info.version.extra) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       BT_LIB_LOGD("Created empty plugin object: %!+l", plugin);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(plugin);
+
+end:
+       return plugin;
+}
+
+static inline
+void bt_plugin_set_path(struct bt_plugin *plugin, const char *path)
+{
+       BT_ASSERT(plugin);
+       BT_ASSERT(path);
+       g_string_assign(plugin->info.path, path);
+       plugin->info.path_set = BT_TRUE;
+       BT_LIB_LOGV("Set plugin's path: %![plugin-]+l, path=\"%s\"",
+               plugin, path);
+}
+
+static inline
+void bt_plugin_set_name(struct bt_plugin *plugin, const char *name)
+{
+       BT_ASSERT(plugin);
+       BT_ASSERT(name);
+       g_string_assign(plugin->info.name, name);
+       plugin->info.name_set = BT_TRUE;
+       BT_LIB_LOGV("Set plugin's name: %![plugin-]+l, name=\"%s\"",
+               plugin, name);
+}
+
+static inline
+void bt_plugin_set_description(struct bt_plugin *plugin,
+               const char *description)
+{
+       BT_ASSERT(plugin);
+       BT_ASSERT(description);
+       g_string_assign(plugin->info.description, description);
+       plugin->info.description_set = BT_TRUE;
+       BT_LIB_LOGV("Set plugin's description: %![plugin-]+l", plugin);
+}
+
+static inline
+void bt_plugin_set_author(struct bt_plugin *plugin, const char *author)
+{
+       BT_ASSERT(plugin);
+       BT_ASSERT(author);
+       g_string_assign(plugin->info.author, author);
+       plugin->info.author_set = BT_TRUE;
+       BT_LIB_LOGV("Set plugin's author: %![plugin-]+l, author=\"%s\"",
+               plugin, author);
+}
+
+static inline
+void bt_plugin_set_license(struct bt_plugin *plugin, const char *license)
+{
+       BT_ASSERT(plugin);
+       BT_ASSERT(license);
+       g_string_assign(plugin->info.license, license);
+       plugin->info.license_set = BT_TRUE;
+       BT_LIB_LOGV("Set plugin's path: %![plugin-]+l, license=\"%s\"",
+               plugin, license);
+}
+
+static inline
+void bt_plugin_set_version(struct bt_plugin *plugin, unsigned int major,
+               unsigned int minor, unsigned int patch, const char *extra)
+{
+       BT_ASSERT(plugin);
+       plugin->info.version.major = major;
+       plugin->info.version.minor = minor;
+       plugin->info.version.patch = patch;
+
+       if (extra) {
+               g_string_assign(plugin->info.version.extra, extra);
+       }
+
+       plugin->info.version_set = BT_TRUE;
+       BT_LIB_LOGV("Set plugin's version: %![plugin-]+l, "
+               "major=%u, minor=%u, patch=%u, extra=\"%s\"",
+               plugin, major, minor, patch, extra);
+}
+
+static inline
+enum bt_plugin_status bt_plugin_add_component_class(
+       struct bt_plugin *plugin, struct bt_component_class *comp_class)
+{
+       GPtrArray *comp_classes;
+
+       BT_ASSERT(plugin);
+       BT_ASSERT(comp_class);
+
+       switch (comp_class->type) {
+       case BT_COMPONENT_CLASS_TYPE_SOURCE:
+               comp_classes = plugin->src_comp_classes;
+               break;
+       case BT_COMPONENT_CLASS_TYPE_FILTER:
+               comp_classes = plugin->flt_comp_classes;
+               break;
+       case BT_COMPONENT_CLASS_TYPE_SINK:
+               comp_classes = plugin->sink_comp_classes;
+               break;
+       default:
+               abort();
+       }
+
+       /* Add new component class */
+       bt_object_get_ref(comp_class);
+       g_ptr_array_add(comp_classes, comp_class);
+
+       /* Special case for a shared object plugin */
+       if (plugin->type == BT_PLUGIN_TYPE_SO) {
+               bt_plugin_so_on_add_component_class(plugin, comp_class);
+       }
+
+       BT_LIB_LOGD("Added component class to plugin: "
+               "%![plugin-]+l, %![cc-]+C", plugin, comp_class);
+       return BT_PLUGIN_STATUS_OK;
+}
+
+static
+void bt_plugin_set_destroy(struct bt_object *obj)
+{
+       struct bt_plugin_set *plugin_set =
+               container_of(obj, struct bt_plugin_set, base);
+
+       if (!plugin_set) {
+               return;
+       }
+
+       BT_LOGD("Destroying plugin set: addr=%p", plugin_set);
+
+       if (plugin_set->plugins) {
+               BT_LOGD_STR("Putting plugins.");
+               g_ptr_array_free(plugin_set->plugins, TRUE);
+       }
+
+       g_free(plugin_set);
+}
+
+static inline
+struct bt_plugin_set *bt_plugin_set_create(void)
+{
+       struct bt_plugin_set *plugin_set = g_new0(struct bt_plugin_set, 1);
+
+       if (!plugin_set) {
+               goto end;
+       }
+
+       BT_LOGD_STR("Creating empty plugin set.");
+       bt_object_init_shared(&plugin_set->base, bt_plugin_set_destroy);
+
+       plugin_set->plugins = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_put_ref);
+       if (!plugin_set->plugins) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
+               goto end;
+       }
+
+       BT_LOGD("Created empty plugin set: addr=%p", plugin_set);
+
+end:
+       return plugin_set;
+}
+
+static inline
+void bt_plugin_set_add_plugin(struct bt_plugin_set *plugin_set,
+               struct bt_plugin *plugin)
+{
+       BT_ASSERT(plugin_set);
+       BT_ASSERT(plugin);
+       bt_object_get_ref(plugin);
+       g_ptr_array_add(plugin_set->plugins, plugin);
+       BT_LIB_LOGV("Added plugin to plugin set: "
+               "plugin-set-addr=%p, %![plugin-]+l",
+               plugin_set, plugin);
+}
+
+#endif /* BABELTRACE_PLUGIN_PLUGIN_INTERNAL_H */
diff --git a/src/lib/prio-heap/Makefile.am b/src/lib/prio-heap/Makefile.am
new file mode 100644 (file)
index 0000000..c7a54d4
--- /dev/null
@@ -0,0 +1,5 @@
+noinst_LTLIBRARIES = libprio-heap.la
+
+libprio_heap_la_SOURCES = \
+       prio-heap.c \
+       prio-heap.h
diff --git a/src/lib/prio-heap/prio-heap.c b/src/lib/prio-heap/prio-heap.c
new file mode 100644 (file)
index 0000000..29e9068
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Static-sized priority heap containing pointers. Based on CLRS,
+ * chapter 6.
+ *
+ * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "prio-heap.h"
+
+#ifdef DEBUG_HEAP
+void check_heap(const struct ptr_heap *heap)
+{
+       size_t i;
+
+       if (!heap->len)
+               return;
+
+       for (i = 1; i < heap->len; i++)
+               BT_ASSERT(!heap->gt(heap->ptrs[i], heap->ptrs[0]));
+}
+#endif
+
+static
+size_t parent(size_t i)
+{
+       return (i - 1) >> 1;
+}
+
+static
+size_t left(size_t i)
+{
+       return (i << 1) + 1;
+}
+
+static
+size_t right(size_t i)
+{
+       return (i << 1) + 2;
+}
+
+/*
+ * Copy of heap->ptrs pointer is invalid after heap_grow.
+ */
+static
+int heap_grow(struct ptr_heap *heap, size_t new_len)
+{
+       void **new_ptrs;
+
+       if (likely(heap->alloc_len >= new_len))
+               return 0;
+
+       heap->alloc_len = max_t(size_t, new_len, heap->alloc_len << 1);
+       new_ptrs = calloc(heap->alloc_len, sizeof(void *));
+       if (unlikely(!new_ptrs))
+               return -ENOMEM;
+       if (likely(heap->ptrs))
+               memcpy(new_ptrs, heap->ptrs, heap->len * sizeof(void *));
+       free(heap->ptrs);
+       heap->ptrs = new_ptrs;
+       return 0;
+}
+
+static
+int heap_set_len(struct ptr_heap *heap, size_t new_len)
+{
+       int ret;
+
+       ret = heap_grow(heap, new_len);
+       if (unlikely(ret))
+               return ret;
+       heap->len = new_len;
+       return 0;
+}
+
+int bt_heap_init(struct ptr_heap *heap, size_t alloc_len,
+             int gt(void *a, void *b))
+{
+       heap->ptrs = NULL;
+       heap->len = 0;
+       heap->alloc_len = 0;
+       heap->gt = gt;
+       /*
+        * Minimum size allocated is 1 entry to ensure memory allocation
+        * never fails within bt_heap_replace_max.
+        */
+       return heap_grow(heap, max_t(size_t, 1, alloc_len));
+}
+
+void bt_heap_free(struct ptr_heap *heap)
+{
+       free(heap->ptrs);
+}
+
+static void heapify(struct ptr_heap *heap, size_t i)
+{
+       void **ptrs = heap->ptrs;
+       size_t l, r, largest;
+
+       for (;;) {
+               void *tmp;
+
+               l = left(i);
+               r = right(i);
+               if (l < heap->len && heap->gt(ptrs[l], ptrs[i]))
+                       largest = l;
+               else
+                       largest = i;
+               if (r < heap->len && heap->gt(ptrs[r], ptrs[largest]))
+                       largest = r;
+               if (unlikely(largest == i))
+                       break;
+               tmp = ptrs[i];
+               ptrs[i] = ptrs[largest];
+               ptrs[largest] = tmp;
+               i = largest;
+       }
+       check_heap(heap);
+}
+
+void *bt_heap_replace_max(struct ptr_heap *heap, void *p)
+{
+       void *res;
+
+       if (unlikely(!heap->len)) {
+               (void) heap_set_len(heap, 1);
+               heap->ptrs[0] = p;
+               check_heap(heap);
+               return NULL;
+       }
+
+       /* Replace the current max and heapify */
+       res = heap->ptrs[0];
+       heap->ptrs[0] = p;
+       heapify(heap, 0);
+       return res;
+}
+
+int bt_heap_insert(struct ptr_heap *heap, void *p)
+{
+       void **ptrs;
+       size_t pos;
+       int ret;
+
+       ret = heap_set_len(heap, heap->len + 1);
+       if (unlikely(ret))
+               return ret;
+       ptrs = heap->ptrs;
+       pos = heap->len - 1;
+       while (pos > 0 && heap->gt(p, ptrs[parent(pos)])) {
+               /* Move parent down until we find the right spot */
+               ptrs[pos] = ptrs[parent(pos)];
+               pos = parent(pos);
+       }
+       ptrs[pos] = p;
+       check_heap(heap);
+       return 0;
+}
+
+void *bt_heap_remove(struct ptr_heap *heap)
+{
+       switch (heap->len) {
+       case 0:
+               return NULL;
+       case 1:
+               (void) heap_set_len(heap, 0);
+               return heap->ptrs[0];
+       }
+       /* Shrink, replace the current max by previous last entry and heapify */
+       heap_set_len(heap, heap->len - 1);
+       /* len changed. previous last entry is at heap->len */
+       return bt_heap_replace_max(heap, heap->ptrs[heap->len]);
+}
+
+void *bt_heap_cherrypick(struct ptr_heap *heap, void *p)
+{
+       size_t pos, len = heap->len;
+
+       for (pos = 0; pos < len; pos++)
+               if (unlikely(heap->ptrs[pos] == p))
+                       goto found;
+       return NULL;
+found:
+       if (unlikely(heap->len == 1)) {
+               (void) heap_set_len(heap, 0);
+               check_heap(heap);
+               return heap->ptrs[0];
+       }
+       /* Replace p with previous last entry and heapify. */
+       heap_set_len(heap, heap->len - 1);
+       /* len changed. previous last entry is at heap->len */
+       heap->ptrs[pos] = heap->ptrs[heap->len];
+       heapify(heap, pos);
+       return p;
+}
+
+int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src)
+{
+       int ret;
+
+       ret = bt_heap_init(dst, src->alloc_len, src->gt);
+       if (ret < 0)
+               goto end;
+
+       ret = heap_set_len(dst, src->len);
+       if (ret < 0)
+               goto end;
+
+       memcpy(dst->ptrs, src->ptrs, src->len * sizeof(void *));
+
+end:
+       return ret;
+}
diff --git a/src/lib/prio-heap/prio-heap.h b/src/lib/prio-heap/prio-heap.h
new file mode 100644 (file)
index 0000000..8ea51bc
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef _BABELTRACE_PRIO_HEAP_H
+#define _BABELTRACE_PRIO_HEAP_H
+
+/*
+ * Static-sized priority heap containing pointers. Based on CLRS,
+ * chapter 6.
+ *
+ * Copyright 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <unistd.h>
+#include "common/babeltrace.h"
+
+struct ptr_heap {
+       size_t len, alloc_len;
+       void **ptrs;
+       int (*gt)(void *a, void *b);
+};
+
+#ifdef DEBUG_HEAP
+void check_heap(const struct ptr_heap *heap);
+#else
+static inline
+void check_heap(const struct ptr_heap *heap)
+{
+}
+#endif
+
+/**
+ * bt_heap_maximum - return the largest element in the heap
+ * @heap: the heap to be operated on
+ *
+ * Returns the largest element in the heap, without performing any modification
+ * to the heap structure. Returns NULL if the heap is empty.
+ */
+static inline void *bt_heap_maximum(const struct ptr_heap *heap)
+{
+       check_heap(heap);
+       return likely(heap->len) ? heap->ptrs[0] : NULL;
+}
+
+/**
+ * bt_heap_init - initialize the heap
+ * @heap: the heap to initialize
+ * @alloc_len: number of elements initially allocated
+ * @gt: function to compare the elements
+ *
+ * Returns -ENOMEM if out of memory.
+ */
+extern int bt_heap_init(struct ptr_heap *heap,
+                    size_t alloc_len,
+                    int gt(void *a, void *b));
+
+/**
+ * bt_heap_free - free the heap
+ * @heap: the heap to free
+ */
+extern void bt_heap_free(struct ptr_heap *heap);
+
+/**
+ * bt_heap_insert - insert an element into the heap
+ * @heap: the heap to be operated on
+ * @p: the element to add
+ *
+ * Insert an element into the heap.
+ *
+ * Returns -ENOMEM if out of memory.
+ */
+extern int bt_heap_insert(struct ptr_heap *heap, void *p);
+
+/**
+ * bt_heap_remove - remove the largest element from the heap
+ * @heap: the heap to be operated on
+ *
+ * Returns the largest element in the heap. It removes this element from the
+ * heap. Returns NULL if the heap is empty.
+ */
+extern void *bt_heap_remove(struct ptr_heap *heap);
+
+/**
+ * bt_heap_cherrypick - remove a given element from the heap
+ * @heap: the heap to be operated on
+ * @p: the element
+ *
+ * Remove the given element from the heap. Return the element if present, else
+ * return NULL. This algorithm has a complexity of O(n), which is higher than
+ * O(log(n)) provided by the rest of this API.
+ */
+extern void *bt_heap_cherrypick(struct ptr_heap *heap, void *p);
+
+/**
+ * bt_heap_replace_max - replace the the largest element from the heap
+ * @heap: the heap to be operated on
+ * @p: the pointer to be inserted as topmost element replacement
+ *
+ * Returns the largest element in the heap. It removes this element from the
+ * heap. The heap is rebalanced only once after the insertion. Returns NULL if
+ * the heap is empty.
+ *
+ * This is the equivalent of calling bt_heap_remove() and then bt_heap_insert(), but
+ * it only rebalances the heap once. It never allocates memory.
+ */
+extern void *bt_heap_replace_max(struct ptr_heap *heap, void *p);
+
+/**
+ * bt_heap_copy - copy a heap
+ * @dst: the destination heap (must be allocated)
+ * @src: the source heap
+ *
+ * Returns -ENOMEM if out of memory.
+ */
+extern int bt_heap_copy(struct ptr_heap *dst, struct ptr_heap *src);
+
+#endif /* _BABELTRACE_PRIO_HEAP_H */
diff --git a/src/lib/property.h b/src/lib/property.h
new file mode 100644 (file)
index 0000000..9bc3f48
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef BABELTRACE_PROPERTY_INTERNAL_H
+#define BABELTRACE_PROPERTY_INTERNAL_H
+
+/*
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/assert.h"
+#include <babeltrace2/property.h>
+#include <babeltrace2/types.h>
+#include <glib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+struct bt_property {
+       enum bt_property_availability avail;
+};
+
+struct bt_property_uint {
+       struct bt_property base;
+       uint64_t value;
+};
+
+static inline
+void bt_property_uint_set(struct bt_property_uint *prop, uint64_t value)
+{
+       BT_ASSERT(prop);
+       prop->base.avail = BT_PROPERTY_AVAILABILITY_AVAILABLE;
+       prop->value = value;
+}
+
+static inline
+void bt_property_uint_init(struct bt_property_uint *prop,
+               enum bt_property_availability avail, uint64_t value)
+{
+       BT_ASSERT(prop);
+       prop->base.avail = avail;
+       prop->value = value;
+}
+
+#endif /* BABELTRACE_PROPERTY_INTERNAL_H */
diff --git a/src/lib/trace-ir/Makefile.am b/src/lib/trace-ir/Makefile.am
new file mode 100644 (file)
index 0000000..159f4b4
--- /dev/null
@@ -0,0 +1,39 @@
+noinst_LTLIBRARIES = libtrace-ir.la
+
+libtrace_ir_la_SOURCES = \
+       attributes.c \
+       attributes.h \
+       clock-class.c \
+       clock-class.h \
+       clock-snapshot.c \
+       clock-snapshot.h \
+       clock-snapshot-set.h \
+       event.c \
+       event-class.c \
+       event-class.h \
+       event.h \
+       field.c \
+       field-class.c \
+       field-class.h \
+       field.h \
+       field-path.c \
+       field-path.h \
+       field-wrapper.c \
+       field-wrapper.h \
+       packet.c \
+       packet-context-field.c \
+       packet.h \
+       resolve-field-path.c \
+       resolve-field-path.h \
+       stream.c \
+       stream-class.c \
+       stream-class.h \
+       stream.h \
+       trace.c \
+       trace-class.c \
+       trace-class.h \
+       trace.h \
+       utils.c \
+       utils.h
+
+libtrace_ir_la_LIBADD = $(UUID_LIBS)
diff --git a/src/lib/trace-ir/attributes.c b/src/lib/trace-ir/attributes.c
new file mode 100644 (file)
index 0000000..7d20c1e
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "ATTRS"
+#include "lib/lib-logging.h"
+
+#include "common/babeltrace.h"
+#include <babeltrace2/value.h>
+#include "lib/assert-pre.h"
+#include "lib/object.h"
+#include <babeltrace2/value-const.h>
+#include "lib/value.h"
+#include "attributes.h"
+#include <inttypes.h>
+#include "compat/string.h"
+#include "common/assert.h"
+
+#define BT_ATTR_NAME_INDEX             0
+#define BT_ATTR_VALUE_INDEX            1
+
+BT_HIDDEN
+struct bt_value *bt_attributes_create(void)
+{
+       struct bt_value *attr_obj;
+
+       /*
+        * Attributes: array value object of array value objects, each one
+        * containing two entries: a string value object (attributes
+        * field name), and a value object (attributes field value).
+        *
+        * Example (JSON representation):
+        *
+        *     [
+        *         ["hostname", "eeppdesk"],
+        *         ["sysname", "Linux"],
+        *         ["tracer_major", 2],
+        *         ["tracer_minor", 5]
+        *     ]
+        */
+       BT_LOGD_STR("Creating attributes object.");
+       attr_obj = bt_value_array_create();
+       if (!attr_obj) {
+               BT_LOGE_STR("Failed to create array value.");
+       } else {
+               BT_LOGD("Created attributes object: addr=%p",
+                       attr_obj);
+       }
+
+       return attr_obj;
+}
+
+BT_HIDDEN
+void bt_attributes_destroy(struct bt_value *attr_obj)
+{
+       BT_LOGD("Destroying attributes object: addr=%p", attr_obj);
+       BT_OBJECT_PUT_REF_AND_RESET(attr_obj);
+}
+
+BT_HIDDEN
+int64_t bt_attributes_get_count(const struct bt_value *attr_obj)
+{
+       return bt_value_array_get_size(attr_obj);
+}
+
+BT_HIDDEN
+const char *bt_attributes_get_field_name(const struct bt_value *attr_obj,
+               uint64_t index)
+{
+       const char *ret = NULL;
+       const struct bt_value *attr_field_obj = NULL;
+       const struct bt_value *attr_field_name_obj = NULL;
+
+       if (!attr_obj) {
+               BT_LOGW_STR("Invalid parameter: attributes object is NULL.");
+               goto end;
+       }
+
+       if (index >= bt_value_array_get_size(attr_obj)) {
+               BT_LOGW("Invalid parameter: index is out of bounds: "
+                       "index=%" PRIu64 ", count=%" PRId64,
+                       index, bt_value_array_get_size(attr_obj));
+               goto end;
+       }
+
+       attr_field_obj = bt_value_array_borrow_element_by_index_const(
+               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_borrow_element_by_index_const(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;
+       }
+
+       ret = bt_value_string_get(attr_field_name_obj);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_value *bt_attributes_borrow_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;
+       }
+
+       if (index >= bt_value_array_get_size(attr_obj)) {
+               BT_LOGW("Invalid parameter: index is out of bounds: "
+                       "index=%" PRIu64 ", count=%" PRId64,
+                       index, bt_value_array_get_size(attr_obj));
+               goto end;
+       }
+
+       attr_field_obj =
+               bt_value_array_borrow_element_by_index(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_borrow_element_by_index(
+               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:
+       return value_obj;
+}
+
+static
+struct bt_value *bt_attributes_borrow_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_get_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) {
+               const char *field_name;
+
+               value_obj = bt_value_array_borrow_element_by_index(
+                       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_borrow_element_by_index(
+                               value_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,
+                               value_obj, (int64_t) BT_ATTR_NAME_INDEX);
+                       goto error;
+               }
+
+               field_name = bt_value_string_get(attr_field_name_obj);
+
+               if (!strcmp(field_name, name)) {
+                       break;
+               }
+
+               value_obj = NULL;
+       }
+
+       return value_obj;
+
+error:
+       value_obj = NULL;
+       return value_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_borrow_field_by_name(attr_obj, name);
+       if (attr_field_obj) {
+               ret = bt_value_array_set_element_by_index(
+                       attr_field_obj, BT_ATTR_VALUE_INDEX,
+                       value_obj);
+               attr_field_obj = NULL;
+               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_element(attr_field_obj,
+               name);
+       ret |= bt_value_array_append_element(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_element(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_object_put_ref(attr_field_obj);
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_value *bt_attributes_borrow_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_borrow_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_borrow_element_by_index(
+               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:
+       return value_obj;
+}
+
+BT_HIDDEN
+int bt_attributes_freeze(const 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_get_size(attr_obj);
+       BT_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_borrow_field_value(
+                       (void *) 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);
+       }
+
+end:
+       return ret;
+}
diff --git a/src/lib/trace-ir/attributes.h b/src/lib/trace-ir/attributes.h
new file mode 100644 (file)
index 0000000..e493815
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef BABELTRACE_TRACE_IR_ATTRIBUTES_H
+#define BABELTRACE_TRACE_IR_ATTRIBUTES_H
+
+/*
+ * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/value.h>
+
+BT_HIDDEN
+struct bt_value *bt_attributes_create(void);
+
+BT_HIDDEN
+void bt_attributes_destroy(struct bt_value *attr_obj);
+
+BT_HIDDEN
+int64_t bt_attributes_get_count(const struct bt_value *attr_obj);
+
+BT_HIDDEN
+const char *bt_attributes_get_field_name(const struct bt_value *attr_obj,
+               uint64_t index);
+
+BT_HIDDEN
+struct bt_value *bt_attributes_borrow_field_value(
+               struct bt_value *attr_obj,
+               uint64_t index);
+
+BT_HIDDEN
+int bt_attributes_set_field_value(struct bt_value *attr_obj,
+               const char *name, struct bt_value *value_obj);
+
+BT_HIDDEN
+struct bt_value *bt_attributes_borrow_field_value_by_name(
+               struct bt_value *attr_obj, const char *name);
+
+BT_HIDDEN
+int bt_attributes_freeze(const struct bt_value *attr_obj);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_TRACE_IR_ATTRIBUTES_H */
diff --git a/src/lib/trace-ir/clock-class.c b/src/lib/trace-ir/clock-class.c
new file mode 100644 (file)
index 0000000..46fa733
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CLOCK-CLASS"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include "compat/uuid.h"
+#include <babeltrace2/trace-ir/clock-class-const.h>
+#include <babeltrace2/trace-ir/clock-class.h>
+#include "clock-class.h"
+#include "clock-snapshot.h"
+#include "utils.h"
+#include "compat/compiler.h"
+#include <babeltrace2/types.h>
+#include "compat/string.h"
+#include <inttypes.h>
+#include "lib/object.h"
+#include "common/assert.h"
+
+#define BT_ASSERT_PRE_CLOCK_CLASS_HOT(_cc) \
+       BT_ASSERT_PRE_HOT((_cc), "Clock class", ": %!+K", (_cc))
+
+static
+void destroy_clock_class(struct bt_object *obj)
+{
+       struct bt_clock_class *clock_class = (void *) obj;
+
+       BT_LIB_LOGD("Destroying clock class: %!+K", clock_class);
+
+       if (clock_class->name.str) {
+               g_string_free(clock_class->name.str, TRUE);
+               clock_class->name.str = NULL;
+               clock_class->name.value = NULL;
+       }
+
+       if (clock_class->description.str) {
+               g_string_free(clock_class->description.str, TRUE);
+               clock_class->description.str = NULL;
+               clock_class->description.value = NULL;
+       }
+
+       bt_object_pool_finalize(&clock_class->cs_pool);
+       g_free(clock_class);
+}
+
+static
+void free_clock_snapshot(struct bt_clock_snapshot *clock_snapshot,
+               struct bt_clock_class *clock_class)
+{
+       bt_clock_snapshot_destroy(clock_snapshot);
+}
+
+static inline
+void set_base_offset(struct bt_clock_class *clock_class)
+{
+       clock_class->base_offset.overflows = bt_util_get_base_offset_ns(
+               clock_class->offset_seconds, clock_class->offset_cycles,
+               clock_class->frequency, &clock_class->base_offset.value_ns);
+}
+
+struct bt_clock_class *bt_clock_class_create(bt_self_component *self_comp)
+{
+       int ret;
+       struct bt_clock_class *clock_class = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(self_comp, "Self component");
+       BT_LOGD_STR("Creating default clock class object");
+
+       clock_class = g_new0(struct bt_clock_class, 1);
+       if (!clock_class) {
+               BT_LOGE_STR("Failed to allocate one clock class.");
+               goto error;
+       }
+
+       bt_object_init_shared(&clock_class->base, destroy_clock_class);
+       clock_class->name.str = g_string_new(NULL);
+       if (!clock_class->name.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       clock_class->description.str = g_string_new(NULL);
+       if (!clock_class->description.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       clock_class->frequency = UINT64_C(1000000000);
+       clock_class->origin_is_unix_epoch = BT_TRUE;
+       set_base_offset(clock_class);
+       ret = bt_object_pool_initialize(&clock_class->cs_pool,
+               (bt_object_pool_new_object_func) bt_clock_snapshot_new,
+               (bt_object_pool_destroy_object_func)
+                       free_clock_snapshot,
+               clock_class);
+       if (ret) {
+               BT_LOGE("Failed to initialize clock snapshot pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
+       BT_LIB_LOGD("Created clock class object: %!+K", clock_class);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(clock_class);
+
+end:
+       return clock_class;
+}
+
+const char *bt_clock_class_get_name(const struct bt_clock_class *clock_class)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->name.value;
+}
+
+enum bt_clock_class_status bt_clock_class_set_name(
+               struct bt_clock_class *clock_class, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       g_string_assign(clock_class->name.str, name);
+       clock_class->name.value = clock_class->name.str->str;
+       BT_LIB_LOGV("Set clock class's name: %!+K", clock_class);
+       return BT_CLOCK_CLASS_STATUS_OK;
+}
+
+const char *bt_clock_class_get_description(
+               const struct bt_clock_class *clock_class)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->description.value;
+}
+
+enum bt_clock_class_status bt_clock_class_set_description(
+               struct bt_clock_class *clock_class, const char *descr)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(descr, "Description");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       g_string_assign(clock_class->description.str, descr);
+       clock_class->description.value = clock_class->description.str->str;
+       BT_LIB_LOGV("Set clock class's description: %!+K",
+               clock_class);
+       return BT_CLOCK_CLASS_STATUS_OK;
+}
+
+uint64_t bt_clock_class_get_frequency(const struct bt_clock_class *clock_class)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->frequency;
+}
+
+void bt_clock_class_set_frequency(struct bt_clock_class *clock_class,
+               uint64_t frequency)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       BT_ASSERT_PRE(frequency != UINT64_C(-1) && frequency != 0,
+               "Invalid frequency: %![cc-]+K, new-freq=%" PRIu64,
+               clock_class, frequency);
+       BT_ASSERT_PRE(clock_class->offset_cycles < frequency,
+               "Offset (cycles) is greater than clock class's frequency: "
+               "%![cc-]+K, new-freq=%" PRIu64, clock_class, frequency);
+       clock_class->frequency = frequency;
+       set_base_offset(clock_class);
+       BT_LIB_LOGV("Set clock class's frequency: %!+K", clock_class);
+}
+
+uint64_t bt_clock_class_get_precision(const struct bt_clock_class *clock_class)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->precision;
+}
+
+void bt_clock_class_set_precision(struct bt_clock_class *clock_class,
+               uint64_t precision)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       BT_ASSERT_PRE(precision != UINT64_C(-1),
+               "Invalid precision: %![cc-]+K, new-precision=%" PRIu64,
+               clock_class, precision);
+       clock_class->precision = precision;
+       BT_LIB_LOGV("Set clock class's precision: %!+K", clock_class);
+}
+
+void bt_clock_class_get_offset(const struct bt_clock_class *clock_class,
+               int64_t *seconds, uint64_t *cycles)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(seconds, "Seconds (output)");
+       BT_ASSERT_PRE_NON_NULL(cycles, "Cycles (output)");
+       *seconds = clock_class->offset_seconds;
+       *cycles = clock_class->offset_cycles;
+}
+
+void bt_clock_class_set_offset(struct bt_clock_class *clock_class,
+               int64_t seconds, uint64_t cycles)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       BT_ASSERT_PRE(cycles < clock_class->frequency,
+               "Offset (cycles) is greater than clock class's frequency: "
+               "%![cc-]+K, new-offset-cycles=%" PRIu64, clock_class, cycles);
+       clock_class->offset_seconds = seconds;
+       clock_class->offset_cycles = cycles;
+       set_base_offset(clock_class);
+       BT_LIB_LOGV("Set clock class's offset: %!+K", clock_class);
+}
+
+bt_bool bt_clock_class_origin_is_unix_epoch(const struct bt_clock_class *clock_class)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return (bool) clock_class->origin_is_unix_epoch;
+}
+
+void bt_clock_class_set_origin_is_unix_epoch(struct bt_clock_class *clock_class,
+               bt_bool origin_is_unix_epoch)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       clock_class->origin_is_unix_epoch = (bool) origin_is_unix_epoch;
+       BT_LIB_LOGV("Set clock class's origin is Unix epoch property: %!+K",
+               clock_class);
+}
+
+bt_uuid bt_clock_class_get_uuid(const struct bt_clock_class *clock_class)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       return clock_class->uuid.value;
+}
+
+void bt_clock_class_set_uuid(struct bt_clock_class *clock_class,
+               bt_uuid uuid)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(uuid, "UUID");
+       BT_ASSERT_PRE_CLOCK_CLASS_HOT(clock_class);
+       memcpy(clock_class->uuid.uuid, uuid, BABELTRACE_UUID_LEN);
+       clock_class->uuid.value = clock_class->uuid.uuid;
+       BT_LIB_LOGV("Set clock class's UUID: %!+K", clock_class);
+}
+
+BT_HIDDEN
+void _bt_clock_class_freeze(const struct bt_clock_class *clock_class)
+{
+       BT_ASSERT(clock_class);
+
+       if (clock_class->frozen) {
+               return;
+       }
+
+       BT_LIB_LOGD("Freezing clock class: %!+K", clock_class);
+       ((struct bt_clock_class *) clock_class)->frozen = 1;
+}
+
+enum bt_clock_class_status bt_clock_class_cycles_to_ns_from_origin(
+               const struct bt_clock_class *clock_class,
+               uint64_t cycles, int64_t *ns)
+{
+       int ret;
+
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds (output)");
+       ret = bt_util_ns_from_origin_clock_class(clock_class, cycles, ns);
+       if (ret) {
+               ret = BT_CLOCK_CLASS_STATUS_OVERFLOW;
+               BT_LIB_LOGW("Cannot convert cycles to nanoseconds "
+                       "from origin for given clock class: "
+                       "value overflows the signed 64-bit integer range: "
+                       "%![cc-]+K, cycles=%" PRIu64,
+                       clock_class, cycles);
+       }
+
+       return ret;
+}
+
+void bt_clock_class_get_ref(const struct bt_clock_class *clock_class)
+{
+       bt_object_get_ref(clock_class);
+}
+
+void bt_clock_class_put_ref(const struct bt_clock_class *clock_class)
+{
+       bt_object_put_ref(clock_class);
+}
diff --git a/src/lib/trace-ir/clock-class.h b/src/lib/trace-ir/clock-class.h
new file mode 100644 (file)
index 0000000..e6e57e9
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef BABELTRACE_TRACE_IR_CLOCK_CLASS_INTERNAL_H
+#define BABELTRACE_TRACE_IR_CLOCK_CLASS_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/trace-ir/clock-class.h>
+#include "lib/object.h"
+#include "common/babeltrace.h"
+#include "common/common.h"
+#include "lib/object-pool.h"
+#include "compat/uuid.h"
+#include <babeltrace2/types.h>
+#include "lib/property.h"
+#include "common/assert.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include <glib.h>
+
+struct bt_clock_class {
+       struct bt_object base;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } description;
+
+       uint64_t frequency;
+       uint64_t precision;
+       int64_t offset_seconds;
+       uint64_t offset_cycles;
+
+       struct {
+               uint8_t uuid[BABELTRACE_UUID_LEN];
+
+               /* NULL or `uuid` above */
+               bt_uuid value;
+       } uuid;
+
+       bool origin_is_unix_epoch;
+
+       /*
+        * This is computed every time you call
+        * bt_clock_class_set_frequency() or
+        * bt_clock_class_set_offset(), as well as initially. It is the
+        * base offset in nanoseconds including both `offset_seconds`
+        * and `offset_cycles` above in the result. It is used to
+        * accelerate future calls to
+        * bt_clock_snapshot_get_ns_from_origin() and
+        * bt_clock_class_cycles_to_ns_from_origin().
+        *
+        * `overflows` is true if the base offset cannot be computed
+        * because of an overflow.
+        */
+       struct {
+               int64_t value_ns;
+               bool overflows;
+       } base_offset;
+
+       /* Pool of `struct bt_clock_snapshot *` */
+       struct bt_object_pool cs_pool;
+
+       bool frozen;
+};
+
+BT_HIDDEN
+void _bt_clock_class_freeze(const struct bt_clock_class *clock_class);
+
+#ifdef BT_DEV_MODE
+# define bt_clock_class_freeze         _bt_clock_class_freeze
+#else
+# define bt_clock_class_freeze(_cc)
+#endif
+
+BT_HIDDEN
+bt_bool bt_clock_class_is_valid(struct bt_clock_class *clock_class);
+
+static inline
+int bt_clock_class_clock_value_from_ns_from_origin(
+               struct bt_clock_class *cc, int64_t ns_from_origin,
+               uint64_t *raw_value)
+{
+       BT_ASSERT(cc);
+
+       return bt_common_clock_value_from_ns_from_origin(cc->offset_seconds,
+               cc->offset_cycles, cc->frequency, ns_from_origin,
+               raw_value);
+}
+
+#endif /* BABELTRACE_TRACE_IR_CLOCK_CLASS_INTERNAL_H */
diff --git a/src/lib/trace-ir/clock-snapshot-set.h b/src/lib/trace-ir/clock-snapshot-set.h
new file mode 100644 (file)
index 0000000..0ad9280
--- /dev/null
@@ -0,0 +1,160 @@
+#ifndef BABELTRACE_GRAPH_CLOCK_SNAPSHOT_SET_H
+#define BABELTRACE_GRAPH_CLOCK_SNAPSHOT_SET_H
+
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <glib.h>
+#include "common/assert.h"
+
+#include "clock-snapshot.h"
+#include "clock-class.h"
+
+struct bt_clock_snapshot_set {
+       /* Unique objects owned by this */
+       GPtrArray *clock_snapshots;
+
+       /* Weak; points to one of the clock snapshots above */
+       struct bt_clock_snapshot *default_cs;
+};
+
+static inline
+int bt_clock_snapshot_set_initialize(struct bt_clock_snapshot_set *cs_set)
+{
+       int ret = 0;
+
+       cs_set->clock_snapshots = g_ptr_array_sized_new(1);
+       if (!cs_set->clock_snapshots) {
+#ifdef BT_LOGE_STR
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+#endif
+
+               ret = -1;
+               goto end;
+       }
+
+       cs_set->default_cs = NULL;
+
+end:
+       return ret;
+}
+
+static inline
+void bt_clock_snapshot_set_reset(struct bt_clock_snapshot_set *cs_set)
+{
+       uint64_t i;
+
+       BT_ASSERT(cs_set);
+       BT_ASSERT(cs_set->clock_snapshots);
+
+       for (i = 0; i < cs_set->clock_snapshots->len; i++) {
+               struct bt_clock_snapshot *cs = cs_set->clock_snapshots->pdata[i];
+
+               BT_ASSERT(cs);
+               bt_clock_snapshot_reset(cs);
+       }
+
+       cs_set->default_cs = NULL;
+}
+
+static inline
+void bt_clock_snapshot_set_finalize(struct bt_clock_snapshot_set *cs_set)
+{
+       uint64_t i;
+
+       BT_ASSERT(cs_set);
+
+       if (cs_set->clock_snapshots) {
+               for (i = 0; i < cs_set->clock_snapshots->len; i++) {
+                       struct bt_clock_snapshot *cs =
+                               cs_set->clock_snapshots->pdata[i];
+
+                       BT_ASSERT(cs);
+                       bt_clock_snapshot_recycle(cs);
+               }
+
+               g_ptr_array_free(cs_set->clock_snapshots, TRUE);
+       }
+
+       cs_set->default_cs = NULL;
+}
+
+static inline
+int bt_clock_snapshot_set_set_clock_snapshot(struct bt_clock_snapshot_set *cs_set,
+               struct bt_clock_class *cc, uint64_t raw_value)
+{
+       int ret = 0;
+       struct bt_clock_snapshot *clock_snapshot = NULL;
+       uint64_t i;
+
+       BT_ASSERT(cs_set);
+       BT_ASSERT(cc);
+
+       /*
+        * Check if we already have a value for this clock class.
+        *
+        * TODO: When we have many clock classes, make this more
+        * efficient.
+        */
+       for (i = 0; i < cs_set->clock_snapshots->len; i++) {
+               struct bt_clock_snapshot *cs = cs_set->clock_snapshots->pdata[i];
+
+               BT_ASSERT(cs);
+
+               if (cs->clock_class == cc) {
+                       clock_snapshot = cs;
+                       break;
+               }
+       }
+
+       if (!clock_snapshot) {
+               clock_snapshot = bt_clock_snapshot_create(cc);
+               if (!clock_snapshot) {
+#ifdef BT_LIB_LOGE
+                       BT_LIB_LOGE("Cannot create a clock snapshot from a clock class: "
+                               "%![cc-]+K", cc);
+#endif
+
+                       ret = -1;
+                       goto end;
+               }
+
+               g_ptr_array_add(cs_set->clock_snapshots, clock_snapshot);
+       }
+
+       bt_clock_snapshot_set_raw_value(clock_snapshot, raw_value);
+
+end:
+       return ret;
+}
+
+static inline
+void  bt_clock_snapshot_set_set_default_clock_snapshot(
+               struct bt_clock_snapshot_set *cs_set, uint64_t raw_value)
+{
+       BT_ASSERT(cs_set);
+       BT_ASSERT(cs_set->default_cs);
+       bt_clock_snapshot_set_raw_value(cs_set->default_cs, raw_value);
+}
+
+#endif /* BABELTRACE_GRAPH_CLOCK_SNAPSHOT_SET_H */
diff --git a/src/lib/trace-ir/clock-snapshot.c b/src/lib/trace-ir/clock-snapshot.c
new file mode 100644 (file)
index 0000000..04ef345
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "CLOCK-SNAPSHOT"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include "compat/uuid.h"
+#include "clock-class.h"
+#include "clock-snapshot.h"
+#include <babeltrace2/trace-ir/clock-snapshot-const.h>
+#include "compat/compiler.h"
+#include <babeltrace2/types.h>
+#include "compat/string.h"
+#include <inttypes.h>
+#include "lib/object.h"
+#include "common/assert.h"
+
+BT_HIDDEN
+void bt_clock_snapshot_destroy(struct bt_clock_snapshot *clock_snapshot)
+{
+       BT_LIB_LOGD("Destroying clock snapshot: %!+k", clock_snapshot);
+       BT_OBJECT_PUT_REF_AND_RESET(clock_snapshot->clock_class);
+       g_free(clock_snapshot);
+}
+
+BT_HIDDEN
+struct bt_clock_snapshot *bt_clock_snapshot_new(
+               struct bt_clock_class *clock_class)
+{
+       struct bt_clock_snapshot *ret = NULL;
+
+       BT_ASSERT(clock_class);
+       BT_LIB_LOGD("Creating clock snapshot object: %![cc-]+K=",
+               clock_class);
+       ret = g_new0(struct bt_clock_snapshot, 1);
+       if (!ret) {
+               BT_LOGE_STR("Failed to allocate one clock snapshot.");
+               goto end;
+       }
+
+       bt_object_init_unique(&ret->base);
+       ret->clock_class = clock_class;
+       bt_object_get_no_null_check(clock_class);
+       bt_clock_class_freeze(clock_class);
+       BT_LIB_LOGD("Created clock snapshot object: %!+k", ret);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_clock_snapshot *bt_clock_snapshot_create(
+               struct bt_clock_class *clock_class)
+{
+       struct bt_clock_snapshot *clock_snapshot = NULL;
+
+       BT_ASSERT(clock_class);
+       clock_snapshot = bt_object_pool_create_object(&clock_class->cs_pool);
+       if (!clock_snapshot) {
+               BT_LIB_LOGE("Cannot allocate one clock snapshot from clock class's clock snapshot pool: "
+                       "%![cc-]+K", clock_class);
+               goto error;
+       }
+
+       if (likely(!clock_snapshot->clock_class)) {
+               clock_snapshot->clock_class = clock_class;
+               bt_object_get_no_null_check(clock_class);
+       }
+
+       goto end;
+
+error:
+       if (clock_snapshot) {
+               bt_clock_snapshot_recycle(clock_snapshot);
+               clock_snapshot = NULL;
+       }
+
+end:
+       return clock_snapshot;
+}
+
+BT_HIDDEN
+void bt_clock_snapshot_recycle(struct bt_clock_snapshot *clock_snapshot)
+{
+       struct bt_clock_class *clock_class;
+
+       BT_ASSERT(clock_snapshot);
+       BT_LIB_LOGD("Recycling clock snapshot: %!+k", clock_snapshot);
+
+       /*
+        * Those are the important ordered steps:
+        *
+        * 1. Reset the clock snapshot object, but do NOT put its clock
+        *    class's reference. This clock class contains the pool to
+        *    which we're about to recycle this clock snapshot object,
+        *    so we must guarantee its existence thanks to this existing
+        *    reference.
+        *
+        * 2. Move the clock class reference to our `clock_class`
+        *    variable so that we can set the clock snapshot's clock
+        *    class member to NULL before recycling it. We CANNOT do
+        *    this after we put the clock class reference because this
+        *    bt_object_put_ref() could destroy the clock class, also
+        *    destroying its clock snapshot pool, thus also destroying
+        *    our clock snapshot object (this would result in an invalid
+        *    write access).
+        *
+        * 3. Recycle the clock snapshot object.
+        *
+        * 4. Put our clock class reference.
+        */
+       bt_clock_snapshot_reset(clock_snapshot);
+       clock_class = clock_snapshot->clock_class;
+       BT_ASSERT(clock_class);
+       clock_snapshot->clock_class = NULL;
+       bt_object_pool_recycle_object(&clock_class->cs_pool, clock_snapshot);
+       bt_object_put_ref(clock_class);
+}
+
+uint64_t bt_clock_snapshot_get_value(
+               const struct bt_clock_snapshot *clock_snapshot)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_snapshot, "Clock snapshot");
+       BT_ASSERT_PRE(clock_snapshot->is_set,
+               "Clock snapshot is not set: %!+k", clock_snapshot);
+       return clock_snapshot->value_cycles;
+}
+
+enum bt_clock_snapshot_status bt_clock_snapshot_get_ns_from_origin(
+               const struct bt_clock_snapshot *clock_snapshot,
+               int64_t *ret_value_ns)
+{
+       int ret = BT_CLOCK_SNAPSHOT_STATUS_OK;
+
+       BT_ASSERT_PRE_NON_NULL(clock_snapshot, "Clock snapshot");
+       BT_ASSERT_PRE_NON_NULL(ret_value_ns, "Value (ns) (output)");
+       BT_ASSERT_PRE(clock_snapshot->is_set,
+               "Clock snapshot is not set: %!+k", clock_snapshot);
+
+       if (clock_snapshot->ns_from_origin_overflows) {
+               BT_LIB_LOGD("Clock snapshot, once converted to nanoseconds from origin, "
+                       "overflows the signed 64-bit integer range: "
+                       "%![cs-]+k", clock_snapshot);
+               ret = BT_CLOCK_SNAPSHOT_STATUS_OVERFLOW;
+               goto end;
+       }
+
+       *ret_value_ns = clock_snapshot->ns_from_origin;
+
+end:
+       return ret;
+}
+
+const struct bt_clock_class *bt_clock_snapshot_borrow_clock_class_const(
+               const struct bt_clock_snapshot *clock_snapshot)
+{
+       BT_ASSERT_PRE_NON_NULL(clock_snapshot, "Clock snapshot");
+       return clock_snapshot->clock_class;
+}
diff --git a/src/lib/trace-ir/clock-snapshot.h b/src/lib/trace-ir/clock-snapshot.h
new file mode 100644 (file)
index 0000000..5375f3a
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef BABELTRACE_TRACE_IR_CLOCK_SNAPSHOT_INTERNAL_H
+#define BABELTRACE_TRACE_IR_CLOCK_SNAPSHOT_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "lib/object.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "clock-class.h"
+#include "utils.h"
+
+struct bt_clock_class;
+
+struct bt_clock_snapshot {
+       struct bt_object base;
+       struct bt_clock_class *clock_class;
+       uint64_t value_cycles;
+       bool ns_from_origin_overflows;
+       int64_t ns_from_origin;
+       bool is_set;
+};
+
+static inline
+void bt_clock_snapshot_set(struct bt_clock_snapshot *clock_snapshot)
+{
+       BT_ASSERT(clock_snapshot);
+       clock_snapshot->is_set = true;
+}
+
+static inline
+void bt_clock_snapshot_reset(struct bt_clock_snapshot *clock_snapshot)
+{
+       BT_ASSERT(clock_snapshot);
+       clock_snapshot->is_set = false;
+}
+
+static inline
+void set_ns_from_origin(struct bt_clock_snapshot *clock_snapshot)
+{
+       if (bt_util_ns_from_origin_clock_class(clock_snapshot->clock_class,
+                       clock_snapshot->value_cycles,
+                       &clock_snapshot->ns_from_origin)) {
+               clock_snapshot->ns_from_origin_overflows = true;
+       }
+}
+
+static inline
+void bt_clock_snapshot_set_raw_value(struct bt_clock_snapshot *clock_snapshot,
+               uint64_t cycles)
+{
+       BT_ASSERT(clock_snapshot);
+       clock_snapshot->value_cycles = cycles;
+       set_ns_from_origin(clock_snapshot);
+       bt_clock_snapshot_set(clock_snapshot);
+}
+
+BT_HIDDEN
+void bt_clock_snapshot_destroy(struct bt_clock_snapshot *clock_snapshot);
+
+BT_HIDDEN
+struct bt_clock_snapshot *bt_clock_snapshot_new(struct bt_clock_class *clock_class);
+
+BT_HIDDEN
+struct bt_clock_snapshot *bt_clock_snapshot_create(
+               struct bt_clock_class *clock_class);
+
+BT_HIDDEN
+void bt_clock_snapshot_recycle(struct bt_clock_snapshot *clock_snapshot);
+
+#endif /* BABELTRACE_TRACE_IR_CLOCK_SNAPSHOT_INTERNAL_H */
diff --git a/src/lib/trace-ir/event-class.c b/src/lib/trace-ir/event-class.c
new file mode 100644 (file)
index 0000000..e467663
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "EVENT-CLASS"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/field-class.h>
+#include <babeltrace2/trace-ir/event-class.h>
+#include <babeltrace2/trace-ir/event-class-const.h>
+#include <babeltrace2/trace-ir/stream-class.h>
+#include "compat/compiler.h"
+#include "compat/endian.h"
+#include <babeltrace2/types.h>
+#include "lib/value.h"
+#include "common/assert.h"
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "attributes.h"
+#include "clock-snapshot.h"
+#include "event-class.h"
+#include "event.h"
+#include "field-class.h"
+#include "field.h"
+#include "resolve-field-path.h"
+#include "stream-class.h"
+#include "trace.h"
+#include "utils.h"
+
+#define BT_ASSERT_PRE_EVENT_CLASS_HOT(_ec) \
+       BT_ASSERT_PRE_HOT(((const struct bt_event_class *) (_ec)),      \
+               "Event class", ": %!+E", (_ec))
+
+static
+void destroy_event_class(struct bt_object *obj)
+{
+       struct bt_event_class *event_class = (void *) obj;
+
+       BT_LIB_LOGD("Destroying event class: %!+E", event_class);
+
+       if (event_class->name.str) {
+               g_string_free(event_class->name.str, TRUE);
+               event_class->name.str = NULL;
+       }
+
+       if (event_class->emf_uri.str) {
+               g_string_free(event_class->emf_uri.str, TRUE);
+               event_class->emf_uri.str = NULL;
+       }
+
+       BT_LOGD_STR("Putting context field class.");
+       BT_OBJECT_PUT_REF_AND_RESET(event_class->specific_context_fc);
+       BT_LOGD_STR("Putting payload field class.");
+       BT_OBJECT_PUT_REF_AND_RESET(event_class->payload_fc);
+       bt_object_pool_finalize(&event_class->event_pool);
+       g_free(obj);
+}
+
+static
+void free_event(struct bt_event *event,
+               struct bt_event_class *event_class)
+{
+       bt_event_destroy(event);
+}
+
+BT_ASSERT_PRE_FUNC
+static
+bool event_class_id_is_unique(const struct bt_stream_class *stream_class,
+               uint64_t id)
+{
+       uint64_t i;
+       bool is_unique = true;
+
+       for (i = 0; i < stream_class->event_classes->len; i++) {
+               const struct bt_event_class *ec =
+                       stream_class->event_classes->pdata[i];
+
+               if (ec->id == id) {
+                       is_unique = false;
+                       goto end;
+               }
+       }
+
+end:
+       return is_unique;
+}
+
+static
+struct bt_event_class *create_event_class_with_id(
+               struct bt_stream_class *stream_class, uint64_t id)
+{
+       int ret;
+       struct bt_event_class *event_class;
+
+       BT_ASSERT(stream_class);
+       BT_ASSERT_PRE(event_class_id_is_unique(stream_class, id),
+               "Duplicate event class ID: %![sc-]+S, id=%" PRIu64,
+               stream_class, id);
+       BT_LIB_LOGD("Creating event class object: %![sc-]+S, id=%" PRIu64,
+               stream_class, id);
+       event_class = g_new0(struct bt_event_class, 1);
+       if (!event_class) {
+               BT_LOGE_STR("Failed to allocate one event class.");
+               goto error;
+       }
+
+       bt_object_init_shared_with_parent(&event_class->base,
+               destroy_event_class);
+       event_class->id = id;
+       bt_property_uint_init(&event_class->log_level,
+                       BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE, 0);
+       event_class->name.str = g_string_new(NULL);
+       if (!event_class->name.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = -1;
+               goto end;
+       }
+
+       event_class->emf_uri.str = g_string_new(NULL);
+       if (!event_class->emf_uri.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_object_pool_initialize(&event_class->event_pool,
+               (bt_object_pool_new_object_func) bt_event_new,
+               (bt_object_pool_destroy_object_func) free_event,
+               event_class);
+       if (ret) {
+               BT_LOGE("Failed to initialize event pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
+       bt_object_set_parent(&event_class->base, &stream_class->base);
+       g_ptr_array_add(stream_class->event_classes, event_class);
+       bt_stream_class_freeze(stream_class);
+       BT_LIB_LOGD("Created event class object: %!+E", event_class);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(event_class);
+
+end:
+       return event_class;
+}
+
+struct bt_event_class *bt_event_class_create(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE(stream_class->assigns_automatic_event_class_id,
+               "Stream class does not automatically assigns event class IDs: "
+               "%![sc-]+S", stream_class);
+       return create_event_class_with_id(stream_class,
+               (uint64_t) stream_class->event_classes->len);
+}
+
+struct bt_event_class *bt_event_class_create_with_id(
+               struct bt_stream_class *stream_class, uint64_t id)
+{
+       BT_ASSERT_PRE(!stream_class->assigns_automatic_event_class_id,
+               "Stream class automatically assigns event class IDs: "
+               "%![sc-]+S", stream_class);
+       return create_event_class_with_id(stream_class, id);
+}
+
+const char *bt_event_class_get_name(const struct bt_event_class *event_class)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->name.value;
+}
+
+enum bt_event_class_status bt_event_class_set_name(
+               struct bt_event_class *event_class, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       g_string_assign(event_class->name.str, name);
+       event_class->name.value = event_class->name.str->str;
+       BT_LIB_LOGV("Set event class's name: %!+E", event_class);
+       return BT_EVENT_CLASS_STATUS_OK;
+}
+
+uint64_t bt_event_class_get_id(const struct bt_event_class *event_class)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->id;
+}
+
+enum bt_property_availability bt_event_class_get_log_level(
+               const struct bt_event_class *event_class,
+               enum bt_event_class_log_level *log_level)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(log_level, "Log level (output)");
+       *log_level = (enum bt_event_class_log_level)
+               event_class->log_level.value;
+       return event_class->log_level.base.avail;
+}
+
+void bt_event_class_set_log_level(
+               struct bt_event_class *event_class,
+               enum bt_event_class_log_level log_level)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       bt_property_uint_set(&event_class->log_level,
+               (uint64_t) log_level);
+       BT_LIB_LOGV("Set event class's log level: %!+E", event_class);
+}
+
+const char *bt_event_class_get_emf_uri(const struct bt_event_class *event_class)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->emf_uri.value;
+}
+
+enum bt_event_class_status bt_event_class_set_emf_uri(
+               struct bt_event_class *event_class,
+               const char *emf_uri)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(emf_uri, "EMF URI");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       g_string_assign(event_class->emf_uri.str, emf_uri);
+       event_class->emf_uri.value = event_class->emf_uri.str->str;
+       BT_LIB_LOGV("Set event class's EMF URI: %!+E", event_class);
+       return BT_EVENT_CLASS_STATUS_OK;
+}
+
+struct bt_stream_class *bt_event_class_borrow_stream_class(
+               struct bt_event_class *event_class)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return bt_event_class_borrow_stream_class_inline(event_class);
+}
+
+const struct bt_stream_class *
+bt_event_class_borrow_stream_class_const(
+               const struct bt_event_class *event_class)
+{
+       return bt_event_class_borrow_stream_class((void *) event_class);
+}
+
+const struct bt_field_class *
+bt_event_class_borrow_specific_context_field_class_const(
+               const struct bt_event_class *event_class)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->specific_context_fc;
+}
+
+struct bt_field_class *
+bt_event_class_borrow_specific_context_field_class(
+               struct bt_event_class *event_class)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->specific_context_fc;
+}
+
+enum bt_event_class_status bt_event_class_set_specific_context_field_class(
+               struct bt_event_class *event_class,
+               struct bt_field_class *field_class)
+{
+       int ret;
+       struct bt_stream_class *stream_class;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_context = NULL,
+               .event_common_context = NULL,
+               .event_specific_context = field_class,
+               .event_payload = NULL,
+       };
+
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
+               BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Specific context field class is not a structure field class: "
+               "%!+F", field_class);
+       stream_class = bt_event_class_borrow_stream_class_inline(
+               event_class);
+       resolve_ctx.packet_context = stream_class->packet_context_fc;
+       resolve_ctx.event_common_context =
+               stream_class->event_common_context_fc;
+
+       ret = bt_resolve_field_paths(field_class, &resolve_ctx);
+       if (ret) {
+               /*
+                * This is the only reason for which
+                * bt_resolve_field_paths() can fail: anything else
+                * would be because a precondition is not satisfied.
+                */
+               ret = BT_EVENT_CLASS_STATUS_NOMEM;
+               goto end;
+       }
+
+       bt_field_class_make_part_of_trace_class(field_class);
+       bt_object_put_ref(event_class->specific_context_fc);
+       event_class->specific_context_fc = field_class;
+       bt_object_get_no_null_check(event_class->specific_context_fc);
+       bt_field_class_freeze(field_class);
+       BT_LIB_LOGV("Set event class's specific context field class: %!+E",
+               event_class);
+
+end:
+       return ret;
+}
+
+const struct bt_field_class *bt_event_class_borrow_payload_field_class_const(
+               const struct bt_event_class *event_class)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->payload_fc;
+}
+
+struct bt_field_class *bt_event_class_borrow_payload_field_class(
+               struct bt_event_class *event_class)
+{
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       return event_class->payload_fc;
+}
+
+enum bt_event_class_status bt_event_class_set_payload_field_class(
+               struct bt_event_class *event_class,
+               struct bt_field_class *field_class)
+{
+       int ret;
+       struct bt_stream_class *stream_class;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_context = NULL,
+               .event_common_context = NULL,
+               .event_specific_context = NULL,
+               .event_payload = field_class,
+       };
+
+       BT_ASSERT_PRE_NON_NULL(event_class, "Event class");
+       BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
+       BT_ASSERT_PRE_EVENT_CLASS_HOT(event_class);
+       BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
+               BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Payload field class is not a structure field class: %!+F",
+               field_class);
+       stream_class = bt_event_class_borrow_stream_class_inline(
+               event_class);
+       resolve_ctx.packet_context = stream_class->packet_context_fc;
+       resolve_ctx.event_common_context =
+               stream_class->event_common_context_fc;
+       resolve_ctx.event_specific_context = event_class->specific_context_fc;
+
+       ret = bt_resolve_field_paths(field_class, &resolve_ctx);
+       if (ret) {
+               /*
+                * This is the only reason for which
+                * bt_resolve_field_paths() can fail: anything else
+                * would be because a precondition is not satisfied.
+                */
+               ret = BT_EVENT_CLASS_STATUS_NOMEM;
+               goto end;
+       }
+
+       bt_field_class_make_part_of_trace_class(field_class);
+       bt_object_put_ref(event_class->payload_fc);
+       event_class->payload_fc = field_class;
+       bt_object_get_no_null_check(event_class->payload_fc);
+       bt_field_class_freeze(field_class);
+       BT_LIB_LOGV("Set event class's payload field class: %!+E", event_class);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void _bt_event_class_freeze(const struct bt_event_class *event_class)
+{
+       /* The field classes are already frozen */
+       BT_ASSERT(event_class);
+       BT_LIB_LOGD("Freezing event class: %!+E", event_class);
+       ((struct bt_event_class *) event_class)->frozen = true;
+}
+
+void bt_event_class_get_ref(const struct bt_event_class *event_class)
+{
+       bt_object_get_ref(event_class);
+}
+
+void bt_event_class_put_ref(const struct bt_event_class *event_class)
+{
+       bt_object_put_ref(event_class);
+}
diff --git a/src/lib/trace-ir/event-class.h b/src/lib/trace-ir/event-class.h
new file mode 100644 (file)
index 0000000..b368a28
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef BABELTRACE_TRACE_IR_EVENT_CLASS_INTERNAL_H
+#define BABELTRACE_TRACE_IR_EVENT_CLASS_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/field-class.h>
+#include <babeltrace2/trace-ir/field.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/trace-ir/stream-class.h>
+#include <babeltrace2/trace-ir/stream.h>
+#include <babeltrace2/trace-ir/event-class.h>
+#include "lib/object.h"
+#include "common/assert.h"
+#include "lib/object-pool.h"
+#include "lib/property.h"
+#include <glib.h>
+#include <stdbool.h>
+
+#include "trace.h"
+
+struct bt_event_class {
+       struct bt_object base;
+       struct bt_field_class *specific_context_fc;
+       struct bt_field_class *payload_fc;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       uint64_t id;
+       struct bt_property_uint log_level;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } emf_uri;
+
+       /* Pool of `struct bt_event *` */
+       struct bt_object_pool event_pool;
+
+       bool frozen;
+};
+
+BT_HIDDEN
+void _bt_event_class_freeze(const struct bt_event_class *event_class);
+
+#ifdef BT_DEV_MODE
+# define bt_event_class_freeze         _bt_event_class_freeze
+#else
+# define bt_event_class_freeze(_ec)
+#endif
+
+static inline
+struct bt_stream_class *bt_event_class_borrow_stream_class_inline(
+               const struct bt_event_class *event_class)
+{
+       BT_ASSERT(event_class);
+       return (void *) bt_object_borrow_parent(&event_class->base);
+}
+
+#endif /* BABELTRACE_TRACE_IR_EVENT_CLASS_INTERNAL_H */
diff --git a/src/lib/trace-ir/event.c b/src/lib/trace-ir/event.c
new file mode 100644 (file)
index 0000000..133d0d2
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "EVENT"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/event-const.h>
+#include <babeltrace2/trace-ir/event-class.h>
+#include <babeltrace2/trace-ir/stream-class.h>
+#include <babeltrace2/trace-ir/stream-class-const.h>
+#include <babeltrace2/trace-ir/packet.h>
+#include <babeltrace2/trace-ir/trace.h>
+#include "common/assert.h"
+#include "compat/compiler.h"
+#include <inttypes.h>
+
+#include "field.h"
+#include "field-class.h"
+#include "event.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "packet.h"
+#include "trace.h"
+#include "packet.h"
+#include "attributes.h"
+#include "event-class.h"
+
+BT_HIDDEN
+void _bt_event_set_is_frozen(const struct bt_event *event, bool is_frozen)
+{
+       BT_ASSERT(event);
+       BT_LIB_LOGD("Setting event's frozen state: %!+e, is-frozen=%d",
+               event, is_frozen);
+
+       if (event->common_context_field) {
+               BT_LOGD_STR("Setting event's common context field's frozen state.");
+               bt_field_set_is_frozen(
+                       event->common_context_field, is_frozen);
+       }
+
+       if (event->specific_context_field) {
+               BT_LOGD_STR("Setting event's specific context field's frozen state.");
+               bt_field_set_is_frozen(event->specific_context_field,
+                       is_frozen);
+       }
+
+       if (event->payload_field) {
+               BT_LOGD_STR("Setting event's payload field's frozen state.");
+               bt_field_set_is_frozen(event->payload_field,
+                       is_frozen);
+       }
+
+       ((struct bt_event *) event)->frozen = is_frozen;
+       BT_LOGD_STR("Setting event's packet's frozen state.");
+       bt_packet_set_is_frozen(event->packet, is_frozen);
+}
+
+BT_HIDDEN
+struct bt_event *bt_event_new(struct bt_event_class *event_class)
+{
+       struct bt_event *event = NULL;
+       struct bt_stream_class *stream_class;
+       struct bt_field_class *fc;
+
+       BT_ASSERT(event_class);
+       event = g_new0(struct bt_event, 1);
+       if (!event) {
+               BT_LOGE_STR("Failed to allocate one event.");
+               goto error;
+       }
+
+       bt_object_init_unique(&event->base);
+       stream_class = bt_event_class_borrow_stream_class(event_class);
+       BT_ASSERT(stream_class);
+       fc = stream_class->event_common_context_fc;
+       if (fc) {
+               event->common_context_field = bt_field_create(fc);
+               if (!event->common_context_field) {
+                       /* bt_field_create() logs errors */
+                       goto error;
+               }
+       }
+
+       fc = event_class->specific_context_fc;
+       if (fc) {
+               event->specific_context_field = bt_field_create(fc);
+               if (!event->specific_context_field) {
+                       /* bt_field_create() logs errors */
+                       goto error;
+               }
+       }
+
+       fc = event_class->payload_fc;
+       if (fc) {
+               event->payload_field = bt_field_create(fc);
+               if (!event->payload_field) {
+                       /* bt_field_create() logs errors */
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       if (event) {
+               bt_event_destroy(event);
+               event = NULL;
+       }
+
+end:
+       return event;
+}
+
+struct bt_event_class *bt_event_borrow_class(struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->class;
+}
+
+const struct bt_event_class *bt_event_borrow_class_const(
+               const struct bt_event *event)
+{
+       return bt_event_borrow_class((void *) event);
+}
+
+struct bt_stream *bt_event_borrow_stream(struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->packet ? event->packet->stream : NULL;
+}
+
+const struct bt_stream *bt_event_borrow_stream_const(
+               const struct bt_event *event)
+{
+       return bt_event_borrow_stream((void *) event);
+}
+
+struct bt_field *bt_event_borrow_common_context_field(struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->common_context_field;
+}
+
+const struct bt_field *bt_event_borrow_common_context_field_const(
+               const struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->common_context_field;
+}
+
+struct bt_field *bt_event_borrow_specific_context_field(struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->specific_context_field;
+}
+
+const struct bt_field *bt_event_borrow_specific_context_field_const(
+               const struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->specific_context_field;
+}
+
+struct bt_field *bt_event_borrow_payload_field(struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->payload_field;
+}
+
+const struct bt_field *bt_event_borrow_payload_field_const(
+               const struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->payload_field;
+}
+
+BT_HIDDEN
+void bt_event_destroy(struct bt_event *event)
+{
+       BT_ASSERT(event);
+       BT_LIB_LOGD("Destroying event: %!+e", event);
+
+       if (event->common_context_field) {
+               BT_LOGD_STR("Destroying event's stream event context field.");
+               bt_field_destroy(event->common_context_field);
+               event->common_context_field = NULL;
+       }
+
+       if (event->specific_context_field) {
+               BT_LOGD_STR("Destroying event's context field.");
+               bt_field_destroy(event->specific_context_field);
+               event->specific_context_field = NULL;
+       }
+
+       if (event->payload_field) {
+               BT_LOGD_STR("Destroying event's payload field.");
+               bt_field_destroy(event->payload_field);
+               event->payload_field = NULL;
+       }
+
+       BT_LOGD_STR("Putting event's class.");
+       bt_object_put_ref(event->class);
+       BT_LOGD_STR("Putting event's packet.");
+       BT_OBJECT_PUT_REF_AND_RESET(event->packet);
+       g_free(event);
+}
+
+struct bt_packet *bt_event_borrow_packet(struct bt_event *event)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       return event->packet;
+}
+
+const struct bt_packet *bt_event_borrow_packet_const(
+               const struct bt_event *event)
+{
+       return bt_event_borrow_packet((void *) event);
+}
diff --git a/src/lib/trace-ir/event.h b/src/lib/trace-ir/event.h
new file mode 100644 (file)
index 0000000..308c451
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef BABELTRACE_TRACE_IR_EVENT_INTERNAL_H
+#define BABELTRACE_TRACE_IR_EVENT_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Protection: this file uses BT_LIB_LOG*() macros directly */
+#ifndef BABELTRACE_LIB_LOGGING_INTERNAL_H
+# error Please include <lib/lib-logging.h> before including this file.
+#endif
+
+#include "lib/assert-pre.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/trace-ir/stream-class.h>
+#include <babeltrace2/trace-ir/stream.h>
+#include <babeltrace2/trace-ir/packet.h>
+#include <babeltrace2/trace-ir/field.h>
+#include "lib/object.h"
+#include "common/assert.h"
+#include <glib.h>
+
+#include "event-class.h"
+#include "field.h"
+#include "field-wrapper.h"
+#include "packet.h"
+#include "stream.h"
+
+#define BT_ASSERT_PRE_EVENT_HOT(_event) \
+       BT_ASSERT_PRE_HOT(((const struct bt_event *) (_event)),         \
+               "Event", ": %!+e", (_event))
+
+struct bt_event {
+       struct bt_object base;
+
+       /* Owned by this */
+       struct bt_event_class *class;
+
+       /* Owned by this */
+       struct bt_packet *packet;
+
+       struct bt_field *common_context_field;
+       struct bt_field *specific_context_field;
+       struct bt_field *payload_field;
+       bool frozen;
+};
+
+BT_HIDDEN
+void bt_event_destroy(struct bt_event *event);
+
+BT_HIDDEN
+struct bt_event *bt_event_new(struct bt_event_class *event_class);
+
+BT_HIDDEN
+void _bt_event_set_is_frozen(const struct bt_event *event, bool is_frozen);
+
+#ifdef BT_DEV_MODE
+# define bt_event_set_is_frozen                _bt_event_set_is_frozen
+#else
+# define bt_event_set_is_frozen(_event, _is_frozen)
+#endif
+
+BT_UNUSED
+static inline
+void _bt_event_reset_dev_mode(struct bt_event *event)
+{
+       BT_ASSERT(event);
+
+       if (event->common_context_field) {
+               bt_field_set_is_frozen(
+                       event->common_context_field, false);
+               bt_field_reset(
+                       event->common_context_field);
+       }
+
+       if (event->specific_context_field) {
+               bt_field_set_is_frozen(
+                       event->specific_context_field, false);
+               bt_field_reset(event->specific_context_field);
+       }
+
+       if (event->payload_field) {
+               bt_field_set_is_frozen(
+                       event->payload_field, false);
+               bt_field_reset(event->payload_field);
+       }
+}
+
+#ifdef BT_DEV_MODE
+# define bt_event_reset_dev_mode       _bt_event_reset_dev_mode
+#else
+# define bt_event_reset_dev_mode(_x)
+#endif
+
+static inline
+void bt_event_reset(struct bt_event *event)
+{
+       BT_ASSERT(event);
+       BT_LIB_LOGD("Resetting event: %!+e", event);
+       bt_event_set_is_frozen(event, false);
+       bt_object_put_no_null_check(&event->packet->base);
+       event->packet = NULL;
+}
+
+static inline
+void bt_event_recycle(struct bt_event *event)
+{
+       struct bt_event_class *event_class;
+
+       BT_ASSERT(event);
+       BT_LIB_LOGD("Recycling event: %!+e", event);
+
+       /*
+        * Those are the important ordered steps:
+        *
+        * 1. Reset the event object (put any permanent reference it
+        *    has, unfreeze it and its fields in developer mode, etc.),
+        *    but do NOT put its class's reference. This event class
+        *    contains the pool to which we're about to recycle this
+        *    event object, so we must guarantee its existence thanks
+        *    to this existing reference.
+        *
+        * 2. Move the event class reference to our `event_class`
+        *    variable so that we can set the event's class member
+        *    to NULL before recycling it. We CANNOT do this after
+        *    we put the event class reference because this bt_object_put_ref()
+        *    could destroy the event class, also destroying its
+        *    event pool, thus also destroying our event object (this
+        *    would result in an invalid write access).
+        *
+        * 3. Recycle the event object.
+        *
+        * 4. Put our event class reference.
+        */
+       bt_event_reset(event);
+       event_class = event->class;
+       BT_ASSERT(event_class);
+       event->class = NULL;
+       bt_object_pool_recycle_object(&event_class->event_pool, event);
+       bt_object_put_no_null_check(&event_class->base);
+}
+
+static inline
+void bt_event_set_packet(struct bt_event *event, struct bt_packet *packet)
+{
+       BT_ASSERT_PRE_NON_NULL(event, "Event");
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
+       BT_ASSERT_PRE_EVENT_HOT(event);
+       BT_ASSERT_PRE(bt_event_class_borrow_stream_class(
+               event->class) == packet->stream->class,
+               "Packet's stream class and event's stream class differ: "
+               "%![event-]+e, %![packet-]+a", event, packet);
+
+       BT_ASSERT(!event->packet);
+       event->packet = packet;
+       bt_object_get_no_null_check_no_parent_check(&event->packet->base);
+       BT_LIB_LOGV("Set event's packet: %![event-]+e, %![packet-]+a",
+               event, packet);
+}
+
+static inline
+struct bt_event *bt_event_create(struct bt_event_class *event_class,
+               struct bt_packet *packet)
+{
+       struct bt_event *event = NULL;
+
+       BT_ASSERT(event_class);
+       event = bt_object_pool_create_object(&event_class->event_pool);
+       if (unlikely(!event)) {
+               BT_LIB_LOGE("Cannot allocate one event from event class's event pool: "
+                       "%![ec-]+E", event_class);
+               goto end;
+       }
+
+       if (likely(!event->class)) {
+               event->class = event_class;
+               bt_object_get_no_null_check(&event_class->base);
+       }
+
+       BT_ASSERT(packet);
+       bt_event_set_packet(event, packet);
+       goto end;
+
+end:
+       return event;
+}
+
+#endif /* BABELTRACE_TRACE_IR_EVENT_INTERNAL_H */
diff --git a/src/lib/trace-ir/field-class.c b/src/lib/trace-ir/field-class.c
new file mode 100644 (file)
index 0000000..40fe215
--- /dev/null
@@ -0,0 +1,1356 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "FIELD-CLASSES"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/field-class.h>
+#include <babeltrace2/trace-ir/field-class-const.h>
+#include <babeltrace2/trace-ir/field-const.h>
+#include <babeltrace2/trace-ir/field.h>
+#include <babeltrace2/trace-ir/clock-class.h>
+#include "lib/object.h"
+#include "compat/compiler.h"
+#include "compat/endian.h"
+#include "common/assert.h"
+#include "compat/glib.h"
+#include <float.h>
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include "clock-class.h"
+#include "field-class.h"
+#include "field.h"
+#include "field-path.h"
+#include "utils.h"
+
+enum bt_field_class_type bt_field_class_get_type(
+               const struct bt_field_class *fc)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       return fc->type;
+}
+
+static
+void init_field_class(struct bt_field_class *fc, enum bt_field_class_type type,
+               bt_object_release_func release_func)
+{
+       BT_ASSERT(fc);
+       BT_ASSERT(bt_field_class_has_known_type(fc));
+       BT_ASSERT(release_func);
+       bt_object_init_shared(&fc->base, release_func);
+       fc->type = type;
+}
+
+static
+void init_integer_field_class(struct bt_field_class_integer *fc,
+               enum bt_field_class_type type,
+               bt_object_release_func release_func)
+{
+       init_field_class((void *) fc, type, release_func);
+       fc->range = 64;
+       fc->base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
+}
+
+static
+void destroy_integer_field_class(struct bt_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying integer field class object: %!+F", obj);
+       g_free(obj);
+}
+
+static inline
+struct bt_field_class *create_integer_field_class(bt_trace_class *trace_class,
+               enum bt_field_class_type type)
+{
+       struct bt_field_class_integer *int_fc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
+       BT_LOGD("Creating default integer field class object: type=%s",
+               bt_common_field_class_type_string(type));
+       int_fc = g_new0(struct bt_field_class_integer, 1);
+       if (!int_fc) {
+               BT_LOGE_STR("Failed to allocate one integer field class.");
+               goto error;
+       }
+
+       init_integer_field_class(int_fc, type, destroy_integer_field_class);
+       BT_LIB_LOGD("Created integer field class object: %!+F", int_fc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(int_fc);
+
+end:
+       return (void *) int_fc;
+}
+
+struct bt_field_class *bt_field_class_unsigned_integer_create(
+               bt_trace_class *trace_class)
+{
+       return create_integer_field_class(trace_class,
+               BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER);
+}
+
+struct bt_field_class *bt_field_class_signed_integer_create(
+               bt_trace_class *trace_class)
+{
+       return create_integer_field_class(trace_class,
+               BT_FIELD_CLASS_TYPE_SIGNED_INTEGER);
+}
+
+uint64_t bt_field_class_integer_get_field_value_range(
+               const struct bt_field_class *fc)
+{
+       const struct bt_field_class_integer *int_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_IS_INT(fc, "Field class");
+       return int_fc->range;
+}
+
+BT_ASSERT_PRE_FUNC
+static
+bool size_is_valid_for_enumeration_field_class(struct bt_field_class *fc,
+               uint64_t size)
+{
+       // TODO
+       return true;
+}
+
+void bt_field_class_integer_set_field_value_range(
+               struct bt_field_class *fc, uint64_t size)
+{
+       struct bt_field_class_integer *int_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_IS_INT(fc, "Field class");
+       BT_ASSERT_PRE_FC_HOT(fc, "Field class");
+       BT_ASSERT_PRE(size <= 64,
+               "Unsupported size for integer field class's field value range "
+               "(maximum is 64): size=%" PRIu64, size);
+       BT_ASSERT_PRE(
+               int_fc->common.type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
+               int_fc->common.type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
+               size_is_valid_for_enumeration_field_class(fc, size),
+               "Invalid field value range for enumeration field class: "
+               "at least one of the current mapping ranges contains values "
+               "which are outside this range: %!+F, size=%" PRIu64, fc, size);
+       int_fc->range = size;
+       BT_LIB_LOGV("Set integer field class's field value range: %!+F", fc);
+}
+
+enum bt_field_class_integer_preferred_display_base
+bt_field_class_integer_get_preferred_display_base(const struct bt_field_class *fc)
+{
+       const struct bt_field_class_integer *int_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_IS_INT(fc, "Field class");
+       return int_fc->base;
+}
+
+void bt_field_class_integer_set_preferred_display_base(
+               struct bt_field_class *fc,
+               enum bt_field_class_integer_preferred_display_base base)
+{
+       struct bt_field_class_integer *int_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_IS_INT(fc, "Field class");
+       BT_ASSERT_PRE_FC_HOT(fc, "Field class");
+       int_fc->base = base;
+       BT_LIB_LOGV("Set integer field class's preferred display base: %!+F", fc);
+}
+
+static
+void finalize_enumeration_field_class_mapping(
+               struct bt_field_class_enumeration_mapping *mapping)
+{
+       BT_ASSERT(mapping);
+
+       if (mapping->label) {
+               g_string_free(mapping->label, TRUE);
+       }
+
+       if (mapping->ranges) {
+               g_array_free(mapping->ranges, TRUE);
+       }
+}
+
+static
+void destroy_enumeration_field_class(struct bt_object *obj)
+{
+       struct bt_field_class_enumeration *fc = (void *) obj;
+
+       BT_ASSERT(fc);
+       BT_LIB_LOGD("Destroying enumeration field class object: %!+F", fc);
+
+       if (fc->mappings) {
+               uint64_t i;
+
+               for (i = 0; i < fc->mappings->len; i++) {
+                       finalize_enumeration_field_class_mapping(
+                               BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(fc, i));
+               }
+
+               g_array_free(fc->mappings, TRUE);
+               fc->mappings = NULL;
+       }
+
+       if (fc->label_buf) {
+               g_ptr_array_free(fc->label_buf, TRUE);
+               fc->label_buf = NULL;
+       }
+
+       g_free(fc);
+}
+
+static
+struct bt_field_class *create_enumeration_field_class(
+               bt_trace_class *trace_class, enum bt_field_class_type type)
+{
+       struct bt_field_class_enumeration *enum_fc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
+       BT_LOGD("Creating default enumeration field class object: type=%s",
+               bt_common_field_class_type_string(type));
+       enum_fc = g_new0(struct bt_field_class_enumeration, 1);
+       if (!enum_fc) {
+               BT_LOGE_STR("Failed to allocate one enumeration field class.");
+               goto error;
+       }
+
+       init_integer_field_class((void *) enum_fc, type,
+               destroy_enumeration_field_class);
+       enum_fc->mappings = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_field_class_enumeration_mapping));
+       if (!enum_fc->mappings) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
+       }
+
+       enum_fc->label_buf = g_ptr_array_new();
+       if (!enum_fc->label_buf) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
+       }
+
+       BT_LIB_LOGD("Created enumeration field class object: %!+F", enum_fc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(enum_fc);
+
+end:
+       return (void *) enum_fc;
+}
+
+struct bt_field_class *bt_field_class_unsigned_enumeration_create(
+               bt_trace_class *trace_class)
+{
+       return create_enumeration_field_class(trace_class,
+               BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION);
+}
+
+struct bt_field_class *bt_field_class_signed_enumeration_create(
+               bt_trace_class *trace_class)
+{
+       return create_enumeration_field_class(trace_class,
+               BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION);
+}
+
+uint64_t bt_field_class_enumeration_get_mapping_count(
+               const struct bt_field_class *fc)
+{
+       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_IS_ENUM(fc, "Field class");
+       return (uint64_t) enum_fc->mappings->len;
+}
+
+const struct bt_field_class_unsigned_enumeration_mapping *
+bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
+               const struct bt_field_class *fc, uint64_t index)
+{
+       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_VALID_INDEX(index, enum_fc->mappings->len);
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
+               "Field class");
+       return (const void *) BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(fc, index);
+}
+
+const struct bt_field_class_signed_enumeration_mapping *
+bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
+               const struct bt_field_class *fc, uint64_t index)
+{
+       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_VALID_INDEX(index, enum_fc->mappings->len);
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
+               "Field class");
+       return (const void *) BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(fc, index);
+}
+
+const char *bt_field_class_enumeration_mapping_get_label(
+               const struct bt_field_class_enumeration_mapping *mapping)
+{
+       BT_ASSERT_PRE_NON_NULL(mapping, "Enumeration field class mapping");
+       return mapping->label->str;
+}
+
+uint64_t bt_field_class_enumeration_mapping_get_range_count(
+               const struct bt_field_class_enumeration_mapping *mapping)
+{
+       BT_ASSERT_PRE_NON_NULL(mapping, "Enumeration field class mapping");
+       return (uint64_t) mapping->ranges->len;
+}
+
+static inline
+void get_enumeration_field_class_mapping_range_at_index(
+               const struct bt_field_class_enumeration_mapping *mapping,
+               uint64_t index, uint64_t *lower, uint64_t *upper)
+{
+       const struct bt_field_class_enumeration_mapping_range *range;
+
+       BT_ASSERT_PRE_NON_NULL(mapping, "Ranges");
+       BT_ASSERT_PRE_NON_NULL(lower, "Range's lower (output)");
+       BT_ASSERT_PRE_NON_NULL(upper, "Range's upper (output)");
+       BT_ASSERT_PRE_VALID_INDEX(index, mapping->ranges->len);
+       range = BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(mapping, index);
+       *lower = range->lower.u;
+       *upper = range->upper.u;
+}
+
+void bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
+               const struct bt_field_class_unsigned_enumeration_mapping *ranges,
+               uint64_t index, uint64_t *lower, uint64_t *upper)
+{
+       get_enumeration_field_class_mapping_range_at_index(
+               (const void *) ranges, index, lower, upper);
+}
+
+void bt_field_class_signed_enumeration_mapping_get_range_by_index(
+               const struct bt_field_class_signed_enumeration_mapping *ranges,
+               uint64_t index, int64_t *lower, int64_t *upper)
+{
+       get_enumeration_field_class_mapping_range_at_index(
+               (const void *) ranges, index,
+               (uint64_t *) lower, (uint64_t *) upper);
+}
+
+enum bt_field_class_status
+bt_field_class_unsigned_enumeration_get_mapping_labels_by_value(
+               const struct bt_field_class *fc, uint64_t value,
+               bt_field_class_enumeration_mapping_label_array *label_array,
+               uint64_t *count)
+{
+       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
+       uint64_t i;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
+       BT_ASSERT_PRE_NON_NULL(count, "Count (output)");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
+               "Field class");
+       g_ptr_array_set_size(enum_fc->label_buf, 0);
+
+       for (i = 0; i < enum_fc->mappings->len; i++) {
+               uint64_t j;
+               const struct bt_field_class_enumeration_mapping *mapping =
+                       BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i);
+
+               for (j = 0; j < mapping->ranges->len; j++) {
+                       const struct bt_field_class_enumeration_mapping_range *range =
+                               BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(
+                                       mapping, j);
+
+                       if (value >= range->lower.u &&
+                                       value <= range->upper.u) {
+                               g_ptr_array_add(enum_fc->label_buf,
+                                       mapping->label->str);
+                               break;
+                       }
+               }
+       }
+
+       *label_array = (void *) enum_fc->label_buf->pdata;
+       *count = (uint64_t) enum_fc->label_buf->len;
+       return BT_FIELD_CLASS_STATUS_OK;
+}
+
+enum bt_field_class_status
+bt_field_class_signed_enumeration_get_mapping_labels_by_value(
+               const struct bt_field_class *fc, int64_t value,
+               bt_field_class_enumeration_mapping_label_array *label_array,
+               uint64_t *count)
+{
+       const struct bt_field_class_enumeration *enum_fc = (const void *) fc;
+       uint64_t i;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
+       BT_ASSERT_PRE_NON_NULL(count, "Count (output)");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
+               "Field class");
+       g_ptr_array_set_size(enum_fc->label_buf, 0);
+
+       for (i = 0; i < enum_fc->mappings->len; i++) {
+               uint64_t j;
+               const struct bt_field_class_enumeration_mapping *mapping =
+                       BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i);
+
+               for (j = 0; j < mapping->ranges->len; j++) {
+                       const struct bt_field_class_enumeration_mapping_range *range =
+                               BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(
+                                       mapping, j);
+
+                       if (value >= range->lower.i &&
+                                       value <= range->upper.i) {
+                               g_ptr_array_add(enum_fc->label_buf,
+                                       mapping->label->str);
+                               break;
+                       }
+               }
+       }
+
+       *label_array = (void *) enum_fc->label_buf->pdata;
+       *count = (uint64_t) enum_fc->label_buf->len;
+       return BT_FIELD_CLASS_STATUS_OK;
+}
+
+static inline
+enum bt_field_class_status add_mapping_to_enumeration_field_class(
+               struct bt_field_class *fc,
+               const char *label, uint64_t lower, uint64_t upper)
+{
+       int ret = BT_FIELD_CLASS_STATUS_OK;
+       uint64_t i;
+       struct bt_field_class_enumeration *enum_fc = (void *) fc;
+       struct bt_field_class_enumeration_mapping *mapping = NULL;
+       struct bt_field_class_enumeration_mapping_range *range;
+
+       BT_ASSERT(fc);
+       BT_ASSERT_PRE_NON_NULL(label, "Label");
+
+       /* Find existing mapping identified by this label */
+       for (i = 0; i < enum_fc->mappings->len; i++) {
+               struct bt_field_class_enumeration_mapping *mapping_candidate =
+                       BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc, i);
+
+               if (strcmp(mapping_candidate->label->str, label) == 0) {
+                       mapping = mapping_candidate;
+                       break;
+               }
+       }
+
+       if (!mapping) {
+               /* Create new mapping for this label */
+               g_array_set_size(enum_fc->mappings, enum_fc->mappings->len + 1);
+               mapping = BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(enum_fc,
+                       enum_fc->mappings->len - 1);
+               mapping->ranges = g_array_new(FALSE, TRUE,
+                       sizeof(struct bt_field_class_enumeration_mapping_range));
+               if (!mapping->ranges) {
+                       finalize_enumeration_field_class_mapping(mapping);
+                       g_array_set_size(enum_fc->mappings,
+                               enum_fc->mappings->len - 1);
+                       ret = BT_FIELD_CLASS_STATUS_NOMEM;
+                       goto end;
+               }
+
+               mapping->label = g_string_new(label);
+               if (!mapping->label) {
+                       finalize_enumeration_field_class_mapping(mapping);
+                       g_array_set_size(enum_fc->mappings,
+                               enum_fc->mappings->len - 1);
+                       ret = BT_FIELD_CLASS_STATUS_NOMEM;
+                       goto end;
+               }
+       }
+
+       /* Add range */
+       BT_ASSERT(mapping);
+       g_array_set_size(mapping->ranges, mapping->ranges->len + 1);
+       range = BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(mapping,
+               mapping->ranges->len - 1);
+       range->lower.u = lower;
+       range->upper.u = upper;
+       BT_LIB_LOGV("Added mapping to enumeration field class: "
+               "%![fc-]+F, label=\"%s\", lower-unsigned=%" PRIu64 ", "
+               "upper-unsigned=%" PRIu64, fc, label, lower, upper);
+
+end:
+       return ret;
+}
+
+enum bt_field_class_status bt_field_class_unsigned_enumeration_map_range(
+               struct bt_field_class *fc, const char *label,
+               uint64_t range_lower, uint64_t range_upper)
+{
+       struct bt_field_class_enumeration *enum_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION,
+               "Field class");
+       BT_ASSERT_PRE(range_lower <= range_upper,
+               "Range's upper bound is less than lower bound: "
+               "upper=%" PRIu64 ", lower=%" PRIu64,
+               range_lower, range_upper);
+       BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(enum_fc->common.range,
+               range_lower),
+               "Range's lower bound is outside the enumeration field class's value range: "
+               "%![fc-]+F, lower=%" PRIu64, fc, range_lower);
+       BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(enum_fc->common.range,
+               range_upper),
+               "Range's upper bound is outside the enumeration field class's value range: "
+               "%![fc-]+F, upper=%" PRIu64, fc, range_upper);
+       return add_mapping_to_enumeration_field_class(fc, label, range_lower,
+               range_upper);
+}
+
+enum bt_field_class_status bt_field_class_signed_enumeration_map_range(
+               struct bt_field_class *fc, const char *label,
+               int64_t range_lower, int64_t range_upper)
+{
+       struct bt_field_class_enumeration *enum_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION,
+               "Field class");
+       BT_ASSERT_PRE(range_lower <= range_upper,
+               "Range's upper bound is less than lower bound: "
+               "upper=%" PRId64 ", lower=%" PRId64,
+               range_lower, range_upper);
+       BT_ASSERT_PRE(bt_util_value_is_in_range_signed(enum_fc->common.range,
+               range_lower),
+               "Range's lower bound is outside the enumeration field class's value range: "
+               "%![fc-]+F, lower=%" PRId64, fc, range_lower);
+       BT_ASSERT_PRE(bt_util_value_is_in_range_signed(enum_fc->common.range,
+               range_upper),
+               "Range's upper bound is outside the enumeration field class's value range: "
+               "%![fc-]+F, upper=%" PRId64, fc, range_upper);
+       return add_mapping_to_enumeration_field_class(fc, label, range_lower,
+               range_upper);
+}
+
+static
+void destroy_real_field_class(struct bt_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying real field class object: %!+F", obj);
+       g_free(obj);
+}
+
+struct bt_field_class *bt_field_class_real_create(bt_trace_class *trace_class)
+{
+       struct bt_field_class_real *real_fc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
+       BT_LOGD_STR("Creating default real field class object.");
+       real_fc = g_new0(struct bt_field_class_real, 1);
+       if (!real_fc) {
+               BT_LOGE_STR("Failed to allocate one real field class.");
+               goto error;
+       }
+
+       init_field_class((void *) real_fc, BT_FIELD_CLASS_TYPE_REAL,
+               destroy_real_field_class);
+       BT_LIB_LOGD("Created real field class object: %!+F", real_fc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(real_fc);
+
+end:
+       return (void *) real_fc;
+}
+
+bt_bool bt_field_class_real_is_single_precision(const struct bt_field_class *fc)
+{
+       const struct bt_field_class_real *real_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_REAL, "Field class");
+       return real_fc->is_single_precision;
+}
+
+void bt_field_class_real_set_is_single_precision(struct bt_field_class *fc,
+               bt_bool is_single_precision)
+{
+       struct bt_field_class_real *real_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_REAL, "Field class");
+       BT_ASSERT_PRE_FC_HOT(fc, "Field class");
+       real_fc->is_single_precision = (bool) is_single_precision;
+       BT_LIB_LOGV("Set real field class's \"is single precision\" property: "
+               "%!+F", fc);
+}
+
+static
+int init_named_field_classes_container(
+               struct bt_field_class_named_field_class_container *fc,
+               enum bt_field_class_type type,
+               bt_object_release_func release_func)
+{
+       int ret = 0;
+
+       init_field_class((void *) fc, type, release_func);
+       fc->named_fcs = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_named_field_class));
+       if (!fc->named_fcs) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               ret = -1;
+               goto end;
+       }
+
+       fc->name_to_index = g_hash_table_new(g_str_hash, g_str_equal);
+       if (!fc->name_to_index) {
+               BT_LOGE_STR("Failed to allocate a GHashTable.");
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+void finalize_named_field_class(struct bt_named_field_class *named_fc)
+{
+       BT_ASSERT(named_fc);
+       BT_LIB_LOGD("Finalizing named field class: "
+               "addr=%p, name=\"%s\", %![fc-]+F",
+               named_fc, named_fc->name ? named_fc->name->str : NULL,
+               named_fc->fc);
+
+       if (named_fc->name) {
+               g_string_free(named_fc->name, TRUE);
+       }
+
+       BT_LOGD_STR("Putting named field class's field class.");
+       BT_OBJECT_PUT_REF_AND_RESET(named_fc->fc);
+}
+
+static
+void finalize_named_field_classes_container(
+               struct bt_field_class_named_field_class_container *fc)
+{
+       uint64_t i;
+
+       BT_ASSERT(fc);
+
+       if (fc->named_fcs) {
+               for (i = 0; i < fc->named_fcs->len; i++) {
+                       finalize_named_field_class(
+                               &g_array_index(fc->named_fcs,
+                                       struct bt_named_field_class, i));
+               }
+
+               g_array_free(fc->named_fcs, TRUE);
+       }
+
+       if (fc->name_to_index) {
+               g_hash_table_destroy(fc->name_to_index);
+       }
+}
+
+static
+void destroy_structure_field_class(struct bt_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying structure field class object: %!+F", obj);
+       finalize_named_field_classes_container((void *) obj);
+       g_free(obj);
+}
+
+struct bt_field_class *bt_field_class_structure_create(
+               bt_trace_class *trace_class)
+{
+       int ret;
+       struct bt_field_class_structure *struct_fc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
+       BT_LOGD_STR("Creating default structure field class object.");
+       struct_fc = g_new0(struct bt_field_class_structure, 1);
+       if (!struct_fc) {
+               BT_LOGE_STR("Failed to allocate one structure field class.");
+               goto error;
+       }
+
+       ret = init_named_field_classes_container((void *) struct_fc,
+               BT_FIELD_CLASS_TYPE_STRUCTURE, destroy_structure_field_class);
+       if (ret) {
+               goto error;
+       }
+
+       BT_LIB_LOGD("Created structure field class object: %!+F", struct_fc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(struct_fc);
+
+end:
+       return (void *) struct_fc;
+}
+
+static
+enum bt_field_class_status append_named_field_class_to_container_field_class(
+               struct bt_field_class_named_field_class_container *container_fc,
+               const char *name, struct bt_field_class *fc)
+{
+       int ret = BT_FIELD_CLASS_STATUS_OK;
+       struct bt_named_field_class *named_fc;
+       GString *name_str;
+
+       BT_ASSERT(container_fc);
+       BT_ASSERT_PRE_FC_HOT(container_fc, "Field class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE(!bt_g_hash_table_contains(container_fc->name_to_index,
+               name),
+               "Duplicate member/option name in structure/variant field class: "
+               "%![container-fc-]+F, name=\"%s\"", container_fc, name);
+       name_str = g_string_new(name);
+       if (!name_str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = BT_FIELD_CLASS_STATUS_NOMEM;
+               goto end;
+       }
+
+       g_array_set_size(container_fc->named_fcs,
+               container_fc->named_fcs->len + 1);
+       named_fc = &g_array_index(container_fc->named_fcs,
+               struct bt_named_field_class, container_fc->named_fcs->len - 1);
+       named_fc->name = name_str;
+       named_fc->fc = fc;
+       bt_object_get_no_null_check(fc);
+       g_hash_table_insert(container_fc->name_to_index, named_fc->name->str,
+               GUINT_TO_POINTER(container_fc->named_fcs->len - 1));
+
+       /*
+        * Freeze the field class, but not the named field class (the
+        * user can still modify it, if possible, until the container
+        * itself is frozen).
+        */
+       bt_field_class_freeze(fc);
+
+end:
+       return ret;
+}
+
+enum bt_field_class_status bt_field_class_structure_append_member(
+               struct bt_field_class *fc, const char *name,
+               struct bt_field_class *member_fc)
+{
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Field class");
+       return append_named_field_class_to_container_field_class((void *) fc,
+               name, member_fc);
+}
+
+uint64_t bt_field_class_structure_get_member_count(
+               const struct bt_field_class *fc)
+{
+       struct bt_field_class_structure *struct_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Field class");
+       return (uint64_t) struct_fc->common.named_fcs->len;
+}
+
+static
+struct bt_named_field_class *
+borrow_named_field_class_from_container_field_class_at_index(
+               struct bt_field_class_named_field_class_container *fc,
+               uint64_t index)
+{
+       BT_ASSERT(fc);
+       BT_ASSERT_PRE_VALID_INDEX(index, fc->named_fcs->len);
+       return BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc, index);
+}
+
+const struct bt_field_class_structure_member *
+bt_field_class_structure_borrow_member_by_index_const(
+               const struct bt_field_class *fc, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Field class");
+       return (const void *)
+               borrow_named_field_class_from_container_field_class_at_index(
+                       (void *) fc, index);
+}
+
+struct bt_field_class_structure_member *
+bt_field_class_structure_borrow_member_by_index(
+               struct bt_field_class *fc, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Field class");
+       return (void *)
+               borrow_named_field_class_from_container_field_class_at_index(
+                       (void *) fc, index);
+}
+
+static
+struct bt_named_field_class *
+borrow_named_field_class_from_container_field_class_by_name(
+               struct bt_field_class_named_field_class_container *fc,
+               const char *name)
+{
+       struct bt_named_field_class *named_fc = NULL;
+       gpointer orig_key;
+       gpointer value;
+
+       BT_ASSERT(fc);
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       if (!g_hash_table_lookup_extended(fc->name_to_index, name, &orig_key,
+                       &value)) {
+               goto end;
+       }
+
+       named_fc = BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc,
+               GPOINTER_TO_UINT(value));
+
+end:
+       return named_fc;
+}
+
+const struct bt_field_class_structure_member *
+bt_field_class_structure_borrow_member_by_name_const(
+               const struct bt_field_class *fc, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Field class");
+       return (const void *)
+               borrow_named_field_class_from_container_field_class_by_name(
+                       (void *) fc, name);
+}
+
+struct bt_field_class_structure_member *
+bt_field_class_structure_borrow_member_by_name(
+               struct bt_field_class *fc, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Field class");
+       return (void *)
+               borrow_named_field_class_from_container_field_class_by_name(
+                       (void *) fc, name);
+}
+
+const char *bt_field_class_structure_member_get_name(
+               const struct bt_field_class_structure_member *member)
+{
+       const struct bt_named_field_class *named_fc = (const void *) member;
+
+       BT_ASSERT_PRE_NON_NULL(member, "Structure field class member");
+       return named_fc->name->str;
+}
+
+const struct bt_field_class *
+bt_field_class_structure_member_borrow_field_class_const(
+               const struct bt_field_class_structure_member *member)
+{
+       const struct bt_named_field_class *named_fc = (const void *) member;
+
+       BT_ASSERT_PRE_NON_NULL(member, "Structure field class member");
+       return named_fc->fc;
+}
+
+struct bt_field_class *
+bt_field_class_structure_member_borrow_field_class(
+               struct bt_field_class_structure_member *member)
+{
+       struct bt_named_field_class *named_fc = (void *) member;
+
+       BT_ASSERT_PRE_NON_NULL(member, "Structure field class member");
+       return named_fc->fc;
+}
+
+static
+void destroy_variant_field_class(struct bt_object *obj)
+{
+       struct bt_field_class_variant *fc = (void *) obj;
+
+       BT_ASSERT(fc);
+       BT_LIB_LOGD("Destroying variant field class object: %!+F", fc);
+       finalize_named_field_classes_container((void *) fc);
+       BT_LOGD_STR("Putting selector field path.");
+       BT_OBJECT_PUT_REF_AND_RESET(fc->selector_field_path);
+       BT_LOGD_STR("Putting selector field class.");
+       BT_OBJECT_PUT_REF_AND_RESET(fc->selector_fc);
+       g_free(fc);
+}
+
+struct bt_field_class *bt_field_class_variant_create(
+               bt_trace_class *trace_class)
+{
+       int ret;
+       struct bt_field_class_variant *var_fc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
+       BT_LOGD_STR("Creating default variant field class object.");
+       var_fc = g_new0(struct bt_field_class_variant, 1);
+       if (!var_fc) {
+               BT_LOGE_STR("Failed to allocate one variant field class.");
+               goto error;
+       }
+
+       ret = init_named_field_classes_container((void *) var_fc,
+               BT_FIELD_CLASS_TYPE_VARIANT, destroy_variant_field_class);
+       if (ret) {
+               goto error;
+       }
+
+       BT_LIB_LOGD("Created variant field class object: %!+F", var_fc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(var_fc);
+
+end:
+       return (void *) var_fc;
+}
+
+enum bt_field_class_status bt_field_class_variant_set_selector_field_class(
+               struct bt_field_class *fc,
+               struct bt_field_class *selector_fc)
+{
+       struct bt_field_class_variant *var_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Variant field class");
+       BT_ASSERT_PRE_NON_NULL(selector_fc, "Selector field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
+       BT_ASSERT_PRE_FC_IS_ENUM(selector_fc, "Selector field class");
+       BT_ASSERT_PRE_FC_HOT(fc, "Variant field class");
+       var_fc->selector_fc = selector_fc;
+       bt_object_get_no_null_check(selector_fc);
+       bt_field_class_freeze(selector_fc);
+       return BT_FIELD_CLASS_STATUS_OK;
+}
+
+enum bt_field_class_status bt_field_class_variant_append_option(
+               struct bt_field_class *fc,
+               const char *name, struct bt_field_class *option_fc)
+{
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
+       return append_named_field_class_to_container_field_class((void *) fc,
+               name, option_fc);
+}
+
+const struct bt_field_class_variant_option *
+bt_field_class_variant_borrow_option_by_name_const(
+               const struct bt_field_class *fc, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
+       return (const void *)
+               borrow_named_field_class_from_container_field_class_by_name(
+                       (void *) fc, name);
+}
+
+struct bt_field_class_variant_option *
+bt_field_class_variant_borrow_option_by_name(
+               struct bt_field_class *fc, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
+       return (void *)
+               borrow_named_field_class_from_container_field_class_by_name(
+                       (void *) fc, name);
+}
+
+uint64_t bt_field_class_variant_get_option_count(const struct bt_field_class *fc)
+{
+       const struct bt_field_class_variant *var_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
+       return (uint64_t) var_fc->common.named_fcs->len;
+}
+
+const struct bt_field_class_variant_option *
+bt_field_class_variant_borrow_option_by_index_const(
+               const struct bt_field_class *fc, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
+       return (const void *)
+               borrow_named_field_class_from_container_field_class_at_index(
+                       (void *) fc, index);
+}
+
+struct bt_field_class_variant_option *
+bt_field_class_variant_borrow_option_by_index(
+               struct bt_field_class *fc, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT, "Field class");
+       return (void *)
+               borrow_named_field_class_from_container_field_class_at_index(
+                       (void *) fc, index);
+}
+
+const char *bt_field_class_variant_option_get_name(
+               const struct bt_field_class_variant_option *option)
+{
+       const struct bt_named_field_class *named_fc = (const void *) option;
+
+       BT_ASSERT_PRE_NON_NULL(option, "Variant field class option");
+       return named_fc->name->str;
+}
+
+const struct bt_field_class *
+bt_field_class_variant_option_borrow_field_class_const(
+               const struct bt_field_class_variant_option *option)
+{
+       const struct bt_named_field_class *named_fc = (const void *) option;
+
+       BT_ASSERT_PRE_NON_NULL(option, "Variant field class option");
+       return named_fc->fc;
+}
+
+struct bt_field_class *
+bt_field_class_variant_option_borrow_field_class(
+               struct bt_field_class_variant_option *option)
+{
+       struct bt_named_field_class *named_fc = (void *) option;
+
+       BT_ASSERT_PRE_NON_NULL(option, "Variant field class option");
+       return named_fc->fc;
+}
+
+const struct bt_field_path *
+bt_field_class_variant_borrow_selector_field_path_const(
+               const struct bt_field_class *fc)
+{
+       const struct bt_field_class_variant *var_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_VARIANT,
+               "Field class");
+       return var_fc->selector_field_path;
+}
+
+static
+void init_array_field_class(struct bt_field_class_array *fc,
+               enum bt_field_class_type type, bt_object_release_func release_func,
+               struct bt_field_class *element_fc)
+{
+       BT_ASSERT(element_fc);
+       init_field_class((void *) fc, type, release_func);
+       fc->element_fc = element_fc;
+       bt_object_get_no_null_check(element_fc);
+       bt_field_class_freeze(element_fc);
+}
+
+static
+void finalize_array_field_class(struct bt_field_class_array *array_fc)
+{
+       BT_ASSERT(array_fc);
+       BT_LOGD_STR("Putting element field class.");
+       BT_OBJECT_PUT_REF_AND_RESET(array_fc->element_fc);
+}
+
+static
+void destroy_static_array_field_class(struct bt_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying static array field class object: %!+F", obj);
+       finalize_array_field_class((void *) obj);
+       g_free(obj);
+}
+
+struct bt_field_class *
+bt_field_class_static_array_create(bt_trace_class *trace_class,
+               struct bt_field_class *element_fc, uint64_t length)
+{
+       struct bt_field_class_static_array *array_fc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(element_fc, "Element field class");
+       BT_LOGD_STR("Creating default static array field class object.");
+       array_fc = g_new0(struct bt_field_class_static_array, 1);
+       if (!array_fc) {
+               BT_LOGE_STR("Failed to allocate one static array field class.");
+               goto error;
+       }
+
+       init_array_field_class((void *) array_fc, BT_FIELD_CLASS_TYPE_STATIC_ARRAY,
+               destroy_static_array_field_class, element_fc);
+       array_fc->length = length;
+       BT_LIB_LOGD("Created static array field class object: %!+F", array_fc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(array_fc);
+
+end:
+       return (void *) array_fc;
+}
+
+const struct bt_field_class *
+bt_field_class_array_borrow_element_field_class_const(
+               const struct bt_field_class *fc)
+{
+       const struct bt_field_class_array *array_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_IS_ARRAY(fc, "Field class");
+       return array_fc->element_fc;
+}
+
+struct bt_field_class *
+bt_field_class_array_borrow_element_field_class(struct bt_field_class *fc)
+{
+       struct bt_field_class_array *array_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_IS_ARRAY(fc, "Field class");
+       return array_fc->element_fc;
+}
+
+uint64_t bt_field_class_static_array_get_length(const struct bt_field_class *fc)
+{
+       const struct bt_field_class_static_array *array_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_STATIC_ARRAY,
+               "Field class");
+       return (uint64_t) array_fc->length;
+}
+
+static
+void destroy_dynamic_array_field_class(struct bt_object *obj)
+{
+       struct bt_field_class_dynamic_array *fc = (void *) obj;
+
+       BT_ASSERT(fc);
+       BT_LIB_LOGD("Destroying dynamic array field class object: %!+F", fc);
+       finalize_array_field_class((void *) fc);
+       BT_LOGD_STR("Putting length field path.");
+       BT_OBJECT_PUT_REF_AND_RESET(fc->length_field_path);
+       BT_LOGD_STR("Putting length field class.");
+       BT_OBJECT_PUT_REF_AND_RESET(fc->length_fc);
+       g_free(fc);
+}
+
+struct bt_field_class *bt_field_class_dynamic_array_create(
+               bt_trace_class *trace_class,
+               struct bt_field_class *element_fc)
+{
+       struct bt_field_class_dynamic_array *array_fc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(element_fc, "Element field class");
+       BT_LOGD_STR("Creating default dynamic array field class object.");
+       array_fc = g_new0(struct bt_field_class_dynamic_array, 1);
+       if (!array_fc) {
+               BT_LOGE_STR("Failed to allocate one dynamic array field class.");
+               goto error;
+       }
+
+       init_array_field_class((void *) array_fc,
+               BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY,
+               destroy_dynamic_array_field_class, element_fc);
+       BT_LIB_LOGD("Created dynamic array field class object: %!+F", array_fc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(array_fc);
+
+end:
+       return (void *) array_fc;
+}
+
+enum bt_field_class_status bt_field_class_dynamic_array_set_length_field_class(
+               struct bt_field_class *fc,
+               struct bt_field_class *length_fc)
+{
+       struct bt_field_class_dynamic_array *array_fc = (void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Dynamic array field class");
+       BT_ASSERT_PRE_NON_NULL(length_fc, "Length field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY,
+               "Field class");
+       BT_ASSERT_PRE_FC_IS_UNSIGNED_INT(length_fc, "Length field class");
+       BT_ASSERT_PRE_FC_HOT(fc, "Dynamic array field class");
+       array_fc->length_fc = length_fc;
+       bt_object_get_no_null_check(length_fc);
+       bt_field_class_freeze(length_fc);
+       return BT_FIELD_CLASS_STATUS_OK;
+}
+
+const struct bt_field_path *
+bt_field_class_dynamic_array_borrow_length_field_path_const(
+               const struct bt_field_class *fc)
+{
+       const struct bt_field_class_dynamic_array *seq_fc = (const void *) fc;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT_PRE_FC_HAS_ID(fc, BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY,
+               "Field class");
+       return seq_fc->length_field_path;
+}
+
+static
+void destroy_string_field_class(struct bt_object *obj)
+{
+       BT_ASSERT(obj);
+       BT_LIB_LOGD("Destroying string field class object: %!+F", obj);
+       g_free(obj);
+}
+
+struct bt_field_class *bt_field_class_string_create(bt_trace_class *trace_class)
+{
+       struct bt_field_class_string *string_fc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(trace_class, "Trace class");
+       BT_LOGD_STR("Creating default string field class object.");
+       string_fc = g_new0(struct bt_field_class_string, 1);
+       if (!string_fc) {
+               BT_LOGE_STR("Failed to allocate one string field class.");
+               goto error;
+       }
+
+       init_field_class((void *) string_fc, BT_FIELD_CLASS_TYPE_STRING,
+               destroy_string_field_class);
+       BT_LIB_LOGD("Created string field class object: %!+F", string_fc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(string_fc);
+
+end:
+       return (void *) string_fc;
+}
+
+BT_HIDDEN
+void _bt_field_class_freeze(const struct bt_field_class *c_fc)
+{
+       struct bt_field_class *fc = (void *) c_fc;
+
+       /*
+        * Element/member/option field classes are frozen when added to
+        * their owner.
+        */
+       BT_ASSERT(fc);
+       fc->frozen = true;
+
+       switch (fc->type) {
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct bt_field_class_named_field_class_container *container_fc =
+                       (void *) fc;
+               uint64_t i;
+
+               for (i = 0; i < container_fc->named_fcs->len; i++) {
+                       struct bt_named_field_class *named_fc =
+                               BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
+                                       container_fc, i);
+
+                       bt_named_field_class_freeze(named_fc);
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+BT_HIDDEN
+void _bt_named_field_class_freeze(const struct bt_named_field_class *named_fc)
+{
+       BT_ASSERT(named_fc);
+       ((struct bt_named_field_class *) named_fc)->frozen = true;
+       bt_field_class_freeze(named_fc->fc);
+}
+
+BT_HIDDEN
+void _bt_field_class_make_part_of_trace_class(const struct bt_field_class *c_fc)
+{
+       struct bt_field_class *fc = (void *) c_fc;
+
+       BT_ASSERT(fc);
+       BT_ASSERT_PRE(!fc->part_of_trace_class,
+               "Field class is already part of a trace: %!+F", fc);
+       fc->part_of_trace_class = true;
+
+       switch (fc->type) {
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct bt_field_class_named_field_class_container *container_fc =
+                       (void *) fc;
+               uint64_t i;
+
+               for (i = 0; i < container_fc->named_fcs->len; i++) {
+                       struct bt_named_field_class *named_fc =
+                               BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
+                                       container_fc, i);
+
+                       bt_field_class_make_part_of_trace_class(named_fc->fc);
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+       {
+               struct bt_field_class_array *array_fc = (void *) fc;
+
+               bt_field_class_make_part_of_trace_class(array_fc->element_fc);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+void bt_field_class_get_ref(const struct bt_field_class *field_class)
+{
+       bt_object_get_ref(field_class);
+}
+
+void bt_field_class_put_ref(const struct bt_field_class *field_class)
+{
+       bt_object_put_ref(field_class);
+}
diff --git a/src/lib/trace-ir/field-class.h b/src/lib/trace-ir/field-class.h
new file mode 100644 (file)
index 0000000..b5692da
--- /dev/null
@@ -0,0 +1,270 @@
+#ifndef BABELTRACE_TRACE_IR_FIELD_CLASSES_INTERNAL_H
+#define BABELTRACE_TRACE_IR_FIELD_CLASSES_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/clock-class.h>
+#include <babeltrace2/trace-ir/field-class.h>
+#include "common/babeltrace.h"
+#include "lib/object.h"
+#include <babeltrace2/types.h>
+#include <stdint.h>
+#include <glib.h>
+
+#define BT_ASSERT_PRE_FC_IS_INT(_fc, _name)                            \
+       BT_ASSERT_PRE(                                                  \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER || \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER || \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION || \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, \
+               _name " is not an integer field class: %![fc-]+F", (_fc))
+
+#define BT_ASSERT_PRE_FC_IS_UNSIGNED_INT(_fc, _name)                   \
+       BT_ASSERT_PRE(                                                  \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER || \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, \
+               _name " is not an unsigned integer field class: %![fc-]+F", (_fc))
+
+#define BT_ASSERT_PRE_FC_IS_ENUM(_fc, _name)                           \
+       BT_ASSERT_PRE(                                                  \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION || \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, \
+               _name " is not an enumeration field class: %![fc-]+F", (_fc))
+
+#define BT_ASSERT_PRE_FC_IS_ARRAY(_fc, _name)                          \
+       BT_ASSERT_PRE(                                                  \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY || \
+               ((const struct bt_field_class *) (_fc))->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, \
+               _name " is not an array field class: %![fc-]+F", (_fc))
+
+#define BT_ASSERT_PRE_FC_HAS_ID(_fc, _type, _name)                     \
+       BT_ASSERT_PRE(((const struct bt_field_class *) (_fc))->type == (_type),         \
+               _name " has the wrong type: expected-type=%s, "         \
+               "%![fc-]+F", bt_common_field_class_type_string(_type), (_fc))
+
+#define BT_ASSERT_PRE_FC_HOT(_fc, _name)                               \
+       BT_ASSERT_PRE_HOT((const struct bt_field_class *) (_fc),                \
+               (_name), ": %!+F", (_fc))
+
+#define BT_FIELD_CLASS_NAMED_FC_AT_INDEX(_fc, _index)          \
+       (&g_array_index(((struct bt_field_class_named_field_class_container *) (_fc))->named_fcs, \
+               struct bt_named_field_class, (_index)))
+
+#define BT_FIELD_CLASS_ENUM_MAPPING_AT_INDEX(_fc, _index)              \
+       (&g_array_index(((struct bt_field_class_enumeration *) (_fc))->mappings, \
+               struct bt_field_class_enumeration_mapping, (_index)))
+
+#define BT_FIELD_CLASS_ENUM_MAPPING_RANGE_AT_INDEX(_mapping, _index)   \
+       (&g_array_index((_mapping)->ranges,                             \
+               struct bt_field_class_enumeration_mapping_range, (_index)))
+
+struct bt_field;
+struct bt_field_class;
+
+struct bt_field_class {
+       struct bt_object base;
+       enum bt_field_class_type type;
+       bool frozen;
+
+       /*
+        * Only used in developer mode, this flag indicates whether or
+        * not this field class is part of a trace class.
+        */
+       bool part_of_trace_class;
+};
+
+struct bt_field_class_integer {
+       struct bt_field_class common;
+
+       /*
+        * Value range of fields built from this integer field class:
+        * this is an equivalent integer size in bits. More formally,
+        * `range` is `n` in:
+        *
+        * Unsigned range: [0, 2^n - 1]
+        * Signed range: [-2^(n - 1), 2^(n - 1) - 1]
+        */
+       uint64_t range;
+
+       enum bt_field_class_integer_preferred_display_base base;
+};
+
+struct bt_field_class_enumeration_mapping_range {
+       union {
+               uint64_t u;
+               int64_t i;
+       } lower;
+
+       union {
+               uint64_t u;
+               int64_t i;
+       } upper;
+};
+
+struct bt_field_class_enumeration_mapping {
+       GString *label;
+
+       /* Array of `struct bt_field_class_enumeration_mapping_range` */
+       GArray *ranges;
+};
+
+struct bt_field_class_unsigned_enumeration_mapping;
+struct bt_field_class_signed_enumeration_mapping;
+
+struct bt_field_class_enumeration {
+       struct bt_field_class_integer common;
+
+       /* Array of `struct bt_field_class_enumeration_mapping *` */
+       GArray *mappings;
+
+       /*
+        * This is an array of `const char *` which acts as a temporary
+        * (potentially growing) buffer for
+        * bt_field_class_unsigned_enumeration_get_mapping_labels_by_value()
+        * and
+        * bt_field_class_signed_enumeration_get_mapping_labels_by_value().
+        *
+        * The actual strings are owned by the mappings above.
+        */
+       GPtrArray *label_buf;
+};
+
+struct bt_field_class_real {
+       struct bt_field_class common;
+       bool is_single_precision;
+};
+
+struct bt_field_class_string {
+       struct bt_field_class common;
+};
+
+/* A named field class is a (name, field class) pair */
+struct bt_named_field_class {
+       GString *name;
+
+       /* Owned by this */
+       struct bt_field_class *fc;
+
+       bool frozen;
+};
+
+struct bt_field_class_structure_member;
+struct bt_field_class_variant_option;
+
+/*
+ * This is the base field class for a container of named field classes.
+ * Structure and variant field classes inherit this.
+ */
+struct bt_field_class_named_field_class_container {
+       struct bt_field_class common;
+
+       /*
+        * Key: `const char *`, not owned by this (owned by named field
+        * type objects contained in `named_fcs` below).
+        */
+       GHashTable *name_to_index;
+
+       /* Array of `struct bt_named_field_class` */
+       GArray *named_fcs;
+};
+
+struct bt_field_class_structure {
+       struct bt_field_class_named_field_class_container common;
+};
+
+struct bt_field_class_array {
+       struct bt_field_class common;
+
+       /* Owned by this */
+       struct bt_field_class *element_fc;
+};
+
+struct bt_field_class_static_array {
+       struct bt_field_class_array common;
+       uint64_t length;
+};
+
+struct bt_field_class_dynamic_array {
+       struct bt_field_class_array common;
+
+       /* Weak: never dereferenced, only use to find it elsewhere */
+       struct bt_field_class *length_fc;
+
+       /* Owned by this */
+       struct bt_field_path *length_field_path;
+};
+
+struct bt_field_class_variant {
+       struct bt_field_class_named_field_class_container common;
+
+       /* Weak: never dereferenced, only use to find it elsewhere */
+       struct bt_field_class *selector_fc;
+
+       /* Owned by this */
+       struct bt_field_path *selector_field_path;
+};
+
+static inline
+bool bt_field_class_has_known_type(const struct bt_field_class *fc)
+{
+       return fc->type >= BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER &&
+               fc->type <= BT_FIELD_CLASS_TYPE_VARIANT;
+}
+
+BT_HIDDEN
+void _bt_field_class_freeze(const struct bt_field_class *field_class);
+
+#ifdef BT_DEV_MODE
+# define bt_field_class_freeze         _bt_field_class_freeze
+#else
+# define bt_field_class_freeze(_fc)    ((void) _fc)
+#endif
+
+BT_HIDDEN
+void _bt_named_field_class_freeze(const struct bt_named_field_class *named_fc);
+
+#ifdef BT_DEV_MODE
+# define bt_named_field_class_freeze           _bt_named_field_class_freeze
+#else
+# define bt_named_field_class_freeze(_named_fc)        ((void) _named_fc)
+#endif
+
+/*
+ * This function recursively marks `field_class` and its children as
+ * being part of a trace. This is used to validate that all field classes
+ * are used at a single location within trace objects even if they are
+ * shared objects for other purposes.
+ */
+BT_HIDDEN
+void _bt_field_class_make_part_of_trace_class(
+               const struct bt_field_class *field_class);
+
+#ifdef BT_DEV_MODE
+# define bt_field_class_make_part_of_trace_class       _bt_field_class_make_part_of_trace_class
+#else
+# define bt_field_class_make_part_of_trace_class(_fc)  ((void) _fc)
+#endif
+
+#endif /* BABELTRACE_TRACE_IR_FIELD_CLASSES_INTERNAL_H */
diff --git a/src/lib/trace-ir/field-path.c b/src/lib/trace-ir/field-path.c
new file mode 100644 (file)
index 0000000..d43cc5b
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "FIELD-PATH"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/field-class.h>
+#include <babeltrace2/trace-ir/field-path-const.h>
+#include <limits.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include "common/assert.h"
+#include <glib.h>
+
+#include "field-class.h"
+#include "field-path.h"
+
+static
+void destroy_field_path(struct bt_object *obj)
+{
+       struct bt_field_path *field_path = (struct bt_field_path *) obj;
+
+       BT_ASSERT(field_path);
+       BT_LIB_LOGD("Destroying field path: %!+P", field_path);
+       g_array_free(field_path->items, TRUE);
+       field_path->items = NULL;
+       g_free(field_path);
+}
+
+BT_HIDDEN
+struct bt_field_path *bt_field_path_create(void)
+{
+       struct bt_field_path *field_path = NULL;
+
+       BT_LOGD_STR("Creating empty field path object.");
+
+       field_path = g_new0(struct bt_field_path, 1);
+       if (!field_path) {
+               BT_LOGE_STR("Failed to allocate one field path.");
+               goto error;
+       }
+
+       bt_object_init_shared(&field_path->base, destroy_field_path);
+       field_path->items = g_array_new(FALSE, FALSE,
+               sizeof(struct bt_field_path_item));
+       if (!field_path->items) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
+       }
+
+       BT_LIB_LOGD("Created empty field path object: %!+P", field_path);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(field_path);
+
+end:
+       return field_path;
+}
+
+enum bt_scope bt_field_path_get_root_scope(
+               const struct bt_field_path *field_path)
+{
+       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
+       return field_path->root;
+}
+
+uint64_t bt_field_path_get_item_count(const struct bt_field_path *field_path)
+{
+       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
+       return (uint64_t) field_path->items->len;
+}
+
+const struct bt_field_path_item *bt_field_path_borrow_item_by_index_const(
+               const struct bt_field_path *field_path, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(field_path, "Field path");
+       BT_ASSERT_PRE_VALID_INDEX(index, field_path->items->len);
+       return bt_field_path_borrow_item_by_index_inline(field_path, index);
+}
+
+enum bt_field_path_item_type bt_field_path_item_get_type(
+               const struct bt_field_path_item *field_path_item)
+{
+       BT_ASSERT_PRE_NON_NULL(field_path_item, "Field path item");
+       return field_path_item->type;
+}
+
+uint64_t bt_field_path_item_index_get_index(
+               const struct bt_field_path_item *field_path_item)
+{
+       BT_ASSERT_PRE_NON_NULL(field_path_item, "Field path item");
+       BT_ASSERT_PRE(field_path_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX,
+               "Field path item is not an index field path item: "
+               "addr=%p, type=%s", field_path_item,
+               bt_field_path_item_type_string(field_path_item->type));
+       return  field_path_item->index;
+}
+
+void bt_field_path_get_ref(const struct bt_field_path *field_path)
+{
+       bt_object_get_ref(field_path);
+}
+
+void bt_field_path_put_ref(const struct bt_field_path *field_path)
+{
+       bt_object_put_ref(field_path);
+}
diff --git a/src/lib/trace-ir/field-path.h b/src/lib/trace-ir/field-path.h
new file mode 100644 (file)
index 0000000..506c006
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef BABELTRACE_TRACE_IR_FIELD_PATH_INTERNAL
+#define BABELTRACE_TRACE_IR_FIELD_PATH_INTERNAL
+
+/*
+ * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include "lib/object.h"
+#include <babeltrace2/trace-ir/field-path-const.h>
+#include "common/assert.h"
+#include <glib.h>
+
+struct bt_field_path_item {
+       enum bt_field_path_item_type type;
+       uint64_t index;
+};
+
+struct bt_field_path {
+       struct bt_object base;
+       enum bt_scope root;
+
+       /* Array of `struct bt_field_path_item` (items) */
+       GArray *items;
+};
+
+BT_HIDDEN
+struct bt_field_path *bt_field_path_create(void);
+
+static inline
+struct bt_field_path_item *bt_field_path_borrow_item_by_index_inline(
+               const struct bt_field_path *field_path, uint64_t index)
+{
+       BT_ASSERT(field_path);
+       BT_ASSERT(index < field_path->items->len);
+       return &g_array_index(field_path->items, struct bt_field_path_item,
+               index);
+}
+
+static inline
+void bt_field_path_append_item(struct bt_field_path *field_path,
+               struct bt_field_path_item *item)
+{
+       BT_ASSERT(field_path);
+       BT_ASSERT(item);
+       g_array_append_val(field_path->items, *item);
+}
+
+static inline
+void bt_field_path_remove_last_item(struct bt_field_path *field_path)
+{
+       BT_ASSERT(field_path);
+       BT_ASSERT(field_path->items->len > 0);
+       g_array_set_size(field_path->items, field_path->items->len - 1);
+}
+
+static inline
+const char *bt_field_path_item_type_string(enum bt_field_path_item_type type)
+{
+       switch (type) {
+       case BT_FIELD_PATH_ITEM_TYPE_INDEX:
+               return "BT_FIELD_PATH_ITEM_TYPE_INDEX";
+       case BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT:
+               return "BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT";
+       default:
+               return "(unknown)";
+       }
+};
+
+#endif /* BABELTRACE_TRACE_IR_FIELD_PATH_INTERNAL */
diff --git a/src/lib/trace-ir/field-wrapper.c b/src/lib/trace-ir/field-wrapper.c
new file mode 100644 (file)
index 0000000..778d865
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "FIELD-WRAPPER"
+#include "lib/lib-logging.h"
+
+#include "lib/object-pool.h"
+#include "lib/object.h"
+#include <glib.h>
+
+#include "field-wrapper.h"
+#include "field.h"
+
+BT_HIDDEN
+struct bt_field_wrapper *bt_field_wrapper_new(void *data)
+{
+       struct bt_field_wrapper *field_wrapper =
+               g_new0(struct bt_field_wrapper, 1);
+
+       BT_LOGD_STR("Creating empty field wrapper object.");
+
+       if (!field_wrapper) {
+               BT_LOGE("Failed to allocate one field wrapper.");
+               goto end;
+       }
+
+       bt_object_init_unique(&field_wrapper->base);
+       BT_LOGD("Created empty field wrapper object: addr=%p",
+               field_wrapper);
+
+end:
+       return field_wrapper;
+}
+
+BT_HIDDEN
+void bt_field_wrapper_destroy(struct bt_field_wrapper *field_wrapper)
+{
+       BT_LOGD("Destroying field wrapper: addr=%p", field_wrapper);
+
+       if (field_wrapper->field) {
+               BT_LOGD_STR("Destroying field.");
+               bt_field_destroy((void *) field_wrapper->field);
+               field_wrapper->field = NULL;
+       }
+
+       BT_LOGD_STR("Putting stream class.");
+       g_free(field_wrapper);
+}
+
+BT_HIDDEN
+struct bt_field_wrapper *bt_field_wrapper_create(
+               struct bt_object_pool *pool, struct bt_field_class *fc)
+{
+       struct bt_field_wrapper *field_wrapper = NULL;
+
+       BT_ASSERT(pool);
+       BT_ASSERT(fc);
+       field_wrapper = bt_object_pool_create_object(pool);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one field wrapper from field wrapper pool: "
+                       "%![pool-]+o", pool);
+               goto error;
+       }
+
+       if (!field_wrapper->field) {
+               field_wrapper->field = (void *) bt_field_create(fc);
+               if (!field_wrapper->field) {
+                       BT_LIB_LOGE("Cannot create field wrapper from field class: "
+                               "%![fc-]+F", fc);
+                       goto error;
+               }
+
+               BT_LIB_LOGD("Created initial field wrapper object: "
+                       "wrapper-addr=%p, %![field-]+f", field_wrapper,
+                       field_wrapper->field);
+       }
+
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return field_wrapper;
+}
diff --git a/src/lib/trace-ir/field-wrapper.h b/src/lib/trace-ir/field-wrapper.h
new file mode 100644 (file)
index 0000000..97728e0
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef BABELTRACE_TRACE_IR_FIELD_WRAPPER_INTERNAL_H
+#define BABELTRACE_TRACE_IR_FIELD_WRAPPER_INTERNAL_H
+
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "lib/object-pool.h"
+#include "lib/object.h"
+
+#include "field.h"
+
+struct bt_field_wrapper {
+       struct bt_object base;
+
+       /* Owned by this */
+       struct bt_field *field;
+};
+
+BT_HIDDEN
+struct bt_field_wrapper *bt_field_wrapper_new(void *data);
+
+BT_HIDDEN
+void bt_field_wrapper_destroy(struct bt_field_wrapper *field);
+
+BT_HIDDEN
+struct bt_field_wrapper *bt_field_wrapper_create(
+               struct bt_object_pool *pool, struct bt_field_class *fc);
+
+#endif /* BABELTRACE_TRACE_IR_FIELD_WRAPPER_INTERNAL_H */
diff --git a/src/lib/trace-ir/field.c b/src/lib/trace-ir/field.c
new file mode 100644 (file)
index 0000000..4f75c34
--- /dev/null
@@ -0,0 +1,1180 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "FIELDS"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/field.h>
+#include <babeltrace2/trace-ir/field-const.h>
+#include "lib/object.h"
+#include "compat/compiler.h"
+#include "compat/fcntl.h"
+#include "common/align.h"
+#include "common/assert.h"
+#include <inttypes.h>
+
+#include "field.h"
+#include "field-class.h"
+
+static
+void reset_single_field(struct bt_field *field);
+
+static
+void reset_array_field(struct bt_field *field);
+
+static
+void reset_structure_field(struct bt_field *field);
+
+static
+void reset_variant_field(struct bt_field *field);
+
+static
+void set_single_field_is_frozen(struct bt_field *field, bool is_frozen);
+
+static
+void set_array_field_is_frozen(struct bt_field *field, bool is_frozen);
+
+static
+void set_structure_field_is_frozen(struct bt_field *field, bool is_frozen);
+
+static
+void set_variant_field_is_frozen(struct bt_field *field, bool is_frozen);
+
+static
+bool single_field_is_set(const struct bt_field *field);
+
+static
+bool array_field_is_set(const struct bt_field *field);
+
+static
+bool structure_field_is_set(const struct bt_field *field);
+
+static
+bool variant_field_is_set(const struct bt_field *field);
+
+static
+struct bt_field_methods integer_field_methods = {
+       .set_is_frozen = set_single_field_is_frozen,
+       .is_set = single_field_is_set,
+       .reset = reset_single_field,
+};
+
+static
+struct bt_field_methods real_field_methods = {
+       .set_is_frozen = set_single_field_is_frozen,
+       .is_set = single_field_is_set,
+       .reset = reset_single_field,
+};
+
+static
+struct bt_field_methods string_field_methods = {
+       .set_is_frozen = set_single_field_is_frozen,
+       .is_set = single_field_is_set,
+       .reset = reset_single_field,
+};
+
+static
+struct bt_field_methods structure_field_methods = {
+       .set_is_frozen = set_structure_field_is_frozen,
+       .is_set = structure_field_is_set,
+       .reset = reset_structure_field,
+};
+
+static
+struct bt_field_methods array_field_methods = {
+       .set_is_frozen = set_array_field_is_frozen,
+       .is_set = array_field_is_set,
+       .reset = reset_array_field,
+};
+
+static
+struct bt_field_methods variant_field_methods = {
+       .set_is_frozen = set_variant_field_is_frozen,
+       .is_set = variant_field_is_set,
+       .reset = reset_variant_field,
+};
+
+static
+struct bt_field *create_integer_field(struct bt_field_class *);
+
+static
+struct bt_field *create_real_field(struct bt_field_class *);
+
+static
+struct bt_field *create_string_field(struct bt_field_class *);
+
+static
+struct bt_field *create_structure_field(struct bt_field_class *);
+
+static
+struct bt_field *create_static_array_field(struct bt_field_class *);
+
+static
+struct bt_field *create_dynamic_array_field(struct bt_field_class *);
+
+static
+struct bt_field *create_variant_field(struct bt_field_class *);
+
+static
+struct bt_field *(* const field_create_funcs[])(struct bt_field_class *) = {
+       [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER]  = create_integer_field,
+       [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER]    = create_integer_field,
+       [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = create_integer_field,
+       [BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION]        = create_integer_field,
+       [BT_FIELD_CLASS_TYPE_REAL]                      = create_real_field,
+       [BT_FIELD_CLASS_TYPE_STRING]            = create_string_field,
+       [BT_FIELD_CLASS_TYPE_STRUCTURE]         = create_structure_field,
+       [BT_FIELD_CLASS_TYPE_STATIC_ARRAY]              = create_static_array_field,
+       [BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY]     = create_dynamic_array_field,
+       [BT_FIELD_CLASS_TYPE_VARIANT]           = create_variant_field,
+};
+
+static
+void destroy_integer_field(struct bt_field *field);
+
+static
+void destroy_real_field(struct bt_field *field);
+
+static
+void destroy_string_field(struct bt_field *field);
+
+static
+void destroy_structure_field(struct bt_field *field);
+
+static
+void destroy_array_field(struct bt_field *field);
+
+static
+void destroy_variant_field(struct bt_field *field);
+
+static
+void (* const field_destroy_funcs[])(struct bt_field *) = {
+       [BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER]  = destroy_integer_field,
+       [BT_FIELD_CLASS_TYPE_SIGNED_INTEGER]    = destroy_integer_field,
+       [BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION] = destroy_integer_field,
+       [BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION]        = destroy_integer_field,
+       [BT_FIELD_CLASS_TYPE_REAL]                      = destroy_real_field,
+       [BT_FIELD_CLASS_TYPE_STRING]            = destroy_string_field,
+       [BT_FIELD_CLASS_TYPE_STRUCTURE]         = destroy_structure_field,
+       [BT_FIELD_CLASS_TYPE_STATIC_ARRAY]              = destroy_array_field,
+       [BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY]     = destroy_array_field,
+       [BT_FIELD_CLASS_TYPE_VARIANT]           = destroy_variant_field,
+};
+
+struct bt_field_class *bt_field_borrow_class(const struct bt_field *field)
+{
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       return field->class;
+}
+
+const struct bt_field_class *bt_field_borrow_class_const(
+               const struct bt_field *field)
+{
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       return field->class;
+}
+
+enum bt_field_class_type bt_field_get_class_type(const struct bt_field *field)
+{
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       return field->class->type;
+}
+
+BT_HIDDEN
+struct bt_field *bt_field_create(struct bt_field_class *fc)
+{
+       struct bt_field *field = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(fc, "Field class");
+       BT_ASSERT(bt_field_class_has_known_type(fc));
+       field = field_create_funcs[fc->type](fc);
+       if (!field) {
+               BT_LIB_LOGE("Cannot create field object from field class: "
+                       "%![fc-]+F", fc);
+               goto end;
+       }
+
+end:
+       return field;
+}
+
+static inline
+void init_field(struct bt_field *field, struct bt_field_class *fc,
+               struct bt_field_methods *methods)
+{
+       BT_ASSERT(field);
+       BT_ASSERT(fc);
+       bt_object_init_unique(&field->base);
+       field->methods = methods;
+       field->class = fc;
+       bt_object_get_no_null_check(fc);
+}
+
+static
+struct bt_field *create_integer_field(struct bt_field_class *fc)
+{
+       struct bt_field_integer *int_field;
+
+       BT_LIB_LOGD("Creating integer field object: %![fc-]+F", fc);
+       int_field = g_new0(struct bt_field_integer, 1);
+       if (!int_field) {
+               BT_LOGE_STR("Failed to allocate one integer field.");
+               goto end;
+       }
+
+       init_field((void *) int_field, fc, &integer_field_methods);
+       BT_LIB_LOGD("Created integer field object: %!+f", int_field);
+
+end:
+       return (void *) int_field;
+}
+
+static
+struct bt_field *create_real_field(struct bt_field_class *fc)
+{
+       struct bt_field_real *real_field;
+
+       BT_LIB_LOGD("Creating real field object: %![fc-]+F", fc);
+       real_field = g_new0(struct bt_field_real, 1);
+       if (!real_field) {
+               BT_LOGE_STR("Failed to allocate one real field.");
+               goto end;
+       }
+
+       init_field((void *) real_field, fc, &real_field_methods);
+       BT_LIB_LOGD("Created real field object: %!+f", real_field);
+
+end:
+       return (void *) real_field;
+}
+
+static
+struct bt_field *create_string_field(struct bt_field_class *fc)
+{
+       struct bt_field_string *string_field;
+
+       BT_LIB_LOGD("Creating string field object: %![fc-]+F", fc);
+       string_field = g_new0(struct bt_field_string, 1);
+       if (!string_field) {
+               BT_LOGE_STR("Failed to allocate one string field.");
+               goto end;
+       }
+
+       init_field((void *) string_field, fc, &string_field_methods);
+       string_field->buf = g_array_sized_new(FALSE, FALSE,
+               sizeof(char), 1);
+       if (!string_field->buf) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               BT_OBJECT_PUT_REF_AND_RESET(string_field);
+               goto end;
+       }
+
+       g_array_index(string_field->buf, char, 0) = '\0';
+       BT_LIB_LOGD("Created string field object: %!+f", string_field);
+
+end:
+       return (void *) string_field;
+}
+
+static inline
+int create_fields_from_named_field_classes(
+               struct bt_field_class_named_field_class_container *fc,
+               GPtrArray **fields)
+{
+       int ret = 0;
+       uint64_t i;
+
+       *fields = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_field_destroy);
+       if (!*fields) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_set_size(*fields, fc->named_fcs->len);
+
+       for (i = 0; i < fc->named_fcs->len; i++) {
+               struct bt_field *field;
+               struct bt_named_field_class *named_fc =
+                       BT_FIELD_CLASS_NAMED_FC_AT_INDEX(fc, i);
+
+               field = bt_field_create(named_fc->fc);
+               if (!field) {
+                       BT_LIB_LOGE("Failed to create structure member or variant option field: "
+                               "name=\"%s\", %![fc-]+F",
+                               named_fc->name->str, named_fc->fc);
+                       ret = -1;
+                       goto end;
+               }
+
+               g_ptr_array_index(*fields, i) = field;
+       }
+
+end:
+       return ret;
+}
+
+static
+struct bt_field *create_structure_field(struct bt_field_class *fc)
+{
+       struct bt_field_structure *struct_field;
+
+       BT_LIB_LOGD("Creating structure field object: %![fc-]+F", fc);
+       struct_field = g_new0(struct bt_field_structure, 1);
+       if (!struct_field) {
+               BT_LOGE_STR("Failed to allocate one structure field.");
+               goto end;
+       }
+
+       init_field((void *) struct_field, fc, &structure_field_methods);
+
+       if (create_fields_from_named_field_classes((void *) fc,
+                       &struct_field->fields)) {
+               BT_LIB_LOGE("Cannot create structure member fields: "
+                       "%![fc-]+F", fc);
+               BT_OBJECT_PUT_REF_AND_RESET(struct_field);
+               goto end;
+       }
+
+       BT_LIB_LOGD("Created structure field object: %!+f", struct_field);
+
+end:
+       return (void *) struct_field;
+}
+
+static
+struct bt_field *create_variant_field(struct bt_field_class *fc)
+{
+       struct bt_field_variant *var_field;
+
+       BT_LIB_LOGD("Creating variant field object: %![fc-]+F", fc);
+       var_field = g_new0(struct bt_field_variant, 1);
+       if (!var_field) {
+               BT_LOGE_STR("Failed to allocate one variant field.");
+               goto end;
+       }
+
+       init_field((void *) var_field, fc, &variant_field_methods);
+
+       if (create_fields_from_named_field_classes((void *) fc,
+                       &var_field->fields)) {
+               BT_LIB_LOGE("Cannot create variant member fields: "
+                       "%![fc-]+F", fc);
+               BT_OBJECT_PUT_REF_AND_RESET(var_field);
+               goto end;
+       }
+
+       BT_LIB_LOGD("Created variant field object: %!+f", var_field);
+
+end:
+       return (void *) var_field;
+}
+
+static inline
+int init_array_field_fields(struct bt_field_array *array_field)
+{
+       int ret = 0;
+       uint64_t i;
+       struct bt_field_class_array *array_fc;
+
+       BT_ASSERT(array_field);
+       array_fc = (void *) array_field->common.class;
+       array_field->fields = g_ptr_array_sized_new(array_field->length);
+       if (!array_field->fields) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               ret = -1;
+               goto end;
+       }
+
+       g_ptr_array_set_free_func(array_field->fields,
+               (GDestroyNotify) bt_field_destroy);
+       g_ptr_array_set_size(array_field->fields, array_field->length);
+
+       for (i = 0; i < array_field->length; i++) {
+               array_field->fields->pdata[i] = bt_field_create(
+                       array_fc->element_fc);
+               if (!array_field->fields->pdata[i]) {
+                       BT_LIB_LOGE("Cannot create array field's element field: "
+                               "index=%" PRIu64 ", %![fc-]+F", i, array_fc);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+struct bt_field *create_static_array_field(struct bt_field_class *fc)
+{
+       struct bt_field_class_static_array *array_fc = (void *) fc;
+       struct bt_field_array *array_field;
+
+       BT_LIB_LOGD("Creating static array field object: %![fc-]+F", fc);
+       array_field = g_new0(struct bt_field_array, 1);
+       if (!array_field) {
+               BT_LOGE_STR("Failed to allocate one static array field.");
+               goto end;
+       }
+
+       init_field((void *) array_field, fc, &array_field_methods);
+       array_field->length = array_fc->length;
+
+       if (init_array_field_fields(array_field)) {
+               BT_LIB_LOGE("Cannot create static array fields: "
+                       "%![fc-]+F", fc);
+               BT_OBJECT_PUT_REF_AND_RESET(array_field);
+               goto end;
+       }
+
+       BT_LIB_LOGD("Created static array field object: %!+f", array_field);
+
+end:
+       return (void *) array_field;
+}
+
+static
+struct bt_field *create_dynamic_array_field(struct bt_field_class *fc)
+{
+       struct bt_field_array *array_field;
+
+       BT_LIB_LOGD("Creating dynamic array field object: %![fc-]+F", fc);
+       array_field = g_new0(struct bt_field_array, 1);
+       if (!array_field) {
+               BT_LOGE_STR("Failed to allocate one dynamic array field.");
+               goto end;
+       }
+
+       init_field((void *) array_field, fc, &array_field_methods);
+
+       if (init_array_field_fields(array_field)) {
+               BT_LIB_LOGE("Cannot create dynamic array fields: "
+                       "%![fc-]+F", fc);
+               BT_OBJECT_PUT_REF_AND_RESET(array_field);
+               goto end;
+       }
+
+       BT_LIB_LOGD("Created dynamic array field object: %!+f", array_field);
+
+end:
+       return (void *) array_field;
+}
+
+int64_t bt_field_signed_integer_get_value(const struct bt_field *field)
+{
+       const struct bt_field_integer *int_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(field, "Field");
+       return int_field->value.i;
+}
+
+void bt_field_signed_integer_set_value(struct bt_field *field, int64_t value)
+{
+       struct bt_field_integer *int_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(field, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE(bt_util_value_is_in_range_signed(
+               ((struct bt_field_class_integer *) field->class)->range, value),
+               "Value is out of bounds: value=%" PRId64 ", %![field-]+f, "
+               "%![fc-]+F", value, field, field->class);
+       int_field->value.i = value;
+       bt_field_set_single(field, true);
+}
+
+uint64_t bt_field_unsigned_integer_get_value(const struct bt_field *field)
+{
+       const struct bt_field_integer *int_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(field, "Field");
+       return int_field->value.u;
+}
+
+void bt_field_unsigned_integer_set_value(struct bt_field *field, uint64_t value)
+{
+       struct bt_field_integer *int_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(field, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE(bt_util_value_is_in_range_unsigned(
+               ((struct bt_field_class_integer *) field->class)->range, value),
+               "Value is out of bounds: value=%" PRIu64 ", %![field-]+f, "
+               "%![fc-]+F", value, field, field->class);
+       int_field->value.u = value;
+       bt_field_set_single(field, true);
+}
+
+double bt_field_real_get_value(const struct bt_field *field)
+{
+       const struct bt_field_real *real_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_REAL, "Field");
+       return real_field->value;
+}
+
+void bt_field_real_set_value(struct bt_field *field, double value)
+{
+       struct bt_field_real *real_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_REAL, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE(
+               !((struct bt_field_class_real *) field->class)->is_single_precision ||
+               (double) (float) value == value,
+               "Invalid value for a single-precision real number: value=%f, "
+               "%![fc-]+F", value, field->class);
+       real_field->value = value;
+       bt_field_set_single(field, true);
+}
+
+enum bt_field_status bt_field_unsigned_enumeration_get_mapping_labels(
+               const struct bt_field *field,
+               bt_field_class_enumeration_mapping_label_array *label_array,
+               uint64_t *count)
+{
+       const struct bt_field_integer *int_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Count (output)");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, "Field");
+       return (int)
+               bt_field_class_unsigned_enumeration_get_mapping_labels_by_value(
+                       field->class, int_field->value.u, label_array, count);
+}
+
+enum bt_field_status bt_field_signed_enumeration_get_mapping_labels(
+               const struct bt_field *field,
+               bt_field_class_enumeration_mapping_label_array *label_array,
+               uint64_t *count)
+{
+       const struct bt_field_integer *int_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Label array (output)");
+       BT_ASSERT_PRE_NON_NULL(label_array, "Count (output)");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, "Field");
+       return (int)
+               bt_field_class_signed_enumeration_get_mapping_labels_by_value(
+                       field->class, int_field->value.i, label_array, count);
+}
+
+const char *bt_field_string_get_value(const struct bt_field *field)
+{
+       const struct bt_field_string *string_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_STRING,
+               "Field");
+       return (const char *) string_field->buf->data;
+}
+
+uint64_t bt_field_string_get_length(const struct bt_field *field)
+{
+       const struct bt_field_string *string_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_SET(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_STRING,
+               "Field");
+       return string_field->length;
+}
+
+static inline
+void clear_string_field(struct bt_field *field)
+{
+       struct bt_field_string *string_field = (void *) field;
+
+       BT_ASSERT(field);
+       string_field->length = 0;
+       bt_field_set_single(field, true);
+}
+
+enum bt_field_status bt_field_string_set_value(struct bt_field *field,
+               const char *value)
+{
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field, BT_FIELD_CLASS_TYPE_STRING,
+               "Field");
+       clear_string_field(field);
+       return bt_field_string_append_with_length(field, value,
+               (uint64_t) strlen(value));
+}
+
+enum bt_field_status bt_field_string_append(struct bt_field *field, const char *value)
+{
+       return bt_field_string_append_with_length(field,
+               value, (uint64_t) strlen(value));
+}
+
+enum bt_field_status bt_field_string_append_with_length(struct bt_field *field,
+               const char *value, uint64_t length)
+{
+       struct bt_field_string *string_field = (void *) field;
+       char *data;
+       uint64_t new_length;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_STRING, "Field");
+
+       /* Make sure no null bytes are appended */
+       BT_ASSERT_PRE(memchr(value, '\0', length) == NULL,
+               "String value to append contains a null character: "
+               "partial-value=\"%.32s\", length=%" PRIu64, value, length);
+
+       new_length = length + string_field->length;
+
+       if (unlikely(new_length + 1 > string_field->buf->len)) {
+               g_array_set_size(string_field->buf, new_length + 1);
+       }
+
+       data = string_field->buf->data;
+       memcpy(data + string_field->length, value, length);
+       ((char *) string_field->buf->data)[new_length] = '\0';
+       string_field->length = new_length;
+       bt_field_set_single(field, true);
+       return BT_FIELD_STATUS_OK;
+}
+
+enum bt_field_status bt_field_string_clear(struct bt_field *field)
+{
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_STRING, "Field");
+       clear_string_field(field);
+       return BT_FIELD_STATUS_OK;
+}
+
+uint64_t bt_field_array_get_length(const struct bt_field *field)
+{
+       const struct bt_field_array *array_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_ARRAY(field, "Field");
+       return array_field->length;
+}
+
+enum bt_field_status bt_field_dynamic_array_set_length(struct bt_field *field,
+               uint64_t length)
+{
+       int ret = BT_FIELD_STATUS_OK;
+       struct bt_field_array *array_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+
+       if (unlikely(length > array_field->fields->len)) {
+               /* Make more room */
+               struct bt_field_class_array *array_fc;
+               uint64_t cur_len = array_field->fields->len;
+               uint64_t i;
+
+               g_ptr_array_set_size(array_field->fields, length);
+               array_fc = (void *) field->class;
+
+               for (i = cur_len; i < array_field->fields->len; i++) {
+                       struct bt_field *elem_field = bt_field_create(
+                               array_fc->element_fc);
+
+                       if (!elem_field) {
+                               BT_LIB_LOGE("Cannot create element field for "
+                                       "dynamic array field: "
+                                       "index=%" PRIu64 ", "
+                                       "%![array-field-]+f", i, field);
+                               ret = BT_FIELD_STATUS_NOMEM;
+                               goto end;
+                       }
+
+                       BT_ASSERT(!array_field->fields->pdata[i]);
+                       array_field->fields->pdata[i] = elem_field;
+               }
+       }
+
+       array_field->length = length;
+
+end:
+       return ret;
+}
+
+static inline
+struct bt_field *borrow_array_field_element_field_by_index(
+               struct bt_field *field, uint64_t index)
+{
+       struct bt_field_array *array_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_IS_ARRAY(field, "Field");
+       BT_ASSERT_PRE_VALID_INDEX(index, array_field->length);
+       return array_field->fields->pdata[index];
+}
+
+struct bt_field *bt_field_array_borrow_element_field_by_index(
+               struct bt_field *field, uint64_t index)
+{
+       return borrow_array_field_element_field_by_index(field, index);
+}
+
+const struct bt_field *
+bt_field_array_borrow_element_field_by_index_const(
+               const struct bt_field *field, uint64_t index)
+{
+       return borrow_array_field_element_field_by_index((void *) field, index);
+}
+
+static inline
+struct bt_field *borrow_structure_field_member_field_by_index(
+               struct bt_field *field, uint64_t index)
+{
+       struct bt_field_structure *struct_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_STRUCTURE, "Field");
+       BT_ASSERT_PRE_VALID_INDEX(index, struct_field->fields->len);
+       return struct_field->fields->pdata[index];
+}
+
+struct bt_field *bt_field_structure_borrow_member_field_by_index(
+               struct bt_field *field, uint64_t index)
+{
+       return borrow_structure_field_member_field_by_index(field,
+               index);
+}
+
+const struct bt_field *
+bt_field_structure_borrow_member_field_by_index_const(
+               const struct bt_field *field, uint64_t index)
+{
+       return borrow_structure_field_member_field_by_index(
+               (void *) field, index);
+}
+
+static inline
+struct bt_field *borrow_structure_field_member_field_by_name(
+               struct bt_field *field, const char *name)
+{
+       struct bt_field *ret_field = NULL;
+       struct bt_field_class_structure *struct_fc;
+       struct bt_field_structure *struct_field = (void *) field;
+       gpointer orig_key;
+       gpointer index;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_NON_NULL(name, "Field name");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_STRUCTURE, "Field");
+       struct_fc = (void *) field->class;
+
+       if (!g_hash_table_lookup_extended(struct_fc->common.name_to_index, name,
+                       &orig_key, &index)) {
+               goto end;
+       }
+
+       ret_field = struct_field->fields->pdata[GPOINTER_TO_UINT(index)];
+       BT_ASSERT(ret_field);
+
+end:
+       return ret_field;
+}
+
+struct bt_field *bt_field_structure_borrow_member_field_by_name(
+               struct bt_field *field, const char *name)
+{
+       return borrow_structure_field_member_field_by_name(field, name);
+}
+
+const struct bt_field *bt_field_structure_borrow_member_field_by_name_const(
+               const struct bt_field *field, const char *name)
+{
+       return borrow_structure_field_member_field_by_name(
+               (void *) field, name);
+}
+
+static inline
+struct bt_field *borrow_variant_field_selected_option_field(
+               struct bt_field *field)
+{
+       struct bt_field_variant *var_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_VARIANT, "Field");
+       BT_ASSERT_PRE(var_field->selected_field,
+               "Variant field has no selected field: %!+f", field);
+       return var_field->selected_field;
+}
+
+struct bt_field *bt_field_variant_borrow_selected_option_field(
+               struct bt_field *field)
+{
+       return borrow_variant_field_selected_option_field(field);
+}
+
+const struct bt_field *bt_field_variant_borrow_selected_option_field_const(
+               const struct bt_field *field)
+{
+       return borrow_variant_field_selected_option_field((void *) field);
+}
+
+enum bt_field_status bt_field_variant_select_option_field(
+               struct bt_field *field, uint64_t index)
+{
+       struct bt_field_variant *var_field = (void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_VARIANT, "Field");
+       BT_ASSERT_PRE_FIELD_HOT(field, "Field");
+       BT_ASSERT_PRE_VALID_INDEX(index, var_field->fields->len);
+       var_field->selected_field = var_field->fields->pdata[index];
+       var_field->selected_index = index;
+       return BT_FIELD_STATUS_OK;
+}
+
+uint64_t bt_field_variant_get_selected_option_field_index(
+               const struct bt_field *field)
+{
+       const struct bt_field_variant *var_field = (const void *) field;
+
+       BT_ASSERT_PRE_NON_NULL(field, "Field");
+       BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(field,
+               BT_FIELD_CLASS_TYPE_VARIANT, "Field");
+       BT_ASSERT_PRE(var_field->selected_field,
+               "Variant field has no selected field: %!+f", field);
+       return var_field->selected_index;
+}
+
+static inline
+void bt_field_finalize(struct bt_field *field)
+{
+       BT_ASSERT(field);
+       BT_LOGD_STR("Putting field's class.");
+       BT_OBJECT_PUT_REF_AND_RESET(field->class);
+}
+
+static
+void destroy_integer_field(struct bt_field *field)
+{
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying integer field object: %!+f", field);
+       bt_field_finalize(field);
+       g_free(field);
+}
+
+static
+void destroy_real_field(struct bt_field *field)
+{
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying real field object: %!+f", field);
+       bt_field_finalize(field);
+       g_free(field);
+}
+
+static
+void destroy_structure_field(struct bt_field *field)
+{
+       struct bt_field_structure *struct_field = (void *) field;
+
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying structure field object: %!+f", field);
+       bt_field_finalize(field);
+
+       if (struct_field->fields) {
+               g_ptr_array_free(struct_field->fields, TRUE);
+               struct_field->fields = NULL;
+       }
+
+       g_free(field);
+}
+
+static
+void destroy_variant_field(struct bt_field *field)
+{
+       struct bt_field_variant *var_field = (void *) field;
+
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying variant field object: %!+f", field);
+       bt_field_finalize(field);
+
+       if (var_field->fields) {
+               g_ptr_array_free(var_field->fields, TRUE);
+               var_field->fields = NULL;
+       }
+
+       g_free(field);
+}
+
+static
+void destroy_array_field(struct bt_field *field)
+{
+       struct bt_field_array *array_field = (void *) field;
+
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying array field object: %!+f", field);
+       bt_field_finalize(field);
+
+       if (array_field->fields) {
+               g_ptr_array_free(array_field->fields, TRUE);
+               array_field->fields = NULL;
+       }
+
+       g_free(field);
+}
+
+static
+void destroy_string_field(struct bt_field *field)
+{
+       struct bt_field_string *string_field = (void *) field;
+
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Destroying string field object: %!+f", field);
+       bt_field_finalize(field);
+
+       if (string_field->buf) {
+               g_array_free(string_field->buf, TRUE);
+               string_field->buf = NULL;
+       }
+
+       g_free(field);
+}
+
+BT_HIDDEN
+void bt_field_destroy(struct bt_field *field)
+{
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_class_has_known_type(field->class));
+       field_destroy_funcs[field->class->type](field);
+}
+
+static
+void reset_single_field(struct bt_field *field)
+{
+       BT_ASSERT(field);
+       field->is_set = false;
+}
+
+static
+void reset_structure_field(struct bt_field *field)
+{
+       uint64_t i;
+       struct bt_field_structure *struct_field = (void *) field;
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < struct_field->fields->len; i++) {
+               bt_field_reset(struct_field->fields->pdata[i]);
+       }
+}
+
+static
+void reset_variant_field(struct bt_field *field)
+{
+       uint64_t i;
+       struct bt_field_variant *var_field = (void *) field;
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < var_field->fields->len; i++) {
+               bt_field_reset(var_field->fields->pdata[i]);
+       }
+}
+
+static
+void reset_array_field(struct bt_field *field)
+{
+       uint64_t i;
+       struct bt_field_array *array_field = (void *) field;
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < array_field->fields->len; i++) {
+               bt_field_reset(array_field->fields->pdata[i]);
+       }
+}
+
+static
+void set_single_field_is_frozen(struct bt_field *field, bool is_frozen)
+{
+       field->frozen = is_frozen;
+}
+
+static
+void set_structure_field_is_frozen(struct bt_field *field, bool is_frozen)
+{
+       uint64_t i;
+       struct bt_field_structure *struct_field = (void *) field;
+
+       BT_LIB_LOGD("Setting structure field's frozen state: "
+               "%![field-]+f, is-frozen=%d", field, is_frozen);
+
+       for (i = 0; i < struct_field->fields->len; i++) {
+               struct bt_field *member_field = struct_field->fields->pdata[i];
+
+               BT_LIB_LOGD("Setting structure field's member field's "
+                       "frozen state: %![field-]+f, index=%" PRIu64,
+                       member_field, i);
+               bt_field_set_is_frozen(member_field, is_frozen);
+       }
+
+       set_single_field_is_frozen(field, is_frozen);
+}
+
+static
+void set_variant_field_is_frozen(struct bt_field *field, bool is_frozen)
+{
+       uint64_t i;
+       struct bt_field_variant *var_field = (void *) field;
+
+       BT_LIB_LOGD("Setting variant field's frozen state: "
+               "%![field-]+f, is-frozen=%d", field, is_frozen);
+
+       for (i = 0; i < var_field->fields->len; i++) {
+               struct bt_field *option_field = var_field->fields->pdata[i];
+
+               BT_LIB_LOGD("Setting variant field's option field's "
+                       "frozen state: %![field-]+f, index=%" PRIu64,
+                       option_field, i);
+               bt_field_set_is_frozen(option_field, is_frozen);
+       }
+
+       set_single_field_is_frozen(field, is_frozen);
+}
+
+static
+void set_array_field_is_frozen(struct bt_field *field, bool is_frozen)
+{
+       uint64_t i;
+       struct bt_field_array *array_field = (void *) field;
+
+       BT_LIB_LOGD("Setting array field's frozen state: "
+               "%![field-]+f, is-frozen=%d", field, is_frozen);
+
+       for (i = 0; i < array_field->fields->len; i++) {
+               struct bt_field *elem_field = array_field->fields->pdata[i];
+
+               BT_LIB_LOGD("Setting array field's element field's "
+                       "frozen state: %![field-]+f, index=%" PRIu64,
+                       elem_field, i);
+               bt_field_set_is_frozen(elem_field, is_frozen);
+       }
+
+       set_single_field_is_frozen(field, is_frozen);
+}
+
+BT_HIDDEN
+void _bt_field_set_is_frozen(const struct bt_field *field,
+               bool is_frozen)
+{
+       BT_ASSERT(field);
+       BT_LIB_LOGD("Setting field object's frozen state: %!+f, is-frozen=%d",
+               field, is_frozen);
+       BT_ASSERT(field->methods->set_is_frozen);
+       field->methods->set_is_frozen((void *) field, is_frozen);
+}
+
+static
+bool single_field_is_set(const struct bt_field *field)
+{
+       BT_ASSERT(field);
+       return field->is_set;
+}
+
+static
+bool structure_field_is_set(const struct bt_field *field)
+{
+       bool is_set = true;
+       uint64_t i;
+       const struct bt_field_structure *struct_field = (const void *) field;
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < struct_field->fields->len; i++) {
+               is_set = bt_field_is_set(struct_field->fields->pdata[i]);
+               if (!is_set) {
+                       goto end;
+               }
+       }
+
+end:
+       return is_set;
+}
+
+static
+bool variant_field_is_set(const struct bt_field *field)
+{
+       const struct bt_field_variant *var_field = (const void *) field;
+       bool is_set = false;
+
+       BT_ASSERT(field);
+
+       if (var_field->selected_field) {
+               is_set = bt_field_is_set(var_field->selected_field);
+       }
+
+       return is_set;
+}
+
+static
+bool array_field_is_set(const struct bt_field *field)
+{
+       bool is_set = true;
+       uint64_t i;
+       const struct bt_field_array *array_field = (const void *) field;
+
+       BT_ASSERT(field);
+
+       for (i = 0; i < array_field->length; i++) {
+               is_set = bt_field_is_set(array_field->fields->pdata[i]);
+               if (!is_set) {
+                       goto end;
+               }
+       }
+
+end:
+       return is_set;
+}
diff --git a/src/lib/trace-ir/field.h b/src/lib/trace-ir/field.h
new file mode 100644 (file)
index 0000000..3cd4bfe
--- /dev/null
@@ -0,0 +1,204 @@
+#ifndef BABELTRACE_TRACE_IR_FIELDS_INTERNAL_H
+#define BABELTRACE_TRACE_IR_FIELDS_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "lib/assert-pre.h"
+#include "common/common.h"
+#include "lib/object.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/types.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <glib.h>
+
+#include "field-class.h"
+#include "utils.h"
+
+#define BT_ASSERT_PRE_FIELD_HAS_CLASS_TYPE(_field, _cls_type, _name)   \
+       BT_ASSERT_PRE(((const struct bt_field *) (_field))->class->type == (_cls_type), \
+               _name " has the wrong class type: expected-class-type=%s, " \
+               "%![field-]+f",                                         \
+               bt_common_field_class_type_string(_cls_type), (_field))
+
+#define BT_ASSERT_PRE_FIELD_IS_UNSIGNED_INT(_field, _name)             \
+       BT_ASSERT_PRE(                                                  \
+               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER || \
+               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION, \
+               _name " is not an unsigned integer field: %![field-]+f", \
+               (_field))
+
+#define BT_ASSERT_PRE_FIELD_IS_SIGNED_INT(_field, _name)               \
+       BT_ASSERT_PRE(                                                  \
+               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER || \
+               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION, \
+               _name " is not a signed integer field: %![field-]+f", \
+               (_field))
+
+#define BT_ASSERT_PRE_FIELD_IS_ARRAY(_field, _name)                    \
+       BT_ASSERT_PRE(                                                  \
+               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY || \
+               ((const struct bt_field *) (_field))->class->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY, \
+               _name " is not an array field: %![field-]+f", (_field))
+
+#define BT_ASSERT_PRE_FIELD_IS_SET(_field, _name)                      \
+       BT_ASSERT_PRE(bt_field_is_set(_field),                          \
+               _name " is not set: %!+f", (_field))
+
+#define BT_ASSERT_PRE_FIELD_HOT(_field, _name)                         \
+       BT_ASSERT_PRE_HOT((const struct bt_field *) (_field), (_name),  \
+               ": %!+f", (_field))
+
+struct bt_field;
+
+typedef struct bt_field *(* bt_field_create_func)(struct bt_field_class *);
+typedef void (*bt_field_method_set_is_frozen)(struct bt_field *, bool);
+typedef bool (*bt_field_method_is_set)(const struct bt_field *);
+typedef void (*bt_field_method_reset)(struct bt_field *);
+
+struct bt_field_methods {
+       bt_field_method_set_is_frozen set_is_frozen;
+       bt_field_method_is_set is_set;
+       bt_field_method_reset reset;
+};
+
+struct bt_field {
+       struct bt_object base;
+
+       /* Owned by this */
+       struct bt_field_class *class;
+
+       /* Virtual table for slow path (dev mode) operations */
+       struct bt_field_methods *methods;
+
+       bool is_set;
+       bool frozen;
+};
+
+struct bt_field_integer {
+       struct bt_field common;
+
+       union {
+               uint64_t u;
+               int64_t i;
+       } value;
+};
+
+struct bt_field_real {
+       struct bt_field common;
+       double value;
+};
+
+struct bt_field_structure {
+       struct bt_field common;
+
+       /* Array of `struct bt_field *`, owned by this */
+       GPtrArray *fields;
+};
+
+struct bt_field_variant {
+       struct bt_field common;
+
+       /* Weak: belongs to `fields` below */
+       struct bt_field *selected_field;
+
+       /* Index of currently selected field */
+       uint64_t selected_index;
+
+       /* Array of `struct bt_field *`, owned by this */
+       GPtrArray *fields;
+};
+
+struct bt_field_array {
+       struct bt_field common;
+
+       /* Array of `struct bt_field *`, owned by this */
+       GPtrArray *fields;
+
+       /* Current effective length */
+       uint64_t length;
+};
+
+struct bt_field_string {
+       struct bt_field common;
+       GArray *buf;
+       uint64_t length;
+};
+
+#ifdef BT_DEV_MODE
+# define bt_field_set_is_frozen                _bt_field_set_is_frozen
+# define bt_field_is_set               _bt_field_is_set
+# define bt_field_reset                        _bt_field_reset
+# define bt_field_set_single           _bt_field_set_single
+#else
+# define bt_field_set_is_frozen(_field, _is_frozen)
+# define bt_field_is_set(_field)       (BT_FALSE)
+# define bt_field_reset(_field)
+# define bt_field_set_single(_field, _val)
+#endif
+
+BT_HIDDEN
+void _bt_field_set_is_frozen(const struct bt_field *field, bool is_frozen);
+
+static inline
+void _bt_field_reset(const struct bt_field *field)
+{
+       BT_ASSERT(field);
+       BT_ASSERT(field->methods->reset);
+       field->methods->reset((void *) field);
+}
+
+static inline
+void _bt_field_set_single(struct bt_field *field, bool value)
+{
+       BT_ASSERT(field);
+       field->is_set = value;
+}
+
+static inline
+bt_bool _bt_field_is_set(const struct bt_field *field)
+{
+       bt_bool is_set = BT_FALSE;
+
+       if (!field) {
+               goto end;
+       }
+
+       BT_ASSERT(bt_field_class_has_known_type(field->class));
+       BT_ASSERT(field->methods->is_set);
+       is_set = field->methods->is_set(field);
+
+end:
+       return is_set;
+}
+
+BT_HIDDEN
+struct bt_field *bt_field_create(struct bt_field_class *class);
+
+BT_HIDDEN
+void bt_field_destroy(struct bt_field *field);
+
+#endif /* BABELTRACE_TRACE_IR_FIELDS_INTERNAL_H */
diff --git a/src/lib/trace-ir/packet-context-field.c b/src/lib/trace-ir/packet-context-field.c
new file mode 100644 (file)
index 0000000..03219a2
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PACKET-CONTEXT-FIELD"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/packet-context-field.h>
+#include <glib.h>
+
+#include "stream-class.h"
+#include "field.h"
+#include "field-wrapper.h"
+
+struct bt_field *bt_packet_context_field_borrow_field(
+               struct bt_packet_context_field *context_field)
+{
+       struct bt_field_wrapper *field_wrapper = (void *) context_field;
+
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet context field");
+       return (void *) field_wrapper->field;
+}
+
+void bt_packet_context_field_release(
+               struct bt_packet_context_field *context_field)
+{
+       struct bt_field_wrapper *field_wrapper = (void *) context_field;
+
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Packet context field");
+
+       /*
+        * Do not recycle because the pool could be destroyed at this
+        * point. This function is only called when there's an error
+        * anyway because the goal of a packet context field wrapper is
+        * to eventually move it to a packet with
+        * bt_packet_move_context() after creating it.
+        */
+       bt_field_wrapper_destroy(field_wrapper);
+}
+
+struct bt_packet_context_field *bt_packet_context_field_create(
+               struct bt_stream_class *stream_class)
+{
+       struct bt_field_wrapper *field_wrapper;
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE(stream_class->frozen,
+               "Stream class is not part of a trace class: %!+S",
+               stream_class);
+       BT_ASSERT_PRE(stream_class->packet_context_fc,
+               "Stream class has no packet context field class: %!+S",
+               stream_class);
+       field_wrapper = bt_field_wrapper_create(
+               &stream_class->packet_context_field_pool,
+               (void *) stream_class->packet_context_fc);
+       if (!field_wrapper) {
+               BT_LIB_LOGE("Cannot allocate one packet context field from stream class: "
+                       "%![sc-]+S", stream_class);
+               goto error;
+       }
+
+       BT_ASSERT(field_wrapper->field);
+       bt_stream_class_freeze(stream_class);
+       goto end;
+
+error:
+       if (field_wrapper) {
+               bt_field_wrapper_destroy(field_wrapper);
+               field_wrapper = NULL;
+       }
+
+end:
+       return (void *) field_wrapper;
+}
diff --git a/src/lib/trace-ir/packet.c b/src/lib/trace-ir/packet.c
new file mode 100644 (file)
index 0000000..585ed48
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PACKET"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/packet-const.h>
+#include <babeltrace2/trace-ir/packet.h>
+#include <babeltrace2/trace-ir/trace.h>
+#include <babeltrace2/trace-ir/stream-class.h>
+#include <babeltrace2/trace-ir/stream.h>
+#include "lib/object.h"
+#include "common/assert.h"
+#include <inttypes.h>
+
+#include "field.h"
+#include "field-wrapper.h"
+#include "packet.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "trace.h"
+
+#define BT_ASSERT_PRE_PACKET_HOT(_packet) \
+       BT_ASSERT_PRE_HOT((_packet), "Packet", ": %!+a", (_packet))
+
+struct bt_stream *bt_packet_borrow_stream(struct bt_packet *packet)
+{
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
+       return packet->stream;
+}
+
+const struct bt_stream *bt_packet_borrow_stream_const(
+               const struct bt_packet *packet)
+{
+       return bt_packet_borrow_stream((void *) packet);
+}
+
+struct bt_field *bt_packet_borrow_context_field(struct bt_packet *packet)
+{
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
+       return packet->context_field ? packet->context_field->field : NULL;
+}
+
+const struct bt_field *bt_packet_borrow_context_field_const(
+               const struct bt_packet *packet)
+{
+       return bt_packet_borrow_context_field((void *) packet);
+}
+
+BT_HIDDEN
+void _bt_packet_set_is_frozen(const struct bt_packet *packet, bool is_frozen)
+{
+       if (!packet) {
+               return;
+       }
+
+       BT_LIB_LOGD("Setting packet's frozen state: %![packet-]+a, "
+               "is-frozen=%d", packet, is_frozen);
+
+       if (packet->context_field) {
+               BT_LOGD_STR("Setting packet's context field's frozen state.");
+               bt_field_set_is_frozen(packet->context_field->field,
+                       is_frozen);
+       }
+
+       ((struct bt_packet *) packet)->frozen = is_frozen;
+}
+
+static inline
+void reset_packet(struct bt_packet *packet)
+{
+       BT_ASSERT(packet);
+       BT_LIB_LOGD("Resetting packet: %!+a", packet);
+       bt_packet_set_is_frozen(packet, false);
+
+       if (packet->context_field) {
+               bt_field_set_is_frozen(packet->context_field->field, false);
+               bt_field_reset(packet->context_field->field);
+       }
+}
+
+static
+void recycle_context_field(struct bt_field_wrapper *context_field,
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT(context_field);
+       BT_LIB_LOGD("Recycling packet context field: "
+               "addr=%p, %![sc-]+S, %![field-]+f", context_field,
+               stream_class, context_field->field);
+       bt_object_pool_recycle_object(&stream_class->packet_context_field_pool,
+               context_field);
+}
+
+BT_HIDDEN
+void bt_packet_recycle(struct bt_packet *packet)
+{
+       struct bt_stream *stream;
+
+       BT_ASSERT(packet);
+       BT_LIB_LOGD("Recycling packet: %!+a", packet);
+
+       /*
+        * Those are the important ordered steps:
+        *
+        * 1. Reset the packet object (put any permanent reference it
+        *    has, unfreeze it and its fields in developer mode, etc.),
+        *    but do NOT put its stream's reference. This stream
+        *    contains the pool to which we're about to recycle this
+        *    packet object, so we must guarantee its existence thanks
+        *    to this existing reference.
+        *
+        * 2. Move the stream reference to our `stream`
+        *    variable so that we can set the packet's stream member
+        *    to NULL before recycling it. We CANNOT do this after
+        *    we put the stream reference because this bt_object_put_ref()
+        *    could destroy the stream, also destroying its
+        *    packet pool, thus also destroying our packet object (this
+        *    would result in an invalid write access).
+        *
+        * 3. Recycle the packet object.
+        *
+        * 4. Put our stream reference.
+        */
+       reset_packet(packet);
+       stream = packet->stream;
+       BT_ASSERT(stream);
+       packet->stream = NULL;
+       bt_object_pool_recycle_object(&stream->packet_pool, packet);
+       bt_object_put_no_null_check(&stream->base);
+}
+
+BT_HIDDEN
+void bt_packet_destroy(struct bt_packet *packet)
+{
+       BT_LIB_LOGD("Destroying packet: %!+a", packet);
+
+       if (packet->context_field) {
+               if (packet->stream) {
+                       BT_LOGD_STR("Recycling packet's context field.");
+                       recycle_context_field(packet->context_field,
+                               packet->stream->class);
+               } else {
+                       bt_field_wrapper_destroy(packet->context_field);
+               }
+
+               packet->context_field = NULL;
+       }
+
+       BT_LOGD_STR("Putting packet's stream.");
+       BT_OBJECT_PUT_REF_AND_RESET(packet->stream);
+       g_free(packet);
+}
+
+BT_HIDDEN
+struct bt_packet *bt_packet_new(struct bt_stream *stream)
+{
+       struct bt_packet *packet = NULL;
+       struct bt_trace_class *trace_class = NULL;
+
+       BT_ASSERT(stream);
+       BT_LIB_LOGD("Creating packet object: %![stream-]+s", stream);
+       packet = g_new0(struct bt_packet, 1);
+       if (!packet) {
+               BT_LOGE_STR("Failed to allocate one packet object.");
+               goto error;
+       }
+
+       bt_object_init_shared(&packet->base,
+               (bt_object_release_func) bt_packet_recycle);
+       packet->stream = stream;
+       bt_object_get_no_null_check(stream);
+       trace_class = bt_stream_class_borrow_trace_class_inline(stream->class);
+       BT_ASSERT(trace_class);
+
+       if (stream->class->packet_context_fc) {
+               BT_LOGD_STR("Creating initial packet context field.");
+               packet->context_field = bt_field_wrapper_create(
+                       &stream->class->packet_context_field_pool,
+                       stream->class->packet_context_fc);
+               if (!packet->context_field) {
+                       BT_LOGE_STR("Cannot create packet context field wrapper.");
+                       goto error;
+               }
+       }
+
+       BT_LIB_LOGD("Created packet object: %!+a", packet);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(packet);
+
+end:
+       return packet;
+}
+
+struct bt_packet *bt_packet_create(const struct bt_stream *c_stream)
+{
+       struct bt_packet *packet = NULL;
+       struct bt_stream *stream = (void *) c_stream;
+
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       packet = bt_object_pool_create_object(&stream->packet_pool);
+       if (unlikely(!packet)) {
+               BT_LIB_LOGE("Cannot allocate one packet from stream's packet pool: "
+                       "%![stream-]+s", stream);
+               goto end;
+       }
+
+       if (likely(!packet->stream)) {
+               packet->stream = stream;
+               bt_object_get_no_null_check_no_parent_check(
+                       &packet->stream->base);
+       }
+
+end:
+       return (void *) packet;
+}
+
+enum bt_packet_status bt_packet_move_context_field(struct bt_packet *packet,
+               struct bt_packet_context_field *context_field)
+{
+       struct bt_stream_class *stream_class;
+       struct bt_field_wrapper *field_wrapper = (void *) context_field;
+
+       BT_ASSERT_PRE_NON_NULL(packet, "Packet");
+       BT_ASSERT_PRE_NON_NULL(field_wrapper, "Context field");
+       BT_ASSERT_PRE_HOT(packet, "Packet", ": %!+a", packet);
+       stream_class = packet->stream->class;
+       BT_ASSERT_PRE(stream_class->packet_context_fc,
+               "Stream class has no packet context field class: %!+S",
+               stream_class);
+       BT_ASSERT_PRE(field_wrapper->field->class ==
+               stream_class->packet_context_fc,
+               "Unexpected packet context field's class: "
+               "%![fc-]+F, %![expected-fc-]+F", field_wrapper->field->class,
+               stream_class->packet_context_fc);
+
+       /* Recycle current context field: always exists */
+       BT_ASSERT(packet->context_field);
+       recycle_context_field(packet->context_field, stream_class);
+
+       /* Move new field */
+       packet->context_field = field_wrapper;
+       return BT_PACKET_STATUS_OK;
+}
+
+void bt_packet_get_ref(const struct bt_packet *packet)
+{
+       bt_object_get_ref(packet);
+}
+
+void bt_packet_put_ref(const struct bt_packet *packet)
+{
+       bt_object_put_ref(packet);
+}
diff --git a/src/lib/trace-ir/packet.h b/src/lib/trace-ir/packet.h
new file mode 100644 (file)
index 0000000..7b19760
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef BABELTRACE_TRACE_IR_PACKET_INTERNAL_H
+#define BABELTRACE_TRACE_IR_PACKET_INTERNAL_H
+
+/*
+ * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "common/assert.h"
+#include <babeltrace2/trace-ir/clock-snapshot-const.h>
+#include <babeltrace2/trace-ir/packet.h>
+#include <babeltrace2/trace-ir/field.h>
+#include <babeltrace2/trace-ir/stream.h>
+#include "lib/object.h"
+#include "common/babeltrace.h"
+#include "lib/property.h"
+
+#include "field-wrapper.h"
+
+struct bt_packet {
+       struct bt_object base;
+       struct bt_field_wrapper *context_field;
+       struct bt_stream *stream;
+       bool frozen;
+};
+
+BT_HIDDEN
+void _bt_packet_set_is_frozen(const struct bt_packet *packet, bool is_frozen);
+
+#ifdef BT_DEV_MODE
+# define bt_packet_set_is_frozen       _bt_packet_set_is_frozen
+#else
+# define bt_packet_set_is_frozen(_packet, _is_frozen)
+#endif /* BT_DEV_MODE */
+
+BT_HIDDEN
+struct bt_packet *bt_packet_new(struct bt_stream *stream);
+
+BT_HIDDEN
+void bt_packet_recycle(struct bt_packet *packet);
+
+BT_HIDDEN
+void bt_packet_destroy(struct bt_packet *packet);
+
+#endif /* BABELTRACE_TRACE_IR_PACKET_INTERNAL_H */
diff --git a/src/lib/trace-ir/resolve-field-path.c b/src/lib/trace-ir/resolve-field-path.c
new file mode 100644 (file)
index 0000000..a7fe29b
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "RESOLVE-FIELD-PATH"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include "common/assert.h"
+#include <babeltrace2/trace-ir/field-path-const.h>
+#include <limits.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <glib.h>
+
+#include "field-class.h"
+#include "field-path.h"
+#include "resolve-field-path.h"
+
+static
+bool find_field_class_recursive(struct bt_field_class *fc,
+               struct bt_field_class *tgt_fc, struct bt_field_path *field_path)
+{
+       bool found = false;
+
+       if (tgt_fc == fc) {
+               found = true;
+               goto end;
+       }
+
+       switch (fc->type) {
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct bt_field_class_named_field_class_container *container_fc =
+                       (void *) fc;
+               uint64_t i;
+
+               for (i = 0; i < container_fc->named_fcs->len; i++) {
+                       struct bt_named_field_class *named_fc =
+                               BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
+                                       container_fc, i);
+                       struct bt_field_path_item item = {
+                               .type = BT_FIELD_PATH_ITEM_TYPE_INDEX,
+                               .index = i,
+                       };
+
+                       bt_field_path_append_item(field_path, &item);
+                       found = find_field_class_recursive(named_fc->fc,
+                               tgt_fc, field_path);
+                       if (found) {
+                               goto end;
+                       }
+
+                       bt_field_path_remove_last_item(field_path);
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+       {
+               struct bt_field_class_array *array_fc = (void *) fc;
+               struct bt_field_path_item item = {
+                       .type = BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT,
+                       .index = UINT64_C(-1),
+               };
+
+               bt_field_path_append_item(field_path, &item);
+               found = find_field_class_recursive(array_fc->element_fc,
+                       tgt_fc, field_path);
+               if (found) {
+                       goto end;
+               }
+
+               bt_field_path_remove_last_item(field_path);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return found;
+}
+
+static
+int find_field_class(struct bt_field_class *root_fc,
+               enum bt_scope root_scope, struct bt_field_class *tgt_fc,
+               struct bt_field_path **ret_field_path)
+{
+       int ret = 0;
+       struct bt_field_path *field_path = NULL;
+
+       if (!root_fc) {
+               goto end;
+       }
+
+       field_path = bt_field_path_create();
+       if (!field_path) {
+               ret = -1;
+               goto end;
+       }
+
+       field_path->root = root_scope;
+       if (!find_field_class_recursive(root_fc, tgt_fc, field_path)) {
+               /* Not found here */
+               BT_OBJECT_PUT_REF_AND_RESET(field_path);
+       }
+
+end:
+       *ret_field_path = field_path;
+       return ret;
+}
+
+static
+struct bt_field_path *find_field_class_in_ctx(struct bt_field_class *fc,
+               struct bt_resolve_field_path_context *ctx)
+{
+       struct bt_field_path *field_path = NULL;
+       int ret;
+
+       ret = find_field_class(ctx->packet_context, BT_SCOPE_PACKET_CONTEXT,
+               fc, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+       ret = find_field_class(ctx->event_common_context,
+               BT_SCOPE_EVENT_COMMON_CONTEXT, fc, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+       ret = find_field_class(ctx->event_specific_context,
+               BT_SCOPE_EVENT_SPECIFIC_CONTEXT, fc, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+       ret = find_field_class(ctx->event_payload, BT_SCOPE_EVENT_PAYLOAD,
+               fc, &field_path);
+       if (ret || field_path) {
+               goto end;
+       }
+
+end:
+       return field_path;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool target_is_before_source(struct bt_field_path *src_field_path,
+               struct bt_field_path *tgt_field_path)
+{
+       bool is_valid = true;
+       uint64_t src_i = 0, tgt_i = 0;
+
+       if (tgt_field_path->root < src_field_path->root) {
+               goto end;
+       }
+
+       if (tgt_field_path->root > src_field_path->root) {
+               is_valid = false;
+               goto end;
+       }
+
+       BT_ASSERT(tgt_field_path->root == src_field_path->root);
+
+       for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
+                       tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
+               struct bt_field_path_item *src_fp_item =
+                       bt_field_path_borrow_item_by_index_inline(
+                               src_field_path, src_i);
+               struct bt_field_path_item *tgt_fp_item =
+                       bt_field_path_borrow_item_by_index_inline(
+                               tgt_field_path, tgt_i);
+
+               if (src_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX &&
+                               tgt_fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX) {
+                       if (tgt_fp_item->index > src_fp_item->index) {
+                               is_valid = false;
+                               goto end;
+                       }
+               }
+
+               src_i++;
+               tgt_i++;
+       }
+
+end:
+       return is_valid;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+struct bt_field_class *borrow_root_field_class(
+               struct bt_resolve_field_path_context *ctx, enum bt_scope scope)
+{
+       switch (scope) {
+       case BT_SCOPE_PACKET_CONTEXT:
+               return ctx->packet_context;
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               return ctx->event_common_context;
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               return ctx->event_specific_context;
+       case BT_SCOPE_EVENT_PAYLOAD:
+               return ctx->event_payload;
+       default:
+               abort();
+       }
+
+       return NULL;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+struct bt_field_class *borrow_child_field_class(
+               struct bt_field_class *parent_fc,
+               struct bt_field_path_item *fp_item)
+{
+       struct bt_field_class *child_fc = NULL;
+
+       switch (parent_fc->type) {
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct bt_named_field_class *named_fc;
+
+               BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX);
+               named_fc = BT_FIELD_CLASS_NAMED_FC_AT_INDEX(parent_fc,
+                       fp_item->index);
+               child_fc = named_fc->fc;
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+       {
+               struct bt_field_class_array *array_fc = (void *) parent_fc;
+
+               BT_ASSERT(fp_item->type ==
+                       BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
+               child_fc = array_fc->element_fc;
+               break;
+       }
+       default:
+               break;
+       }
+
+       return child_fc;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool target_field_path_in_different_scope_has_struct_fc_only(
+               struct bt_field_path *src_field_path,
+               struct bt_field_path *tgt_field_path,
+               struct bt_resolve_field_path_context *ctx)
+{
+       bool is_valid = true;
+       uint64_t i = 0;
+       struct bt_field_class *fc;
+
+       if (src_field_path->root == tgt_field_path->root) {
+               goto end;
+       }
+
+       fc = borrow_root_field_class(ctx, tgt_field_path->root);
+
+       for (i = 0; i < tgt_field_path->items->len; i++) {
+               struct bt_field_path_item *fp_item =
+                       bt_field_path_borrow_item_by_index_inline(
+                               tgt_field_path, i);
+
+               if (fc->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY ||
+                               fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY ||
+                               fc->type == BT_FIELD_CLASS_TYPE_VARIANT) {
+                       is_valid = false;
+                       goto end;
+               }
+
+               BT_ASSERT(fp_item->type == BT_FIELD_PATH_ITEM_TYPE_INDEX);
+               fc = borrow_child_field_class(fc, fp_item);
+       }
+
+end:
+       return is_valid;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool lca_is_structure_field_class(struct bt_field_path *src_field_path,
+               struct bt_field_path *tgt_field_path,
+               struct bt_resolve_field_path_context *ctx)
+{
+       bool is_valid = true;
+       struct bt_field_class *src_fc;
+       struct bt_field_class *tgt_fc;
+       struct bt_field_class *prev_fc = NULL;
+       uint64_t src_i = 0, tgt_i = 0;
+
+       if (src_field_path->root != tgt_field_path->root) {
+               goto end;
+       }
+
+       src_fc = borrow_root_field_class(ctx, src_field_path->root);
+       tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
+       BT_ASSERT(src_fc);
+       BT_ASSERT(tgt_fc);
+
+       for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
+                       tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
+               struct bt_field_path_item *src_fp_item =
+                       bt_field_path_borrow_item_by_index_inline(
+                               src_field_path, src_i);
+               struct bt_field_path_item *tgt_fp_item =
+                       bt_field_path_borrow_item_by_index_inline(
+                               tgt_field_path, tgt_i);
+
+               if (src_fc != tgt_fc) {
+                       if (!prev_fc) {
+                               /*
+                                * This is correct: the LCA is the root
+                                * scope field class, which must be a
+                                * structure field class.
+                                */
+                               break;
+                       }
+
+                       if (prev_fc->type != BT_FIELD_CLASS_TYPE_STRUCTURE) {
+                               is_valid = false;
+                       }
+
+                       break;
+               }
+
+               prev_fc = src_fc;
+               src_fc = borrow_child_field_class(src_fc, src_fp_item);
+               tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
+       }
+
+end:
+       return is_valid;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool lca_to_target_has_struct_fc_only(struct bt_field_path *src_field_path,
+               struct bt_field_path *tgt_field_path,
+               struct bt_resolve_field_path_context *ctx)
+{
+       bool is_valid = true;
+       struct bt_field_class *src_fc;
+       struct bt_field_class *tgt_fc;
+       uint64_t src_i = 0, tgt_i = 0;
+
+       if (src_field_path->root != tgt_field_path->root) {
+               goto end;
+       }
+
+       src_fc = borrow_root_field_class(ctx, src_field_path->root);
+       tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
+       BT_ASSERT(src_fc);
+       BT_ASSERT(tgt_fc);
+       BT_ASSERT(src_fc == tgt_fc);
+
+       /* Find LCA */
+       for (src_i = 0, tgt_i = 0; src_i < src_field_path->items->len &&
+                       tgt_i < tgt_field_path->items->len; src_i++, tgt_i++) {
+               struct bt_field_path_item *src_fp_item =
+                       bt_field_path_borrow_item_by_index_inline(
+                               src_field_path, src_i);
+               struct bt_field_path_item *tgt_fp_item =
+                       bt_field_path_borrow_item_by_index_inline(
+                               tgt_field_path, tgt_i);
+
+               if (src_i != tgt_i) {
+                       /* Next field class is different: LCA is `tgt_fc` */
+                       break;
+               }
+
+               src_fc = borrow_child_field_class(src_fc, src_fp_item);
+               tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
+       }
+
+       /* Only structure field classes to the target */
+       for (; tgt_i < tgt_field_path->items->len; tgt_i++) {
+               struct bt_field_path_item *tgt_fp_item =
+                       bt_field_path_borrow_item_by_index_inline(
+                               tgt_field_path, tgt_i);
+
+               if (tgt_fc->type == BT_FIELD_CLASS_TYPE_STATIC_ARRAY ||
+                               tgt_fc->type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY ||
+                               tgt_fc->type == BT_FIELD_CLASS_TYPE_VARIANT) {
+                       is_valid = false;
+                       goto end;
+               }
+
+               tgt_fc = borrow_child_field_class(tgt_fc, tgt_fp_item);
+       }
+
+end:
+       return is_valid;
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool field_path_is_valid(struct bt_field_class *src_fc,
+               struct bt_field_class *tgt_fc,
+               struct bt_resolve_field_path_context *ctx)
+{
+       bool is_valid = true;
+       struct bt_field_path *src_field_path = find_field_class_in_ctx(
+               src_fc, ctx);
+       struct bt_field_path *tgt_field_path = find_field_class_in_ctx(
+               tgt_fc, ctx);
+
+       if (!src_field_path) {
+               BT_ASSERT_PRE_MSG("Cannot find requesting field class in "
+                       "resolving context: %!+F", src_fc);
+               is_valid = false;
+               goto end;
+       }
+
+       if (!tgt_field_path) {
+               BT_ASSERT_PRE_MSG("Cannot find target field class in "
+                       "resolving context: %!+F", tgt_fc);
+               is_valid = false;
+               goto end;
+       }
+
+       /* Target must be before source */
+       if (!target_is_before_source(src_field_path, tgt_field_path)) {
+               BT_ASSERT_PRE_MSG("Target field class is located after "
+                       "requesting field class: %![req-fc-]+F, %![tgt-fc-]+F",
+                       src_fc, tgt_fc);
+               is_valid = false;
+               goto end;
+       }
+
+       /*
+        * If target is in a different scope than source, there are no
+        * array or variant field classes on the way to the target.
+        */
+       if (!target_field_path_in_different_scope_has_struct_fc_only(
+                       src_field_path, tgt_field_path, ctx)) {
+               BT_ASSERT_PRE_MSG("Target field class is located in a "
+                       "different scope than requesting field class, "
+                       "but within an array or a variant field class: "
+                       "%![req-fc-]+F, %![tgt-fc-]+F",
+                       src_fc, tgt_fc);
+               is_valid = false;
+               goto end;
+       }
+
+       /* Same scope: LCA must be a structure field class */
+       if (!lca_is_structure_field_class(src_field_path, tgt_field_path, ctx)) {
+               BT_ASSERT_PRE_MSG("Lowest common ancestor of target and "
+                       "requesting field classes is not a structure field class: "
+                       "%![req-fc-]+F, %![tgt-fc-]+F",
+                       src_fc, tgt_fc);
+               is_valid = false;
+               goto end;
+       }
+
+       /* Same scope: path from LCA to target has no array/variant FTs */
+       if (!lca_to_target_has_struct_fc_only(src_field_path, tgt_field_path,
+                       ctx)) {
+               BT_ASSERT_PRE_MSG("Path from lowest common ancestor of target "
+                       "and requesting field classes to target field class "
+                       "contains an array or a variant field class: "
+                       "%![req-fc-]+F, %![tgt-fc-]+F", src_fc, tgt_fc);
+               is_valid = false;
+               goto end;
+       }
+
+end:
+       bt_object_put_ref(src_field_path);
+       bt_object_put_ref(tgt_field_path);
+       return is_valid;
+}
+
+static
+struct bt_field_path *resolve_field_path(struct bt_field_class *src_fc,
+               struct bt_field_class *tgt_fc,
+               struct bt_resolve_field_path_context *ctx)
+{
+       BT_ASSERT_PRE(field_path_is_valid(src_fc, tgt_fc, ctx),
+               "Invalid target field class: %![req-fc-]+F, %![tgt-fc-]+F",
+               src_fc, tgt_fc);
+       return find_field_class_in_ctx(tgt_fc, ctx);
+}
+
+BT_HIDDEN
+int bt_resolve_field_paths(struct bt_field_class *fc,
+               struct bt_resolve_field_path_context *ctx)
+{
+       int ret = 0;
+
+       BT_ASSERT(fc);
+
+       /* Resolving part for dynamic array and variant field classes */
+       switch (fc->type) {
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+       {
+               struct bt_field_class_dynamic_array *dyn_array_fc = (void *) fc;
+
+               if (dyn_array_fc->length_fc) {
+                       BT_ASSERT(!dyn_array_fc->length_field_path);
+                       dyn_array_fc->length_field_path = resolve_field_path(
+                               fc, dyn_array_fc->length_fc, ctx);
+                       if (!dyn_array_fc->length_field_path) {
+                               ret = -1;
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct bt_field_class_variant *var_fc = (void *) fc;
+
+               if (var_fc->selector_fc) {
+                       BT_ASSERT(!var_fc->selector_field_path);
+                       var_fc->selector_field_path =
+                               resolve_field_path(fc,
+                                       var_fc->selector_fc, ctx);
+                       if (!var_fc->selector_field_path) {
+                               ret = -1;
+                               goto end;
+                       }
+               }
+       }
+       default:
+               break;
+       }
+
+       /* Recursive part */
+       switch (fc->type) {
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct bt_field_class_named_field_class_container *container_fc =
+                       (void *) fc;
+               uint64_t i;
+
+               for (i = 0; i < container_fc->named_fcs->len; i++) {
+                       struct bt_named_field_class *named_fc =
+                               BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
+                                       container_fc, i);
+
+                       ret = bt_resolve_field_paths(named_fc->fc, ctx);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+       {
+               struct bt_field_class_array *array_fc = (void *) fc;
+
+               ret = bt_resolve_field_paths(array_fc->element_fc, ctx);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
diff --git a/src/lib/trace-ir/resolve-field-path.h b/src/lib/trace-ir/resolve-field-path.h
new file mode 100644 (file)
index 0000000..48f14ac
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef BABELTRACE_TRACE_IR_RESOLVE_FIELD_PATH_INTERNAL
+#define BABELTRACE_TRACE_IR_RESOLVE_FIELD_PATH_INTERNAL
+
+/*
+ * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include "lib/object.h"
+#include <babeltrace2/trace-ir/field-class-const.h>
+#include <babeltrace2/trace-ir/field-path-const.h>
+#include <glib.h>
+
+struct bt_resolve_field_path_context {
+       struct bt_field_class *packet_context;
+       struct bt_field_class *event_common_context;
+       struct bt_field_class *event_specific_context;
+       struct bt_field_class *event_payload;
+};
+
+BT_HIDDEN
+int bt_resolve_field_paths(struct bt_field_class *field_class,
+               struct bt_resolve_field_path_context *ctx);
+
+#endif /* BABELTRACE_TRACE_IR_RESOLVE_FIELD_PATH_INTERNAL */
diff --git a/src/lib/trace-ir/stream-class.c b/src/lib/trace-ir/stream-class.c
new file mode 100644 (file)
index 0000000..67b24aa
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "STREAM-CLASS"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/trace-const.h>
+#include "compat/compiler.h"
+#include "common/align.h"
+#include "compat/endian.h"
+#include "common/assert.h"
+#include "lib/property.h"
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "clock-class.h"
+#include "event-class.h"
+#include "field-class.h"
+#include "field.h"
+#include "field-wrapper.h"
+#include "resolve-field-path.h"
+#include "stream-class.h"
+#include "trace.h"
+#include "utils.h"
+
+#define BT_ASSERT_PRE_STREAM_CLASS_HOT(_sc) \
+       BT_ASSERT_PRE_HOT((_sc), "Stream class", ": %!+S", (_sc))
+
+static
+void destroy_stream_class(struct bt_object *obj)
+{
+       struct bt_stream_class *stream_class = (void *) obj;
+
+       BT_LIB_LOGD("Destroying stream class: %!+S", stream_class);
+       BT_LOGD_STR("Putting default clock class.");
+       BT_OBJECT_PUT_REF_AND_RESET(stream_class->default_clock_class);
+
+       if (stream_class->event_classes) {
+               BT_LOGD_STR("Destroying event classes.");
+               g_ptr_array_free(stream_class->event_classes, TRUE);
+               stream_class->event_classes = NULL;
+       }
+
+       if (stream_class->name.str) {
+               g_string_free(stream_class->name.str, TRUE);
+               stream_class->name.str = NULL;
+               stream_class->name.value = NULL;
+       }
+
+       BT_LOGD_STR("Putting packet context field class.");
+       BT_OBJECT_PUT_REF_AND_RESET(stream_class->packet_context_fc);
+       BT_LOGD_STR("Putting event common context field class.");
+       BT_OBJECT_PUT_REF_AND_RESET(stream_class->event_common_context_fc);
+       bt_object_pool_finalize(&stream_class->packet_context_field_pool);
+       g_free(stream_class);
+}
+
+static
+void free_field_wrapper(struct bt_field_wrapper *field_wrapper,
+               struct bt_stream_class *stream_class)
+{
+       bt_field_wrapper_destroy((void *) field_wrapper);
+}
+
+BT_ASSERT_PRE_FUNC
+static
+bool stream_class_id_is_unique(const struct bt_trace_class *tc, uint64_t id)
+{
+       uint64_t i;
+       bool is_unique = true;
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               const struct bt_stream_class *sc =
+                       tc->stream_classes->pdata[i];
+
+               if (sc->id == id) {
+                       is_unique = false;
+                       goto end;
+               }
+       }
+
+end:
+       return is_unique;
+}
+
+static
+struct bt_stream_class *create_stream_class_with_id(
+               struct bt_trace_class *tc, uint64_t id)
+{
+       struct bt_stream_class *stream_class = NULL;
+       int ret;
+
+       BT_ASSERT(tc);
+       BT_ASSERT_PRE(stream_class_id_is_unique(tc, id),
+               "Duplicate stream class ID: %![tc-]+T, id=%" PRIu64, tc, id);
+       BT_LIB_LOGD("Creating stream class object: %![tc-]+T, id=%" PRIu64,
+               tc, id);
+       stream_class = g_new0(struct bt_stream_class, 1);
+       if (!stream_class) {
+               BT_LOGE_STR("Failed to allocate one stream class.");
+               goto error;
+       }
+
+       bt_object_init_shared_with_parent(&stream_class->base,
+               destroy_stream_class);
+
+       stream_class->name.str = g_string_new(NULL);
+       if (!stream_class->name.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = -1;
+               goto end;
+       }
+
+       stream_class->id = id;
+       stream_class->assigns_automatic_event_class_id = true;
+       stream_class->assigns_automatic_stream_id = true;
+       stream_class->event_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!stream_class->event_classes) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       ret = bt_object_pool_initialize(&stream_class->packet_context_field_pool,
+               (bt_object_pool_new_object_func) bt_field_wrapper_new,
+               (bt_object_pool_destroy_object_func) free_field_wrapper,
+               stream_class);
+       if (ret) {
+               BT_LOGE("Failed to initialize packet context field pool: ret=%d",
+                       ret);
+               goto error;
+       }
+
+       bt_object_set_parent(&stream_class->base, &tc->base);
+       g_ptr_array_add(tc->stream_classes, stream_class);
+       bt_trace_class_freeze(tc);
+       BT_LIB_LOGD("Created stream class object: %!+S", stream_class);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(stream_class);
+
+end:
+       return stream_class;
+}
+
+struct bt_stream_class *bt_stream_class_create(struct bt_trace_class *tc)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE(tc->assigns_automatic_stream_class_id,
+               "Trace class does not automatically assigns stream class IDs: "
+               "%![sc-]+T", tc);
+       return create_stream_class_with_id(tc,
+               (uint64_t) tc->stream_classes->len);
+}
+
+struct bt_stream_class *bt_stream_class_create_with_id(
+               struct bt_trace_class *tc, uint64_t id)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE(!tc->assigns_automatic_stream_class_id,
+               "Trace class automatically assigns stream class IDs: "
+               "%![sc-]+T", tc);
+       return create_stream_class_with_id(tc, id);
+}
+
+struct bt_trace_class *bt_stream_class_borrow_trace_class(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return bt_stream_class_borrow_trace_class_inline(stream_class);
+}
+
+const struct bt_trace_class *bt_stream_class_borrow_trace_class_const(
+               const struct bt_stream_class *stream_class)
+{
+       return bt_stream_class_borrow_trace_class((void *) stream_class);
+}
+
+const char *bt_stream_class_get_name(const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->name.value;
+}
+
+enum bt_stream_class_status bt_stream_class_set_name(
+               struct bt_stream_class *stream_class,
+               const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       g_string_assign(stream_class->name.str, name);
+       stream_class->name.value = stream_class->name.str->str;
+       BT_LIB_LOGV("Set stream class's name: %!+S", stream_class);
+       return BT_STREAM_CLASS_STATUS_OK;
+}
+
+uint64_t bt_stream_class_get_id(const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->id;
+}
+
+uint64_t bt_stream_class_get_event_class_count(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (uint64_t) stream_class->event_classes->len;
+}
+
+struct bt_event_class *bt_stream_class_borrow_event_class_by_index(
+               struct bt_stream_class *stream_class, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_VALID_INDEX(index, stream_class->event_classes->len);
+       return g_ptr_array_index(stream_class->event_classes, index);
+}
+
+const struct bt_event_class *
+bt_stream_class_borrow_event_class_by_index_const(
+               const struct bt_stream_class *stream_class, uint64_t index)
+{
+       return bt_stream_class_borrow_event_class_by_index(
+               (void *) stream_class, index);
+}
+
+struct bt_event_class *bt_stream_class_borrow_event_class_by_id(
+               struct bt_stream_class *stream_class, uint64_t id)
+{
+       struct bt_event_class *event_class = NULL;
+       uint64_t i;
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+
+       for (i = 0; i < stream_class->event_classes->len; i++) {
+               struct bt_event_class *event_class_candidate =
+                       g_ptr_array_index(stream_class->event_classes, i);
+
+               if (event_class_candidate->id == id) {
+                       event_class = event_class_candidate;
+                       goto end;
+               }
+       }
+
+end:
+       return event_class;
+}
+
+const struct bt_event_class *
+bt_stream_class_borrow_event_class_by_id_const(
+               const struct bt_stream_class *stream_class, uint64_t id)
+{
+       return bt_stream_class_borrow_event_class_by_id(
+               (void *) stream_class, id);
+}
+
+const struct bt_field_class *
+bt_stream_class_borrow_packet_context_field_class_const(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->packet_context_fc;
+}
+
+struct bt_field_class *
+bt_stream_class_borrow_packet_context_field_class(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->packet_context_fc;
+}
+
+enum bt_stream_class_status bt_stream_class_set_packet_context_field_class(
+               struct bt_stream_class *stream_class,
+               struct bt_field_class *field_class)
+{
+       int ret;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_context = field_class,
+               .event_common_context = NULL,
+               .event_specific_context = NULL,
+               .event_payload = NULL,
+       };
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
+               BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Packet context field class is not a structure field class: %!+F",
+               field_class);
+       ret = bt_resolve_field_paths(field_class, &resolve_ctx);
+       if (ret) {
+               /*
+                * This is the only reason for which
+                * bt_resolve_field_paths() can fail: anything else
+                * would be because a precondition is not satisfied.
+                */
+               ret = BT_STREAM_CLASS_STATUS_NOMEM;
+               goto end;
+       }
+
+       bt_field_class_make_part_of_trace_class(field_class);
+       bt_object_put_ref(stream_class->packet_context_fc);
+       stream_class->packet_context_fc = field_class;
+       bt_object_get_no_null_check(stream_class->packet_context_fc);
+       bt_field_class_freeze(field_class);
+       BT_LIB_LOGV("Set stream class's packet context field class: %!+S",
+               stream_class);
+
+end:
+       return ret;
+}
+
+const struct bt_field_class *
+bt_stream_class_borrow_event_common_context_field_class_const(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->event_common_context_fc;
+}
+
+struct bt_field_class *
+bt_stream_class_borrow_event_common_context_field_class(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->event_common_context_fc;
+}
+
+enum bt_stream_class_status
+bt_stream_class_set_event_common_context_field_class(
+               struct bt_stream_class *stream_class,
+               struct bt_field_class *field_class)
+{
+       int ret;
+       struct bt_resolve_field_path_context resolve_ctx = {
+               .packet_context = NULL,
+               .event_common_context = field_class,
+               .event_specific_context = NULL,
+               .event_payload = NULL,
+       };
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
+               BT_FIELD_CLASS_TYPE_STRUCTURE,
+               "Event common context field class is not a structure field class: %!+F",
+               field_class);
+       resolve_ctx.packet_context = stream_class->packet_context_fc;
+       ret = bt_resolve_field_paths(field_class, &resolve_ctx);
+       if (ret) {
+               /*
+                * This is the only reason for which
+                * bt_resolve_field_paths() can fail: anything else
+                * would be because a precondition is not satisfied.
+                */
+               ret = BT_STREAM_CLASS_STATUS_NOMEM;
+               goto end;
+       }
+
+       bt_field_class_make_part_of_trace_class(field_class);
+       bt_object_put_ref(stream_class->event_common_context_fc);
+       stream_class->event_common_context_fc = field_class;
+       bt_object_get_no_null_check(stream_class->event_common_context_fc);
+       bt_field_class_freeze(field_class);
+       BT_LIB_LOGV("Set stream class's event common context field class: %!+S",
+               stream_class);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void _bt_stream_class_freeze(const struct bt_stream_class *stream_class)
+{
+       /* The field classes and default clock class are already frozen */
+       BT_ASSERT(stream_class);
+       BT_LIB_LOGD("Freezing stream class: %!+S", stream_class);
+       ((struct bt_stream_class *) stream_class)->frozen = true;
+}
+
+enum bt_stream_class_status bt_stream_class_set_default_clock_class(
+               struct bt_stream_class *stream_class,
+               struct bt_clock_class *clock_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       bt_object_put_ref(stream_class->default_clock_class);
+       stream_class->default_clock_class = clock_class;
+       bt_object_get_no_null_check(stream_class->default_clock_class);
+       bt_clock_class_freeze(clock_class);
+       BT_LIB_LOGV("Set stream class's default clock class: %!+S",
+               stream_class);
+       return BT_STREAM_CLASS_STATUS_OK;
+}
+
+struct bt_clock_class *bt_stream_class_borrow_default_clock_class(
+               struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->default_clock_class;
+}
+
+const struct bt_clock_class *bt_stream_class_borrow_default_clock_class_const(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return stream_class->default_clock_class;
+}
+
+bt_bool bt_stream_class_assigns_automatic_event_class_id(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->assigns_automatic_event_class_id;
+}
+
+void bt_stream_class_set_assigns_automatic_event_class_id(
+               struct bt_stream_class *stream_class,
+               bt_bool value)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       stream_class->assigns_automatic_event_class_id = (bool) value;
+       BT_LIB_LOGV("Set stream class's automatic event class ID "
+               "assignment property: %!+S", stream_class);
+}
+
+bt_bool bt_stream_class_packets_have_beginning_default_clock_snapshot(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->packets_have_beginning_default_clock_snapshot;
+}
+
+void bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
+               struct bt_stream_class *stream_class, bt_bool value)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(!value || stream_class->default_clock_class,
+               "Stream class has no default clock class: %!+S", stream_class);
+       stream_class->packets_have_beginning_default_clock_snapshot =
+               (bool) value;
+       BT_LIB_LOGV("Set stream class's \"packets have default beginning "
+               "clock snapshot\" property: %!+S", stream_class);
+}
+
+bt_bool bt_stream_class_packets_have_end_default_clock_snapshot(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->packets_have_end_default_clock_snapshot;
+}
+
+void bt_stream_class_set_packets_have_end_default_clock_snapshot(
+               struct bt_stream_class *stream_class, bt_bool value)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(!value || stream_class->default_clock_class,
+               "Stream class has no default clock class: %!+S", stream_class);
+       stream_class->packets_have_end_default_clock_snapshot =
+               (bool) value;
+       BT_LIB_LOGV("Set stream class's \"packets have default end "
+               "clock snapshot\" property: %!+S", stream_class);
+}
+
+bt_bool bt_stream_class_assigns_automatic_stream_id(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->assigns_automatic_stream_id;
+}
+
+void bt_stream_class_set_supports_discarded_events(
+               struct bt_stream_class *stream_class,
+               bt_bool supports_discarded_events,
+               bt_bool with_default_clock_snapshots)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(supports_discarded_events ||
+               !with_default_clock_snapshots,
+               "Discarded events cannot have default clock snapshots when "
+               "not supported: %!+S", stream_class);
+       BT_ASSERT_PRE(!with_default_clock_snapshots ||
+               stream_class->default_clock_class,
+               "Stream class has no default clock class: %!+S", stream_class);
+       stream_class->supports_discarded_events =
+               (bool) supports_discarded_events;
+       stream_class->discarded_events_have_default_clock_snapshots =
+               (bool) with_default_clock_snapshots;
+       BT_LIB_LOGV("Set stream class's discarded events support property: "
+               "%!+S", stream_class);
+}
+
+bt_bool bt_stream_class_supports_discarded_events(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->supports_discarded_events;
+}
+
+bt_bool bt_stream_class_discarded_events_have_default_clock_snapshots(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->discarded_events_have_default_clock_snapshots;
+}
+
+void bt_stream_class_set_supports_discarded_packets(
+               struct bt_stream_class *stream_class,
+               bt_bool supports_discarded_packets,
+               bt_bool with_default_clock_snapshots)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       BT_ASSERT_PRE(supports_discarded_packets ||
+               !with_default_clock_snapshots,
+               "Discarded packets cannot have default clock snapshots when "
+               "not supported: %!+S", stream_class);
+       BT_ASSERT_PRE(!with_default_clock_snapshots ||
+               stream_class->default_clock_class,
+               "Stream class has no default clock class: %!+S", stream_class);
+       stream_class->supports_discarded_packets =
+               (bool) supports_discarded_packets;
+       stream_class->discarded_packets_have_default_clock_snapshots =
+               (bool) with_default_clock_snapshots;
+       BT_LIB_LOGV("Set stream class's discarded packets support property: "
+               "%!+S", stream_class);
+}
+
+bt_bool bt_stream_class_supports_discarded_packets(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->supports_discarded_packets;
+}
+
+bt_bool bt_stream_class_discarded_packets_have_default_clock_snapshots(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       return (bt_bool) stream_class->discarded_packets_have_default_clock_snapshots;
+}
+
+void bt_stream_class_set_assigns_automatic_stream_id(
+               struct bt_stream_class *stream_class,
+               bt_bool value)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
+       stream_class->assigns_automatic_stream_id = (bool) value;
+       BT_LIB_LOGV("Set stream class's automatic stream ID "
+               "assignment property: %!+S", stream_class);
+}
+
+void bt_stream_class_get_ref(const struct bt_stream_class *stream_class)
+{
+       bt_object_get_ref(stream_class);
+}
+
+void bt_stream_class_put_ref(const struct bt_stream_class *stream_class)
+{
+       bt_object_put_ref(stream_class);
+}
diff --git a/src/lib/trace-ir/stream-class.h b/src/lib/trace-ir/stream-class.h
new file mode 100644 (file)
index 0000000..1efa770
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef BABELTRACE_TRACE_IR_STREAM_CLASS_INTERNAL_H
+#define BABELTRACE_TRACE_IR_STREAM_CLASS_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/assert.h"
+#include "common/common.h"
+#include <babeltrace2/trace-ir/stream-class.h>
+#include "lib/object.h"
+#include "lib/object-pool.h"
+#include "common/babeltrace.h"
+#include <glib.h>
+#include <inttypes.h>
+
+#include "field-class.h"
+#include "utils.h"
+
+struct bt_stream_class {
+       struct bt_object base;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       uint64_t id;
+       bool assigns_automatic_event_class_id;
+       bool assigns_automatic_stream_id;
+       bool packets_have_beginning_default_clock_snapshot;
+       bool packets_have_end_default_clock_snapshot;
+       bool supports_discarded_events;
+       bool supports_discarded_packets;
+       bool discarded_events_have_default_clock_snapshots;
+       bool discarded_packets_have_default_clock_snapshots;
+       struct bt_field_class *packet_context_fc;
+       struct bt_field_class *event_common_context_fc;
+       struct bt_clock_class *default_clock_class;
+
+       /* Array of `struct bt_event_class *` */
+       GPtrArray *event_classes;
+
+       /* Pool of `struct bt_field_wrapper *` */
+       struct bt_object_pool packet_context_field_pool;
+
+       bool frozen;
+};
+
+BT_HIDDEN
+void _bt_stream_class_freeze(const struct bt_stream_class *stream_class);
+
+#ifdef BT_DEV_MODE
+# define bt_stream_class_freeze                _bt_stream_class_freeze
+#else
+# define bt_stream_class_freeze(_sc)
+#endif
+
+static inline
+struct bt_trace_class *bt_stream_class_borrow_trace_class_inline(
+               const struct bt_stream_class *stream_class)
+{
+       BT_ASSERT(stream_class);
+       return (void *) bt_object_borrow_parent(&stream_class->base);
+}
+
+#endif /* BABELTRACE_TRACE_IR_STREAM_CLASS_INTERNAL_H */
diff --git a/src/lib/trace-ir/stream.c b/src/lib/trace-ir/stream.c
new file mode 100644 (file)
index 0000000..4e017e4
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "STREAM"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/stream-const.h>
+#include <babeltrace2/trace-ir/stream.h>
+#include <babeltrace2/trace-ir/stream-class.h>
+#include <babeltrace2/trace-ir/trace.h>
+#include "compat/compiler.h"
+#include "common/align.h"
+#include "common/assert.h"
+#include "lib/property.h"
+#include <inttypes.h>
+#include <unistd.h>
+
+#include "packet.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "trace.h"
+
+#define BT_ASSERT_PRE_STREAM_HOT(_stream) \
+       BT_ASSERT_PRE_HOT((_stream), "Stream", ": %!+s", (_stream))
+
+static
+void destroy_stream(struct bt_object *obj)
+{
+       struct bt_stream *stream = (void *) obj;
+
+       BT_LIB_LOGD("Destroying stream object: %!+s", stream);
+
+       if (stream->name.str) {
+               g_string_free(stream->name.str, TRUE);
+               stream->name.str = NULL;
+               stream->name.value = NULL;
+       }
+
+       BT_LOGD_STR("Putting stream's class.");
+       bt_object_put_ref(stream->class);
+       bt_object_pool_finalize(&stream->packet_pool);
+       g_free(stream);
+}
+
+static
+void bt_stream_free_packet(struct bt_packet *packet, struct bt_stream *stream)
+{
+       bt_packet_destroy(packet);
+}
+
+BT_ASSERT_PRE_FUNC
+static inline
+bool stream_id_is_unique(struct bt_trace *trace,
+               struct bt_stream_class *stream_class, uint64_t id)
+{
+       uint64_t i;
+       bool is_unique = true;
+
+       for (i = 0; i < trace->streams->len; i++) {
+               struct bt_stream *stream = trace->streams->pdata[i];
+
+               if (stream->class != stream_class) {
+                       continue;
+               }
+
+               if (stream->id == id) {
+                       is_unique = false;
+                       goto end;
+               }
+       }
+
+end:
+       return is_unique;
+}
+
+static
+struct bt_stream *create_stream_with_id(struct bt_stream_class *stream_class,
+               struct bt_trace *trace, uint64_t id)
+{
+       int ret;
+       struct bt_stream *stream;
+
+       BT_ASSERT(stream_class);
+       BT_ASSERT(trace);
+       BT_ASSERT_PRE(trace->class ==
+               bt_stream_class_borrow_trace_class_inline(stream_class),
+               "Trace's class is different from stream class's parent trace class: "
+               "%![sc-]+S, %![trace-]+t", stream_class, trace);
+       BT_ASSERT_PRE(stream_id_is_unique(trace, stream_class, id),
+               "Duplicate stream ID: %![trace-]+t, id=%" PRIu64, trace, id);
+       BT_LIB_LOGD("Creating stream object: %![trace-]+t, id=%" PRIu64,
+               trace, id);
+       stream = g_new0(struct bt_stream, 1);
+       if (!stream) {
+               BT_LOGE_STR("Failed to allocate one stream.");
+               goto error;
+       }
+
+       bt_object_init_shared_with_parent(&stream->base, destroy_stream);
+       stream->name.str = g_string_new(NULL);
+       if (!stream->name.str) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       stream->id = id;
+       ret = bt_object_pool_initialize(&stream->packet_pool,
+               (bt_object_pool_new_object_func) bt_packet_new,
+               (bt_object_pool_destroy_object_func) bt_stream_free_packet,
+               stream);
+       if (ret) {
+               BT_LOGE("Failed to initialize packet pool: ret=%d", ret);
+               goto error;
+       }
+
+       stream->class = stream_class;
+       bt_object_get_no_null_check(stream_class);
+
+       /* bt_trace_add_stream() sets the parent trace, and freezes the trace */
+       bt_trace_add_stream(trace, stream);
+
+       bt_stream_class_freeze(stream_class);
+       BT_LIB_LOGD("Created stream object: %!+s", stream);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(stream);
+
+end:
+       return stream;
+}
+
+struct bt_stream *bt_stream_create(struct bt_stream_class *stream_class,
+               struct bt_trace *trace)
+{
+       uint64_t id;
+
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE(stream_class->assigns_automatic_stream_id,
+               "Stream class does not automatically assigns stream IDs: "
+               "%![sc-]+S", stream_class);
+       id = bt_trace_get_automatic_stream_id(trace, stream_class);
+       return create_stream_with_id(stream_class, trace, id);
+}
+
+struct bt_stream *bt_stream_create_with_id(struct bt_stream_class *stream_class,
+               struct bt_trace *trace, uint64_t id)
+{
+       BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE(!stream_class->assigns_automatic_stream_id,
+               "Stream class automatically assigns stream IDs: "
+               "%![sc-]+S", stream_class);
+       return create_stream_with_id(stream_class, trace, id);
+}
+
+struct bt_stream_class *bt_stream_borrow_class(struct bt_stream *stream)
+{
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       return stream->class;
+}
+
+const struct bt_stream_class *bt_stream_borrow_class_const(
+               const struct bt_stream *stream)
+{
+       return bt_stream_borrow_class((void *) stream);
+}
+
+struct bt_trace *bt_stream_borrow_trace(struct bt_stream *stream)
+{
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       return bt_stream_borrow_trace_inline(stream);
+}
+
+const struct bt_trace *bt_stream_borrow_trace_const(
+               const struct bt_stream *stream)
+{
+       return bt_stream_borrow_trace((void *) stream);
+}
+
+const char *bt_stream_get_name(const struct bt_stream *stream)
+{
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       return stream->name.value;
+}
+
+enum bt_stream_status bt_stream_set_name(struct bt_stream *stream,
+               const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_STREAM_HOT(stream);
+       g_string_assign(stream->name.str, name);
+       stream->name.value = stream->name.str->str;
+       BT_LIB_LOGV("Set stream's name: %!+s", stream);
+       return BT_STREAM_STATUS_OK;
+}
+
+uint64_t bt_stream_get_id(const struct bt_stream *stream)
+{
+       BT_ASSERT_PRE_NON_NULL(stream, "Stream class");
+       return stream->id;
+}
+
+BT_HIDDEN
+void _bt_stream_freeze(const struct bt_stream *stream)
+{
+       BT_ASSERT(stream);
+       BT_LIB_LOGD("Freezing stream: %!+s", stream);
+       ((struct bt_stream *) stream)->frozen = true;
+}
+
+void bt_stream_get_ref(const struct bt_stream *stream)
+{
+       bt_object_get_ref(stream);
+}
+
+void bt_stream_put_ref(const struct bt_stream *stream)
+{
+       bt_object_put_ref(stream);
+}
diff --git a/src/lib/trace-ir/stream.h b/src/lib/trace-ir/stream.h
new file mode 100644 (file)
index 0000000..96985a9
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef BABELTRACE_TRACE_IR_STREAM_INTERNAL_H
+#define BABELTRACE_TRACE_IR_STREAM_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/trace-ir/stream.h>
+#include "lib/object.h"
+#include "lib/object-pool.h"
+#include "common/babeltrace.h"
+#include <glib.h>
+
+#include "utils.h"
+
+struct bt_stream_class;
+struct bt_stream;
+
+struct bt_stream {
+       struct bt_object base;
+
+       /* Owned by this */
+       struct bt_stream_class *class;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       uint64_t id;
+
+       /* Pool of `struct bt_packet *` */
+       struct bt_object_pool packet_pool;
+
+       bool frozen;
+};
+
+BT_HIDDEN
+void _bt_stream_freeze(const struct bt_stream *stream);
+
+#ifdef BT_DEV_MODE
+# define bt_stream_freeze              _bt_stream_freeze
+#else
+# define bt_stream_freeze(_stream)
+#endif
+
+static inline
+struct bt_trace *bt_stream_borrow_trace_inline(const struct bt_stream *stream)
+{
+       BT_ASSERT(stream);
+       return (void *) bt_object_borrow_parent(&stream->base);
+}
+
+#endif /* BABELTRACE_TRACE_IR_STREAM_INTERNAL_H */
diff --git a/src/lib/trace-ir/trace-class.c b/src/lib/trace-ir/trace-class.c
new file mode 100644 (file)
index 0000000..f05c771
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "TRACE"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/trace-class.h>
+#include <babeltrace2/trace-ir/trace-class-const.h>
+#include <babeltrace2/trace-ir/event-class.h>
+#include "ctf-writer/functor.h"
+#include "ctf-writer/clock.h"
+#include "compat/compiler.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/value-const.h>
+#include "lib/value.h"
+#include <babeltrace2/types.h>
+#include "compat/endian.h"
+#include "common/assert.h"
+#include "compat/glib.h"
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "attributes.h"
+#include "clock-class.h"
+#include "event-class.h"
+#include "event.h"
+#include "field-class.h"
+#include "field-wrapper.h"
+#include "resolve-field-path.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "trace.h"
+#include "utils.h"
+
+struct bt_trace_class_destruction_listener_elem {
+       bt_trace_class_destruction_listener_func func;
+       void *data;
+};
+
+#define BT_ASSERT_PRE_TRACE_CLASS_HOT(_tc)                             \
+       BT_ASSERT_PRE_HOT((_tc), "Trace class", ": %!+T", (_tc))
+
+static
+void destroy_trace_class(struct bt_object *obj)
+{
+       struct bt_trace_class *tc = (void *) obj;
+
+       BT_LIB_LOGD("Destroying trace class object: %!+T", tc);
+       /*
+        * Call destruction listener functions so that everything else
+        * still exists in the trace class.
+        */
+       if (tc->destruction_listeners) {
+               uint64_t i;
+               BT_LIB_LOGV("Calling trace class destruction listener(s): %!+T", tc);
+
+               /*
+               * The trace class' reference count is 0 if we're here. Increment
+               * it to avoid a double-destroy (possibly infinitely recursive).
+               * This could happen for example if a destruction listener did
+               * bt_object_get_ref() (or anything that causes
+               * bt_object_get_ref() to be called) on the trace class (ref.
+               * count goes from 0 to 1), and then bt_object_put_ref(): the
+               * reference count would go from 1 to 0 again and this function
+               * would be called again.
+               */
+               tc->base.ref_count++;
+
+               /* Call all the trace class destruction listeners */
+               for (i = 0; i < tc->destruction_listeners->len; i++) {
+                       struct bt_trace_class_destruction_listener_elem elem =
+                               g_array_index(tc->destruction_listeners,
+                                               struct bt_trace_class_destruction_listener_elem, i);
+
+                       if (elem.func) {
+                               elem.func(tc, elem.data);
+                       }
+
+                       /*
+                        * The destruction listener should not have kept a
+                        * reference to the trace class.
+                        */
+                       BT_ASSERT_PRE(tc->base.ref_count == 1, "Destruction listener kept a reference to the trace class being destroyed: %![tc-]+T", tc);
+               }
+               g_array_free(tc->destruction_listeners, TRUE);
+               tc->destruction_listeners = NULL;
+       }
+
+       if (tc->environment) {
+               BT_LOGD_STR("Destroying environment attributes.");
+               bt_attributes_destroy(tc->environment);
+               tc->environment = NULL;
+       }
+
+       if (tc->name.str) {
+               g_string_free(tc->name.str, TRUE);
+               tc->name.str = NULL;
+               tc->name.value = NULL;
+       }
+
+       if (tc->stream_classes) {
+               BT_LOGD_STR("Destroying stream classes.");
+               g_ptr_array_free(tc->stream_classes, TRUE);
+               tc->stream_classes = NULL;
+       }
+
+       g_free(tc);
+}
+
+struct bt_trace_class *bt_trace_class_create(bt_self_component *self_comp)
+{
+       struct bt_trace_class *tc = NULL;
+
+       BT_ASSERT_PRE_NON_NULL(self_comp, "Self component");
+       BT_LOGD_STR("Creating default trace class object.");
+       tc = g_new0(struct bt_trace_class, 1);
+       if (!tc) {
+               BT_LOGE_STR("Failed to allocate one trace class.");
+               goto error;
+       }
+
+       bt_object_init_shared_with_parent(&tc->base, destroy_trace_class);
+
+       tc->stream_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!tc->stream_classes) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+
+       tc->name.str = g_string_new(NULL);
+       if (!tc->name.str) {
+               BT_LOGE_STR("Failed to allocate one GString.");
+               goto error;
+       }
+
+       tc->environment = bt_attributes_create();
+       if (!tc->environment) {
+               BT_LOGE_STR("Cannot create empty attributes object.");
+               goto error;
+       }
+
+       tc->destruction_listeners = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_trace_class_destruction_listener_elem));
+       if (!tc->destruction_listeners) {
+               BT_LOGE_STR("Failed to allocate one GArray.");
+               goto error;
+       }
+
+       tc->assigns_automatic_stream_class_id = true;
+       BT_LIB_LOGD("Created trace class object: %!+T", tc);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(tc);
+
+end:
+       return tc;
+}
+
+const char *bt_trace_class_get_name(const struct bt_trace_class *tc)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       return tc->name.value;
+}
+
+enum bt_trace_class_status bt_trace_class_set_name(
+               struct bt_trace_class *tc, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_TRACE_CLASS_HOT(tc);
+       g_string_assign(tc->name.str, name);
+       tc->name.value = tc->name.str->str;
+       BT_LIB_LOGV("Set trace class's name: %!+T", tc);
+       return BT_TRACE_CLASS_STATUS_OK;
+}
+
+bt_uuid bt_trace_class_get_uuid(const struct bt_trace_class *tc)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       return tc->uuid.value;
+}
+
+void bt_trace_class_set_uuid(struct bt_trace_class *tc, bt_uuid uuid)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(uuid, "UUID");
+       BT_ASSERT_PRE_TRACE_CLASS_HOT(tc);
+       memcpy(tc->uuid.uuid, uuid, BABELTRACE_UUID_LEN);
+       tc->uuid.value = tc->uuid.uuid;
+       BT_LIB_LOGV("Set trace class's UUID: %!+T", tc);
+}
+
+enum bt_trace_class_status bt_trace_class_add_destruction_listener(
+               const struct bt_trace_class *_tc,
+               bt_trace_class_destruction_listener_func listener,
+               void *data, uint64_t *listener_id)
+{
+       struct bt_trace_class *tc = (void *) _tc;
+       uint64_t i;
+       struct bt_trace_class_destruction_listener_elem new_elem = {
+               .func = listener,
+               .data = data,
+       };
+
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(listener, "Listener");
+
+       /* Find the next available spot */
+       for (i = 0; i < tc->destruction_listeners->len; i++) {
+               struct bt_trace_class_destruction_listener_elem elem =
+                       g_array_index(tc->destruction_listeners,
+                               struct bt_trace_class_destruction_listener_elem, i);
+
+               if (!elem.func) {
+                       break;
+               }
+       }
+
+       if (i == tc->destruction_listeners->len) {
+               g_array_append_val(tc->destruction_listeners, new_elem);
+       } else {
+               g_array_insert_val(tc->destruction_listeners, i, new_elem);
+       }
+
+       if (listener_id) {
+               *listener_id = i;
+       }
+
+       BT_LIB_LOGV("Added trace class destruction listener: %![tc-]+T, "
+                       "listener-id=%" PRIu64, tc, i);
+       return BT_TRACE_CLASS_STATUS_OK;
+}
+
+BT_ASSERT_PRE_FUNC
+static
+bool has_listener_id(const struct bt_trace_class *tc, uint64_t listener_id)
+{
+       BT_ASSERT(listener_id < tc->destruction_listeners->len);
+       return (&g_array_index(tc->destruction_listeners,
+                       struct bt_trace_class_destruction_listener_elem,
+                       listener_id))->func != NULL;
+}
+
+enum bt_trace_class_status bt_trace_class_remove_destruction_listener(
+               const struct bt_trace_class *_tc, uint64_t listener_id)
+{
+       struct bt_trace_class *tc = (void *) _tc;
+       struct bt_trace_class_destruction_listener_elem *elem;
+
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE(has_listener_id(tc, listener_id),
+               "Trace class has no such trace class destruction listener ID: "
+               "%![tc-]+T, %" PRIu64, tc, listener_id);
+       elem = &g_array_index(tc->destruction_listeners,
+                       struct bt_trace_class_destruction_listener_elem,
+                       listener_id);
+       BT_ASSERT(elem->func);
+
+       elem->func = NULL;
+       elem->data = NULL;
+       BT_LIB_LOGV("Removed trace class destruction listener: "
+               "%![tc-]+T, listener-id=%" PRIu64,
+               tc, listener_id);
+       return BT_TRACE_CLASS_STATUS_OK;
+}
+
+BT_ASSERT_FUNC
+static
+bool trace_has_environment_entry(const struct bt_trace_class *tc, const char *name)
+{
+       BT_ASSERT(tc);
+
+       return bt_attributes_borrow_field_value_by_name(
+               tc->environment, name) != NULL;
+}
+
+static
+enum bt_trace_class_status set_environment_entry(struct bt_trace_class *tc,
+               const char *name, struct bt_value *value)
+{
+       int ret;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(name);
+       BT_ASSERT(value);
+       BT_ASSERT_PRE(!tc->frozen ||
+               !trace_has_environment_entry(tc, name),
+               "Trace class is frozen: cannot replace environment entry: "
+               "%![tc-]+T, entry-name=\"%s\"", tc, name);
+       ret = bt_attributes_set_field_value(tc->environment, name,
+               value);
+       if (ret) {
+               ret = BT_TRACE_CLASS_STATUS_NOMEM;
+               BT_LIB_LOGE("Cannot set trace class's environment entry: "
+                       "%![tc-]+T, entry-name=\"%s\"", tc, name);
+       } else {
+               bt_value_freeze(value);
+               BT_LIB_LOGV("Set trace class's environment entry: "
+                       "%![tc-]+T, entry-name=\"%s\"", tc, name);
+       }
+
+       return ret;
+}
+
+enum bt_trace_class_status bt_trace_class_set_environment_entry_string(
+               struct bt_trace_class *tc, const char *name, const char *value)
+{
+       int ret;
+       struct bt_value *value_obj;
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       value_obj = bt_value_string_create_init(value);
+       if (!value_obj) {
+               BT_LOGE_STR("Cannot create a string value object.");
+               ret = -1;
+               goto end;
+       }
+
+       /* set_environment_entry() logs errors */
+       ret = set_environment_entry(tc, name, value_obj);
+
+end:
+       bt_object_put_ref(value_obj);
+       return ret;
+}
+
+enum bt_trace_class_status bt_trace_class_set_environment_entry_integer(
+               struct bt_trace_class *tc, const char *name, int64_t value)
+{
+       int ret;
+       struct bt_value *value_obj;
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       value_obj = bt_value_signed_integer_create_init(value);
+       if (!value_obj) {
+               BT_LOGE_STR("Cannot create an integer value object.");
+               ret = BT_TRACE_CLASS_STATUS_NOMEM;
+               goto end;
+       }
+
+       /* set_environment_entry() logs errors */
+       ret = set_environment_entry(tc, name, value_obj);
+
+end:
+       bt_object_put_ref(value_obj);
+       return ret;
+}
+
+uint64_t bt_trace_class_get_environment_entry_count(const struct bt_trace_class *tc)
+{
+       int64_t ret;
+
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       ret = bt_attributes_get_count(tc->environment);
+       BT_ASSERT(ret >= 0);
+       return (uint64_t) ret;
+}
+
+void bt_trace_class_borrow_environment_entry_by_index_const(
+               const struct bt_trace_class *tc, uint64_t index,
+               const char **name, const struct bt_value **value)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_NON_NULL(value, "Value");
+       BT_ASSERT_PRE_VALID_INDEX(index,
+               bt_attributes_get_count(tc->environment));
+       *value = bt_attributes_borrow_field_value(tc->environment, index);
+       BT_ASSERT(*value);
+       *name = bt_attributes_get_field_name(tc->environment, index);
+       BT_ASSERT(*name);
+}
+
+const struct bt_value *bt_trace_class_borrow_environment_entry_value_by_name_const(
+               const struct bt_trace_class *tc, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       return bt_attributes_borrow_field_value_by_name(tc->environment,
+               name);
+}
+
+uint64_t bt_trace_class_get_stream_class_count(const struct bt_trace_class *tc)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       return (uint64_t) tc->stream_classes->len;
+}
+
+struct bt_stream_class *bt_trace_class_borrow_stream_class_by_index(
+               struct bt_trace_class *tc, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_VALID_INDEX(index, tc->stream_classes->len);
+       return g_ptr_array_index(tc->stream_classes, index);
+}
+
+const struct bt_stream_class *
+bt_trace_class_borrow_stream_class_by_index_const(
+               const struct bt_trace_class *tc, uint64_t index)
+{
+       return bt_trace_class_borrow_stream_class_by_index(
+               (void *) tc, index);
+}
+
+struct bt_stream_class *bt_trace_class_borrow_stream_class_by_id(
+               struct bt_trace_class *tc, uint64_t id)
+{
+       struct bt_stream_class *stream_class = NULL;
+       uint64_t i;
+
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               struct bt_stream_class *stream_class_candidate =
+                       g_ptr_array_index(tc->stream_classes, i);
+
+               if (stream_class_candidate->id == id) {
+                       stream_class = stream_class_candidate;
+                       goto end;
+               }
+       }
+
+end:
+       return stream_class;
+}
+
+const struct bt_stream_class *
+bt_trace_class_borrow_stream_class_by_id_const(
+               const struct bt_trace_class *tc, uint64_t id)
+{
+       return bt_trace_class_borrow_stream_class_by_id((void *) tc, id);
+}
+
+BT_HIDDEN
+void _bt_trace_class_freeze(const struct bt_trace_class *tc)
+{
+       BT_ASSERT(tc);
+       BT_LIB_LOGD("Freezing trace class: %!+T", tc);
+       ((struct bt_trace_class *) tc)->frozen = true;
+}
+
+bt_bool bt_trace_class_assigns_automatic_stream_class_id(const struct bt_trace_class *tc)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       return (bt_bool) tc->assigns_automatic_stream_class_id;
+}
+
+void bt_trace_class_set_assigns_automatic_stream_class_id(struct bt_trace_class *tc,
+               bt_bool value)
+{
+       BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+       BT_ASSERT_PRE_TRACE_CLASS_HOT(tc);
+       tc->assigns_automatic_stream_class_id = (bool) value;
+       BT_LIB_LOGV("Set trace class's automatic stream class ID "
+               "assignment property: %!+T", tc);
+}
+
+void bt_trace_class_get_ref(const struct bt_trace_class *trace_class)
+{
+       bt_object_get_ref(trace_class);
+}
+
+void bt_trace_class_put_ref(const struct bt_trace_class *trace_class)
+{
+       bt_object_put_ref(trace_class);
+}
diff --git a/src/lib/trace-ir/trace-class.h b/src/lib/trace-ir/trace-class.h
new file mode 100644 (file)
index 0000000..7c8add5
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef BABELTRACE_TRACE_IR_TRACE_CLASS_INTERNAL_H
+#define BABELTRACE_TRACE_IR_TRACE_CLASS_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/trace-class.h>
+#include <babeltrace2/trace-ir/field-class.h>
+#include <babeltrace2/trace-ir/field.h>
+#include "lib/object.h"
+#include "lib/object-pool.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/types.h>
+#include <glib.h>
+#include <sys/types.h>
+#include "compat/uuid.h"
+
+#include "stream-class.h"
+#include "attributes.h"
+#include "clock-class.h"
+
+struct bt_trace_class {
+       struct bt_object base;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       struct {
+               uint8_t uuid[BABELTRACE_UUID_LEN];
+
+               /* NULL or `uuid` above */
+               bt_uuid value;
+       } uuid;
+
+       struct bt_value *environment;
+
+       /* Array of `struct bt_stream_class *` */
+       GPtrArray *stream_classes;
+
+       bool assigns_automatic_stream_class_id;
+       GArray *destruction_listeners;
+       bool frozen;
+};
+
+BT_HIDDEN
+void _bt_trace_class_freeze(const struct bt_trace_class *trace_class);
+
+#ifdef BT_DEV_MODE
+# define bt_trace_class_freeze         _bt_trace_class_freeze
+#else
+# define bt_trace_class_freeze(_tc)
+#endif
+
+#endif /* BABELTRACE_TRACE_IR_TRACE_CLASS_INTERNAL_H */
diff --git a/src/lib/trace-ir/trace.c b/src/lib/trace-ir/trace.c
new file mode 100644 (file)
index 0000000..6dadb10
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "TRACE"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/trace.h>
+#include <babeltrace2/trace-ir/trace-const.h>
+#include <babeltrace2/trace-ir/event-class.h>
+#include "ctf-writer/functor.h"
+#include "ctf-writer/clock.h"
+#include "compat/compiler.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/value-const.h>
+#include "lib/value.h"
+#include <babeltrace2/types.h>
+#include "compat/endian.h"
+#include "common/assert.h"
+#include "compat/glib.h"
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "attributes.h"
+#include "clock-class.h"
+#include "event-class.h"
+#include "event.h"
+#include "field-class.h"
+#include "field-wrapper.h"
+#include "resolve-field-path.h"
+#include "stream-class.h"
+#include "stream.h"
+#include "trace-class.h"
+#include "trace.h"
+#include "utils.h"
+
+struct bt_trace_destruction_listener_elem {
+       bt_trace_destruction_listener_func func;
+       void *data;
+};
+
+#define BT_ASSERT_PRE_TRACE_HOT(_trace) \
+       BT_ASSERT_PRE_HOT((_trace), "Trace", ": %!+t", (_trace))
+
+static
+void destroy_trace(struct bt_object *obj)
+{
+       struct bt_trace *trace = (void *) obj;
+
+       BT_LIB_LOGD("Destroying trace object: %!+t", trace);
+
+       /*
+        * Call destruction listener functions so that everything else
+        * still exists in the trace.
+        */
+       if (trace->destruction_listeners) {
+               uint64_t i;
+               BT_LIB_LOGV("Calling trace destruction listener(s): %!+t", trace);
+
+               /*
+               * The trace's reference count is 0 if we're here. Increment
+               * it to avoid a double-destroy (possibly infinitely recursive).
+               * This could happen for example if a destruction listener did
+               * bt_object_get_ref() (or anything that causes
+               * bt_object_get_ref() to be called) on the trace (ref.
+               * count goes from 0 to 1), and then bt_object_put_ref(): the
+               * reference count would go from 1 to 0 again and this function
+               * would be called again.
+               */
+               trace->base.ref_count++;
+
+               /* Call all the trace destruction listeners */
+               for (i = 0; i < trace->destruction_listeners->len; i++) {
+                       struct bt_trace_destruction_listener_elem elem =
+                               g_array_index(trace->destruction_listeners,
+                                               struct bt_trace_destruction_listener_elem, i);
+
+                       if (elem.func) {
+                               elem.func(trace, elem.data);
+                       }
+
+                       /*
+                        * The destruction listener should not have kept a
+                        * reference to the trace.
+                        */
+                       BT_ASSERT_PRE(trace->base.ref_count == 1, "Destruction listener kept a reference to the trace being destroyed: %![trace-]+t", trace);
+               }
+               g_array_free(trace->destruction_listeners, TRUE);
+               trace->destruction_listeners = NULL;
+       }
+
+       if (trace->name.str) {
+               g_string_free(trace->name.str, TRUE);
+               trace->name.str = NULL;
+               trace->name.value = NULL;
+       }
+
+       if (trace->streams) {
+               BT_LOGD_STR("Destroying streams.");
+               g_ptr_array_free(trace->streams, TRUE);
+               trace->streams = NULL;
+       }
+
+       if (trace->stream_classes_stream_count) {
+               g_hash_table_destroy(trace->stream_classes_stream_count);
+               trace->stream_classes_stream_count = NULL;
+       }
+
+       BT_LOGD_STR("Putting trace's class.");
+       bt_object_put_ref(trace->class);
+       trace->class = NULL;
+       g_free(trace);
+}
+
+struct bt_trace *bt_trace_create(struct bt_trace_class *tc)
+{
+       struct bt_trace *trace = NULL;
+
+       BT_LIB_LOGD("Creating trace object: %![tc-]+T", tc);
+       trace = g_new0(struct bt_trace, 1);
+       if (!trace) {
+               BT_LOGE_STR("Failed to allocate one trace.");
+               goto error;
+       }
+
+       bt_object_init_shared(&trace->base, destroy_trace);
+       trace->streams = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) bt_object_try_spec_release);
+       if (!trace->streams) {
+               BT_LOGE_STR("Failed to allocate one GPtrArray.");
+               goto error;
+       }
+
+       trace->stream_classes_stream_count = g_hash_table_new(g_direct_hash,
+               g_direct_equal);
+       if (!trace->stream_classes_stream_count) {
+               BT_LOGE_STR("Failed to allocate one GHashTable.");
+               goto error;
+       }
+
+       trace->name.str = g_string_new(NULL);
+       if (!trace->name.str) {
+               BT_LOGE_STR("Failed to allocate one GString.");
+               goto error;
+       }
+
+       trace->destruction_listeners = g_array_new(FALSE, TRUE,
+               sizeof(struct bt_trace_destruction_listener_elem));
+       if (!trace->destruction_listeners) {
+               BT_LOGE_STR("Failed to allocate one GArray.");
+               goto error;
+       }
+
+       trace->class = tc;
+       bt_object_get_no_null_check(trace->class);
+       BT_LIB_LOGD("Created trace object: %!+t", trace);
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(trace);
+
+end:
+       return trace;
+}
+
+const char *bt_trace_get_name(const struct bt_trace *trace)
+{
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return trace->name.value;
+}
+
+enum bt_trace_status bt_trace_set_name(struct bt_trace *trace, const char *name)
+{
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_NON_NULL(name, "Name");
+       BT_ASSERT_PRE_TRACE_HOT(trace);
+       g_string_assign(trace->name.str, name);
+       trace->name.value = trace->name.str->str;
+       BT_LIB_LOGV("Set trace's name: %!+t", trace);
+       return BT_TRACE_STATUS_OK;
+}
+
+uint64_t bt_trace_get_stream_count(const struct bt_trace *trace)
+{
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return (uint64_t) trace->streams->len;
+}
+
+struct bt_stream *bt_trace_borrow_stream_by_index(
+               struct bt_trace *trace, uint64_t index)
+{
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_VALID_INDEX(index, trace->streams->len);
+       return g_ptr_array_index(trace->streams, index);
+}
+
+const struct bt_stream *bt_trace_borrow_stream_by_index_const(
+               const struct bt_trace *trace, uint64_t index)
+{
+       return bt_trace_borrow_stream_by_index((void *) trace, index);
+}
+
+struct bt_stream *bt_trace_borrow_stream_by_id(struct bt_trace *trace,
+               uint64_t id)
+{
+       struct bt_stream *stream = NULL;
+       uint64_t i;
+
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+
+       for (i = 0; i < trace->streams->len; i++) {
+               struct bt_stream *stream_candidate =
+                       g_ptr_array_index(trace->streams, i);
+
+               if (stream_candidate->id == id) {
+                       stream = stream_candidate;
+                       goto end;
+               }
+       }
+
+end:
+       return stream;
+}
+
+const struct bt_stream *bt_trace_borrow_stream_by_id_const(
+               const struct bt_trace *trace, uint64_t id)
+{
+       return bt_trace_borrow_stream_by_id((void *) trace, id);
+}
+
+enum bt_trace_status bt_trace_add_destruction_listener(
+               const struct bt_trace *c_trace,
+               bt_trace_destruction_listener_func listener,
+               void *data, uint64_t *listener_id)
+{
+       struct bt_trace *trace = (void *) c_trace;
+       uint64_t i;
+       struct bt_trace_destruction_listener_elem new_elem = {
+               .func = listener,
+               .data = data,
+       };
+
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE_NON_NULL(listener, "Listener");
+
+       /* Find the next available spot */
+       for (i = 0; i < trace->destruction_listeners->len; i++) {
+               struct bt_trace_destruction_listener_elem elem =
+                       g_array_index(trace->destruction_listeners,
+                               struct bt_trace_destruction_listener_elem, i);
+
+               if (!elem.func) {
+                       break;
+               }
+       }
+
+       if (i == trace->destruction_listeners->len) {
+               g_array_append_val(trace->destruction_listeners, new_elem);
+       } else {
+               g_array_insert_val(trace->destruction_listeners, i, new_elem);
+       }
+
+       if (listener_id) {
+               *listener_id = i;
+       }
+
+       BT_LIB_LOGV("Added destruction listener: " "%![trace-]+t, "
+                       "listener-id=%" PRIu64, trace, i);
+       return BT_TRACE_STATUS_OK;
+}
+
+BT_ASSERT_PRE_FUNC
+static
+bool has_listener_id(const struct bt_trace *trace, uint64_t listener_id)
+{
+       BT_ASSERT(listener_id < trace->destruction_listeners->len);
+       return (&g_array_index(trace->destruction_listeners,
+                       struct bt_trace_destruction_listener_elem,
+                       listener_id))->func != NULL;
+}
+
+enum bt_trace_status bt_trace_remove_destruction_listener(
+               const struct bt_trace *c_trace, uint64_t listener_id)
+{
+       struct bt_trace *trace = (void *) c_trace;
+       struct bt_trace_destruction_listener_elem *elem;
+
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       BT_ASSERT_PRE(has_listener_id(trace, listener_id),
+               "Trace has no such trace destruction listener ID: "
+               "%![trace-]+t, %" PRIu64, trace, listener_id);
+       elem = &g_array_index(trace->destruction_listeners,
+                       struct bt_trace_destruction_listener_elem,
+                       listener_id);
+       BT_ASSERT(elem->func);
+
+       elem->func = NULL;
+       elem->data = NULL;
+       BT_LIB_LOGV("Removed \"trace destruction listener: "
+               "%![trace-]+t, listener-id=%" PRIu64,
+               trace, listener_id);
+       return BT_TRACE_STATUS_OK;
+}
+
+BT_HIDDEN
+void _bt_trace_freeze(const struct bt_trace *trace)
+{
+       BT_ASSERT(trace);
+       BT_LIB_LOGD("Freezing trace's class: %!+T", trace->class);
+       bt_trace_class_freeze(trace->class);
+       BT_LIB_LOGD("Freezing trace: %!+t", trace);
+       ((struct bt_trace *) trace)->frozen = true;
+}
+
+BT_HIDDEN
+void bt_trace_add_stream(struct bt_trace *trace, struct bt_stream *stream)
+{
+       guint count = 0;
+
+       bt_object_set_parent(&stream->base, &trace->base);
+       g_ptr_array_add(trace->streams, stream);
+       bt_trace_freeze(trace);
+
+       if (bt_g_hash_table_contains(trace->stream_classes_stream_count,
+                       stream->class)) {
+               count = GPOINTER_TO_UINT(g_hash_table_lookup(
+                       trace->stream_classes_stream_count, stream->class));
+       }
+
+       g_hash_table_insert(trace->stream_classes_stream_count,
+               stream->class, GUINT_TO_POINTER(count + 1));
+}
+
+BT_HIDDEN
+uint64_t bt_trace_get_automatic_stream_id(const struct bt_trace *trace,
+               const struct bt_stream_class *stream_class)
+{
+       gpointer orig_key;
+       gpointer value;
+       uint64_t id = 0;
+
+       BT_ASSERT(stream_class);
+       BT_ASSERT(trace);
+       if (g_hash_table_lookup_extended(trace->stream_classes_stream_count,
+                       stream_class, &orig_key, &value)) {
+               id = (uint64_t) GPOINTER_TO_UINT(value);
+       }
+
+       return id;
+}
+
+struct bt_trace_class *bt_trace_borrow_class(struct bt_trace *trace)
+{
+       BT_ASSERT_PRE_NON_NULL(trace, "Trace");
+       return trace->class;
+}
+
+const struct bt_trace_class *bt_trace_borrow_class_const(
+               const struct bt_trace *trace)
+{
+       return bt_trace_borrow_class((void *) trace);
+}
+
+void bt_trace_get_ref(const struct bt_trace *trace)
+{
+       bt_object_get_ref(trace);
+}
+
+void bt_trace_put_ref(const struct bt_trace *trace)
+{
+       bt_object_put_ref(trace);
+}
diff --git a/src/lib/trace-ir/trace.h b/src/lib/trace-ir/trace.h
new file mode 100644 (file)
index 0000000..3a12fd7
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef BABELTRACE_TRACE_IR_TRACE_INTERNAL_H
+#define BABELTRACE_TRACE_IR_TRACE_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "lib/assert-pre.h"
+#include <babeltrace2/trace-ir/trace.h>
+#include <babeltrace2/trace-ir/field-class.h>
+#include <babeltrace2/trace-ir/field.h>
+#include "lib/object.h"
+#include "lib/object-pool.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/types.h>
+#include <glib.h>
+#include <sys/types.h>
+#include "compat/uuid.h"
+
+#include "attributes.h"
+#include "clock-class.h"
+#include "stream-class.h"
+#include "trace-class.h"
+
+struct bt_trace {
+       struct bt_object base;
+
+       /* Owned by this */
+       struct bt_trace_class *class;
+
+       struct {
+               GString *str;
+
+               /* NULL or `str->str` above */
+               const char *value;
+       } name;
+
+       /* Array of `struct bt_stream *` */
+       GPtrArray *streams;
+
+       /*
+        * Stream class (weak, owned by owned trace class) to number of
+        * instantiated streams, used to automatically assign stream IDs
+        * per stream class within this trace.
+        */
+       GHashTable *stream_classes_stream_count;
+
+       GArray *destruction_listeners;
+       bool frozen;
+};
+
+BT_HIDDEN
+void _bt_trace_freeze(const struct bt_trace *trace);
+
+#ifdef BT_DEV_MODE
+# define bt_trace_freeze               _bt_trace_freeze
+#else
+# define bt_trace_freeze(_trace)
+#endif
+
+BT_HIDDEN
+void bt_trace_add_stream(struct bt_trace *trace, struct bt_stream *stream);
+
+BT_HIDDEN
+uint64_t bt_trace_get_automatic_stream_id(const struct bt_trace *trace,
+               const struct bt_stream_class *stream_class);
+
+#endif /* BABELTRACE_TRACE_IR_TRACE_INTERNAL_H */
diff --git a/src/lib/trace-ir/utils.c b/src/lib/trace-ir/utils.c
new file mode 100644 (file)
index 0000000..3b446e0
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "TRACE-IR-UTILS"
+#include "lib/lib-logging.h"
+
+#include <stdlib.h>
+#include <glib.h>
+#include <babeltrace2/trace-ir/clock-class.h>
+#include "common/assert.h"
+
+#include "field-class.h"
diff --git a/src/lib/trace-ir/utils.h b/src/lib/trace-ir/utils.h
new file mode 100644 (file)
index 0000000..d68bd54
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef BABELTRACE_TRACE_IR_UTILS_INTERNAL_H
+#define BABELTRACE_TRACE_IR_UTILS_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/trace-ir/field-class.h>
+#include <stdint.h>
+
+#include "clock-class.h"
+
+struct search_query {
+       gpointer value;
+       int found;
+};
+
+static inline
+uint64_t bt_util_ns_from_value(uint64_t frequency, uint64_t value_cycles)
+{
+       uint64_t ns;
+
+       if (frequency == UINT64_C(1000000000)) {
+               ns = value_cycles;
+       } else {
+               double dblres = ((1e9 * (double) value_cycles) / (double) frequency);
+
+               if (dblres >= (double) UINT64_MAX) {
+                       /* Overflows uint64_t */
+                       ns = UINT64_C(-1);
+               } else {
+                       ns = (uint64_t) dblres;
+               }
+       }
+
+       return ns;
+}
+
+static inline
+bool bt_util_get_base_offset_ns(int64_t offset_seconds, uint64_t offset_cycles,
+               uint64_t frequency, int64_t *base_offset_ns)
+{
+       bool overflows = false;
+       uint64_t offset_cycles_ns;
+
+       BT_ASSERT(base_offset_ns);
+
+       /* Initialize nanosecond timestamp to clock's offset in seconds */
+       if (offset_seconds <= (INT64_MIN / INT64_C(1000000000) - 1) ||
+                       offset_seconds >= (INT64_MAX / INT64_C(1000000000)) - 1) {
+               /*
+                * Overflow: offset in seconds converted to nanoseconds
+                * is outside the int64_t range. We also subtract 1 here
+                * to leave "space" for the offset in cycles converted
+                * to nanoseconds (which is always less than 1 second by
+                * contract).
+                */
+               overflows = true;
+               goto end;
+       }
+
+       /* Offset (seconds) to nanoseconds */
+       *base_offset_ns = offset_seconds * INT64_C(1000000000);
+
+       /* Add offset in cycles */
+       BT_ASSERT(offset_cycles < frequency);
+       offset_cycles_ns = bt_util_ns_from_value(frequency,
+               offset_cycles);
+       BT_ASSERT(offset_cycles_ns < 1000000000);
+       *base_offset_ns += (int64_t) offset_cycles_ns;
+
+end:
+       return overflows;
+}
+
+static inline
+int bt_util_ns_from_origin_inline(int64_t base_offset_ns,
+               int64_t offset_seconds, uint64_t offset_cycles,
+               uint64_t frequency, uint64_t value, int64_t *ns_from_origin)
+{
+       int ret = 0;
+       uint64_t value_ns_unsigned;
+       int64_t value_ns_signed;
+
+       /* Initialize to clock class's base offset */
+       *ns_from_origin = base_offset_ns;
+
+       /* Add given value in cycles */
+       value_ns_unsigned = bt_util_ns_from_value(frequency, value);
+       if (value_ns_unsigned >= (uint64_t) INT64_MAX) {
+               /*
+                * FIXME: `value_ns_unsigned` could be greater than
+                * `INT64_MAX` in fact: in this case, we need to
+                * subtract `INT64_MAX` from `value_ns_unsigned`, make
+                * sure that the difference is less than `INT64_MAX`,
+                * and try to add them one after the other to
+                * `*ns_from_origin`.
+                */
+               ret = -1;
+               goto end;
+       }
+
+       value_ns_signed = (int64_t) value_ns_unsigned;
+       BT_ASSERT(value_ns_signed >= 0);
+
+       if (*ns_from_origin <= 0) {
+               goto add_value;
+       }
+
+       if (value_ns_signed > INT64_MAX - *ns_from_origin) {
+               ret = -1;
+               goto end;
+       }
+
+add_value:
+       *ns_from_origin += value_ns_signed;
+
+end:
+       return ret;
+}
+
+static inline
+int bt_util_ns_from_origin_clock_class(const struct bt_clock_class *clock_class,
+               uint64_t value, int64_t *ns_from_origin)
+{
+       int ret = 0;
+
+       if (clock_class->base_offset.overflows) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = bt_util_ns_from_origin_inline(clock_class->base_offset.value_ns,
+               clock_class->offset_seconds, clock_class->offset_cycles,
+               clock_class->frequency, value, ns_from_origin);
+
+end:
+       return ret;
+}
+
+static inline
+bool bt_util_value_is_in_range_signed(uint64_t size, int64_t value)
+{
+       int64_t min_value = UINT64_C(-1) << (size - 1);
+       int64_t max_value = (UINT64_C(1) << (size - 1)) - 1;
+       return value >= min_value && value <= max_value;
+}
+
+static inline
+bool bt_util_value_is_in_range_unsigned(unsigned int size, uint64_t value)
+{
+       uint64_t max_value = (size == 64) ? UINT64_MAX :
+               (UINT64_C(1) << size) - 1;
+       return value <= max_value;
+}
+
+#endif /* BABELTRACE_TRACE_IR_UTILS_INTERNAL_H */
diff --git a/src/lib/util.c b/src/lib/util.c
new file mode 100644 (file)
index 0000000..b17fe2f
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "UTIL"
+#include "lib/lib-logging.h"
+
+#include "lib/assert-pre.h"
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <inttypes.h>
+#include <babeltrace2/util.h>
+#include "lib/trace-ir/utils.h"
+
+bt_util_status bt_util_clock_cycles_to_ns_from_origin(uint64_t cycles,
+               uint64_t frequency, int64_t offset_seconds,
+               uint64_t offset_cycles, int64_t *ns)
+{
+       bool overflows;
+       int64_t base_offset_ns;
+       bt_util_status status = BT_UTIL_STATUS_OK;
+       int ret;
+
+       BT_ASSERT_PRE_NON_NULL(ns, "Nanoseconds (output)");
+       BT_ASSERT_PRE(frequency != UINT64_C(-1) && frequency != 0,
+               "Invalid frequency: freq=%" PRIu64, frequency);
+       BT_ASSERT_PRE(offset_cycles < frequency,
+               "Offset (cycles) is greater than frequency: "
+               "offset-cycles=%" PRIu64 ", freq=%" PRIu64,
+               offset_cycles, frequency);
+
+       overflows = bt_util_get_base_offset_ns(offset_seconds, offset_cycles,
+               frequency, &base_offset_ns);
+       if (overflows) {
+               status = BT_UTIL_STATUS_OVERFLOW;
+               goto end;
+       }
+
+       ret = bt_util_ns_from_origin_inline(base_offset_ns,
+               offset_seconds, offset_cycles,
+               frequency, cycles, ns);
+       if (ret) {
+               status = BT_UTIL_STATUS_OVERFLOW;
+       }
+
+end:
+       return status;
+}
diff --git a/src/lib/value.c b/src/lib/value.c
new file mode 100644 (file)
index 0000000..ca1687f
--- /dev/null
@@ -0,0 +1,1369 @@
+/*
+ * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "VALUES"
+#include "lib/lib-logging.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <string.h>
+#include <inttypes.h>
+#include "compat/compiler.h"
+#include "common/common.h"
+#include <babeltrace2/value-const.h>
+#include <babeltrace2/value.h>
+#include "compat/glib.h"
+#include <babeltrace2/types.h>
+#include "lib/assert-pre.h"
+#include "lib/value.h"
+#include "common/assert.h"
+
+#define BT_VALUE_TO_BOOL(_base) ((struct bt_value_bool *) (_base))
+#define BT_VALUE_TO_INTEGER(_base) ((struct bt_value_integer *) (_base))
+#define BT_VALUE_TO_REAL(_base) ((struct bt_value_real *) (_base))
+#define BT_VALUE_TO_STRING(_base) ((struct bt_value_string *) (_base))
+#define BT_VALUE_TO_ARRAY(_base) ((struct bt_value_array *) (_base))
+#define BT_VALUE_TO_MAP(_base) ((struct bt_value_map *) (_base))
+
+#define BT_ASSERT_PRE_VALUE_IS_TYPE(_value, _type)                     \
+       BT_ASSERT_PRE(((struct bt_value *) (_value))->type == (_type),  \
+               "Value has the wrong type ID: expected-type=%s, "       \
+               "%![value-]+v", bt_common_value_type_string(_type),     \
+               (_value))
+
+#define BT_ASSERT_PRE_VALUE_HOT(_value, _name)                         \
+       BT_ASSERT_PRE_HOT(((struct bt_value *) (_value)), (_name),      \
+               ": %!+v", (_value))
+
+#define BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(_index, _count)            \
+       BT_ASSERT_PRE((_index) < (_count),                              \
+               "Index is out of bound: "                               \
+               "index=%" PRIu64 ", count=%u", (_index), (_count));
+
+static
+void bt_value_null_instance_release_func(struct bt_object *obj)
+{
+       BT_LOGW("Releasing the null value singleton: addr=%p", obj);
+}
+
+static
+struct bt_value bt_value_null_instance = {
+       .base = {
+               .is_shared = true,
+               .ref_count = 1,
+               .release_func = bt_value_null_instance_release_func,
+               .spec_release_func = NULL,
+               .parent_is_owner_listener_func = NULL,
+               .parent = NULL,
+       },
+       .type = BT_VALUE_TYPE_NULL,
+       .frozen = BT_TRUE,
+};
+
+struct bt_value *const bt_value_null = &bt_value_null_instance;
+
+static
+void bt_value_destroy(struct bt_object *obj);
+
+static
+void bt_value_string_destroy(struct bt_value *object)
+{
+       g_string_free(BT_VALUE_TO_STRING(object)->gstr, TRUE);
+       BT_VALUE_TO_STRING(object)->gstr = NULL;
+}
+
+static
+void bt_value_array_destroy(struct bt_value *object)
+{
+       /*
+        * Pointer array's registered value destructor will take care
+        * of putting each contained object.
+        */
+       g_ptr_array_free(BT_VALUE_TO_ARRAY(object)->garray, TRUE);
+       BT_VALUE_TO_ARRAY(object)->garray = NULL;
+}
+
+static
+void bt_value_map_destroy(struct bt_value *object)
+{
+       /*
+        * Hash table's registered value destructor will take care of
+        * putting each contained object. Keys are GQuarks and cannot
+        * be destroyed anyway.
+        */
+       g_hash_table_destroy(BT_VALUE_TO_MAP(object)->ght);
+       BT_VALUE_TO_MAP(object)->ght = NULL;
+}
+
+static
+void (* const destroy_funcs[])(struct bt_value *) = {
+       [BT_VALUE_TYPE_NULL] =                  NULL,
+       [BT_VALUE_TYPE_BOOL] =                  NULL,
+       [BT_VALUE_TYPE_UNSIGNED_INTEGER] =      NULL,
+       [BT_VALUE_TYPE_SIGNED_INTEGER] =        NULL,
+       [BT_VALUE_TYPE_REAL] =                  NULL,
+       [BT_VALUE_TYPE_STRING] =                bt_value_string_destroy,
+       [BT_VALUE_TYPE_ARRAY] =                 bt_value_array_destroy,
+       [BT_VALUE_TYPE_MAP] =                   bt_value_map_destroy,
+};
+
+static
+struct bt_value *bt_value_null_copy(const struct bt_value *null_obj)
+{
+       return (void *) bt_value_null;
+}
+
+static
+struct bt_value *bt_value_bool_copy(const struct bt_value *bool_obj)
+{
+       return bt_value_bool_create_init(
+               BT_VALUE_TO_BOOL(bool_obj)->value);
+}
+
+static inline
+struct bt_value *bt_value_integer_create_init(enum bt_value_type type,
+               uint64_t uval);
+
+static
+struct bt_value *bt_value_integer_copy(
+               const struct bt_value *integer_obj)
+{
+       return bt_value_integer_create_init(integer_obj->type,
+               BT_VALUE_TO_INTEGER(integer_obj)->value.u);
+}
+
+static
+struct bt_value *bt_value_real_copy(const struct bt_value *real_obj)
+{
+       return bt_value_real_create_init(
+               BT_VALUE_TO_REAL(real_obj)->value);
+}
+
+static
+struct bt_value *bt_value_string_copy(const struct bt_value *string_obj)
+{
+       return bt_value_string_create_init(
+               BT_VALUE_TO_STRING(string_obj)->gstr->str);
+}
+
+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;
+}
+
+static
+struct bt_value *(* const copy_funcs[])(const struct bt_value *) = {
+       [BT_VALUE_TYPE_NULL] =                  bt_value_null_copy,
+       [BT_VALUE_TYPE_BOOL] =                  bt_value_bool_copy,
+       [BT_VALUE_TYPE_UNSIGNED_INTEGER] =      bt_value_integer_copy,
+       [BT_VALUE_TYPE_SIGNED_INTEGER] =        bt_value_integer_copy,
+       [BT_VALUE_TYPE_REAL] =                  bt_value_real_copy,
+       [BT_VALUE_TYPE_STRING] =                bt_value_string_copy,
+       [BT_VALUE_TYPE_ARRAY] =                 bt_value_array_copy,
+       [BT_VALUE_TYPE_MAP] =                   bt_value_map_copy,
+};
+
+static
+bt_bool bt_value_null_compare(const struct bt_value *object_a,
+               const struct bt_value *object_b)
+{
+       /*
+        * Always BT_TRUE since bt_value_compare() already checks if both
+        * object_a and object_b have the same type, and in the case of
+        * null value objects, they're always the same if it is so.
+        */
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_value_bool_compare(const struct bt_value *object_a,
+               const struct bt_value *object_b)
+{
+       if (BT_VALUE_TO_BOOL(object_a)->value !=
+                       BT_VALUE_TO_BOOL(object_b)->value) {
+               BT_LOGV("Boolean value objects are different: "
+                       "bool-a-val=%d, bool-b-val=%d",
+                       BT_VALUE_TO_BOOL(object_a)->value,
+                       BT_VALUE_TO_BOOL(object_b)->value);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_value_integer_compare(const struct bt_value *object_a,
+               const struct bt_value *object_b)
+{
+       if (BT_VALUE_TO_INTEGER(object_a)->value.u !=
+                       BT_VALUE_TO_INTEGER(object_b)->value.u) {
+               if (object_a->type == BT_VALUE_TYPE_UNSIGNED_INTEGER) {
+                       BT_LOGV("Unsigned integer value objects are different: "
+                               "int-a-val=%" PRIu64 ", int-b-val=%" PRIu64,
+                               BT_VALUE_TO_INTEGER(object_a)->value.u,
+                               BT_VALUE_TO_INTEGER(object_b)->value.u);
+               } else {
+                       BT_LOGV("Signed integer value objects are different: "
+                               "int-a-val=%" PRId64 ", int-b-val=%" PRId64,
+                               BT_VALUE_TO_INTEGER(object_a)->value.i,
+                               BT_VALUE_TO_INTEGER(object_b)->value.i);
+               }
+
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_value_real_compare(const struct bt_value *object_a,
+               const struct bt_value *object_b)
+{
+       if (BT_VALUE_TO_REAL(object_a)->value !=
+                       BT_VALUE_TO_REAL(object_b)->value) {
+               BT_LOGV("Real number value objects are different: "
+                       "real-a-val=%f, real-b-val=%f",
+                       BT_VALUE_TO_REAL(object_a)->value,
+                       BT_VALUE_TO_REAL(object_b)->value);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_value_string_compare(const struct bt_value *object_a,
+               const struct bt_value *object_b)
+{
+       if (strcmp(BT_VALUE_TO_STRING(object_a)->gstr->str,
+                       BT_VALUE_TO_STRING(object_b)->gstr->str) != 0) {
+               BT_LOGV("String value objects are different: "
+                       "string-a-val=\"%s\", string-b-val=\"%s\"",
+                       BT_VALUE_TO_STRING(object_a)->gstr->str,
+                       BT_VALUE_TO_STRING(object_b)->gstr->str);
+               return BT_FALSE;
+       }
+
+       return BT_TRUE;
+}
+
+static
+bt_bool bt_value_array_compare(const struct bt_value *object_a,
+               const struct bt_value *object_b)
+{
+       int i;
+       bt_bool ret = BT_TRUE;
+       const struct bt_value_array *array_obj_a =
+               BT_VALUE_TO_ARRAY(object_a);
+
+       if (bt_value_array_get_size(object_a) !=
+                       bt_value_array_get_size(object_b)) {
+               BT_LOGV("Array values are different: size mismatch "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
+                       object_a, object_b,
+                       bt_value_array_get_size(object_a),
+                       bt_value_array_get_size(object_b));
+               ret = BT_FALSE;
+               goto end;
+       }
+
+       for (i = 0; i < array_obj_a->garray->len; ++i) {
+               const struct bt_value *element_obj_a;
+               const struct bt_value *element_obj_b;
+
+               element_obj_a = bt_value_array_borrow_element_by_index_const(
+                       object_a, i);
+               element_obj_b = bt_value_array_borrow_element_by_index_const(
+                       object_b, i);
+
+               if (!bt_value_compare(element_obj_a, element_obj_b)) {
+                       BT_LOGV("Array values's elements are different: "
+                               "value-a-addr=%p, value-b-addr=%p, index=%d",
+                               element_obj_a, element_obj_b, i);
+                       ret = BT_FALSE;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_bool bt_value_map_compare(const struct bt_value *object_a,
+               const struct bt_value *object_b)
+{
+       bt_bool ret = BT_TRUE;
+       GHashTableIter iter;
+       gpointer key, element_obj_a;
+       const struct bt_value_map *map_obj_a = BT_VALUE_TO_MAP(object_a);
+
+       if (bt_value_map_get_size(object_a) !=
+                       bt_value_map_get_size(object_b)) {
+               BT_LOGV("Map values are different: size mismatch "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-size=%" PRId64 ", value-b-size=%" PRId64,
+                       object_a, object_b,
+                       bt_value_map_get_size(object_a),
+                       bt_value_map_get_size(object_b));
+               ret = BT_FALSE;
+               goto end;
+       }
+
+       g_hash_table_iter_init(&iter, map_obj_a->ght);
+
+       while (g_hash_table_iter_next(&iter, &key, &element_obj_a)) {
+               const struct bt_value *element_obj_b;
+               const char *key_str = g_quark_to_string(GPOINTER_TO_UINT(key));
+
+               element_obj_b = bt_value_map_borrow_entry_value_const(object_b,
+                       key_str);
+
+               if (!bt_value_compare(element_obj_a, element_obj_b)) {
+                       BT_LOGV("Map values's elements are different: "
+                               "value-a-addr=%p, value-b-addr=%p, key=\"%s\"",
+                               element_obj_a, element_obj_b, key_str);
+                       ret = BT_FALSE;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+bt_bool (* const compare_funcs[])(const struct bt_value *,
+               const struct bt_value *) = {
+       [BT_VALUE_TYPE_NULL] =                  bt_value_null_compare,
+       [BT_VALUE_TYPE_BOOL] =                  bt_value_bool_compare,
+       [BT_VALUE_TYPE_UNSIGNED_INTEGER] =      bt_value_integer_compare,
+       [BT_VALUE_TYPE_SIGNED_INTEGER] =        bt_value_integer_compare,
+       [BT_VALUE_TYPE_REAL] =                  bt_value_real_compare,
+       [BT_VALUE_TYPE_STRING] =                bt_value_string_compare,
+       [BT_VALUE_TYPE_ARRAY] =                 bt_value_array_compare,
+       [BT_VALUE_TYPE_MAP] =                   bt_value_map_compare,
+};
+
+static
+void bt_value_null_freeze(struct bt_value *object)
+{
+}
+
+static
+void bt_value_generic_freeze(struct bt_value *object)
+{
+       object->frozen = BT_TRUE;
+}
+
+static
+void bt_value_array_freeze(struct bt_value *object)
+{
+       int i;
+       struct bt_value_array *typed_array_obj =
+               BT_VALUE_TO_ARRAY(object);
+
+       for (i = 0; i < typed_array_obj->garray->len; ++i) {
+               bt_value_freeze(g_ptr_array_index(typed_array_obj->garray, i));
+       }
+
+       bt_value_generic_freeze(object);
+}
+
+static
+void bt_value_map_freeze(struct bt_value *object)
+{
+       GHashTableIter iter;
+       gpointer key, element_obj;
+       const struct bt_value_map *map_obj = BT_VALUE_TO_MAP(object);
+
+       g_hash_table_iter_init(&iter, map_obj->ght);
+
+       while (g_hash_table_iter_next(&iter, &key, &element_obj)) {
+               bt_value_freeze(element_obj);
+       }
+
+       bt_value_generic_freeze(object);
+}
+
+static
+void (* const freeze_funcs[])(struct bt_value *) = {
+       [BT_VALUE_TYPE_NULL] =                  bt_value_null_freeze,
+       [BT_VALUE_TYPE_BOOL] =                  bt_value_generic_freeze,
+       [BT_VALUE_TYPE_UNSIGNED_INTEGER] =      bt_value_generic_freeze,
+       [BT_VALUE_TYPE_SIGNED_INTEGER] =        bt_value_generic_freeze,
+       [BT_VALUE_TYPE_REAL] =                  bt_value_generic_freeze,
+       [BT_VALUE_TYPE_STRING] =                bt_value_generic_freeze,
+       [BT_VALUE_TYPE_ARRAY] =                 bt_value_array_freeze,
+       [BT_VALUE_TYPE_MAP] =                   bt_value_map_freeze,
+};
+
+static
+void bt_value_destroy(struct bt_object *obj)
+{
+       struct bt_value *value;
+
+       value = container_of(obj, struct bt_value, base);
+       BT_LOGD("Destroying value: addr=%p", value);
+
+       if (bt_value_is_null(value)) {
+               BT_LOGD_STR("Not destroying the null value singleton.");
+               return;
+       }
+
+       if (destroy_funcs[value->type]) {
+               destroy_funcs[value->type](value);
+       }
+
+       g_free(value);
+}
+
+BT_HIDDEN
+enum bt_value_status _bt_value_freeze(const struct bt_value *c_object)
+{
+       const struct bt_value *object = (void *) c_object;
+       enum bt_value_status ret = BT_VALUE_STATUS_OK;
+
+       BT_ASSERT(object);
+
+       if (object->frozen) {
+               goto end;
+       }
+
+       BT_LOGD("Freezing value: addr=%p", object);
+       freeze_funcs[object->type]((void *) object);
+
+end:
+       return ret;
+}
+
+enum bt_value_type bt_value_get_type(const struct bt_value *object)
+{
+       BT_ASSERT_PRE_NON_NULL(object, "Value object");
+       return object->type;
+}
+
+static
+struct bt_value bt_value_create_base(enum bt_value_type type)
+{
+       struct bt_value value;
+
+       value.type = type;
+       value.frozen = BT_FALSE;
+       bt_object_init_shared(&value.base, bt_value_destroy);
+       return value;
+}
+
+struct bt_value *bt_value_bool_create_init(bt_bool val)
+{
+       struct bt_value_bool *bool_obj;
+
+       BT_LOGD("Creating boolean value object: val=%d", val);
+       bool_obj = g_new0(struct bt_value_bool, 1);
+       if (!bool_obj) {
+               BT_LOGE_STR("Failed to allocate one boolean value object.");
+               goto end;
+       }
+
+       bool_obj->base = bt_value_create_base(BT_VALUE_TYPE_BOOL);
+       bool_obj->value = val;
+       BT_LOGD("Created boolean value object: addr=%p", bool_obj);
+
+end:
+       return (void *) bool_obj;
+}
+
+struct bt_value *bt_value_bool_create(void)
+{
+       return bt_value_bool_create_init(BT_FALSE);
+}
+
+static inline
+struct bt_value *bt_value_integer_create_init(enum bt_value_type type,
+               uint64_t uval)
+{
+       struct bt_value_integer *integer_obj;
+
+       BT_ASSERT(type == BT_VALUE_TYPE_UNSIGNED_INTEGER ||
+               type == BT_VALUE_TYPE_SIGNED_INTEGER);
+
+       if (type == BT_VALUE_TYPE_UNSIGNED_INTEGER) {
+               BT_LOGD("Creating unsigned integer value object: val=%" PRIu64,
+                       uval);
+       } else {
+               BT_LOGD("Creating signed integer value object: val=%" PRId64,
+                       (int64_t) uval);
+       }
+
+       integer_obj = g_new0(struct bt_value_integer, 1);
+       if (!integer_obj) {
+               BT_LOGE_STR("Failed to allocate one integer value object.");
+               goto end;
+       }
+
+       integer_obj->base = bt_value_create_base(type);
+       integer_obj->value.u = uval;
+       BT_LOGD("Created %ssigned integer value object: addr=%p",
+               type == BT_VALUE_TYPE_UNSIGNED_INTEGER ? "un" : "",
+               integer_obj);
+
+end:
+       return (void *) integer_obj;
+}
+
+struct bt_value *bt_value_unsigned_integer_create_init(uint64_t val)
+{
+       return bt_value_integer_create_init(BT_VALUE_TYPE_UNSIGNED_INTEGER,
+               val);
+}
+
+struct bt_value *bt_value_unsigned_integer_create(void)
+{
+       return bt_value_unsigned_integer_create_init(0);
+}
+
+struct bt_value *bt_value_signed_integer_create_init(int64_t val)
+{
+       return bt_value_integer_create_init(BT_VALUE_TYPE_SIGNED_INTEGER,
+               (uint64_t) val);
+}
+
+struct bt_value *bt_value_signed_integer_create(void)
+{
+       return bt_value_signed_integer_create_init(0);
+}
+
+struct bt_value *bt_value_real_create_init(double val)
+{
+       struct bt_value_real *real_obj;
+
+       BT_LOGD("Creating real number value object: val=%f", val);
+       real_obj = g_new0(struct bt_value_real, 1);
+       if (!real_obj) {
+               BT_LOGE_STR("Failed to allocate one real number value object.");
+               goto end;
+       }
+
+       real_obj->base = bt_value_create_base(BT_VALUE_TYPE_REAL);
+       real_obj->value = val;
+       BT_LOGD("Created real number value object: addr=%p",
+               real_obj);
+
+end:
+       return (void *) real_obj;
+}
+
+struct bt_value *bt_value_real_create(void)
+{
+       return bt_value_real_create_init(0.);
+}
+
+struct bt_value *bt_value_string_create_init(const char *val)
+{
+       struct bt_value_string *string_obj = NULL;
+
+       if (!val) {
+               BT_LOGW_STR("Invalid parameter: value is NULL.");
+               goto end;
+       }
+
+       BT_LOGD("Creating string value object: val-len=%zu", strlen(val));
+       string_obj = g_new0(struct bt_value_string, 1);
+       if (!string_obj) {
+               BT_LOGE_STR("Failed to allocate one string object.");
+               goto end;
+       }
+
+       string_obj->base = bt_value_create_base(BT_VALUE_TYPE_STRING);
+       string_obj->gstr = g_string_new(val);
+       if (!string_obj->gstr) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               g_free(string_obj);
+               string_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created string value object: addr=%p",
+               string_obj);
+
+end:
+       return (void *) string_obj;
+}
+
+struct bt_value *bt_value_string_create(void)
+{
+       return bt_value_string_create_init("");
+}
+
+struct bt_value *bt_value_array_create(void)
+{
+       struct bt_value_array *array_obj;
+
+       BT_LOGD_STR("Creating empty array value object.");
+       array_obj = g_new0(struct bt_value_array, 1);
+       if (!array_obj) {
+               BT_LOGE_STR("Failed to allocate one array object.");
+               goto end;
+       }
+
+       array_obj->base = bt_value_create_base(BT_VALUE_TYPE_ARRAY);
+       array_obj->garray = bt_g_ptr_array_new_full(0,
+               (GDestroyNotify) bt_object_put_ref);
+       if (!array_obj->garray) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               g_free(array_obj);
+               array_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created array value object: addr=%p",
+               array_obj);
+
+end:
+       return (void *) array_obj;
+}
+
+struct bt_value *bt_value_map_create(void)
+{
+       struct bt_value_map *map_obj;
+
+       BT_LOGD_STR("Creating empty map value object.");
+       map_obj = g_new0(struct bt_value_map, 1);
+       if (!map_obj) {
+               BT_LOGE_STR("Failed to allocate one map object.");
+               goto end;
+       }
+
+       map_obj->base = bt_value_create_base(BT_VALUE_TYPE_MAP);
+       map_obj->ght = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+               NULL, (GDestroyNotify) bt_object_put_ref);
+       if (!map_obj->ght) {
+               BT_LOGE_STR("Failed to allocate a GHashTable.");
+               g_free(map_obj);
+               map_obj = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created map value object: addr=%p",
+               map_obj);
+
+end:
+       return (void *) map_obj;
+}
+
+bt_bool bt_value_bool_get(const struct bt_value *bool_obj)
+{
+       BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_VALUE_TYPE_BOOL);
+       return BT_VALUE_TO_BOOL(bool_obj)->value;
+}
+
+void bt_value_bool_set(struct bt_value *bool_obj, bt_bool val)
+{
+       BT_ASSERT_PRE_NON_NULL(bool_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(bool_obj, BT_VALUE_TYPE_BOOL);
+       BT_ASSERT_PRE_VALUE_HOT(bool_obj, "Value object");
+       BT_VALUE_TO_BOOL(bool_obj)->value = val;
+       BT_LOGV("Set boolean value's raw value: value-addr=%p, value=%d",
+               bool_obj, val);
+}
+
+uint64_t bt_value_unsigned_integer_get(const struct bt_value *integer_obj)
+{
+       BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj,
+               BT_VALUE_TYPE_UNSIGNED_INTEGER);
+       return BT_VALUE_TO_INTEGER(integer_obj)->value.u;
+}
+
+int64_t bt_value_signed_integer_get(const struct bt_value *integer_obj)
+{
+       BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj,
+               BT_VALUE_TYPE_SIGNED_INTEGER);
+       return BT_VALUE_TO_INTEGER(integer_obj)->value.i;
+}
+
+static inline
+void bt_value_integer_set(struct bt_value *integer_obj,
+               enum bt_value_type expected_type, uint64_t uval)
+{
+       BT_ASSERT_PRE_NON_NULL(integer_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(integer_obj, expected_type);
+       BT_ASSERT_PRE_VALUE_HOT(integer_obj, "Value object");
+       BT_VALUE_TO_INTEGER(integer_obj)->value.u = uval;
+}
+
+void bt_value_unsigned_integer_set(struct bt_value *integer_obj,
+               uint64_t val)
+{
+       bt_value_integer_set(integer_obj, BT_VALUE_TYPE_UNSIGNED_INTEGER, val);
+       BT_LOGV("Set unsigned integer value's raw value: "
+               "value-addr=%p, value=%" PRIu64, integer_obj, val);
+}
+
+void bt_value_signed_integer_set(struct bt_value *integer_obj,
+               int64_t val)
+{
+       bt_value_integer_set(integer_obj, BT_VALUE_TYPE_SIGNED_INTEGER,
+               (uint64_t) val);
+       BT_LOGV("Set signed integer value's raw value: "
+               "value-addr=%p, value=%" PRId64, integer_obj, val);
+}
+
+double bt_value_real_get(const struct bt_value *real_obj)
+{
+       BT_ASSERT_PRE_NON_NULL(real_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_VALUE_TYPE_REAL);
+       return BT_VALUE_TO_REAL(real_obj)->value;
+}
+
+void bt_value_real_set(struct bt_value *real_obj, double val)
+{
+       BT_ASSERT_PRE_NON_NULL(real_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(real_obj, BT_VALUE_TYPE_REAL);
+       BT_ASSERT_PRE_VALUE_HOT(real_obj, "Value object");
+       BT_VALUE_TO_REAL(real_obj)->value = val;
+       BT_LOGV("Set real number value's raw value: value-addr=%p, value=%f",
+               real_obj, val);
+}
+
+const char *bt_value_string_get(const struct bt_value *string_obj)
+{
+       BT_ASSERT_PRE_NON_NULL(string_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_VALUE_TYPE_STRING);
+       return BT_VALUE_TO_STRING(string_obj)->gstr->str;
+}
+
+enum bt_value_status bt_value_string_set(
+               struct bt_value *string_obj, const char *val)
+{
+       BT_ASSERT_PRE_NON_NULL(string_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(string_obj, BT_VALUE_TYPE_STRING);
+       BT_ASSERT_PRE_VALUE_HOT(string_obj, "Value object");
+       g_string_assign(BT_VALUE_TO_STRING(string_obj)->gstr, val);
+       BT_LOGV("Set string value's raw value: value-addr=%p, raw-value-addr=%p",
+               string_obj, val);
+       return BT_VALUE_STATUS_OK;
+}
+
+uint64_t bt_value_array_get_size(const struct bt_value *array_obj)
+{
+       BT_ASSERT_PRE_NON_NULL(array_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
+       return (uint64_t) BT_VALUE_TO_ARRAY(array_obj)->garray->len;
+}
+
+struct bt_value *bt_value_array_borrow_element_by_index(
+               struct bt_value *array_obj, uint64_t index)
+{
+       struct bt_value_array *typed_array_obj =
+               BT_VALUE_TO_ARRAY(array_obj);
+
+       BT_ASSERT_PRE_NON_NULL(array_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
+       BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
+               typed_array_obj->garray->len);
+       return g_ptr_array_index(typed_array_obj->garray, index);
+}
+
+const struct bt_value *bt_value_array_borrow_element_by_index_const(
+               const struct bt_value *array_obj,
+               uint64_t index)
+{
+       return bt_value_array_borrow_element_by_index(
+               (void *) array_obj, index);
+}
+
+enum bt_value_status bt_value_array_append_element(
+               struct bt_value *array_obj,
+               struct bt_value *element_obj)
+{
+       struct bt_value_array *typed_array_obj =
+               BT_VALUE_TO_ARRAY(array_obj);
+
+       BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
+       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
+       BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
+       g_ptr_array_add(typed_array_obj->garray, element_obj);
+       bt_object_get_ref(element_obj);
+       BT_LOGV("Appended element to array value: array-value-addr=%p, "
+               "element-value-addr=%p, new-size=%u",
+               array_obj, element_obj, typed_array_obj->garray->len);
+       return BT_VALUE_STATUS_OK;
+}
+
+enum bt_value_status bt_value_array_append_bool_element(
+               struct bt_value *array_obj, bt_bool val)
+{
+       enum bt_value_status ret;
+       struct bt_value *bool_obj = NULL;
+
+       bool_obj = bt_value_bool_create_init(val);
+       ret = bt_value_array_append_element(array_obj,
+               (void *) bool_obj);
+       bt_object_put_ref(bool_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_array_append_unsigned_integer_element(
+               struct bt_value *array_obj, uint64_t val)
+{
+       enum bt_value_status ret;
+       struct bt_value *integer_obj = NULL;
+
+       integer_obj = bt_value_unsigned_integer_create_init(val);
+       ret = bt_value_array_append_element(array_obj,
+               (void *) integer_obj);
+       bt_object_put_ref(integer_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_array_append_signed_integer_element(
+               struct bt_value *array_obj, int64_t val)
+{
+       enum bt_value_status ret;
+       struct bt_value *integer_obj = NULL;
+
+       integer_obj = bt_value_signed_integer_create_init(val);
+       ret = bt_value_array_append_element(array_obj,
+               (void *) integer_obj);
+       bt_object_put_ref(integer_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_array_append_real_element(
+               struct bt_value *array_obj, double val)
+{
+       enum bt_value_status ret;
+       struct bt_value *real_obj = NULL;
+
+       real_obj = bt_value_real_create_init(val);
+       ret = bt_value_array_append_element(array_obj,
+               (void *) real_obj);
+       bt_object_put_ref(real_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_array_append_string_element(
+               struct bt_value *array_obj, const char *val)
+{
+       enum bt_value_status ret;
+       struct bt_value *string_obj = NULL;
+
+       string_obj = bt_value_string_create_init(val);
+       ret = bt_value_array_append_element(array_obj,
+               (void *) string_obj);
+       bt_object_put_ref(string_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_array_append_empty_array_element(
+               struct bt_value *array_obj)
+{
+       enum bt_value_status ret;
+       struct bt_value *empty_array_obj = NULL;
+
+       empty_array_obj = bt_value_array_create();
+       ret = bt_value_array_append_element(array_obj,
+               (void *) empty_array_obj);
+       bt_object_put_ref(empty_array_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_array_append_empty_map_element(
+               struct bt_value *array_obj)
+{
+       enum bt_value_status ret;
+       struct bt_value *map_obj = NULL;
+
+       map_obj = bt_value_map_create();
+       ret = bt_value_array_append_element(array_obj,
+               (void *) map_obj);
+       bt_object_put_ref(map_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_array_set_element_by_index(
+               struct bt_value *array_obj, uint64_t index,
+               struct bt_value *element_obj)
+{
+       struct bt_value_array *typed_array_obj =
+               BT_VALUE_TO_ARRAY(array_obj);
+
+       BT_ASSERT_PRE_NON_NULL(array_obj, "Array value object");
+       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(array_obj, BT_VALUE_TYPE_ARRAY);
+       BT_ASSERT_PRE_VALUE_HOT(array_obj, "Array value object");
+       BT_ASSERT_PRE_VALUE_INDEX_IN_BOUNDS(index,
+               typed_array_obj->garray->len);
+       bt_object_put_ref(g_ptr_array_index(typed_array_obj->garray, index));
+       g_ptr_array_index(typed_array_obj->garray, index) = element_obj;
+       bt_object_get_ref(element_obj);
+       BT_LOGV("Set array value's element: array-value-addr=%p, "
+               "index=%" PRIu64 ", element-value-addr=%p",
+               array_obj, index, element_obj);
+       return BT_VALUE_STATUS_OK;
+}
+
+uint64_t bt_value_map_get_size(const struct bt_value *map_obj)
+{
+       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
+       return (uint64_t) g_hash_table_size(BT_VALUE_TO_MAP(map_obj)->ght);
+}
+
+struct bt_value *bt_value_map_borrow_entry_value(struct bt_value *map_obj,
+               const char *key)
+{
+       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
+       return g_hash_table_lookup(BT_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)));
+}
+
+const struct bt_value *bt_value_map_borrow_entry_value_const(
+               const struct bt_value *map_obj, const char *key)
+{
+       return bt_value_map_borrow_entry_value((void *) map_obj, key);
+}
+
+bt_bool bt_value_map_has_entry(const struct bt_value *map_obj, const char *key)
+{
+       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
+       return bt_g_hash_table_contains(BT_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)));
+}
+
+enum bt_value_status bt_value_map_insert_entry(
+               struct bt_value *map_obj,
+               const char *key, struct bt_value *element_obj)
+{
+       BT_ASSERT_PRE_NON_NULL(map_obj, "Map value object");
+       BT_ASSERT_PRE_NON_NULL(key, "Key");
+       BT_ASSERT_PRE_NON_NULL(element_obj, "Element value object");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
+       BT_ASSERT_PRE_VALUE_HOT(map_obj, "Map value object");
+       g_hash_table_insert(BT_VALUE_TO_MAP(map_obj)->ght,
+               GUINT_TO_POINTER(g_quark_from_string(key)), element_obj);
+       bt_object_get_ref(element_obj);
+       BT_LOGV("Inserted value into map value: map-value-addr=%p, "
+               "key=\"%s\", element-value-addr=%p",
+               map_obj, key, element_obj);
+       return BT_VALUE_STATUS_OK;
+}
+
+enum bt_value_status bt_value_map_insert_bool_entry(
+               struct bt_value *map_obj, const char *key, bt_bool val)
+{
+       enum bt_value_status ret;
+       struct bt_value *bool_obj = NULL;
+
+       bool_obj = bt_value_bool_create_init(val);
+       ret = bt_value_map_insert_entry(map_obj, key,
+               (void *) bool_obj);
+       bt_object_put_ref(bool_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_map_insert_unsigned_integer_entry(
+               struct bt_value *map_obj, const char *key, uint64_t val)
+{
+       enum bt_value_status ret;
+       struct bt_value *integer_obj = NULL;
+
+       integer_obj = bt_value_unsigned_integer_create_init(val);
+       ret = bt_value_map_insert_entry(map_obj, key,
+               (void *) integer_obj);
+       bt_object_put_ref(integer_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_map_insert_signed_integer_entry(
+               struct bt_value *map_obj, const char *key, int64_t val)
+{
+       enum bt_value_status ret;
+       struct bt_value *integer_obj = NULL;
+
+       integer_obj = bt_value_signed_integer_create_init(val);
+       ret = bt_value_map_insert_entry(map_obj, key,
+               (void *) integer_obj);
+       bt_object_put_ref(integer_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_map_insert_real_entry(
+               struct bt_value *map_obj, const char *key, double val)
+{
+       enum bt_value_status ret;
+       struct bt_value *real_obj = NULL;
+
+       real_obj = bt_value_real_create_init(val);
+       ret = bt_value_map_insert_entry(map_obj, key,
+               (void *) real_obj);
+       bt_object_put_ref(real_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_map_insert_string_entry(
+               struct bt_value *map_obj, const char *key,
+               const char *val)
+{
+       enum bt_value_status ret;
+       struct bt_value *string_obj = NULL;
+
+       string_obj = bt_value_string_create_init(val);
+       ret = bt_value_map_insert_entry(map_obj, key,
+               (void *) string_obj);
+       bt_object_put_ref(string_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_map_insert_empty_array_entry(
+               struct bt_value *map_obj, const char *key)
+{
+       enum bt_value_status ret;
+       struct bt_value *array_obj = NULL;
+
+       array_obj = bt_value_array_create();
+       ret = bt_value_map_insert_entry(map_obj, key,
+               (void *) array_obj);
+       bt_object_put_ref(array_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_map_insert_empty_map_entry(
+               struct bt_value *map_obj, const char *key)
+{
+       enum bt_value_status ret;
+       struct bt_value *empty_map_obj = NULL;
+
+       empty_map_obj = bt_value_map_create();
+       ret = bt_value_map_insert_entry(map_obj, key,
+               (void *) empty_map_obj);
+       bt_object_put_ref(empty_map_obj);
+       return ret;
+}
+
+enum bt_value_status bt_value_map_foreach_entry(struct bt_value *map_obj,
+               bt_value_map_foreach_entry_func func, void *data)
+{
+       enum bt_value_status ret = BT_VALUE_STATUS_OK;
+       gpointer key, element_obj;
+       GHashTableIter iter;
+       struct bt_value_map *typed_map_obj = BT_VALUE_TO_MAP(map_obj);
+
+       BT_ASSERT_PRE_NON_NULL(map_obj, "Value object");
+       BT_ASSERT_PRE_NON_NULL(func, "Callback");
+       BT_ASSERT_PRE_VALUE_IS_TYPE(map_obj, BT_VALUE_TYPE_MAP);
+       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));
+
+               if (!func(key_str, element_obj, data)) {
+                       BT_LOGV("User canceled the loop: key=\"%s\", "
+                               "value-addr=%p, data=%p",
+                               key_str, element_obj, data);
+                       ret = BT_VALUE_STATUS_CANCELED;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+enum bt_value_status bt_value_map_foreach_entry_const(
+               const struct bt_value *map_obj,
+               bt_value_map_foreach_entry_const_func func, void *data)
+{
+       return bt_value_map_foreach_entry((void *) map_obj,
+               (bt_value_map_foreach_entry_func) func, data);
+}
+
+struct extend_map_element_data {
+       struct bt_value *extended_obj;
+       enum bt_value_status status;
+};
+
+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;
+}
+
+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;
+}
+
+enum bt_value_status bt_value_copy(const struct bt_value *object,
+               struct bt_value **copy_obj)
+{
+       enum bt_value_status status = BT_VALUE_STATUS_OK;
+
+       BT_ASSERT_PRE_NON_NULL(object, "Value object");
+       BT_ASSERT_PRE_NON_NULL(copy_obj, "Value object copy (output)");
+       BT_LOGD("Copying value object: addr=%p", object);
+       *copy_obj = copy_funcs[object->type](object);
+       if (*copy_obj) {
+               BT_LOGD("Copied value object: copy-value-addr=%p",
+                       copy_obj);
+       } else {
+               status = BT_VALUE_STATUS_NOMEM;
+               *copy_obj = NULL;
+               BT_LOGE_STR("Failed to copy value object.");
+       }
+
+       return status;
+}
+
+bt_bool bt_value_compare(const struct bt_value *object_a,
+       const struct bt_value *object_b)
+{
+       bt_bool ret = BT_FALSE;
+
+       BT_ASSERT_PRE_NON_NULL(object_a, "Value object A");
+       BT_ASSERT_PRE_NON_NULL(object_b, "Value object B");
+
+       if (object_a->type != object_b->type) {
+               BT_LOGV("Values are different: type mismatch: "
+                       "value-a-addr=%p, value-b-addr=%p, "
+                       "value-a-type=%s, value-b-type=%s",
+                       object_a, object_b,
+                       bt_common_value_type_string(object_a->type),
+                       bt_common_value_type_string(object_b->type));
+               goto end;
+       }
+
+       ret = compare_funcs[object_a->type](object_a, object_b);
+
+end:
+       return ret;
+}
+
+void bt_value_get_ref(const struct bt_value *value)
+{
+       bt_object_get_ref(value);
+}
+
+void bt_value_put_ref(const struct bt_value *value)
+{
+       bt_object_put_ref(value);
+}
diff --git a/src/lib/value.h b/src/lib/value.h
new file mode 100644 (file)
index 0000000..aa74188
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef BABELTRACE_VALUES_INTERNAL_H
+#define BABELTRACE_VALUES_INTERNAL_H
+
+/*
+ * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "lib/object.h"
+#include <babeltrace2/value.h>
+#include <babeltrace2/value-const.h>
+#include <babeltrace2/types.h>
+#include <glib.h>
+
+struct bt_value {
+       struct bt_object base;
+       enum bt_value_type type;
+       bt_bool frozen;
+};
+
+struct bt_value_bool {
+       struct bt_value base;
+       bt_bool value;
+};
+
+struct bt_value_integer {
+       struct bt_value base;
+       union {
+               uint64_t i;
+               int64_t u;
+       } value;
+};
+
+struct bt_value_real {
+       struct bt_value base;
+       double value;
+};
+
+struct bt_value_string {
+       struct bt_value base;
+       GString *gstr;
+};
+
+struct bt_value_array {
+       struct bt_value base;
+       GPtrArray *garray;
+};
+
+struct bt_value_map {
+       struct bt_value base;
+       GHashTable *ght;
+};
+
+BT_HIDDEN
+enum bt_value_status _bt_value_freeze(const struct bt_value *object);
+
+#ifdef BT_DEV_MODE
+# define bt_value_freeze       _bt_value_freeze
+#else
+# define bt_value_freeze(_value)
+#endif /* BT_DEV_MODE */
+
+#endif /* BABELTRACE_VALUES_INTERNAL_H */
diff --git a/src/logging/LICENSE b/src/logging/LICENSE
new file mode 100644 (file)
index 0000000..5569c1d
--- /dev/null
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 wonder-mice
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/logging/Makefile.am b/src/logging/Makefile.am
new file mode 100644 (file)
index 0000000..fd6c6b6
--- /dev/null
@@ -0,0 +1,3 @@
+noinst_LTLIBRARIES = libbabeltrace2-logging.la
+
+libbabeltrace2_logging_la_SOURCES = log.c log.h
diff --git a/src/logging/log.c b/src/logging/log.c
new file mode 100644 (file)
index 0000000..d8c8040
--- /dev/null
@@ -0,0 +1,1419 @@
+/*
+ * This is zf_log.c, modified with Babeltrace prefixes.
+ * See <https://github.com/wonder-mice/zf_log/>.
+ * See LICENSE.
+ */
+
+#include "common/babeltrace.h"
+#include "common/common.h"
+#include <pthread.h>
+#include "common/assert.h"
+
+#ifdef __CYGWIN__
+extern unsigned long pthread_getsequence_np(pthread_t *);
+#endif
+
+/* When defined, Android log (android/log.h) will be used by default instead of
+ * stderr (ignored on non-Android platforms). Date, time, pid and tid (context)
+ * will be provided by Android log. Android log features will be used to output
+ * log level and tag.
+ */
+#ifdef BT_LOG_USE_ANDROID_LOG
+       #undef BT_LOG_USE_ANDROID_LOG
+       #if defined(__ANDROID__)
+               #define BT_LOG_USE_ANDROID_LOG 1
+       #else
+               #define BT_LOG_USE_ANDROID_LOG 0
+       #endif
+#else
+       #define BT_LOG_USE_ANDROID_LOG 0
+#endif
+/* When defined, NSLog (uses Apple System Log) will be used instead of stderr
+ * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be
+ * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on
+ * non-public CFLog() function. Both use Apple System Log internally, but it's
+ * easier to call CFLog() from C than NSLog(). Current implementation doesn't
+ * support "%@" format specifier.
+ */
+#ifdef BT_LOG_USE_NSLOG
+       #undef BT_LOG_USE_NSLOG
+       #if defined(__APPLE__) && defined(__MACH__)
+               #define BT_LOG_USE_NSLOG 1
+       #else
+               #define BT_LOG_USE_NSLOG 0
+       #endif
+#else
+       #define BT_LOG_USE_NSLOG 0
+#endif
+/* When defined, OutputDebugString() will be used instead of stderr (ignored on
+ * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with
+ * UTF-8 data.
+ */
+#ifdef BT_LOG_USE_DEBUGSTRING
+       #undef BT_LOG_USE_DEBUGSTRING
+       #if defined(_WIN32) || defined(_WIN64)
+               #define BT_LOG_USE_DEBUGSTRING 1
+       #else
+               #define BT_LOG_USE_DEBUGSTRING 0
+       #endif
+#else
+       #define BT_LOG_USE_DEBUGSTRING 0
+#endif
+/* When defined, bt_log library will not contain definition of tag prefix
+ * variable. In that case it must be defined elsewhere using
+ * BT_LOG_DEFINE_TAG_PREFIX macro, for example:
+ *
+ *   BT_LOG_DEFINE_TAG_PREFIX = "ProcessName";
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef BT_LOG_EXTERN_TAG_PREFIX
+       #undef BT_LOG_EXTERN_TAG_PREFIX
+       #define BT_LOG_EXTERN_TAG_PREFIX 1
+#else
+       #define BT_LOG_EXTERN_TAG_PREFIX 0
+#endif
+/* When defined, bt_log library will not contain definition of global format
+ * variable. In that case it must be defined elsewhere using
+ * BT_LOG_DEFINE_GLOBAL_FORMAT macro, for example:
+ *
+ *   BT_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH};
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef BT_LOG_EXTERN_GLOBAL_FORMAT
+       #undef BT_LOG_EXTERN_GLOBAL_FORMAT
+       #define BT_LOG_EXTERN_GLOBAL_FORMAT 1
+#else
+       #define BT_LOG_EXTERN_GLOBAL_FORMAT 0
+#endif
+/* When defined, bt_log library will not contain definition of global output
+ * variable. In that case it must be defined elsewhere using
+ * BT_LOG_DEFINE_GLOBAL_OUTPUT macro, for example:
+ *
+ *   BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_PUT_STD, custom_output_callback};
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef BT_LOG_EXTERN_GLOBAL_OUTPUT
+       #undef BT_LOG_EXTERN_GLOBAL_OUTPUT
+       #define BT_LOG_EXTERN_GLOBAL_OUTPUT 1
+#else
+       #define BT_LOG_EXTERN_GLOBAL_OUTPUT 0
+#endif
+/* When defined, bt_log library will not contain definition of global output
+ * level variable. In that case it must be defined elsewhere using
+ * BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example:
+ *
+ *   BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = BT_LOG_WARN;
+ *
+ * This allows to specify custom value for static initialization and avoid
+ * overhead of setting this value in runtime.
+ */
+#ifdef BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+       #undef BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+       #define BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1
+#else
+       #define BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0
+#endif
+/* When defined, implementation will prefer smaller code size over speed.
+ * Very rough estimate is that code will be up to 2x smaller and up to 2x
+ * slower. Disabled by default.
+ */
+#ifdef BT_LOG_OPTIMIZE_SIZE
+       #undef BT_LOG_OPTIMIZE_SIZE
+       #define BT_LOG_OPTIMIZE_SIZE 1
+#else
+       #define BT_LOG_OPTIMIZE_SIZE 0
+#endif
+/* Size of the log line buffer. The buffer is a globally allocated per thread.
+ */
+#ifndef BT_LOG_BUF_SZ
+       #define BT_LOG_BUF_SZ (4 * 4096)
+#endif
+/* Default number of bytes in one line of memory output. For large values
+ * BT_LOG_BUF_SZ also must be increased.
+ */
+#ifndef BT_LOG_MEM_WIDTH
+       #define BT_LOG_MEM_WIDTH 32
+#endif
+/* String to put in the end of each log line (can be empty). Its value used by
+ * stderr output callback. Its size used as a default value for BT_LOG_EOL_SZ.
+ */
+#ifndef BT_LOG_EOL
+       #define BT_LOG_EOL "\n"
+#endif
+/* Default delimiter that separates parts of log message. Can NOT contain '%'
+ * or '\0'.
+ *
+ * Log message format specifications can override (or ignore) this value. For
+ * more details see BT_LOG_MESSAGE_CTX_FORMAT, BT_LOG_MESSAGE_SRC_FORMAT and
+ * BT_LOG_MESSAGE_TAG_FORMAT.
+ */
+#ifndef BT_LOG_DEF_DELIMITER
+       #define BT_LOG_DEF_DELIMITER " "
+#endif
+/* Specifies log message context format. Log message context includes date,
+ * time, process id, thread id and message's log level. Custom information can
+ * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,
+ * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * Must be defined as a tuple, for example:
+ *
+ *   #define BT_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY, S(" > "))
+ *
+ * In that case, resulting log message will be:
+ *
+ *   2016.12.22 > TAG function@filename.c:line Message text
+ *
+ * Note, that tag, source location and message text are not impacted by
+ * this setting. See BT_LOG_MESSAGE_TAG_FORMAT and BT_LOG_MESSAGE_SRC_FORMAT.
+ *
+ * If message context must be visually separated from the rest of the message,
+ * it must be reflected in context format (notice trailing S(" > ") in the
+ * example above).
+ *
+ * S(str) adds constant string str. String can NOT contain '%' or '\0'.
+ *
+ * F_INIT(statements) adds initialization statement(s) that will be evaluated
+ * once for each log message. All statements are evaluated in specified order.
+ * Several F_INIT() fields can be used in every log message format
+ * specification. Fields, like F_UINT(width, value), are allowed to use results
+ * of initialization statements. If statement introduces variables (or other
+ * names, like structures) they must be prefixed with "f_". Statements  must be
+ * enclosed into additional "()". Example:
+ *
+ *   #define BT_LOG_MESSAGE_CTX_FORMAT \
+ *       (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \
+ *        YEAR, S("."), MONTH, S("."), DAY, S(" "), \
+ *        F_UINT(5, f_ru.ru_nsignals), \
+ *        S(" "))
+ *
+ * F_UINT(width, value) adds unsigned integer value extended with up to width
+ * spaces (for alignment purposes). Value can be any expression that evaluates
+ * to unsigned integer. If expression contains non-standard functions, they
+ * must be declared with F_INIT(). Example:
+ *
+ *   #define BT_LOG_MESSAGE_CTX_FORMAT \
+ *        (YEAR, S("."), MONTH, S("."), DAY, S(" "), \
+ *        F_INIT(( unsigned tickcount(); )), \
+ *        F_UINT(5, tickcount()), \
+ *        S(" "))
+ *
+ * Other log message format specifications follow same rules, but have a
+ * different set of supported fields.
+ */
+#ifndef BT_LOG_MESSAGE_CTX_FORMAT
+       #define BT_LOG_MESSAGE_CTX_FORMAT \
+               (MONTH, S("-"), DAY, S(BT_LOG_DEF_DELIMITER), \
+                HOUR, S(":"), MINUTE, S(":"), SECOND, S("."), MILLISECOND, S(BT_LOG_DEF_DELIMITER), \
+                PID, S(BT_LOG_DEF_DELIMITER), TID, S(BT_LOG_DEF_DELIMITER), \
+                LEVEL, S(BT_LOG_DEF_DELIMITER))
+#endif
+/* Example:
+ */
+/* Specifies log message tag format. It includes tag prefix and tag. Custom
+ * information can be added as well. Supported fields:
+ * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * TAG(prefix_delimiter, tag_delimiter) adds following string to log message:
+ *
+ *   PREFIX<prefix_delimiter>TAG<tag_delimiter>
+ *
+ * Prefix delimiter will be used only when prefix is not empty. Tag delimiter
+ * will be used only when prefixed tag is not empty. Example:
+ *
+ *   #define BT_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] "))
+ *
+ * See BT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#ifndef BT_LOG_MESSAGE_TAG_FORMAT
+       #define BT_LOG_MESSAGE_TAG_FORMAT \
+               (TAG(".", BT_LOG_DEF_DELIMITER))
+#endif
+/* Specifies log message source location format. It includes function name,
+ * file name and file line. Custom information can be added as well. Supported
+ * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements),
+ * F_UINT(width, value).
+ *
+ * See BT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#ifndef BT_LOG_MESSAGE_SRC_FORMAT
+       #define BT_LOG_MESSAGE_SRC_FORMAT \
+               (FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(BT_LOG_DEF_DELIMITER))
+#endif
+/* Fields that can be used in log message format specifications (see above).
+ * Mentioning them here explicitly, so we know that nobody else defined them
+ * before us. See BT_LOG_MESSAGE_CTX_FORMAT for details.
+ */
+#define YEAR YEAR
+#define MONTH MONTH
+#define DAY DAY
+#define MINUTE MINUTE
+#define SECOND SECOND
+#define MILLISECOND MILLISECOND
+#define PID PID
+#define TID TID
+#define LEVEL LEVEL
+#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim)
+#define FUNCTION FUNCTION
+#define FILENAME FILENAME
+#define FILELINE FILELINE
+#define S(str) S(str)
+#define F_INIT(statements) F_INIT(statements)
+#define F_UINT(width, value) F_UINT(width, value)
+/* Number of bytes to reserve for EOL in the log line buffer (must be >0).
+ * Must be larger than or equal to length of BT_LOG_EOL with terminating null.
+ */
+#ifndef BT_LOG_EOL_SZ
+       #define BT_LOG_EOL_SZ sizeof(BT_LOG_EOL)
+#endif
+/* Compile instrumented version of the library to facilitate unit testing.
+ */
+#ifndef BT_LOG_INSTRUMENTED
+       #define BT_LOG_INSTRUMENTED 0
+#endif
+
+#if defined(__linux__)
+       #if !defined(__ANDROID__) && !defined(_GNU_SOURCE)
+               #define _GNU_SOURCE
+       #endif
+#endif
+#if defined(__MINGW32__)
+       #ifdef __STRICT_ANSI__
+               #undef __STRICT_ANSI__
+       #endif
+#endif
+#include "common/assert.h"
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define BT_LOG_OUTPUT_LEVEL dummy
+
+#include "log.h"
+#include <babeltrace2/logging.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+       #include <windows.h>
+#else
+       #include <unistd.h>
+       #include <sys/time.h>
+       #if defined(__linux__)
+               #include <linux/limits.h>
+       #elif (defined(__sun__) || defined(__CYGWIN__))
+               /* Solaris and Cygwin have no sys/syslimits.h */
+       #else
+               #include <sys/syslimits.h>
+       #endif
+#endif
+
+#if defined(__linux__)
+       #include <sys/prctl.h>
+       #include <sys/types.h>
+       #if !defined(__ANDROID__)
+               #include <sys/syscall.h>
+       #endif
+#endif
+#if defined(__MACH__)
+       #include <pthread.h>
+#endif
+
+#define INLINE _BT_LOG_INLINE
+#define VAR_UNUSED(var) (void)var
+#define RETVAL_UNUSED(expr) do { while(expr) break; } while(0)
+#define STATIC_ASSERT(name, cond) \
+       typedef char assert_##name[(cond)? 1: -1]
+#define ASSERT_UNREACHABLE(why) assert(!sizeof(why))
+#ifndef _countof
+       #define _countof(xs) (sizeof(xs) / sizeof((xs)[0]))
+#endif
+
+#if BT_LOG_INSTRUMENTED
+       #define INSTRUMENTED_CONST
+#else
+       #define INSTRUMENTED_CONST const
+#endif
+
+#define _PP_PASTE_2(a, b) a ## b
+#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b)
+
+#define _PP_PASTE_3(a, b, c) a ## b ## c
+#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c)
+
+/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__
+ * as a single token and requires additional expansion to realize that it's
+ * actually a list. If not for it, there would be no need in this extra
+ * expansion.
+ */
+#define _PP_ID(x) x
+#define _PP_NARGS_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,...) _24
+#define _PP_NARGS(...) _PP_ID(_PP_NARGS_N(__VA_ARGS__,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))
+
+/* There is a more efficient way to implement this, but it requires
+ * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't
+ * have one.
+ */
+#define _PP_HEAD__(x, ...) x
+#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~))
+#define _PP_HEAD(xs) _PP_HEAD_ xs
+#define _PP_TAIL_(x, ...) (__VA_ARGS__)
+#define _PP_TAIL(xs) _PP_TAIL_ xs
+#define _PP_UNTUPLE_(...) __VA_ARGS__
+#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs
+
+/* Apply function macro to each element in tuple. Output is not
+ * enforced to be a tuple.
+ */
+#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs))
+#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs))
+#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs))
+#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs))
+#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs))
+#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs))
+#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs))
+#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs))
+#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs))
+#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs))
+#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs))
+#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs))
+#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs))
+#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs))
+#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs))
+#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs))
+#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs))
+#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs))
+#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs))
+#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs))
+#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs))
+#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs))
+#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs))
+#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs))
+#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs) (f, xs)
+
+/* Apply function macro to each element in tuple in reverse order.
+ * Output is not enforced to be a tuple.
+ */
+#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs))
+#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
+#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs) (f, xs)
+
+/* Used to implement _BT_LOG_MESSAGE_FORMAT_CONTAINS() macro. All possible
+ * fields must be mentioned here. Not counting F_INIT() here because it's
+ * somewhat special and is handled spearatly (at least for now).
+ */
+#define _BT_LOG_MESSAGE_FORMAT_MASK__             (0<<0)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__YEAR         (1<<1)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__MONTH        (1<<2)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__DAY          (1<<3)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__HOUR         (1<<4)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__MINUTE       (1<<5)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__SECOND       (1<<6)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__MILLISECOND  (1<<7)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__PID          (1<<8)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__TID          (1<<9)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__LEVEL        (1<<10)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts)  (1<<11)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__FUNCTION     (1<<12)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__FILENAME     (1<<13)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__FILELINE     (1<<14)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__S(s)         (1<<15)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0<<16)
+#define _BT_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1<<17)
+#define _BT_LOG_MESSAGE_FORMAT_MASK(field) \
+       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_MASK_, _, field)
+
+/* Logical "or" of masks of fields used in specified format specification.
+ */
+#define _BT_LOG_MESSAGE_FORMAT_FIELDS(format) \
+       (0 _PP_MAP(| _BT_LOG_MESSAGE_FORMAT_MASK, format))
+
+/* Expands to expressions that evaluates to true if field is used in
+ * specified format specification. Example:
+ *
+ *   #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT, BT_LOG_MESSAGE_CTX_FORMAT)
+ *       ...
+ *   #endif
+ */
+#define _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \
+       (_BT_LOG_MESSAGE_FORMAT_MASK(field) & _BT_LOG_MESSAGE_FORMAT_FIELDS(format))
+
+/* Same, but checks all supported format specifications.
+ */
+#define _BT_LOG_MESSAGE_FORMAT_FIELD_USED(field) \
+       (_BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_CTX_FORMAT) || \
+        _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_TAG_FORMAT) || \
+        _BT_LOG_MESSAGE_FORMAT_CONTAINS(field, BT_LOG_MESSAGE_SRC_FORMAT))
+
+#define _BT_LOG_MESSAGE_FORMAT_DATETIME_USED \
+       (_BT_LOG_MESSAGE_FORMAT_CONTAINS(YEAR, BT_LOG_MESSAGE_CTX_FORMAT) || \
+        _BT_LOG_MESSAGE_FORMAT_CONTAINS(MONTH, BT_LOG_MESSAGE_CTX_FORMAT) || \
+        _BT_LOG_MESSAGE_FORMAT_CONTAINS(DAY, BT_LOG_MESSAGE_CTX_FORMAT) || \
+        _BT_LOG_MESSAGE_FORMAT_CONTAINS(HOUR, BT_LOG_MESSAGE_CTX_FORMAT) || \
+        _BT_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE, BT_LOG_MESSAGE_CTX_FORMAT) || \
+        _BT_LOG_MESSAGE_FORMAT_CONTAINS(SECOND, BT_LOG_MESSAGE_CTX_FORMAT) || \
+        _BT_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND, BT_LOG_MESSAGE_CTX_FORMAT))
+
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+       #pragma warning(disable:4204) /* nonstandard extension used: non-constant aggregate initializer */
+       #define memccpy _memccpy
+#endif
+
+#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || \
+               (defined(__MINGW64__) && !defined(__USE_MINGW_ANSI_STDIO))
+       #define vsnprintf(s, sz, fmt, va) fake_vsnprintf(s, sz, fmt, va)
+       static int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap)
+       {
+               const int n = vsnprintf_s(s, sz, _TRUNCATE, fmt, ap);
+               return 0 < n? n: (int)sz + 1; /* no need in _vscprintf() for now */
+       }
+       #if BT_LOG_OPTIMIZE_SIZE
+       #define snprintf(s, sz, ...) fake_snprintf(s, sz, __VA_ARGS__)
+       static int fake_snprintf(char *s, size_t sz, const char *fmt, ...)
+       {
+               va_list va;
+               va_start(va, fmt);
+               const int n = fake_vsnprintf(s, sz, fmt, va);
+               va_end(va);
+               return n;
+       }
+       #endif
+#endif
+
+typedef void (*time_cb)(struct tm *const tm, unsigned *const usec);
+typedef void (*pid_cb)(int *const pid, int *const tid);
+typedef void (*buffer_cb)(bt_log_message *msg, char *buf);
+
+typedef struct src_location
+{
+       const char *const func;
+       const char *const file;
+       const unsigned line;
+}
+src_location;
+
+typedef struct mem_block
+{
+       const void *const d;
+       const unsigned d_sz;
+}
+mem_block;
+
+static void time_callback(struct tm *const tm, unsigned *const usec);
+static void pid_callback(int *const pid, int *const tid);
+static void buffer_callback(bt_log_message *msg, char *buf);
+
+STATIC_ASSERT(eol_fits_eol_sz, sizeof(BT_LOG_EOL) <= BT_LOG_EOL_SZ);
+STATIC_ASSERT(eol_sz_greater_than_zero, 0 < BT_LOG_EOL_SZ);
+STATIC_ASSERT(eol_sz_less_than_buf_sz, BT_LOG_EOL_SZ < BT_LOG_BUF_SZ);
+static const char c_hex[] = "0123456789abcdef";
+
+static __thread char logging_buf[4 * 4096];
+
+static INSTRUMENTED_CONST unsigned g_buf_sz = BT_LOG_BUF_SZ - BT_LOG_EOL_SZ;
+static INSTRUMENTED_CONST time_cb g_time_cb = time_callback;
+static INSTRUMENTED_CONST pid_cb g_pid_cb = pid_callback;
+static INSTRUMENTED_CONST buffer_cb g_buffer_cb = buffer_callback;
+
+#if BT_LOG_USE_ANDROID_LOG
+       #include <android/log.h>
+
+       static INLINE int android_lvl(const int lvl)
+       {
+               switch (lvl)
+               {
+               case BT_LOG_VERBOSE:
+                       return ANDROID_LOG_VERBOSE;
+               case BT_LOG_DEBUG:
+                       return ANDROID_LOG_DEBUG;
+               case BT_LOG_INFO:
+                       return ANDROID_LOG_INFO;
+               case BT_LOG_WARN:
+                       return ANDROID_LOG_WARN;
+               case BT_LOG_ERROR:
+                       return ANDROID_LOG_ERROR;
+               case BT_LOG_FATAL:
+                       return ANDROID_LOG_FATAL;
+               default:
+                       ASSERT_UNREACHABLE("Bad log level");
+                       return ANDROID_LOG_UNKNOWN;
+               }
+       }
+
+       static void out_android_callback(const bt_log_message *const msg, void *arg)
+       {
+               VAR_UNUSED(arg);
+               *msg->p = 0;
+               const char *tag = msg->p;
+               if (msg->tag_e != msg->tag_b)
+               {
+                       tag = msg->tag_b;
+                       *msg->tag_e = 0;
+               }
+               __android_log_print(android_lvl(msg->lvl), tag, "%s", msg->msg_b);
+       }
+
+       enum { OUT_ANDROID_MASK = BT_LOG_PUT_STD & ~BT_LOG_PUT_CTX };
+       #define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback
+#endif
+
+#if BT_LOG_USE_NSLOG
+       #include <CoreFoundation/CoreFoundation.h>
+       CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...);
+
+       static INLINE int apple_lvl(const int lvl)
+       {
+               switch (lvl)
+               {
+               case BT_LOG_VERBOSE:
+                       return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;
+               case BT_LOG_DEBUG:
+                       return 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;
+               case BT_LOG_INFO:
+                       return 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */;
+               case BT_LOG_WARN:
+                       return 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */;
+               case BT_LOG_ERROR:
+                       return 3; /* ASL_LEVEL_ERR / kCFLogLevelError */;
+               case BT_LOG_FATAL:
+                       return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;
+               default:
+                       ASSERT_UNREACHABLE("Bad log level");
+                       return 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;
+               }
+       }
+
+       static void out_nslog_callback(const bt_log_message *const msg, void *arg)
+       {
+               VAR_UNUSED(arg);
+               *msg->p = 0;
+               CFLog(apple_lvl(msg->lvl), CFSTR("%s"), msg->tag_b);
+       }
+
+       enum { OUT_NSLOG_MASK = BT_LOG_PUT_STD & ~BT_LOG_PUT_CTX };
+       #define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback
+#endif
+
+#if BT_LOG_USE_DEBUGSTRING
+       #include <windows.h>
+
+       static void out_debugstring_callback(const bt_log_message *const msg, void *arg)
+       {
+               VAR_UNUSED(arg);
+               msg->p[0] = '\n';
+               msg->p[1] = '\0';
+               OutputDebugStringA(msg->buf);
+       }
+
+       enum { OUT_DEBUGSTRING_MASK = BT_LOG_PUT_STD };
+       #define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback
+#endif
+
+BT_HIDDEN
+void bt_log_out_stderr_callback(const bt_log_message *const msg, void *arg)
+{
+       VAR_UNUSED(arg);
+       const size_t eol_len = sizeof(BT_LOG_EOL) - 1;
+       memcpy(msg->p, BT_LOG_EOL, eol_len);
+#if defined(_WIN32) || defined(_WIN64)
+       /* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and
+          without FILE_WRITE_DATA */
+       WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg->buf,
+                         (DWORD)(msg->p - msg->buf + eol_len), 0, 0);
+#else
+       /* write() is atomic for buffers less than or equal to PIPE_BUF. */
+       RETVAL_UNUSED(write(STDERR_FILENO, msg->buf,
+                                               (size_t)(msg->p - msg->buf) + eol_len));
+#endif
+}
+
+static const bt_log_output out_stderr = {BT_LOG_OUT_STDERR};
+
+#if !BT_LOG_EXTERN_TAG_PREFIX
+       BT_LOG_DEFINE_TAG_PREFIX = 0;
+#endif
+
+#if !BT_LOG_EXTERN_GLOBAL_FORMAT
+       BT_LOG_DEFINE_GLOBAL_FORMAT = {BT_LOG_MEM_WIDTH};
+#endif
+
+#if !BT_LOG_EXTERN_GLOBAL_OUTPUT
+       #if BT_LOG_USE_ANDROID_LOG
+               BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_ANDROID};
+       #elif BT_LOG_USE_NSLOG
+               BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_NSLOG};
+       #elif BT_LOG_USE_DEBUGSTRING
+               BT_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_DEBUGSTRING};
+       #else
+               BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_OUT_STDERR};
+       #endif
+#endif
+
+#if !BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+       BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0;
+#endif
+
+BT_HIDDEN
+const bt_log_spec _bt_log_stderr_spec =
+{
+       BT_LOG_GLOBAL_FORMAT,
+       &out_stderr,
+};
+
+static const bt_log_spec global_spec =
+{
+       BT_LOG_GLOBAL_FORMAT,
+       BT_LOG_GLOBAL_OUTPUT,
+};
+
+#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, BT_LOG_MESSAGE_CTX_FORMAT)
+static char lvl_char(const int lvl)
+{
+       switch (lvl)
+       {
+       case BT_LOG_VERBOSE:
+               return 'V';
+       case BT_LOG_DEBUG:
+               return 'D';
+       case BT_LOG_INFO:
+               return 'I';
+       case BT_LOG_WARN:
+               return 'W';
+       case BT_LOG_ERROR:
+               return 'E';
+       case BT_LOG_FATAL:
+               return 'F';
+       default:
+               ASSERT_UNREACHABLE("Bad log level");
+               return '?';
+       }
+}
+#endif
+
+#define GCCVER_LESS(MAJOR, MINOR, PATCH) \
+       (__GNUC__ < MAJOR || \
+               (__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR || \
+                       (__GNUC_MINOR__ == MINOR && __GNUC_PATCHLEVEL__ < PATCH))))
+
+#if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4,7,0)
+       #define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0)
+       #define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n)
+       #define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n)
+       #define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n)
+       #define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n)
+       /* Note: will not store old value of *vp in *ep (non-standard behaviour) */
+       #define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \
+               __sync_bool_compare_and_swap(vp, *(ep), d)
+#endif
+
+#if !BT_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64)
+#define TCACHE
+#define TCACHE_STALE (0x40000000)
+#define TCACHE_FLUID (0x40000000 | 0x80000000)
+static unsigned g_tcache_mode = TCACHE_STALE;
+static struct timeval g_tcache_tv = {0, 0};
+static struct tm g_tcache_tm = {0};
+
+static INLINE int tcache_get(const struct timeval *const tv, struct tm *const tm)
+{
+       unsigned mode;
+       mode = __atomic_load_n(&g_tcache_mode, __ATOMIC_RELAXED);
+       if (0 == (mode & TCACHE_FLUID))
+       {
+               mode = __atomic_fetch_add(&g_tcache_mode, 1, __ATOMIC_ACQUIRE);
+               if (0 == (mode & TCACHE_FLUID))
+               {
+                       if (g_tcache_tv.tv_sec == tv->tv_sec)
+                       {
+                               *tm = g_tcache_tm;
+                               __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
+                               return !0;
+                       }
+                       __atomic_or_fetch(&g_tcache_mode, TCACHE_STALE, __ATOMIC_RELAXED);
+               }
+               __atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);
+       }
+       return 0;
+}
+
+static INLINE void tcache_set(const struct timeval *const tv, struct tm *const tm)
+{
+       unsigned stale = TCACHE_STALE;
+       if (__atomic_compare_exchange_n(&g_tcache_mode, &stale, TCACHE_FLUID,
+                                                                       0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
+       {
+               g_tcache_tv = *tv;
+               g_tcache_tm = *tm;
+               __atomic_and_fetch(&g_tcache_mode, ~TCACHE_FLUID, __ATOMIC_RELEASE);
+       }
+}
+#endif
+
+static void time_callback(struct tm *const tm, unsigned *const msec)
+{
+#if !_BT_LOG_MESSAGE_FORMAT_DATETIME_USED
+       VAR_UNUSED(tm);
+       VAR_UNUSED(msec);
+#else
+       #if defined(_WIN32) || defined(_WIN64)
+       SYSTEMTIME st;
+       GetLocalTime(&st);
+       tm->tm_year = st.wYear;
+       tm->tm_mon = st.wMonth;
+       tm->tm_mday = st.wDay;
+       tm->tm_wday = st.wDayOfWeek;
+       tm->tm_hour = st.wHour;
+       tm->tm_min = st.wMinute;
+       tm->tm_sec = st.wSecond;
+       *msec = st.wMilliseconds;
+       #else
+       struct timeval tv;
+       gettimeofday(&tv, 0);
+               #ifndef TCACHE
+               localtime_r(&tv.tv_sec, tm);
+               #else
+               if (!tcache_get(&tv, tm))
+               {
+                       localtime_r(&tv.tv_sec, tm);
+                       tcache_set(&tv, tm);
+               }
+               #endif
+       *msec = (unsigned)tv.tv_usec / 1000;
+       #endif
+#endif
+}
+
+static void pid_callback(int *const pid, int *const tid)
+{
+#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(PID, BT_LOG_MESSAGE_CTX_FORMAT)
+       VAR_UNUSED(pid);
+#else
+       #if defined(_WIN32) || defined(_WIN64)
+       *pid = GetCurrentProcessId();
+       #else
+       *pid = getpid();
+       #endif
+#endif
+
+#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(TID, BT_LOG_MESSAGE_CTX_FORMAT)
+       VAR_UNUSED(tid);
+#else
+       #if defined(_WIN32) || defined(_WIN64)
+       *tid = GetCurrentThreadId();
+       #elif defined(__CYGWIN__)
+       pthread_t thr = pthread_self();
+       *tid = (int)pthread_getsequence_np(&thr);
+       #elif defined(__sun__)
+       *tid = (int)pthread_self();
+       #elif defined(__ANDROID__)
+       *tid = gettid();
+       #elif defined(__linux__)
+       *tid = syscall(SYS_gettid);
+       #elif defined(__MACH__)
+       *tid = (int)pthread_mach_thread_np(pthread_self());
+       #else
+               #define Platform not supported
+       #endif
+#endif
+}
+
+static void buffer_callback(bt_log_message *msg, char *buf)
+{
+       msg->e = (msg->p = msg->buf = buf) + g_buf_sz;
+}
+
+#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, BT_LOG_MESSAGE_SRC_FORMAT)
+static const char *funcname(const char *func)
+{
+       return func? func: "";
+}
+#endif
+
+#if _BT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, BT_LOG_MESSAGE_SRC_FORMAT)
+static const char *filename(const char *file)
+{
+       const char *f = file;
+       for (const char *p = file; 0 != *p; ++p)
+       {
+               if ('/' == *p || '\\' == *p)
+               {
+                       f = p + 1;
+               }
+       }
+       return f;
+}
+#endif
+
+static INLINE size_t nprintf_size(bt_log_message *const msg)
+{
+       // *nprintf() always puts 0 in the end when input buffer is not empty. This
+       // 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which
+       // leaves space for one more character. Some put_xxx() functions don't use
+       // *nprintf() and could use that last character. In that case log line will
+       // have multiple (two) half-written parts which is confusing. To workaround
+       // that we allow *nprintf() to write its 0 in the eol area (which is always
+       // not empty).
+       return (size_t)(msg->e - msg->p + 1);
+}
+
+static INLINE void put_nprintf(bt_log_message *const msg, const int n)
+{
+       if (0 < n)
+       {
+               msg->p = n < msg->e - msg->p? msg->p + n: msg->e;
+       }
+}
+
+static INLINE char *put_padding_r(const unsigned w, const char wc,
+                                                                 char *p, char *e)
+{
+       for (char *const b = e - w; b < p; *--p = wc) {}
+       return p;
+}
+
+static char *put_integer_r(unsigned v, const int sign,
+                                                  const unsigned w, const char wc, char *const e)
+{
+       static const char _signs[] = {'-', '0', '+'};
+       const char *const signs = _signs + 1;
+       char *p = e;
+       do { *--p = '0' + v % 10; } while (0 != (v /= 10));
+       if (0 == sign) return put_padding_r(w, wc, p, e);
+       if ('0' != wc)
+       {
+               *--p = signs[sign];
+               return put_padding_r(w, wc, p, e);
+       }
+       p = put_padding_r(w, wc, p, e + 1);
+       *--p = signs[sign];
+       return p;
+}
+
+static INLINE char *put_uint_r(const unsigned v, const unsigned w, const char wc,
+                                                          char *const e)
+{
+       return put_integer_r(v, 0, w, wc, e);
+}
+
+static INLINE char *put_int_r(const int v, const unsigned w, const char wc,
+                                                         char *const e)
+{
+       return 0 <= v? put_integer_r((unsigned)v, 0, w, wc, e)
+                                : put_integer_r((unsigned)-v, -1, w, wc, e);
+}
+
+static INLINE char *put_stringn(const char *const s_p, const char *const s_e,
+                                                               char *const p, char *const e)
+{
+       const ptrdiff_t m = e - p;
+       ptrdiff_t n = s_e - s_p;
+       if (n > m)
+       {
+               n = m;
+       }
+       memcpy(p, s_p, n);
+       return p + n;
+}
+
+static INLINE char *put_string(const char *s, char *p, char *const e)
+{
+       const ptrdiff_t n = e - p;
+       char *const c = (char *)memccpy(p, s, '\0', n);
+       return 0 != c? c - 1: e;
+}
+
+static INLINE char *put_uint(unsigned v, const unsigned w, const char wc,
+                                                        char *const p, char *const e)
+{
+       char buf[16];
+       char *const se = buf + _countof(buf);
+       char *sp = put_uint_r(v, w, wc, se);
+       return put_stringn(sp, se, p, e);
+}
+
+#define PUT_CSTR_R(p, STR) \
+       do { \
+               for (unsigned i = sizeof(STR) - 1; 0 < i--;) { \
+                       *--(p) = (STR)[i]; \
+               } \
+       } _BT_LOG_ONCE
+
+#define PUT_CSTR_CHECKED(p, e, STR) \
+       do { \
+               for (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \
+                       *(p)++ = (STR)[i]; \
+               } \
+       } _BT_LOG_ONCE
+
+/* F_INIT field support.
+ */
+#define _BT_LOG_MESSAGE_FORMAT_INIT__
+#define _BT_LOG_MESSAGE_FORMAT_INIT__YEAR
+#define _BT_LOG_MESSAGE_FORMAT_INIT__MONTH
+#define _BT_LOG_MESSAGE_FORMAT_INIT__DAY
+#define _BT_LOG_MESSAGE_FORMAT_INIT__HOUR
+#define _BT_LOG_MESSAGE_FORMAT_INIT__MINUTE
+#define _BT_LOG_MESSAGE_FORMAT_INIT__SECOND
+#define _BT_LOG_MESSAGE_FORMAT_INIT__MILLISECOND
+#define _BT_LOG_MESSAGE_FORMAT_INIT__PID
+#define _BT_LOG_MESSAGE_FORMAT_INIT__TID
+#define _BT_LOG_MESSAGE_FORMAT_INIT__LEVEL
+#define _BT_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts)
+#define _BT_LOG_MESSAGE_FORMAT_INIT__FUNCTION
+#define _BT_LOG_MESSAGE_FORMAT_INIT__FILENAME
+#define _BT_LOG_MESSAGE_FORMAT_INIT__FILELINE
+#define _BT_LOG_MESSAGE_FORMAT_INIT__S(s)
+#define _BT_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr);
+#define _BT_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v)
+#define _BT_LOG_MESSAGE_FORMAT_INIT(field) \
+       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_INIT_, _, field)
+
+/* Implements generation of printf-like format string for log message
+ * format specification.
+ */
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__             ""
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR         "%04u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH        "%02u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY          "%02u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR         "%02u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE       "%02u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND       "%02u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND  "%03u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID          "%5i"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID          "%5i"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL        "%c"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG          UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION     "%s"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME     "%s"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE     "%u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s)         s
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) ""
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) "%" #w "u"
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \
+       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field)
+
+/* Implements generation of printf-like format parameters for log message
+ * format specification.
+ */
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR         ,(unsigned)(tm.tm_year + 1900)
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH        ,(unsigned)(tm.tm_mon + 1)
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY          ,(unsigned)tm.tm_mday
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR         ,(unsigned)tm.tm_hour
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE       ,(unsigned)tm.tm_min
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND       ,(unsigned)tm.tm_sec
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND  ,(unsigned)msec
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID          ,pid
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID          ,tid
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL        ,(char)lvl_char(msg->lvl)
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG          UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION     ,funcname(src->func)
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME     ,filename(src->file)
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE     ,src->line
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s)
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr)
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) ,v
+#define _BT_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \
+       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field)
+
+/* Implements generation of put_xxx_t statements for log message specification.
+ */
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__YEAR         p = put_uint_r(tm.tm_year + 1900, 4, '0', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MONTH        p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__DAY          p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__HOUR         p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MINUTE       p = put_uint_r((unsigned)tm.tm_min, 2, '0', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__SECOND       p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND  p = put_uint_r(msec, 3, '0', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__PID          p = put_int_r(pid, 5, ' ', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__TID          p = put_int_r(tid, 5, ' ', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__LEVEL        *--p = lvl_char(msg->lvl);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__TAG          UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION     UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FILENAME     UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__FILELINE     UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__S(s)         PUT_CSTR_R(p, s);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr)
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) p = put_uint_r(v, w, ' ', p);
+#define _BT_LOG_MESSAGE_FORMAT_PUT_R(field) \
+       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PUT_R_, _, field)
+
+static void put_ctx(bt_log_message *const msg)
+{
+       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_CTX_FORMAT)
+#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_CTX_FORMAT)
+       VAR_UNUSED(msg);
+#else
+       #if _BT_LOG_MESSAGE_FORMAT_DATETIME_USED
+       struct tm tm;
+       unsigned msec;
+       g_time_cb(&tm, &msec);
+       #endif
+       #if _BT_LOG_MESSAGE_FORMAT_CONTAINS(PID, BT_LOG_MESSAGE_CTX_FORMAT) || \
+               _BT_LOG_MESSAGE_FORMAT_CONTAINS(TID, BT_LOG_MESSAGE_CTX_FORMAT)
+       int pid, tid;
+       g_pid_cb(&pid, &tid);
+       #endif
+
+       #if BT_LOG_OPTIMIZE_SIZE
+       int n;
+       n = snprintf(msg->p, nprintf_size(msg),
+                                _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT, BT_LOG_MESSAGE_CTX_FORMAT)
+                 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL, BT_LOG_MESSAGE_CTX_FORMAT));
+       put_nprintf(msg, n);
+       #else
+       char buf[64];
+       char *const e = buf + sizeof(buf);
+       char *p = e;
+       _PP_RMAP(_BT_LOG_MESSAGE_FORMAT_PUT_R, BT_LOG_MESSAGE_CTX_FORMAT)
+       msg->p = put_stringn(p, e, msg->p, msg->e);
+       #endif
+#endif
+}
+
+#define PUT_TAG(msg, tag, prefix_delim, tag_delim) \
+       do { \
+               const char *ch; \
+               msg->tag_b = msg->p; \
+               if (0 != (ch = _bt_log_tag_prefix)) { \
+                       for (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \
+               } \
+               if (0 != (ch = tag) && 0 != tag[0]) { \
+                       if (msg->tag_b != msg->p) { \
+                               PUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim); \
+                       } \
+                       for (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \
+               } \
+               msg->tag_e = msg->p; \
+               if (msg->tag_b != msg->p) { \
+                       PUT_CSTR_CHECKED(msg->p, msg->e, tag_delim); \
+               } \
+       } _BT_LOG_ONCE
+
+/* Implements simple put statements for log message specification.
+ */
+#define _BT_LOG_MESSAGE_FORMAT_PUT__
+#define _BT_LOG_MESSAGE_FORMAT_PUT__YEAR         UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__MONTH        UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__DAY          UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__HOUR         UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__MINUTE       UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__SECOND       UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__MILLISECOND  UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__PID          UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__TID          UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__LEVEL        UNDEFINED
+#define _BT_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td)  PUT_TAG(msg, tag, pd, td);
+#define _BT_LOG_MESSAGE_FORMAT_PUT__FUNCTION     msg->p = put_string(funcname(src->func), msg->p, msg->e);
+#define _BT_LOG_MESSAGE_FORMAT_PUT__FILENAME     msg->p = put_string(filename(src->file), msg->p, msg->e);
+#define _BT_LOG_MESSAGE_FORMAT_PUT__FILELINE     msg->p = put_uint(src->line, 0, '\0', msg->p, msg->e);
+#define _BT_LOG_MESSAGE_FORMAT_PUT__S(s)         PUT_CSTR_CHECKED(msg->p, msg->e, s);
+#define _BT_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr)
+#define _BT_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) msg->p = put_uint(v, w, ' ', msg->p, msg->e);
+#define _BT_LOG_MESSAGE_FORMAT_PUT(field) \
+       _PP_CONCAT_3(_BT_LOG_MESSAGE_FORMAT_PUT_, _, field)
+
+static void put_tag(bt_log_message *const msg, const char *const tag)
+{
+       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_TAG_FORMAT)
+#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(TAG, BT_LOG_MESSAGE_TAG_FORMAT)
+       VAR_UNUSED(tag);
+#endif
+#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_TAG_FORMAT)
+       VAR_UNUSED(msg);
+#else
+       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PUT, BT_LOG_MESSAGE_TAG_FORMAT)
+#endif
+}
+
+static void put_src(bt_log_message *const msg, const src_location *const src)
+{
+       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_INIT, BT_LOG_MESSAGE_SRC_FORMAT)
+#if !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, BT_LOG_MESSAGE_SRC_FORMAT) && \
+       !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, BT_LOG_MESSAGE_SRC_FORMAT) && \
+       !_BT_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE, BT_LOG_MESSAGE_SRC_FORMAT)
+       VAR_UNUSED(src);
+#endif
+#if !_BT_LOG_MESSAGE_FORMAT_FIELDS(BT_LOG_MESSAGE_SRC_FORMAT)
+       VAR_UNUSED(msg);
+#else
+       #if BT_LOG_OPTIMIZE_SIZE
+       int n;
+       n = snprintf(msg->p, nprintf_size(msg),
+                                _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_FMT, BT_LOG_MESSAGE_SRC_FORMAT)
+                 _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PRINTF_VAL, BT_LOG_MESSAGE_SRC_FORMAT));
+       put_nprintf(msg, n);
+       #else
+       _PP_MAP(_BT_LOG_MESSAGE_FORMAT_PUT, BT_LOG_MESSAGE_SRC_FORMAT)
+       #endif
+#endif
+}
+
+static void put_msg(bt_log_message *const msg,
+                                       const char *const fmt, va_list va)
+{
+       int n;
+       msg->msg_b = msg->p;
+       n = vsnprintf(msg->p, nprintf_size(msg), fmt, va);
+       put_nprintf(msg, n);
+}
+
+static void output_mem(const bt_log_spec *log, bt_log_message *const msg,
+                                          const mem_block *const mem)
+{
+       if (0 == mem->d || 0 == mem->d_sz)
+       {
+               return;
+       }
+       const unsigned char *mem_p = (const unsigned char *)mem->d;
+       const unsigned char *const mem_e = mem_p + mem->d_sz;
+       const unsigned char *mem_cut;
+       const ptrdiff_t mem_width = (ptrdiff_t)log->format->mem_width;
+       char *const hex_b = msg->msg_b;
+       char *const ascii_b = hex_b + 2 * mem_width + 2;
+       char *const ascii_e = ascii_b + mem_width;
+       if (msg->e < ascii_e)
+       {
+               return;
+       }
+       while (mem_p != mem_e)
+       {
+               char *hex = hex_b;
+               char *ascii = ascii_b;
+               for (mem_cut = mem_width < mem_e - mem_p? mem_p + mem_width: mem_e;
+                        mem_cut != mem_p; ++mem_p)
+               {
+                       const unsigned char ch = *mem_p;
+                       *hex++ = c_hex[(0xf0 & ch) >> 4];
+                       *hex++ = c_hex[(0x0f & ch)];
+                       *ascii++ = isprint(ch)? (char)ch: '?';
+               }
+               while (hex != ascii_b)
+               {
+                       *hex++ = ' ';
+               }
+               msg->p = ascii;
+               log->output->callback(msg, log->output->arg);
+       }
+}
+
+BT_HIDDEN
+void bt_log_set_tag_prefix(const char *const prefix)
+{
+       _bt_log_tag_prefix = prefix;
+}
+
+BT_HIDDEN
+void bt_log_set_mem_width(const unsigned w)
+{
+       _bt_log_global_format.mem_width = w;
+}
+
+BT_HIDDEN
+void bt_log_set_output_level(const int lvl)
+{
+       _bt_log_global_output_lvl = lvl;
+}
+
+BT_HIDDEN
+void bt_log_set_output_v(const unsigned mask, void *const arg,
+                                                const bt_log_output_cb callback)
+{
+       _bt_log_global_output.mask = mask;
+       _bt_log_global_output.arg = arg;
+       _bt_log_global_output.callback = callback;
+}
+
+static void _bt_log_write_imp(
+               const bt_log_spec *log,
+               const src_location *const src, const mem_block *const mem,
+               const int lvl, const char *const tag, const char *const fmt, va_list va)
+{
+       bt_log_message msg;
+       char *buf = logging_buf;
+       const unsigned mask = log->output->mask;
+       msg.lvl = lvl;
+       msg.tag = tag;
+       g_buffer_cb(&msg, buf);
+       const char *rst_color_p = bt_common_color_reset();
+       const char *rst_color_e = rst_color_p + strlen(rst_color_p);
+       const char *color_p = "";
+       const char *color_e = color_p;
+
+       switch (lvl) {
+       case BT_LOG_INFO:
+               color_p = bt_common_color_fg_blue();
+               color_e = color_p + strlen(color_p);
+               break;
+       case BT_LOG_WARN:
+               color_p = bt_common_color_fg_yellow();
+               color_e = color_p + strlen(color_p);
+               break;
+       case BT_LOG_ERROR:
+       case BT_LOG_FATAL:
+               color_p = bt_common_color_fg_red();
+               color_e = color_p + strlen(color_p);
+               break;
+       default:
+               break;
+       }
+
+       msg.p = put_stringn(color_p, color_e, msg.p, msg.e);
+
+       if (BT_LOG_PUT_CTX & mask)
+       {
+               put_ctx(&msg);
+       }
+       if (BT_LOG_PUT_TAG & mask)
+       {
+               put_tag(&msg, tag);
+       }
+       if (0 != src && BT_LOG_PUT_SRC & mask)
+       {
+               put_src(&msg, src);
+       }
+       if (BT_LOG_PUT_MSG & mask)
+       {
+               put_msg(&msg, fmt, va);
+       }
+       msg.p = put_stringn(rst_color_p, rst_color_e, msg.p, msg.e);
+       log->output->callback(&msg, log->output->arg);
+       if (0 != mem && BT_LOG_PUT_MSG & mask)
+       {
+               output_mem(log, &msg, mem);
+       }
+}
+
+BT_HIDDEN
+void _bt_log_write_d(
+               const char *const func, const char *const file, const unsigned line,
+               const int lvl, const char *const tag,
+               const char *const fmt, ...)
+{
+       const src_location src = {func, file, line};
+       va_list va;
+       va_start(va, fmt);
+       _bt_log_write_imp(&global_spec, &src, 0, lvl, tag, fmt, va);
+       va_end(va);
+}
+
+BT_HIDDEN
+void _bt_log_write_aux_d(
+               const char *const func, const char *const file, const unsigned line,
+               const bt_log_spec *const log, const int lvl, const char *const tag,
+               const char *const fmt, ...)
+{
+       const src_location src = {func, file, line};
+       va_list va;
+       va_start(va, fmt);
+       _bt_log_write_imp(log, &src, 0, lvl, tag, fmt, va);
+       va_end(va);
+}
+
+BT_HIDDEN
+void _bt_log_write(const int lvl, const char *const tag,
+                                  const char *const fmt, ...)
+{
+       va_list va;
+       va_start(va, fmt);
+       _bt_log_write_imp(&global_spec, 0, 0, lvl, tag, fmt, va);
+       va_end(va);
+}
+
+BT_HIDDEN
+void _bt_log_write_aux(
+               const bt_log_spec *const log, const int lvl, const char *const tag,
+               const char *const fmt, ...)
+{
+       va_list va;
+       va_start(va, fmt);
+       _bt_log_write_imp(log, 0, 0, lvl, tag, fmt, va);
+       va_end(va);
+}
+
+BT_HIDDEN
+void _bt_log_write_mem_d(
+               const char *const func, const char *const file, const unsigned line,
+               const int lvl, const char *const tag,
+               const void *const d, const unsigned d_sz,
+               const char *const fmt, ...)
+{
+       const src_location src = {func, file, line};
+       const mem_block mem = {d, d_sz};
+       va_list va;
+       va_start(va, fmt);
+       _bt_log_write_imp(&global_spec, &src, &mem, lvl, tag, fmt, va);
+       va_end(va);
+}
+
+BT_HIDDEN
+void _bt_log_write_mem_aux_d(
+               const char *const func, const char *const file, const unsigned line,
+               const bt_log_spec *const log, const int lvl, const char *const tag,
+               const void *const d, const unsigned d_sz,
+               const char *const fmt, ...)
+{
+       const src_location src = {func, file, line};
+       const mem_block mem = {d, d_sz};
+       va_list va;
+       va_start(va, fmt);
+       _bt_log_write_imp(log, &src, &mem, lvl, tag, fmt, va);
+       va_end(va);
+}
+
+BT_HIDDEN
+void _bt_log_write_mem(const int lvl, const char *const tag,
+                                          const void *const d, const unsigned d_sz,
+                                          const char *const fmt, ...)
+{
+       const mem_block mem = {d, d_sz};
+       va_list va;
+       va_start(va, fmt);
+       _bt_log_write_imp(&global_spec, 0, &mem, lvl, tag, fmt, va);
+       va_end(va);
+}
+
+BT_HIDDEN
+void _bt_log_write_mem_aux(
+               const bt_log_spec *const log, const int lvl, const char *const tag,
+               const void *const d, const unsigned d_sz,
+               const char *const fmt, ...)
+{
+       const mem_block mem = {d, d_sz};
+       va_list va;
+       va_start(va, fmt);
+       _bt_log_write_imp(log, 0, &mem, lvl, tag, fmt, va);
+       va_end(va);
+}
diff --git a/src/logging/log.h b/src/logging/log.h
new file mode 100644 (file)
index 0000000..44f778a
--- /dev/null
@@ -0,0 +1,1054 @@
+/*
+ * This is zf_log.h, modified with Babeltrace prefixes.
+ * See <https://github.com/wonder-mice/zf_log/>.
+ * See logging/LICENSE in the Babeltrace source tree.
+ */
+
+#pragma once
+
+#ifndef BABELTRACE_LOGGING_INTERNAL_H
+#define BABELTRACE_LOGGING_INTERNAL_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <babeltrace2/logging.h>
+#include "common/babeltrace.h"
+
+/* To detect incompatible changes you can define BT_LOG_VERSION_REQUIRED to be
+ * the current value of BT_LOG_VERSION before including this file (or via
+ * compiler command line):
+ *
+ *   #define BT_LOG_VERSION_REQUIRED 4
+ *   #include "logging.h"
+ *
+ * Compilation will fail when included file has different version.
+ */
+#define BT_LOG_VERSION 4
+#if defined(BT_LOG_VERSION_REQUIRED)
+       #if BT_LOG_VERSION_REQUIRED != BT_LOG_VERSION
+               #error different bt_log version required
+       #endif
+#endif
+
+/* Log level guideline:
+ * - BT_LOG_FATAL - happened something impossible and absolutely unexpected.
+ *   Process can't continue and must be terminated.
+ *   Example: division by zero, unexpected modifications from other thread.
+ * - BT_LOG_ERROR - happened something possible, but highly unexpected. The
+ *   process is able to recover and continue execution.
+ *   Example: out of memory (could also be FATAL if not handled properly).
+ * - BT_LOG_WARN - happened something that *usually* should not happen and
+ *   significantly changes application behavior for some period of time.
+ *   Example: configuration file not found, auth error.
+ * - BT_LOG_INFO - happened significant life cycle event or major state
+ *   transition.
+ *   Example: app started, user logged in.
+ * - BT_LOG_DEBUG - minimal set of events that could help to reconstruct the
+ *   execution path. Usually disabled in release builds.
+ * - BT_LOG_VERBOSE - all other events. Usually disabled in release builds.
+ *
+ * *Ideally*, log file of debugged, well tested, production ready application
+ * should be empty or very small. Choosing a right log level is as important as
+ * providing short and self descriptive log message.
+ */
+#define BT_LOG_VERBOSE BT_LOGGING_LEVEL_VERBOSE
+#define BT_LOG_DEBUG   BT_LOGGING_LEVEL_DEBUG
+#define BT_LOG_INFO    BT_LOGGING_LEVEL_INFO
+#define BT_LOG_WARN    BT_LOGGING_LEVEL_WARN
+#define BT_LOG_ERROR   BT_LOGGING_LEVEL_ERROR
+#define BT_LOG_FATAL   BT_LOGGING_LEVEL_FATAL
+#define BT_LOG_NONE    BT_LOGGING_LEVEL_NONE
+
+/* "Current" log level is a compile time check and has no runtime overhead. Log
+ * level that is below current log level it said to be "disabled". Otherwise,
+ * it's "enabled". Log messages that are disabled has no runtime overhead - they
+ * are converted to no-op by preprocessor and then eliminated by compiler.
+ * Current log level is configured per compilation module (.c/.cpp/.m file) by
+ * defining BT_LOG_DEF_LEVEL or BT_LOG_LEVEL. BT_LOG_LEVEL has higer priority
+ * and when defined overrides value provided by BT_LOG_DEF_LEVEL.
+ *
+ * Common practice is to define default current log level with BT_LOG_DEF_LEVEL
+ * in build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
+ * project or target:
+ *
+ *   CC_ARGS := -DBT_LOG_DEF_LEVEL=BT_LOG_INFO
+ *
+ * And when necessary to override it with BT_LOG_LEVEL in .c/.cpp/.m files
+ * before including bt_log.h:
+ *
+ *   #define BT_LOG_LEVEL BT_LOG_VERBOSE
+ *   #include "logging.h"
+ *
+ * If both BT_LOG_DEF_LEVEL and BT_LOG_LEVEL are undefined, then BT_LOG_INFO
+ * will be used for release builds (NDEBUG is defined) and BT_LOG_DEBUG
+ * otherwise (NDEBUG is not defined).
+ */
+#if defined(BT_LOG_LEVEL)
+       #define _BT_LOG_LEVEL BT_LOG_LEVEL
+#elif defined(BT_LOG_DEF_LEVEL)
+       #define _BT_LOG_LEVEL BT_LOG_DEF_LEVEL
+#else
+       #ifdef NDEBUG
+               #define _BT_LOG_LEVEL BT_LOG_INFO
+       #else
+               #define _BT_LOG_LEVEL BT_LOG_DEBUG
+       #endif
+#endif
+
+/* "Output" log level is a runtime check. When log level is below output log
+ * level it said to be "turned off" (or just "off" for short). Otherwise it's
+ * "turned on" (or just "on"). Log levels that were "disabled" (see
+ * BT_LOG_LEVEL and BT_LOG_DEF_LEVEL) can't be "turned on", but "enabled" log
+ * levels could be "turned off". Only messages with log level which is
+ * "turned on" will reach output facility. All other messages will be ignored
+ * (and their arguments will not be evaluated). Output log level is a global
+ * property and configured per process using bt_log_set_output_level() function
+ * which can be called at any time.
+ *
+ * Though in some cases it could be useful to configure output log level per
+ * compilation module or per library. There are two ways to achieve that:
+ * - Define BT_LOG_OUTPUT_LEVEL to expresion that evaluates to desired output
+ *   log level.
+ * - Copy bt_log.h and bt_log.c files into your library and build it with
+ *   BT_LOG_LIBRARY_PREFIX defined to library specific prefix. See
+ *   BT_LOG_LIBRARY_PREFIX for more details.
+ *
+ * When defined, BT_LOG_OUTPUT_LEVEL must evaluate to integral value that
+ * corresponds to desired output log level. Use it only when compilation module
+ * is required to have output log level which is different from global output
+ * log level set by bt_log_set_output_level() function. For other cases,
+ * consider defining BT_LOG_LEVEL or using bt_log_set_output_level() function.
+ *
+ * Example:
+ *
+ *   #define BT_LOG_OUTPUT_LEVEL g_module_log_level
+ *   #include "logging.h"
+ *   static int g_module_log_level = BT_LOG_INFO;
+ *   static void foo() {
+ *       BT_LOGI("Will check g_module_log_level for output log level");
+ *   }
+ *   void debug_log(bool on) {
+ *       g_module_log_level = on? BT_LOG_DEBUG: BT_LOG_INFO;
+ *   }
+ *
+ * Note on performance. This expression will be evaluated each time message is
+ * logged (except when message log level is "disabled" - see BT_LOG_LEVEL for
+ * details). Keep this expression as simple as possible, otherwise it will not
+ * only add runtime overhead, but also will increase size of call site (which
+ * will result in larger executable). The prefered way is to use integer
+ * variable (as in example above). If structure must be used, log_level field
+ * must be the first field in this structure:
+ *
+ *   #define BT_LOG_OUTPUT_LEVEL (g_config.log_level)
+ *   #include "logging.h"
+ *   struct config {
+ *       int log_level;
+ *       unsigned other_field;
+ *       [...]
+ *   };
+ *   static config g_config = {BT_LOG_INFO, 0, ...};
+ *
+ * This allows compiler to generate more compact load instruction (no need to
+ * specify offset since it's zero). Calling a function to get output log level
+ * is generaly a bad idea, since it will increase call site size and runtime
+ * overhead even further.
+ */
+#if defined(BT_LOG_OUTPUT_LEVEL)
+       #define _BT_LOG_OUTPUT_LEVEL BT_LOG_OUTPUT_LEVEL
+#else
+       /*
+        * We disallow this to make sure Babeltrace modules always
+        * have their own local log level.
+        */
+       #error No log level symbol specified: please define BT_LOG_OUTPUT_LEVEL before including this header.
+#endif
+
+/* "Tag" is a compound string that could be associated with a log message. It
+ * consists of tag prefix and tag (both are optional).
+ *
+ * Tag prefix is a global property and configured per process using
+ * bt_log_set_tag_prefix() function. Tag prefix identifies context in which
+ * component or module is running (e.g. process name). For example, the same
+ * library could be used in both client and server processes that work on the
+ * same machine. Tag prefix could be used to easily distinguish between them.
+ * For more details about tag prefix see bt_log_set_tag_prefix() function. Tag
+ * prefix
+ *
+ * Tag identifies component or module. It is configured per compilation module
+ * (.c/.cpp/.m file) by defining BT_LOG_TAG or BT_LOG_DEF_TAG. BT_LOG_TAG has
+ * higer priority and when defined overrides value provided by BT_LOG_DEF_TAG.
+ * When defined, value must evaluate to (const char *), so for strings double
+ * quotes must be used.
+ *
+ * Default tag could be defined with BT_LOG_DEF_TAG in build script (e.g.
+ * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target:
+ *
+ *   CC_ARGS := -DBT_LOG_DEF_TAG=\"MISC\"
+ *
+ * And when necessary could be overriden with BT_LOG_TAG in .c/.cpp/.m files
+ * before including bt_log.h:
+ *
+ *   #define BT_LOG_TAG "MAIN"
+ *   #include "logging.h"
+ *
+ * If both BT_LOG_DEF_TAG and BT_LOG_TAG are undefined no tag will be added to
+ * the log message (tag prefix still could be added though).
+ *
+ * Output example:
+ *
+ *   04-29 22:43:20.244 40059  1299 I hello.MAIN Number of arguments: 1
+ *                                    |     |
+ *                                    |     +- tag (e.g. module)
+ *                                    +- tag prefix (e.g. process name)
+ */
+#if defined(BT_LOG_TAG)
+       #define _BT_LOG_TAG BT_LOG_TAG
+#elif defined(BT_LOG_DEF_TAG)
+       #define _BT_LOG_TAG BT_LOG_DEF_TAG
+#else
+       #define _BT_LOG_TAG 0
+#endif
+
+/* Source location is part of a log line that describes location (function or
+ * method name, file name and line number, e.g. "runloop@main.cpp:68") of a
+ * log statement that produced it.
+ * Source location formats are:
+ * - BT_LOG_SRCLOC_NONE - don't add source location to log line.
+ * - BT_LOG_SRCLOC_SHORT - add source location in short form (file and line
+ *   number, e.g. "@main.cpp:68").
+ * - BT_LOG_SRCLOC_LONG - add source location in long form (function or method
+ *   name, file and line number, e.g. "runloop@main.cpp:68").
+ */
+#define BT_LOG_SRCLOC_NONE  0
+#define BT_LOG_SRCLOC_SHORT 1
+#define BT_LOG_SRCLOC_LONG  2
+
+/* Source location format is configured per compilation module (.c/.cpp/.m
+ * file) by defining BT_LOG_DEF_SRCLOC or BT_LOG_SRCLOC. BT_LOG_SRCLOC has
+ * higer priority and when defined overrides value provided by
+ * BT_LOG_DEF_SRCLOC.
+ *
+ * Common practice is to define default format with BT_LOG_DEF_SRCLOC in
+ * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
+ * project or target:
+ *
+ *   CC_ARGS := -DBT_LOG_DEF_SRCLOC=BT_LOG_SRCLOC_LONG
+ *
+ * And when necessary to override it with BT_LOG_SRCLOC in .c/.cpp/.m files
+ * before including bt_log.h:
+ *
+ *   #define BT_LOG_SRCLOC BT_LOG_SRCLOC_NONE
+ *   #include "logging.h"
+ *
+ * If both BT_LOG_DEF_SRCLOC and BT_LOG_SRCLOC are undefined, then
+ * BT_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) and
+ * BT_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined).
+ */
+#if defined(BT_LOG_SRCLOC)
+       #define _BT_LOG_SRCLOC BT_LOG_SRCLOC
+#elif defined(BT_LOG_DEF_SRCLOC)
+       #define _BT_LOG_SRCLOC BT_LOG_DEF_SRCLOC
+#else
+       #ifdef NDEBUG
+               #define _BT_LOG_SRCLOC BT_LOG_SRCLOC_NONE
+       #else
+               #define _BT_LOG_SRCLOC BT_LOG_SRCLOC_LONG
+       #endif
+#endif
+#if BT_LOG_SRCLOC_LONG == _BT_LOG_SRCLOC
+       #define _BT_LOG_SRCLOC_FUNCTION _BT_LOG_FUNCTION
+#else
+       #define _BT_LOG_SRCLOC_FUNCTION 0
+#endif
+
+/* Censoring provides conditional logging of secret information, also known as
+ * Personally Identifiable Information (PII) or Sensitive Personal Information
+ * (SPI). Censoring can be either enabled (BT_LOG_CENSORED) or disabled
+ * (BT_LOG_UNCENSORED). When censoring is enabled, log statements marked as
+ * "secrets" will be ignored and will have zero overhead (arguments also will
+ * not be evaluated).
+ */
+#define BT_LOG_CENSORED   1
+#define BT_LOG_UNCENSORED 0
+
+/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining
+ * BT_LOG_DEF_CENSORING or BT_LOG_CENSORING. BT_LOG_CENSORING has higer priority
+ * and when defined overrides value provided by BT_LOG_DEF_CENSORING.
+ *
+ * Common practice is to define default censoring with BT_LOG_DEF_CENSORING in
+ * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
+ * project or target:
+ *
+ *   CC_ARGS := -DBT_LOG_DEF_CENSORING=BT_LOG_CENSORED
+ *
+ * And when necessary to override it with BT_LOG_CENSORING in .c/.cpp/.m files
+ * before including bt_log.h (consider doing it only for debug purposes and be
+ * very careful not to push such temporary changes to source control):
+ *
+ *   #define BT_LOG_CENSORING BT_LOG_UNCENSORED
+ *   #include "logging.h"
+ *
+ * If both BT_LOG_DEF_CENSORING and BT_LOG_CENSORING are undefined, then
+ * BT_LOG_CENSORED will be used for release builds (NDEBUG is defined) and
+ * BT_LOG_UNCENSORED otherwise (NDEBUG is not defined).
+ */
+#if defined(BT_LOG_CENSORING)
+       #define _BT_LOG_CENSORING BT_LOG_CENSORING
+#elif defined(BT_LOG_DEF_CENSORING)
+       #define _BT_LOG_CENSORING BT_LOG_DEF_CENSORING
+#else
+       #ifdef NDEBUG
+               #define _BT_LOG_CENSORING BT_LOG_CENSORED
+       #else
+               #define _BT_LOG_CENSORING BT_LOG_UNCENSORED
+       #endif
+#endif
+
+/* Check censoring at compile time. Evaluates to true when censoring is disabled
+ * (i.e. when secrets will be logged). For example:
+ *
+ *   #if BT_LOG_SECRETS
+ *       char ssn[16];
+ *       getSocialSecurityNumber(ssn);
+ *       BT_LOGI("Customer ssn: %s", ssn);
+ *   #endif
+ *
+ * See BT_LOG_SECRET() macro for a more convenient way of guarding single log
+ * statement.
+ */
+#define BT_LOG_SECRETS (BT_LOG_UNCENSORED == _BT_LOG_CENSORING)
+
+/* Static (compile-time) initialization support allows to configure logging
+ * before entering main() function. This mostly useful in C++ where functions
+ * and methods could be called during initialization of global objects. Those
+ * functions and methods could record log messages too and for that reason
+ * static initialization of logging configuration is customizable.
+ *
+ * Macros below allow to specify values to use for initial configuration:
+ * - BT_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none)
+ * - BT_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see
+ *   BT_LOG_MEM_WIDTH in bt_log.c)
+ * - BT_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: stderr or
+ *   platform specific, see BT_LOG_USE_XXX macros in bt_log.c)
+ * - BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level (default: 0 -
+ *   all levals are "turned on")
+ *
+ * For example, in log_config.c:
+ *
+ *   #include "logging.h"
+ *   BT_LOG_DEFINE_TAG_PREFIX = "MyApp";
+ *   BT_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};
+ *   BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_PUT_STD, custom_output_callback, 0};
+ *   BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = BT_LOG_INFO;
+ *
+ * However, to use any of those macros bt_log library must be compiled with
+ * following macros defined:
+ * - to use BT_LOG_DEFINE_TAG_PREFIX define BT_LOG_EXTERN_TAG_PREFIX
+ * - to use BT_LOG_DEFINE_GLOBAL_FORMAT define BT_LOG_EXTERN_GLOBAL_FORMAT
+ * - to use BT_LOG_DEFINE_GLOBAL_OUTPUT define BT_LOG_EXTERN_GLOBAL_OUTPUT
+ * - to use BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define
+ *   BT_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
+ *
+ * When bt_log library compiled with one of BT_LOG_EXTERN_XXX macros defined,
+ * corresponding BT_LOG_DEFINE_XXX macro MUST be used exactly once somewhere.
+ * Otherwise build will fail with link error (undefined symbol).
+ */
+#define BT_LOG_DEFINE_TAG_PREFIX BT_HIDDEN const char *_bt_log_tag_prefix
+#define BT_LOG_DEFINE_GLOBAL_FORMAT BT_HIDDEN bt_log_format _bt_log_global_format
+#define BT_LOG_DEFINE_GLOBAL_OUTPUT BT_HIDDEN bt_log_output _bt_log_global_output
+#define BT_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL BT_HIDDEN int _bt_log_global_output_lvl
+
+/* Pointer to global format options. Direct modification is not allowed. Use
+ * bt_log_set_mem_width() instead. Could be used to initialize bt_log_spec
+ * structure:
+ *
+ *   const bt_log_output g_output = {BT_LOG_PUT_STD, output_callback, 0};
+ *   const bt_log_spec g_spec = {BT_LOG_GLOBAL_FORMAT, &g_output};
+ *   BT_LOGI_AUX(&g_spec, "Hello");
+ */
+#define BT_LOG_GLOBAL_FORMAT ((const bt_log_format *)&_bt_log_global_format)
+
+/* Pointer to global output variable. Direct modification is not allowed. Use
+ * bt_log_set_output_v() or bt_log_set_output_p() instead. Could be used to
+ * initialize bt_log_spec structure:
+ *
+ *   const bt_log_format g_format = {40};
+ *   const bt_log_spec g_spec = {g_format, BT_LOG_GLOBAL_OUTPUT};
+ *   BT_LOGI_AUX(&g_spec, "Hello");
+ */
+#define BT_LOG_GLOBAL_OUTPUT ((const bt_log_output *)&_bt_log_global_output)
+
+/* When defined, all library symbols produced by linker will be prefixed with
+ * provided value. That allows to use bt_log library privately in another
+ * libraries without exposing bt_log symbols in their original form (to avoid
+ * possible conflicts with other libraries / components that also could use
+ * bt_log for logging). Value must be without quotes, for example:
+ *
+ *   CC_ARGS := -DBT_LOG_LIBRARY_PREFIX=my_lib_
+ *
+ * Note, that in this mode BT_LOG_LIBRARY_PREFIX must be defined when building
+ * bt_log library AND it also must be defined to the same value when building
+ * a library that uses it. For example, consider fictional KittyHttp library
+ * that wants to use bt_log for logging. First approach that could be taken is
+ * to add bt_log.h and bt_log.c to the KittyHttp's source code tree directly.
+ * In that case it will be enough just to define BT_LOG_LIBRARY_PREFIX in
+ * KittyHttp's build script:
+ *
+ *   // KittyHttp/CMakeLists.txt
+ *   target_compile_definitions(KittyHttp PRIVATE
+ *                              "BT_LOG_LIBRARY_PREFIX=KittyHttp_")
+ *
+ * If KittyHttp doesn't want to include bt_log source code in its source tree
+ * and wants to build bt_log as a separate library than bt_log library must be
+ * built with BT_LOG_LIBRARY_PREFIX defined to KittyHttp_ AND KittyHttp library
+ * itself also needs to define BT_LOG_LIBRARY_PREFIX to KittyHttp_. It can do
+ * so either in its build script, as in example above, or by providing a
+ * wrapper header that KittyHttp library will need to use instead of bt_log.h:
+ *
+ *   // KittyHttpLogging.h
+ *   #define BT_LOG_LIBRARY_PREFIX KittyHttp_
+ *   #include "logging.h"
+ *
+ * Regardless of the method chosen, the end result is that bt_log symbols will
+ * be prefixed with "KittyHttp_", so if a user of KittyHttp (say DogeBrowser)
+ * also uses bt_log for logging, they will not interferer with each other. Both
+ * will have their own log level, output facility, format options etc.
+ */
+#ifdef BT_LOG_LIBRARY_PREFIX
+       #define _BT_LOG_DECOR__(prefix, name) prefix ## name
+       #define _BT_LOG_DECOR_(prefix, name) _BT_LOG_DECOR__(prefix, name)
+       #define _BT_LOG_DECOR(name) _BT_LOG_DECOR_(BT_LOG_LIBRARY_PREFIX, name)
+
+       #define bt_log_set_tag_prefix _BT_LOG_DECOR(bt_log_set_tag_prefix)
+       #define bt_log_set_mem_width _BT_LOG_DECOR(bt_log_set_mem_width)
+       #define bt_log_set_output_level _BT_LOG_DECOR(bt_log_set_output_level)
+       #define bt_log_set_output_v _BT_LOG_DECOR(bt_log_set_output_v)
+       #define bt_log_set_output_p _BT_LOG_DECOR(bt_log_set_output_p)
+       #define bt_log_out_stderr_callback _BT_LOG_DECOR(bt_log_out_stderr_callback)
+       #define _bt_log_tag_prefix _BT_LOG_DECOR(_bt_log_tag_prefix)
+       #define _bt_log_global_format _BT_LOG_DECOR(_bt_log_global_format)
+       #define _bt_log_global_output _BT_LOG_DECOR(_bt_log_global_output)
+       #define _bt_log_global_output_lvl _BT_LOG_DECOR(_bt_log_global_output_lvl)
+       #define _bt_log_write_d _BT_LOG_DECOR(_bt_log_write_d)
+       #define _bt_log_write_aux_d _BT_LOG_DECOR(_bt_log_write_aux_d)
+       #define _bt_log_write _BT_LOG_DECOR(_bt_log_write)
+       #define _bt_log_write_aux _BT_LOG_DECOR(_bt_log_write_aux)
+       #define _bt_log_write_mem_d _BT_LOG_DECOR(_bt_log_write_mem_d)
+       #define _bt_log_write_mem_aux_d _BT_LOG_DECOR(_bt_log_write_mem_aux_d)
+       #define _bt_log_write_mem _BT_LOG_DECOR(_bt_log_write_mem)
+       #define _bt_log_write_mem_aux _BT_LOG_DECOR(_bt_log_write_mem_aux)
+       #define _bt_log_stderr_spec _BT_LOG_DECOR(_bt_log_stderr_spec)
+#endif
+
+#if defined(__printflike)
+       #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
+               __printflike(str_index, first_to_check)
+#elif defined(__MINGW_PRINTF_FORMAT)
+       #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
+               __attribute__((format(__MINGW_PRINTF_FORMAT, str_index, first_to_check)))
+#elif defined(__GNUC__)
+       #define _BT_LOG_PRINTFLIKE(str_index, first_to_check) \
+               __attribute__((format(__printf__, str_index, first_to_check)))
+#else
+       #define _BT_LOG_PRINTFLIKE(str_index, first_to_check)
+#endif
+
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)
+       #define _BT_LOG_FUNCTION __FUNCTION__
+#else
+       #define _BT_LOG_FUNCTION __func__
+#endif
+
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
+       #define _BT_LOG_INLINE __inline
+       #define _BT_LOG_IF(cond) \
+               __pragma(warning(push)) \
+               __pragma(warning(disable:4127)) \
+               if(cond) \
+               __pragma(warning(pop))
+       #define _BT_LOG_WHILE(cond) \
+               __pragma(warning(push)) \
+               __pragma(warning(disable:4127)) \
+               while(cond) \
+               __pragma(warning(pop))
+#else
+       #define _BT_LOG_INLINE inline
+       #define _BT_LOG_IF(cond) if(cond)
+       #define _BT_LOG_WHILE(cond) while(cond)
+#endif
+#define _BT_LOG_NEVER _BT_LOG_IF(0)
+#define _BT_LOG_ONCE _BT_LOG_WHILE(0)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Set tag prefix. Prefix will be separated from the tag with dot ('.').
+ * Use 0 or empty string to disable (default). Common use is to set it to
+ * the process (or build target) name (e.g. to separate client and server
+ * processes). Function will NOT copy provided prefix string, but will store the
+ * pointer. Hence specified prefix string must remain valid. See
+ * BT_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() function.
+ * See BT_LOG_TAG for more information about tag and tag prefix.
+ */
+void bt_log_set_tag_prefix(const char *const prefix);
+
+/* Set number of bytes per log line in memory (ASCII-HEX) output. Example:
+ *
+ *   I hello.MAIN 4c6f72656d20697073756d20646f6c6f  Lorem ipsum dolo
+ *                |<-          w bytes         ->|  |<-  w chars ->|
+ *
+ * See BT_LOGF_MEM and BT_LOGF_MEM_AUX for more details.
+ */
+void bt_log_set_mem_width(const unsigned w);
+
+/* Set "output" log level. See BT_LOG_LEVEL and BT_LOG_OUTPUT_LEVEL for more
+ * info about log levels.
+ */
+void bt_log_set_output_level(const int lvl);
+
+/* Put mask is a set of flags that define what fields will be added to each
+ * log message. Default value is BT_LOG_PUT_STD and other flags could be used to
+ * alter its behavior. See bt_log_set_output_v() for more details.
+ *
+ * Note about BT_LOG_PUT_SRC: it will be added only in debug builds (NDEBUG is
+ * not defined).
+ */
+enum
+{
+       BT_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */
+       BT_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */
+       BT_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */
+       BT_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */
+       BT_LOG_PUT_STD = 0xffff, /* everything (default) */
+};
+
+typedef struct bt_log_message
+{
+       int lvl; /* Log level of the message */
+       const char *tag; /* Associated tag (without tag prefix) */
+       char *buf; /* Buffer start */
+       char *e; /* Buffer end (last position where EOL with 0 could be written) */
+       char *p; /* Buffer content end (append position) */
+       char *tag_b; /* Prefixed tag start */
+       char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */
+       char *msg_b; /* Message start (expanded format string) */
+}
+bt_log_message;
+
+/* Type of output callback function. It will be called for each log line allowed
+ * by both "current" and "output" log levels ("enabled" and "turned on").
+ * Callback function is allowed to modify content of the buffers pointed by the
+ * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg
+ * is UTF-8 encoded (no BOM mark).
+ */
+typedef void (*bt_log_output_cb)(const bt_log_message *msg, void *arg);
+
+/* Format options. For more details see bt_log_set_mem_width().
+ */
+typedef struct bt_log_format
+{
+       unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */
+}
+bt_log_format;
+
+/* Output facility.
+ */
+typedef struct bt_log_output
+{
+       unsigned mask; /* What to put into log line buffer (see BT_LOG_PUT_XXX) */
+       void *arg; /* User provided output callback argument */
+       bt_log_output_cb callback; /* Output callback function */
+}
+bt_log_output;
+
+/* Set output callback function.
+ *
+ * Mask allows to control what information will be added to the log line buffer
+ * before callback function is invoked. Default mask value is BT_LOG_PUT_STD.
+ */
+void bt_log_set_output_v(const unsigned mask, void *const arg,
+                                                const bt_log_output_cb callback);
+static _BT_LOG_INLINE void bt_log_set_output_p(const bt_log_output *const output)
+{
+       bt_log_set_output_v(output->mask, output->arg, output->callback);
+}
+
+/* Used with _AUX macros and allows to override global format and output
+ * facility. Use BT_LOG_GLOBAL_FORMAT and BT_LOG_GLOBAL_OUTPUT for values from
+ * global configuration. Example:
+ *
+ *   static const bt_log_output module_output = {
+ *       BT_LOG_PUT_STD, 0, custom_output_callback
+ *   };
+ *   static const bt_log_spec module_spec = {
+ *       BT_LOG_GLOBAL_FORMAT, &module_output
+ *   };
+ *   BT_LOGI_AUX(&module_spec, "Position: %ix%i", x, y);
+ *
+ * See BT_LOGF_AUX and BT_LOGF_MEM_AUX for details.
+ */
+typedef struct bt_log_spec
+{
+       const bt_log_format *format;
+       const bt_log_output *output;
+}
+bt_log_spec;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Execute log statement if condition is true. Example:
+ *
+ *   BT_LOG_IF(1 < 2, BT_LOGI("Log this"));
+ *   BT_LOG_IF(1 > 2, BT_LOGI("Don't log this"));
+ *
+ * Keep in mind though, that if condition can't be evaluated at compile time,
+ * then it will be evaluated at run time. This will increase exectuable size
+ * and can have noticeable performance overhead. Try to limit conditions to
+ * expressions that can be evaluated at compile time.
+ */
+#define BT_LOG_IF(cond, f) do { _BT_LOG_IF((cond)) { f; } } _BT_LOG_ONCE
+
+/* Mark log statement as "secret". Log statements that are marked as secrets
+ * will NOT be executed when censoring is enabled (see BT_LOG_CENSORED).
+ * Example:
+ *
+ *   BT_LOG_SECRET(BT_LOGI("Credit card: %s", credit_card));
+ *   BT_LOG_SECRET(BT_LOGD_MEM(cipher, cipher_sz, "Cipher bytes:"));
+ */
+#define BT_LOG_SECRET(f) BT_LOG_IF(BT_LOG_SECRETS, f)
+
+/* Check "current" log level at compile time (ignoring "output" log level).
+ * Evaluates to true when specified log level is enabled. For example:
+ *
+ *   #if BT_LOG_ENABLED_DEBUG
+ *       const char *const g_enum_strings[] = {
+ *           "enum_value_0", "enum_value_1", "enum_value_2"
+ *       };
+ *   #endif
+ *   // ...
+ *   #if BT_LOG_ENABLED_DEBUG
+ *       BT_LOGD("enum value: %s", g_enum_strings[v]);
+ *   #endif
+ *
+ * See BT_LOG_LEVEL for details.
+ */
+#define BT_LOG_ENABLED(lvl)     ((lvl) >= _BT_LOG_LEVEL)
+#define BT_LOG_ENABLED_VERBOSE  BT_LOG_ENABLED(BT_LOG_VERBOSE)
+#define BT_LOG_ENABLED_DEBUG    BT_LOG_ENABLED(BT_LOG_DEBUG)
+#define BT_LOG_ENABLED_INFO     BT_LOG_ENABLED(BT_LOG_INFO)
+#define BT_LOG_ENABLED_WARN     BT_LOG_ENABLED(BT_LOG_WARN)
+#define BT_LOG_ENABLED_ERROR    BT_LOG_ENABLED(BT_LOG_ERROR)
+#define BT_LOG_ENABLED_FATAL    BT_LOG_ENABLED(BT_LOG_FATAL)
+
+/* Check "output" log level at run time (taking into account "current" log
+ * level as well). Evaluates to true when specified log level is turned on AND
+ * enabled. For example:
+ *
+ *   if (BT_LOG_ON_DEBUG)
+ *   {
+ *       char hash[65];
+ *       sha256(data_ptr, data_sz, hash);
+ *       BT_LOGD("data: len=%u, sha256=%s", data_sz, hash);
+ *   }
+ *
+ * See BT_LOG_OUTPUT_LEVEL for details.
+ */
+#define BT_LOG_ON(lvl) \
+               (BT_LOG_ENABLED((lvl)) && (lvl) >= _BT_LOG_OUTPUT_LEVEL)
+#define BT_LOG_ON_VERBOSE   BT_LOG_ON(BT_LOG_VERBOSE)
+#define BT_LOG_ON_DEBUG     BT_LOG_ON(BT_LOG_DEBUG)
+#define BT_LOG_ON_INFO      BT_LOG_ON(BT_LOG_INFO)
+#define BT_LOG_ON_WARN      BT_LOG_ON(BT_LOG_WARN)
+#define BT_LOG_ON_ERROR     BT_LOG_ON(BT_LOG_ERROR)
+#define BT_LOG_ON_FATAL     BT_LOG_ON(BT_LOG_FATAL)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char *_bt_log_tag_prefix;
+extern bt_log_format _bt_log_global_format;
+extern bt_log_output _bt_log_global_output;
+extern int _bt_log_global_output_lvl;
+extern const bt_log_spec _bt_log_stderr_spec;
+
+BT_HIDDEN
+void _bt_log_write_d(
+               const char *const func, const char *const file, const unsigned line,
+               const int lvl, const char *const tag,
+               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(6, 7);
+
+BT_HIDDEN
+void _bt_log_write_aux_d(
+               const char *const func, const char *const file, const unsigned line,
+               const bt_log_spec *const log, const int lvl, const char *const tag,
+               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(7, 8);
+
+BT_HIDDEN
+void _bt_log_write(
+               const int lvl, const char *const tag,
+               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(3, 4);
+
+BT_HIDDEN
+void _bt_log_write_aux(
+               const bt_log_spec *const log, const int lvl, const char *const tag,
+               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(4, 5);
+
+BT_HIDDEN
+void _bt_log_write_mem_d(
+               const char *const func, const char *const file, const unsigned line,
+               const int lvl, const char *const tag,
+               const void *const d, const unsigned d_sz,
+               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(8, 9);
+
+BT_HIDDEN
+void _bt_log_write_mem_aux_d(
+               const char *const func, const char *const file, const unsigned line,
+               const bt_log_spec *const log, const int lvl, const char *const tag,
+               const void *const d, const unsigned d_sz,
+               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(9, 10);
+
+BT_HIDDEN
+void _bt_log_write_mem(
+               const int lvl, const char *const tag,
+               const void *const d, const unsigned d_sz,
+               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(5, 6);
+
+BT_HIDDEN
+void _bt_log_write_mem_aux(
+               const bt_log_spec *const log, const int lvl, const char *const tag,
+               const void *const d, const unsigned d_sz,
+               const char *const fmt, ...) _BT_LOG_PRINTFLIKE(6, 7);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Message logging macros:
+ * - BT_LOGV("format string", args, ...)
+ * - BT_LOGD("format string", args, ...)
+ * - BT_LOGI("format string", args, ...)
+ * - BT_LOGW("format string", args, ...)
+ * - BT_LOGE("format string", args, ...)
+ * - BT_LOGF("format string", args, ...)
+ *
+ * Message and error string (errno) logging macros:
+ * - BT_LOGV_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGD_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGI_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGW_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGE_ERRNO("initial message", "format string", args, ...)
+ * - BT_LOGF_ERRNO("initial message", "format string", args, ...)
+ *
+ * Memory logging macros:
+ * - BT_LOGV_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGD_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGI_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGW_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGE_MEM(data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGF_MEM(data_ptr, data_sz, "format string", args, ...)
+ *
+ * Auxiliary logging macros:
+ * - BT_LOGV_AUX(&log_instance, "format string", args, ...)
+ * - BT_LOGD_AUX(&log_instance, "format string", args, ...)
+ * - BT_LOGI_AUX(&log_instance, "format string", args, ...)
+ * - BT_LOGW_AUX(&log_instance, "format string", args, ...)
+ * - BT_LOGE_AUX(&log_instance, "format string", args, ...)
+ * - BT_LOGF_AUX(&log_instance, "format string", args, ...)
+ *
+ * Auxiliary memory logging macros:
+ * - BT_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
+ *
+ * Preformatted string logging macros:
+ * - BT_LOGV_STR("preformatted string");
+ * - BT_LOGD_STR("preformatted string");
+ * - BT_LOGI_STR("preformatted string");
+ * - BT_LOGW_STR("preformatted string");
+ * - BT_LOGE_STR("preformatted string");
+ * - BT_LOGF_STR("preformatted string");
+ *
+ * Explicit log level and tag macros:
+ * - BT_LOG_WRITE(level, tag, "format string", args, ...)
+ * - BT_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string", args, ...)
+ * - BT_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args, ...)
+ * - BT_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz,
+ *                        "format string", args, ...)
+ *
+ * Format string follows printf() conventions. Both data_ptr and data_sz could
+ * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments
+ * match format specifiers in format string.
+ *
+ * Library assuming UTF-8 encoding for all strings (char *), including format
+ * string itself.
+ */
+#if BT_LOG_SRCLOC_NONE == _BT_LOG_SRCLOC
+       #define BT_LOG_WRITE(lvl, tag, ...) \
+                       do { \
+                               if (BT_LOG_ON(lvl)) \
+                                       _bt_log_write(lvl, tag, __VA_ARGS__); \
+                       } _BT_LOG_ONCE
+       #define BT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
+                       do { \
+                               if (BT_LOG_ON(lvl)) \
+                                       _bt_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \
+                       } _BT_LOG_ONCE
+       #define BT_LOG_WRITE_AUX(log, lvl, tag, ...) \
+                       do { \
+                               if (BT_LOG_ON(lvl)) \
+                                       _bt_log_write_aux(log, lvl, tag, __VA_ARGS__); \
+                       } _BT_LOG_ONCE
+       #define BT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
+                       do { \
+                               if (BT_LOG_ON(lvl)) \
+                                       _bt_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \
+                       } _BT_LOG_ONCE
+#else
+       #define BT_LOG_WRITE(lvl, tag, ...) \
+                       do { \
+                               if (BT_LOG_ON(lvl)) \
+                                       _bt_log_write_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
+                                                       lvl, tag, __VA_ARGS__); \
+                       } _BT_LOG_ONCE
+       #define BT_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
+                       do { \
+                               if (BT_LOG_ON(lvl)) \
+                                       _bt_log_write_mem_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
+                                                       lvl, tag, d, d_sz, __VA_ARGS__); \
+                       } _BT_LOG_ONCE
+       #define BT_LOG_WRITE_AUX(log, lvl, tag, ...) \
+                       do { \
+                               if (BT_LOG_ON(lvl)) \
+                                       _bt_log_write_aux_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
+                                                       log, lvl, tag, __VA_ARGS__); \
+                       } _BT_LOG_ONCE
+       #define BT_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
+                       do { \
+                               if (BT_LOG_ON(lvl)) \
+                                       _bt_log_write_mem_aux_d(_BT_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
+                                                       log, lvl, tag, d, d_sz, __VA_ARGS__); \
+                       } _BT_LOG_ONCE
+#endif
+
+#define BT_LOG_WRITE_ERRNO(lvl, tag, _msg, _fmt, args...) \
+               do { \
+                       const char *error_str; \
+                       error_str = g_strerror(errno); \
+                       BT_LOG_WRITE(lvl, tag, _msg ": %s" _fmt, error_str, ## args); \
+               } _BT_LOG_ONCE
+
+static _BT_LOG_INLINE void _bt_log_unused(const int dummy, ...) {(void)dummy;}
+
+#define _BT_LOG_UNUSED(...) \
+               do { _BT_LOG_NEVER _bt_log_unused(0, __VA_ARGS__); } _BT_LOG_ONCE
+
+#if BT_LOG_ENABLED_VERBOSE
+       #define BT_LOGV(...) \
+                       BT_LOG_WRITE(BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGV_ERRNO(...) \
+                       BT_LOG_WRITE_ERRNO(BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGV_AUX(log, ...) \
+                       BT_LOG_WRITE_AUX(log, BT_LOG_VERBOSE, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGV_MEM(d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM(BT_LOG_VERBOSE, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+       #define BT_LOGV_MEM_AUX(log, d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM(log, BT_LOG_VERBOSE, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+#else
+       #define BT_LOGV(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGV_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGV_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGV_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if BT_LOG_ENABLED_DEBUG
+       #define BT_LOGD(...) \
+                       BT_LOG_WRITE(BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGD_ERRNO(...) \
+                       BT_LOG_WRITE_ERRNO(BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGD_AUX(log, ...) \
+                       BT_LOG_WRITE_AUX(log, BT_LOG_DEBUG, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGD_MEM(d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM(BT_LOG_DEBUG, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+       #define BT_LOGD_MEM_AUX(log, d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_DEBUG, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+#else
+       #define BT_LOGD(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGD_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGD_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGD_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if BT_LOG_ENABLED_INFO
+       #define BT_LOGI(...) \
+                       BT_LOG_WRITE(BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGI_ERRNO(...) \
+                       BT_LOG_WRITE_ERRNO(BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGI_AUX(log, ...) \
+                       BT_LOG_WRITE_AUX(log, BT_LOG_INFO, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGI_MEM(d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM(BT_LOG_INFO, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+       #define BT_LOGI_MEM_AUX(log, d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_INFO, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+#else
+       #define BT_LOGI(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGI_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGI_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGI_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if BT_LOG_ENABLED_WARN
+       #define BT_LOGW(...) \
+                       BT_LOG_WRITE(BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGW_ERRNO(...) \
+                       BT_LOG_WRITE_ERRNO(BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGW_AUX(log, ...) \
+                       BT_LOG_WRITE_AUX(log, BT_LOG_WARN, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGW_MEM(d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM(BT_LOG_WARN, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+       #define BT_LOGW_MEM_AUX(log, d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_WARN, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+#else
+       #define BT_LOGW(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGW_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGW_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGW_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if BT_LOG_ENABLED_ERROR
+       #define BT_LOGE(...) \
+                       BT_LOG_WRITE(BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGE_ERRNO(...) \
+                       BT_LOG_WRITE_ERRNO(BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGE_AUX(log, ...) \
+                       BT_LOG_WRITE_AUX(log, BT_LOG_ERROR, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGE_MEM(d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM(BT_LOG_ERROR, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+       #define BT_LOGE_MEM_AUX(log, d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_ERROR, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+#else
+       #define BT_LOGE(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGE_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGE_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGE_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#if BT_LOG_ENABLED_FATAL
+       #define BT_LOGF(...) \
+                       BT_LOG_WRITE(BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGF_ERRNO(...) \
+                       BT_LOG_WRITE_ERRNO(BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGF_AUX(log, ...) \
+                       BT_LOG_WRITE_AUX(log, BT_LOG_FATAL, _BT_LOG_TAG, __VA_ARGS__)
+       #define BT_LOGF_MEM(d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM(BT_LOG_FATAL, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+       #define BT_LOGF_MEM_AUX(log, d, d_sz, ...) \
+                       BT_LOG_WRITE_MEM_AUX(log, BT_LOG_FATAL, _BT_LOG_TAG, d, d_sz, __VA_ARGS__)
+#else
+       #define BT_LOGF(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGF_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGF_MEM(...) _BT_LOG_UNUSED(__VA_ARGS__)
+       #define BT_LOGF_MEM_AUX(...) _BT_LOG_UNUSED(__VA_ARGS__)
+#endif
+
+#define BT_LOGV_STR(s) BT_LOGV("%s", (s))
+#define BT_LOGD_STR(s) BT_LOGD("%s", (s))
+#define BT_LOGI_STR(s) BT_LOGI("%s", (s))
+#define BT_LOGW_STR(s) BT_LOGW("%s", (s))
+#define BT_LOGE_STR(s) BT_LOGE("%s", (s))
+#define BT_LOGF_STR(s) BT_LOGF("%s", (s))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Output to standard error stream. Library uses it by default, though in few
+ * cases it could be necessary to specify it explicitly. For example, when
+ * bt_log library is compiled with BT_LOG_EXTERN_GLOBAL_OUTPUT, application must
+ * define and initialize global output variable:
+ *
+ *   BT_LOG_DEFINE_GLOBAL_OUTPUT = {BT_LOG_OUT_STDERR};
+ *
+ * Another example is when using custom output, stderr could be used as a
+ * fallback when custom output facility failed to initialize:
+ *
+ *   bt_log_set_output_v(BT_LOG_OUT_STDERR);
+ */
+enum { BT_LOG_OUT_STDERR_MASK = BT_LOG_PUT_STD };
+
+BT_HIDDEN
+void bt_log_out_stderr_callback(const bt_log_message *const msg, void *arg);
+#define BT_LOG_OUT_STDERR BT_LOG_OUT_STDERR_MASK, 0, bt_log_out_stderr_callback
+
+/* Predefined spec for stderr. Uses global format options (BT_LOG_GLOBAL_FORMAT)
+ * and BT_LOG_OUT_STDERR. Could be used to force output to stderr for a
+ * particular message. Example:
+ *
+ *   f = fopen("foo.log", "w");
+ *   if (!f)
+ *       BT_LOGE_AUX(BT_LOG_STDERR, "Failed to open log file");
+ */
+#define BT_LOG_STDERR (&_bt_log_stderr_spec)
+
+static inline
+int bt_log_get_level_from_env(const char *var)
+{
+       const char *varval = getenv(var);
+       int level = BT_LOG_NONE;
+
+       if (!varval) {
+               goto end;
+       }
+
+       if (strcmp(varval, "VERBOSE") == 0 ||
+                       strcmp(varval, "V") == 0) {
+               level = BT_LOG_VERBOSE;
+       } else if (strcmp(varval, "DEBUG") == 0 ||
+                       strcmp(varval, "D") == 0) {
+               level = BT_LOG_DEBUG;
+       } else if (strcmp(varval, "INFO") == 0 ||
+                       strcmp(varval, "I") == 0) {
+               level = BT_LOG_INFO;
+       } else if (strcmp(varval, "WARN") == 0 ||
+                       strcmp(varval, "WARNING") == 0 ||
+                       strcmp(varval, "W") == 0) {
+               level = BT_LOG_WARN;
+       } else if (strcmp(varval, "ERROR") == 0 ||
+                       strcmp(varval, "E") == 0) {
+               level = BT_LOG_ERROR;
+       } else if (strcmp(varval, "FATAL") == 0 ||
+                       strcmp(varval, "F") == 0) {
+               level = BT_LOG_FATAL;
+       } else if (strcmp(varval, "NONE") == 0 ||
+                       strcmp(varval, "N") == 0) {
+               level = BT_LOG_NONE;
+       } else {
+               /* Should we warn here? How? */
+       }
+
+end:
+       return level;
+}
+
+#define BT_LOG_LEVEL_EXTERN_SYMBOL(_level_sym)                         \
+       extern int _level_sym
+
+#define BT_LOG_INIT_LOG_LEVEL(_level_sym, _env_var)                    \
+       BT_HIDDEN int _level_sym = BT_LOG_NONE;                         \
+       static                                                          \
+       void __attribute__((constructor)) _bt_log_level_ctor(void)      \
+       {                                                               \
+               _level_sym = bt_log_get_level_from_env(_env_var);       \
+       }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BABELTRACE_LOGGING_INTERNAL_H */
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
new file mode 100644 (file)
index 0000000..9b23e3c
--- /dev/null
@@ -0,0 +1,7 @@
+SUBDIRS = utils text ctf
+
+if ENABLE_DEBUG_INFO
+SUBDIRS += lttng-utils
+endif
+
+noinst_HEADERS = plugins-common.h
diff --git a/src/plugins/ctf/Makefile.am b/src/plugins/ctf/Makefile.am
new file mode 100644 (file)
index 0000000..bf96269
--- /dev/null
@@ -0,0 +1,30 @@
+SUBDIRS = common \
+       fs-src \
+       fs-sink \
+       lttng-live
+
+noinst_HEADERS = print.h
+
+plugindir = "$(PLUGINSDIR)"
+plugin_LTLIBRARIES = babeltrace-plugin-ctf.la
+
+# ctf plugin
+babeltrace_plugin_ctf_la_SOURCES = plugin.c
+
+babeltrace_plugin_ctf_la_LDFLAGS = \
+       $(LT_NO_UNDEFINED) \
+       -avoid-version -module
+
+babeltrace_plugin_ctf_la_LIBADD = \
+       common/libbabeltrace2-plugin-ctf-common.la \
+       fs-sink/libbabeltrace2-plugin-ctf-fs-sink.la \
+       fs-src/libbabeltrace2-plugin-ctf-fs-src.la \
+       lttng-live/libbabeltrace2-plugin-ctf-lttng-live.la
+
+if !ENABLE_BUILT_IN_PLUGINS
+babeltrace_plugin_ctf_la_LIBADD += \
+       $(top_builddir)/src/lib/libbabeltrace2.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/ctfser/libbabeltrace2-ctfser.la
+endif
diff --git a/src/plugins/ctf/common/Makefile.am b/src/plugins/ctf/common/Makefile.am
new file mode 100644 (file)
index 0000000..055355b
--- /dev/null
@@ -0,0 +1,10 @@
+SUBDIRS = metadata bfcr msg-iter utils
+
+noinst_LTLIBRARIES = libbabeltrace2-plugin-ctf-common.la
+libbabeltrace2_plugin_ctf_common_la_SOURCES = print.h
+libbabeltrace2_plugin_ctf_common_la_LIBADD =           \
+       $(builddir)/metadata/libctf-parser.la           \
+       $(builddir)/metadata/libctf-ast.la              \
+       $(builddir)/bfcr/libctf-bfcr.la                 \
+       $(builddir)/msg-iter/libctf-msg-iter.la \
+       $(builddir)/utils/libctf-utils.la
diff --git a/src/plugins/ctf/common/bfcr/Makefile.am b/src/plugins/ctf/common/bfcr/Makefile.am
new file mode 100644 (file)
index 0000000..d0dd8c6
--- /dev/null
@@ -0,0 +1,6 @@
+noinst_LTLIBRARIES = libctf-bfcr.la
+libctf_bfcr_la_SOURCES = \
+       bfcr.c \
+       bfcr.h \
+       logging.c \
+       logging.h
diff --git a/src/plugins/ctf/common/bfcr/bfcr.c b/src/plugins/ctf/common/bfcr/bfcr.c
new file mode 100644 (file)
index 0000000..2bdd961
--- /dev/null
@@ -0,0 +1,1344 @@
+/*
+ * Babeltrace - CTF binary field class reader (BFCR)
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-BFCR"
+#include "logging.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "common/assert.h"
+#include <string.h>
+#include "compat/bitfield.h"
+#include "common/common.h"
+#include <babeltrace2/babeltrace.h>
+#include "common/align.h"
+#include <glib.h>
+
+#include "bfcr.h"
+#include "../metadata/ctf-meta.h"
+
+#define DIV8(_x)                       ((_x) >> 3)
+#define BYTES_TO_BITS(_x)              ((_x) * 8)
+#define BITS_TO_BYTES_FLOOR(_x)                DIV8(_x)
+#define BITS_TO_BYTES_CEIL(_x)         DIV8((_x) + 7)
+#define IN_BYTE_OFFSET(_at)            ((_at) & 7)
+
+/* A visit stack entry */
+struct stack_entry {
+       /*
+        * Current class of base field, one of:
+        *
+        *   * Structure
+        *   * Array
+        *   * Sequence
+        *   * Variant
+        */
+       struct ctf_field_class *base_class;
+
+       /* Length of base field (always 1 for a variant class) */
+       int64_t base_len;
+
+       /* Index of next field to read */
+       int64_t index;
+};
+
+/* Visit stack */
+struct stack {
+       /* Entries (struct stack_entry) */
+       GArray *entries;
+
+       /* Number of active entries */
+       size_t size;
+};
+
+/* Reading states */
+enum bfcr_state {
+       BFCR_STATE_NEXT_FIELD,
+       BFCR_STATE_ALIGN_BASIC,
+       BFCR_STATE_ALIGN_COMPOUND,
+       BFCR_STATE_READ_BASIC_BEGIN,
+       BFCR_STATE_READ_BASIC_CONTINUE,
+       BFCR_STATE_DONE,
+};
+
+/* Binary class reader */
+struct bt_bfcr {
+       /* Bisit stack */
+       struct stack *stack;
+
+       /* Current basic field class */
+       struct ctf_field_class *cur_basic_field_class;
+
+       /* Current state */
+       enum bfcr_state state;
+
+       /*
+        * Last basic field class's byte order.
+        *
+        * This is used to detect errors since two contiguous basic
+        * classes for which the common boundary is not the boundary of
+        * a byte cannot have different byte orders.
+        *
+        * This is set to -1 on reset and when the last basic field class
+        * was a string class.
+        */
+       enum ctf_byte_order last_bo;
+
+       /* Current byte order (copied to last_bo after a successful read) */
+       enum ctf_byte_order cur_bo;
+
+       /* Stitch buffer infos */
+       struct {
+               /* Stitch buffer */
+               uint8_t buf[16];
+
+               /* Offset, within stitch buffer, of first bit */
+               size_t offset;
+
+               /* Length (bits) of data in stitch buffer from offset */
+               size_t at;
+       } stitch;
+
+       /* User buffer infos */
+       struct {
+               /* Address */
+               const uint8_t *addr;
+
+               /* Offset of data from address (bits) */
+               size_t offset;
+
+               /* Current position from offset (bits) */
+               size_t at;
+
+               /* Offset of offset within whole packet (bits) */
+               size_t packet_offset;
+
+               /* Data size in buffer (bits) */
+               size_t sz;
+
+               /* Buffer size (bytes) */
+               size_t buf_sz;
+       } buf;
+
+       /* User stuff */
+       struct {
+               /* Callback functions */
+               struct bt_bfcr_cbs cbs;
+
+               /* Private data */
+               void *data;
+       } user;
+};
+
+static inline
+const char *bfcr_state_string(enum bfcr_state state)
+{
+       switch (state) {
+       case BFCR_STATE_NEXT_FIELD:
+               return "BFCR_STATE_NEXT_FIELD";
+       case BFCR_STATE_ALIGN_BASIC:
+               return "BFCR_STATE_ALIGN_BASIC";
+       case BFCR_STATE_ALIGN_COMPOUND:
+               return "BFCR_STATE_ALIGN_COMPOUND";
+       case BFCR_STATE_READ_BASIC_BEGIN:
+               return "BFCR_STATE_READ_BASIC_BEGIN";
+       case BFCR_STATE_READ_BASIC_CONTINUE:
+               return "BFCR_STATE_READ_BASIC_CONTINUE";
+       case BFCR_STATE_DONE:
+               return "BFCR_STATE_DONE";
+       default:
+               return "(unknown)";
+       }
+}
+
+static
+struct stack *stack_new(void)
+{
+       struct stack *stack = NULL;
+
+       stack = g_new0(struct stack, 1);
+       if (!stack) {
+               BT_LOGE_STR("Failed to allocate one stack.");
+               goto error;
+       }
+
+       stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
+       if (!stack->entries) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
+       }
+
+       BT_LOGD("Created stack: addr=%p", stack);
+       return stack;
+
+error:
+       g_free(stack);
+       return NULL;
+}
+
+static
+void stack_destroy(struct stack *stack)
+{
+       if (!stack) {
+               return;
+       }
+
+       BT_LOGD("Destroying stack: addr=%p", stack);
+
+       if (stack->entries) {
+               g_array_free(stack->entries, TRUE);
+       }
+
+       g_free(stack);
+}
+
+static
+int stack_push(struct stack *stack, struct ctf_field_class *base_class,
+       size_t base_len)
+{
+       struct stack_entry *entry;
+
+       BT_ASSERT(stack);
+       BT_ASSERT(base_class);
+       BT_LOGV("Pushing field class on stack: stack-addr=%p, "
+               "fc-addr=%p, fc-type=%d, base-length=%zu, "
+               "stack-size-before=%zu, stack-size-after=%zu",
+               stack, base_class, base_class->type,
+               base_len, stack->size, stack->size + 1);
+
+       if (stack->entries->len == stack->size) {
+               g_array_set_size(stack->entries, stack->size + 1);
+       }
+
+       entry = &g_array_index(stack->entries, struct stack_entry, stack->size);
+       entry->base_class = base_class;
+       entry->base_len = base_len;
+       entry->index = 0;
+       stack->size++;
+       return 0;
+}
+
+static inline
+int64_t get_compound_field_class_length(struct bt_bfcr *bfcr,
+               struct ctf_field_class *fc)
+{
+       int64_t length;
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               length = (int64_t) struct_fc->members->len;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               /* Variant field classes always "contain" a single class */
+               length = 1;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       {
+               struct ctf_field_class_array *array_fc = (void *) fc;
+
+               length = (int64_t) array_fc->length;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+               length = bfcr->user.cbs.query.get_sequence_length(fc,
+                       bfcr->user.data);
+               break;
+       default:
+               abort();
+       }
+
+       return length;
+}
+
+static
+int stack_push_with_len(struct bt_bfcr *bfcr, struct ctf_field_class *base_class)
+{
+       int ret;
+       int64_t length = get_compound_field_class_length(bfcr, base_class);
+
+       if (length < 0) {
+               BT_LOGW("Cannot get compound field class's field count: "
+                       "bfcr-addr=%p, fc-addr=%p, fc-type=%d",
+                       bfcr, base_class, base_class->type);
+               ret = BT_BFCR_STATUS_ERROR;
+               goto end;
+       }
+
+       ret = stack_push(bfcr->stack, base_class, (size_t) length);
+
+end:
+       return ret;
+}
+
+static inline
+unsigned int stack_size(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       return stack->size;
+}
+
+static
+void stack_pop(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       BT_ASSERT(stack_size(stack));
+       BT_LOGV("Popping from stack: "
+               "stack-addr=%p, stack-size-before=%u, stack-size-after=%u",
+               stack, stack->entries->len, stack->entries->len - 1);
+       stack->size--;
+}
+
+static inline
+bool stack_empty(struct stack *stack)
+{
+       return stack_size(stack) == 0;
+}
+
+static
+void stack_clear(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       stack->size = 0;
+}
+
+static inline
+struct stack_entry *stack_top(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       BT_ASSERT(stack_size(stack));
+       return &g_array_index(stack->entries, struct stack_entry,
+               stack->size - 1);
+}
+
+static inline
+size_t available_bits(struct bt_bfcr *bfcr)
+{
+       return bfcr->buf.sz - bfcr->buf.at;
+}
+
+static inline
+void consume_bits(struct bt_bfcr *bfcr, size_t incr)
+{
+       BT_LOGV("Advancing cursor: bfcr-addr=%p, cur-before=%zu, cur-after=%zu",
+               bfcr, bfcr->buf.at, bfcr->buf.at + incr);
+       bfcr->buf.at += incr;
+}
+
+static inline
+bool has_enough_bits(struct bt_bfcr *bfcr, size_t sz)
+{
+       return available_bits(bfcr) >= sz;
+}
+
+static inline
+bool at_least_one_bit_left(struct bt_bfcr *bfcr)
+{
+       return has_enough_bits(bfcr, 1);
+}
+
+static inline
+size_t packet_at(struct bt_bfcr *bfcr)
+{
+       return bfcr->buf.packet_offset + bfcr->buf.at;
+}
+
+static inline
+size_t buf_at_from_addr(struct bt_bfcr *bfcr)
+{
+       /*
+        * Considering this:
+        *
+        *     ====== offset ===== (17)
+        *
+        *     xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
+        *     ^
+        *     addr (0)           ==== at ==== (12)
+        *
+        * We want this:
+        *
+        *     =============================== (29)
+        */
+       return bfcr->buf.offset + bfcr->buf.at;
+}
+
+static
+void stitch_reset(struct bt_bfcr *bfcr)
+{
+       bfcr->stitch.offset = 0;
+       bfcr->stitch.at = 0;
+}
+
+static inline
+size_t stitch_at_from_addr(struct bt_bfcr *bfcr)
+{
+       return bfcr->stitch.offset + bfcr->stitch.at;
+}
+
+static
+void stitch_append_from_buf(struct bt_bfcr *bfcr, size_t sz)
+{
+       size_t stitch_byte_at;
+       size_t buf_byte_at;
+       size_t nb_bytes;
+
+       if (sz == 0) {
+               return;
+       }
+
+       stitch_byte_at =
+               BITS_TO_BYTES_FLOOR(stitch_at_from_addr(bfcr));
+       buf_byte_at = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
+       nb_bytes = BITS_TO_BYTES_CEIL(sz);
+       BT_ASSERT(nb_bytes > 0);
+       BT_ASSERT(bfcr->buf.addr);
+       memcpy(&bfcr->stitch.buf[stitch_byte_at], &bfcr->buf.addr[buf_byte_at],
+               nb_bytes);
+       bfcr->stitch.at += sz;
+       consume_bits(bfcr, sz);
+}
+
+static
+void stitch_append_from_remaining_buf(struct bt_bfcr *bfcr)
+{
+       stitch_append_from_buf(bfcr, available_bits(bfcr));
+}
+
+static
+void stitch_set_from_remaining_buf(struct bt_bfcr *bfcr)
+{
+       stitch_reset(bfcr);
+       bfcr->stitch.offset = IN_BYTE_OFFSET(buf_at_from_addr(bfcr));
+       stitch_append_from_remaining_buf(bfcr);
+}
+
+static inline
+void read_unsigned_bitfield(const uint8_t *buf, size_t at,
+               unsigned int field_size, enum ctf_byte_order bo,
+               uint64_t *v)
+{
+       switch (bo) {
+       case CTF_BYTE_ORDER_BIG:
+               bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
+               break;
+       case CTF_BYTE_ORDER_LITTLE:
+               bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
+               break;
+       default:
+               abort();
+       }
+
+       BT_LOGV("Read unsigned bit array: cur=%zu, size=%u, "
+               "bo=%d, val=%" PRIu64, at, field_size, bo, *v);
+}
+
+static inline
+void read_signed_bitfield(const uint8_t *buf, size_t at,
+               unsigned int field_size, enum ctf_byte_order bo, int64_t *v)
+{
+       switch (bo) {
+       case CTF_BYTE_ORDER_BIG:
+               bt_bitfield_read_be(buf, uint8_t, at, field_size, v);
+               break;
+       case CTF_BYTE_ORDER_LITTLE:
+               bt_bitfield_read_le(buf, uint8_t, at, field_size, v);
+               break;
+       default:
+               abort();
+       }
+
+       BT_LOGV("Read signed bit array: cur=%zu, size=%u, "
+               "bo=%d, val=%" PRId64, at, field_size, bo, *v);
+}
+
+typedef enum bt_bfcr_status (* read_basic_and_call_cb_t)(struct bt_bfcr *,
+               const uint8_t *, size_t);
+
+static inline
+enum bt_bfcr_status validate_contiguous_bo(struct bt_bfcr *bfcr,
+               enum ctf_byte_order next_bo)
+{
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+
+       /* Always valid when at a byte boundary */
+       if (packet_at(bfcr) % 8 == 0) {
+               goto end;
+       }
+
+       /* Always valid if last byte order is unknown */
+       if (bfcr->last_bo == -1) {
+               goto end;
+       }
+
+       /* Always valid if next byte order is unknown */
+       if (next_bo == -1) {
+               goto end;
+       }
+
+       /* Make sure last byte order is compatible with the next byte order */
+       switch (bfcr->last_bo) {
+       case CTF_BYTE_ORDER_BIG:
+               if (next_bo != CTF_BYTE_ORDER_BIG) {
+                       status = BT_BFCR_STATUS_ERROR;
+               }
+               break;
+       case CTF_BYTE_ORDER_LITTLE:
+               if (next_bo != CTF_BYTE_ORDER_LITTLE) {
+                       status = BT_BFCR_STATUS_ERROR;
+               }
+               break;
+       default:
+               status = BT_BFCR_STATUS_ERROR;
+       }
+
+end:
+       if (status < 0) {
+               BT_LOGW("Cannot read bit array: two different byte orders not at a byte boundary: "
+                       "bfcr-addr=%p, last-bo=%d, next-bo=%d",
+                       bfcr, bfcr->last_bo, next_bo);
+       }
+
+       return status;
+}
+
+static
+enum bt_bfcr_status read_basic_float_and_call_cb(struct bt_bfcr *bfcr,
+               const uint8_t *buf, size_t at)
+{
+       double dblval;
+       unsigned int field_size;
+       enum ctf_byte_order bo;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       struct ctf_field_class_float *fc = (void *) bfcr->cur_basic_field_class;
+
+       BT_ASSERT(fc);
+       field_size = fc->base.size;
+       bo = fc->base.byte_order;
+       bfcr->cur_bo = bo;
+
+       switch (field_size) {
+       case 32:
+       {
+               uint64_t v;
+               union {
+                       uint32_t u;
+                       float f;
+               } f32;
+
+               read_unsigned_bitfield(buf, at, field_size, bo, &v);
+               f32.u = (uint32_t) v;
+               dblval = (double) f32.f;
+               break;
+       }
+       case 64:
+       {
+               union {
+                       uint64_t u;
+                       double d;
+               } f64;
+
+               read_unsigned_bitfield(buf, at, field_size, bo, &f64.u);
+               dblval = f64.d;
+               break;
+       }
+       default:
+               /* Only 32-bit and 64-bit fields are supported currently */
+               abort();
+       }
+
+       BT_LOGV("Read floating point number value: bfcr=%p, cur=%zu, val=%f",
+               bfcr, at, dblval);
+
+       if (bfcr->user.cbs.classes.floating_point) {
+               BT_LOGV("Calling user function (floating point number).");
+               status = bfcr->user.cbs.classes.floating_point(dblval,
+                       bfcr->cur_basic_field_class, bfcr->user.data);
+               BT_LOGV("User function returned: status=%s",
+                       bt_bfcr_status_string(status));
+               if (status != BT_BFCR_STATUS_OK) {
+                       BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
+                               bfcr, bt_bfcr_status_string(status));
+               }
+       }
+
+       return status;
+}
+
+static inline
+enum bt_bfcr_status read_basic_int_and_call_cb(struct bt_bfcr *bfcr,
+               const uint8_t *buf, size_t at)
+{
+       unsigned int field_size;
+       enum ctf_byte_order bo;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       struct ctf_field_class_int *fc = (void *) bfcr->cur_basic_field_class;
+
+       field_size = fc->base.size;
+       bo = fc->base.byte_order;
+
+       /*
+        * Update current byte order now because we could be reading
+        * the integer value of an enumeration class, and thus we know
+        * here the actual supporting integer class's byte order.
+        */
+       bfcr->cur_bo = bo;
+
+       if (fc->is_signed) {
+               int64_t v;
+
+               read_signed_bitfield(buf, at, field_size, bo, &v);
+
+               if (bfcr->user.cbs.classes.signed_int) {
+                       BT_LOGV("Calling user function (signed integer).");
+                       status = bfcr->user.cbs.classes.signed_int(v,
+                               bfcr->cur_basic_field_class, bfcr->user.data);
+                       BT_LOGV("User function returned: status=%s",
+                               bt_bfcr_status_string(status));
+                       if (status != BT_BFCR_STATUS_OK) {
+                               BT_LOGW("User function failed: "
+                                       "bfcr-addr=%p, status=%s",
+                                       bfcr, bt_bfcr_status_string(status));
+                       }
+               }
+       } else {
+               uint64_t v;
+
+               read_unsigned_bitfield(buf, at, field_size, bo, &v);
+
+               if (bfcr->user.cbs.classes.unsigned_int) {
+                       BT_LOGV("Calling user function (unsigned integer).");
+                       status = bfcr->user.cbs.classes.unsigned_int(v,
+                               bfcr->cur_basic_field_class, bfcr->user.data);
+                       BT_LOGV("User function returned: status=%s",
+                               bt_bfcr_status_string(status));
+                       if (status != BT_BFCR_STATUS_OK) {
+                               BT_LOGW("User function failed: "
+                                       "bfcr-addr=%p, status=%s",
+                                       bfcr, bt_bfcr_status_string(status));
+                       }
+               }
+       }
+
+       return status;
+}
+
+static inline
+enum bt_bfcr_status read_bit_array_class_and_call_continue(struct bt_bfcr *bfcr,
+               read_basic_and_call_cb_t read_basic_and_call_cb)
+{
+       size_t available;
+       size_t needed_bits;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       struct ctf_field_class_bit_array *fc =
+               (void *) bfcr->cur_basic_field_class;
+
+       if (!at_least_one_bit_left(bfcr)) {
+               BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr);
+               status = BT_BFCR_STATUS_EOF;
+               goto end;
+       }
+
+       available = available_bits(bfcr);
+       needed_bits = fc->size - bfcr->stitch.at;
+       BT_LOGV("Continuing basic field decoding: "
+               "bfcr-addr=%p, field-size=%u, needed-size=%zu, "
+               "available-size=%zu",
+               bfcr, fc->size, needed_bits, available);
+       if (needed_bits <= available) {
+               /* We have all the bits; append to stitch, then decode */
+               stitch_append_from_buf(bfcr, needed_bits);
+               status = read_basic_and_call_cb(bfcr, bfcr->stitch.buf,
+                       bfcr->stitch.offset);
+               if (status != BT_BFCR_STATUS_OK) {
+                       BT_LOGW("Cannot read basic field: "
+                               "bfcr-addr=%p, fc-addr=%p, status=%s",
+                               bfcr, bfcr->cur_basic_field_class,
+                               bt_bfcr_status_string(status));
+                       goto end;
+               }
+
+               if (stack_empty(bfcr->stack)) {
+                       /* Root is a basic class */
+                       bfcr->state = BFCR_STATE_DONE;
+               } else {
+                       /* Go to next field */
+                       stack_top(bfcr->stack)->index++;
+                       bfcr->state = BFCR_STATE_NEXT_FIELD;
+                       bfcr->last_bo = bfcr->cur_bo;
+               }
+               goto end;
+       }
+
+       /* We are here; it means we don't have enough data to decode this */
+       BT_LOGV_STR("Not enough data to read the next basic field: appending to stitch buffer.");
+       stitch_append_from_remaining_buf(bfcr);
+       status = BT_BFCR_STATUS_EOF;
+
+end:
+       return status;
+}
+
+static inline
+enum bt_bfcr_status read_bit_array_class_and_call_begin(struct bt_bfcr *bfcr,
+               read_basic_and_call_cb_t read_basic_and_call_cb)
+{
+       size_t available;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       struct ctf_field_class_bit_array *fc =
+               (void *) bfcr->cur_basic_field_class;
+
+       if (!at_least_one_bit_left(bfcr)) {
+               BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr);
+               status = BT_BFCR_STATUS_EOF;
+               goto end;
+       }
+
+       status = validate_contiguous_bo(bfcr, fc->byte_order);
+       if (status != BT_BFCR_STATUS_OK) {
+               /* validate_contiguous_bo() logs errors */
+               goto end;
+       }
+
+       available = available_bits(bfcr);
+
+       if (fc->size <= available) {
+               /* We have all the bits; decode and set now */
+               BT_ASSERT(bfcr->buf.addr);
+               status = read_basic_and_call_cb(bfcr, bfcr->buf.addr,
+                       buf_at_from_addr(bfcr));
+               if (status != BT_BFCR_STATUS_OK) {
+                       BT_LOGW("Cannot read basic field: "
+                               "bfcr-addr=%p, fc-addr=%p, status=%s",
+                               bfcr, bfcr->cur_basic_field_class,
+                               bt_bfcr_status_string(status));
+                       goto end;
+               }
+
+               consume_bits(bfcr, fc->size);
+
+               if (stack_empty(bfcr->stack)) {
+                       /* Root is a basic class */
+                       bfcr->state = BFCR_STATE_DONE;
+               } else {
+                       /* Go to next field */
+                       stack_top(bfcr->stack)->index++;
+                       bfcr->state = BFCR_STATE_NEXT_FIELD;
+                       bfcr->last_bo = bfcr->cur_bo;
+               }
+
+               goto end;
+       }
+
+       /* We are here; it means we don't have enough data to decode this */
+       BT_LOGV_STR("Not enough data to read the next basic field: setting stitch buffer.");
+       stitch_set_from_remaining_buf(bfcr);
+       bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
+       status = BT_BFCR_STATUS_EOF;
+
+end:
+       return status;
+}
+
+static inline
+enum bt_bfcr_status read_basic_int_class_and_call_begin(
+               struct bt_bfcr *bfcr)
+{
+       return read_bit_array_class_and_call_begin(bfcr, read_basic_int_and_call_cb);
+}
+
+static inline
+enum bt_bfcr_status read_basic_int_class_and_call_continue(
+               struct bt_bfcr *bfcr)
+{
+       return read_bit_array_class_and_call_continue(bfcr,
+               read_basic_int_and_call_cb);
+}
+
+static inline
+enum bt_bfcr_status read_basic_float_class_and_call_begin(
+               struct bt_bfcr *bfcr)
+{
+       return read_bit_array_class_and_call_begin(bfcr,
+               read_basic_float_and_call_cb);
+}
+
+static inline
+enum bt_bfcr_status read_basic_float_class_and_call_continue(
+               struct bt_bfcr *bfcr)
+{
+       return read_bit_array_class_and_call_continue(bfcr,
+               read_basic_float_and_call_cb);
+}
+
+static inline
+enum bt_bfcr_status read_basic_string_class_and_call(
+               struct bt_bfcr *bfcr, bool begin)
+{
+       size_t buf_at_bytes;
+       const uint8_t *result;
+       size_t available_bytes;
+       const uint8_t *first_chr;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+
+       if (!at_least_one_bit_left(bfcr)) {
+               BT_LOGV("Reached end of data: bfcr-addr=%p", bfcr);
+               status = BT_BFCR_STATUS_EOF;
+               goto end;
+       }
+
+       BT_ASSERT(buf_at_from_addr(bfcr) % 8 == 0);
+       available_bytes = BITS_TO_BYTES_FLOOR(available_bits(bfcr));
+       buf_at_bytes = BITS_TO_BYTES_FLOOR(buf_at_from_addr(bfcr));
+       BT_ASSERT(bfcr->buf.addr);
+       first_chr = &bfcr->buf.addr[buf_at_bytes];
+       result = memchr(first_chr, '\0', available_bytes);
+
+       if (begin && bfcr->user.cbs.classes.string_begin) {
+               BT_LOGV("Calling user function (string, beginning).");
+               status = bfcr->user.cbs.classes.string_begin(
+                       bfcr->cur_basic_field_class, bfcr->user.data);
+               BT_LOGV("User function returned: status=%s",
+                       bt_bfcr_status_string(status));
+               if (status != BT_BFCR_STATUS_OK) {
+                       BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
+                               bfcr, bt_bfcr_status_string(status));
+                       goto end;
+               }
+       }
+
+       if (!result) {
+               /* No null character yet */
+               if (bfcr->user.cbs.classes.string) {
+                       BT_LOGV("Calling user function (substring).");
+                       status = bfcr->user.cbs.classes.string(
+                               (const char *) first_chr,
+                               available_bytes, bfcr->cur_basic_field_class,
+                               bfcr->user.data);
+                       BT_LOGV("User function returned: status=%s",
+                               bt_bfcr_status_string(status));
+                       if (status != BT_BFCR_STATUS_OK) {
+                               BT_LOGW("User function failed: "
+                                       "bfcr-addr=%p, status=%s",
+                                       bfcr, bt_bfcr_status_string(status));
+                               goto end;
+                       }
+               }
+
+               consume_bits(bfcr, BYTES_TO_BITS(available_bytes));
+               bfcr->state = BFCR_STATE_READ_BASIC_CONTINUE;
+               status = BT_BFCR_STATUS_EOF;
+       } else {
+               /* Found the null character */
+               size_t result_len = (size_t) (result - first_chr);
+
+               if (bfcr->user.cbs.classes.string && result_len) {
+                       BT_LOGV("Calling user function (substring).");
+                       status = bfcr->user.cbs.classes.string(
+                               (const char *) first_chr,
+                               result_len, bfcr->cur_basic_field_class,
+                               bfcr->user.data);
+                       BT_LOGV("User function returned: status=%s",
+                               bt_bfcr_status_string(status));
+                       if (status != BT_BFCR_STATUS_OK) {
+                               BT_LOGW("User function failed: "
+                                       "bfcr-addr=%p, status=%s",
+                                       bfcr, bt_bfcr_status_string(status));
+                               goto end;
+                       }
+               }
+
+               if (bfcr->user.cbs.classes.string_end) {
+                       BT_LOGV("Calling user function (string, end).");
+                       status = bfcr->user.cbs.classes.string_end(
+                               bfcr->cur_basic_field_class, bfcr->user.data);
+                       BT_LOGV("User function returned: status=%s",
+                               bt_bfcr_status_string(status));
+                       if (status != BT_BFCR_STATUS_OK) {
+                               BT_LOGW("User function failed: "
+                                       "bfcr-addr=%p, status=%s",
+                                       bfcr, bt_bfcr_status_string(status));
+                               goto end;
+                       }
+               }
+
+               consume_bits(bfcr, BYTES_TO_BITS(result_len + 1));
+
+               if (stack_empty(bfcr->stack)) {
+                       /* Root is a basic class */
+                       bfcr->state = BFCR_STATE_DONE;
+               } else {
+                       /* Go to next field */
+                       stack_top(bfcr->stack)->index++;
+                       bfcr->state = BFCR_STATE_NEXT_FIELD;
+                       bfcr->last_bo = bfcr->cur_bo;
+               }
+       }
+
+end:
+       return status;
+}
+
+static inline
+enum bt_bfcr_status read_basic_begin_state(struct bt_bfcr *bfcr)
+{
+       enum bt_bfcr_status status;
+
+       BT_ASSERT(bfcr->cur_basic_field_class);
+
+       switch (bfcr->cur_basic_field_class->type) {
+       case CTF_FIELD_CLASS_TYPE_INT:
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+               status = read_basic_int_class_and_call_begin(bfcr);
+               break;
+       case CTF_FIELD_CLASS_TYPE_FLOAT:
+               status = read_basic_float_class_and_call_begin(bfcr);
+               break;
+       case CTF_FIELD_CLASS_TYPE_STRING:
+               status = read_basic_string_class_and_call(bfcr, true);
+               break;
+       default:
+               abort();
+       }
+
+       return status;
+}
+
+static inline
+enum bt_bfcr_status read_basic_continue_state(struct bt_bfcr *bfcr)
+{
+       enum bt_bfcr_status status;
+
+       BT_ASSERT(bfcr->cur_basic_field_class);
+
+       switch (bfcr->cur_basic_field_class->type) {
+       case CTF_FIELD_CLASS_TYPE_INT:
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+               status = read_basic_int_class_and_call_continue(bfcr);
+               break;
+       case CTF_FIELD_CLASS_TYPE_FLOAT:
+               status = read_basic_float_class_and_call_continue(bfcr);
+               break;
+       case CTF_FIELD_CLASS_TYPE_STRING:
+               status = read_basic_string_class_and_call(bfcr, false);
+               break;
+       default:
+               abort();
+       }
+
+       return status;
+}
+
+static inline
+size_t bits_to_skip_to_align_to(struct bt_bfcr *bfcr, size_t align)
+{
+       size_t aligned_packet_at;
+
+       aligned_packet_at = ALIGN(packet_at(bfcr), align);
+       return aligned_packet_at - packet_at(bfcr);
+}
+
+static inline
+enum bt_bfcr_status align_class_state(struct bt_bfcr *bfcr,
+               struct ctf_field_class *field_class, enum bfcr_state next_state)
+{
+       unsigned int field_alignment;
+       size_t skip_bits;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+
+       /* Get field's alignment */
+       field_alignment = field_class->alignment;
+
+       /*
+        * 0 means "undefined" for variants; what we really want is 1
+        * (always aligned)
+        */
+       BT_ASSERT(field_alignment >= 1);
+
+       /* Compute how many bits we need to skip */
+       skip_bits = bits_to_skip_to_align_to(bfcr, (size_t) field_alignment);
+
+       /* Nothing to skip? aligned */
+       if (skip_bits == 0) {
+               bfcr->state = next_state;
+               goto end;
+       }
+
+       /* Make sure there's at least one bit left */
+       if (!at_least_one_bit_left(bfcr)) {
+               status = BT_BFCR_STATUS_EOF;
+               goto end;
+       }
+
+       /* Consume as many bits as possible in what's left */
+       consume_bits(bfcr, MIN(available_bits(bfcr), skip_bits));
+
+       /* Are we done now? */
+       skip_bits = bits_to_skip_to_align_to(bfcr, field_alignment);
+       if (skip_bits == 0) {
+               /* Yes: go to next state */
+               bfcr->state = next_state;
+               goto end;
+       } else {
+               /* No: need more data */
+               BT_LOGV("Reached end of data when aligning: bfcr-addr=%p", bfcr);
+               status = BT_BFCR_STATUS_EOF;
+       }
+
+end:
+       return status;
+}
+
+static inline
+enum bt_bfcr_status next_field_state(struct bt_bfcr *bfcr)
+{
+       int ret;
+       struct stack_entry *top;
+       struct ctf_field_class *next_field_class = NULL;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+
+       if (stack_empty(bfcr->stack)) {
+               goto end;
+       }
+
+       top = stack_top(bfcr->stack);
+
+       /* Are we done with this base class? */
+       while (top->index == top->base_len) {
+               if (bfcr->user.cbs.classes.compound_end) {
+                       BT_LOGV("Calling user function (compound, end).");
+                       status = bfcr->user.cbs.classes.compound_end(
+                               top->base_class, bfcr->user.data);
+                       BT_LOGV("User function returned: status=%s",
+                               bt_bfcr_status_string(status));
+                       if (status != BT_BFCR_STATUS_OK) {
+                               BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
+                                       bfcr, bt_bfcr_status_string(status));
+                               goto end;
+                       }
+               }
+
+               stack_pop(bfcr->stack);
+
+               /* Are we done with the root class? */
+               if (stack_empty(bfcr->stack)) {
+                       bfcr->state = BFCR_STATE_DONE;
+                       goto end;
+               }
+
+               top = stack_top(bfcr->stack);
+               top->index++;
+       }
+
+       /* Get next field's class */
+       switch (top->base_class->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+               next_field_class = ctf_field_class_struct_borrow_member_by_index(
+                       (void *) top->base_class, (uint64_t) top->index)->fc;
+               break;
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc =
+                       (void *) top->base_class;
+
+               next_field_class = array_fc->elem_fc;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+               /* Variant classes are dynamic: the user should know! */
+               next_field_class =
+                       bfcr->user.cbs.query.borrow_variant_selected_field_class(
+                               top->base_class, bfcr->user.data);
+               break;
+       default:
+               break;
+       }
+
+       if (!next_field_class) {
+               BT_LOGW("Cannot get the field class of the next field: "
+                       "bfcr-addr=%p, base-fc-addr=%p, base-fc-type=%d, "
+                       "index=%" PRId64,
+                       bfcr, top->base_class, top->base_class->type,
+                       top->index);
+               status = BT_BFCR_STATUS_ERROR;
+               goto end;
+       }
+
+       if (next_field_class->is_compound) {
+               if (bfcr->user.cbs.classes.compound_begin) {
+                       BT_LOGV("Calling user function (compound, begin).");
+                       status = bfcr->user.cbs.classes.compound_begin(
+                               next_field_class, bfcr->user.data);
+                       BT_LOGV("User function returned: status=%s",
+                               bt_bfcr_status_string(status));
+                       if (status != BT_BFCR_STATUS_OK) {
+                               BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
+                                       bfcr, bt_bfcr_status_string(status));
+                               goto end;
+                       }
+               }
+
+               ret = stack_push_with_len(bfcr, next_field_class);
+               if (ret) {
+                       /* stack_push_with_len() logs errors */
+                       status = BT_BFCR_STATUS_ERROR;
+                       goto end;
+               }
+
+               /* Next state: align a compound class */
+               bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
+       } else {
+               /* Replace current basic field class */
+               BT_LOGV("Replacing current basic field class: "
+                       "bfcr-addr=%p, cur-basic-fc-addr=%p, "
+                       "next-basic-fc-addr=%p",
+                       bfcr, bfcr->cur_basic_field_class, next_field_class);
+               bfcr->cur_basic_field_class = next_field_class;
+
+               /* Next state: align a basic class */
+               bfcr->state = BFCR_STATE_ALIGN_BASIC;
+       }
+
+end:
+       return status;
+}
+
+static inline
+enum bt_bfcr_status handle_state(struct bt_bfcr *bfcr)
+{
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+
+       BT_LOGV("Handling state: bfcr-addr=%p, state=%s",
+               bfcr, bfcr_state_string(bfcr->state));
+
+       switch (bfcr->state) {
+       case BFCR_STATE_NEXT_FIELD:
+               status = next_field_state(bfcr);
+               break;
+       case BFCR_STATE_ALIGN_BASIC:
+               status = align_class_state(bfcr, bfcr->cur_basic_field_class,
+                       BFCR_STATE_READ_BASIC_BEGIN);
+               break;
+       case BFCR_STATE_ALIGN_COMPOUND:
+               status = align_class_state(bfcr, stack_top(bfcr->stack)->base_class,
+                       BFCR_STATE_NEXT_FIELD);
+               break;
+       case BFCR_STATE_READ_BASIC_BEGIN:
+               status = read_basic_begin_state(bfcr);
+               break;
+       case BFCR_STATE_READ_BASIC_CONTINUE:
+               status = read_basic_continue_state(bfcr);
+               break;
+       case BFCR_STATE_DONE:
+               break;
+       }
+
+       BT_LOGV("Handled state: bfcr-addr=%p, status=%s",
+               bfcr, bt_bfcr_status_string(status));
+       return status;
+}
+
+BT_HIDDEN
+struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data)
+{
+       struct bt_bfcr *bfcr;
+
+       BT_LOGD_STR("Creating binary class reader (BFCR).");
+       bfcr = g_new0(struct bt_bfcr, 1);
+       if (!bfcr) {
+               BT_LOGE_STR("Failed to allocate one binary class reader.");
+               goto end;
+       }
+
+       bfcr->stack = stack_new();
+       if (!bfcr->stack) {
+               BT_LOGE_STR("Cannot create BFCR's stack.");
+               bt_bfcr_destroy(bfcr);
+               bfcr = NULL;
+               goto end;
+       }
+
+       bfcr->state = BFCR_STATE_NEXT_FIELD;
+       bfcr->user.cbs = cbs;
+       bfcr->user.data = data;
+       BT_LOGD("Created BFCR: addr=%p", bfcr);
+
+end:
+       return bfcr;
+}
+
+BT_HIDDEN
+void bt_bfcr_destroy(struct bt_bfcr *bfcr)
+{
+       if (bfcr->stack) {
+               stack_destroy(bfcr->stack);
+       }
+
+       BT_LOGD("Destroying BFCR: addr=%p", bfcr);
+       g_free(bfcr);
+}
+
+static
+void reset(struct bt_bfcr *bfcr)
+{
+       BT_LOGD("Resetting BFCR: addr=%p", bfcr);
+       stack_clear(bfcr->stack);
+       stitch_reset(bfcr);
+       bfcr->buf.addr = NULL;
+       bfcr->last_bo = -1;
+}
+
+static
+void update_packet_offset(struct bt_bfcr *bfcr)
+{
+       BT_LOGV("Updating packet offset for next call: "
+               "bfcr-addr=%p, cur-packet-offset=%zu, next-packet-offset=%zu",
+               bfcr, bfcr->buf.packet_offset,
+               bfcr->buf.packet_offset + bfcr->buf.at);
+       bfcr->buf.packet_offset += bfcr->buf.at;
+}
+
+BT_HIDDEN
+size_t bt_bfcr_start(struct bt_bfcr *bfcr,
+       struct ctf_field_class *cls, const uint8_t *buf,
+       size_t offset, size_t packet_offset, size_t sz,
+       enum bt_bfcr_status *status)
+{
+       BT_ASSERT(bfcr);
+       BT_ASSERT(BYTES_TO_BITS(sz) >= offset);
+       reset(bfcr);
+       bfcr->buf.addr = buf;
+       bfcr->buf.offset = offset;
+       bfcr->buf.at = 0;
+       bfcr->buf.packet_offset = packet_offset;
+       bfcr->buf.buf_sz = sz;
+       bfcr->buf.sz = BYTES_TO_BITS(sz) - offset;
+       *status = BT_BFCR_STATUS_OK;
+
+       BT_LOGV("Starting decoding: bfcr-addr=%p, fc-addr=%p, "
+               "buf-addr=%p, buf-size=%zu, offset=%zu, "
+               "packet-offset=%zu",
+               bfcr, cls, buf, sz, offset, packet_offset);
+
+       /* Set root class */
+       if (cls->is_compound) {
+               /* Compound class: push on visit stack */
+               int stack_ret;
+
+               if (bfcr->user.cbs.classes.compound_begin) {
+                       BT_LOGV("Calling user function (compound, begin).");
+                       *status = bfcr->user.cbs.classes.compound_begin(
+                               cls, bfcr->user.data);
+                       BT_LOGV("User function returned: status=%s",
+                               bt_bfcr_status_string(*status));
+                       if (*status != BT_BFCR_STATUS_OK) {
+                               BT_LOGW("User function failed: bfcr-addr=%p, status=%s",
+                                       bfcr, bt_bfcr_status_string(*status));
+                               goto end;
+                       }
+               }
+
+               stack_ret = stack_push_with_len(bfcr, cls);
+               if (stack_ret) {
+                       /* stack_push_with_len() logs errors */
+                       *status = BT_BFCR_STATUS_ERROR;
+                       goto end;
+               }
+
+               bfcr->state = BFCR_STATE_ALIGN_COMPOUND;
+       } else {
+               /* Basic class: set as current basic class */
+               bfcr->cur_basic_field_class = cls;
+               bfcr->state = BFCR_STATE_ALIGN_BASIC;
+       }
+
+       /* Run the machine! */
+       BT_LOGV_STR("Running the state machine.");
+
+       while (true) {
+               *status = handle_state(bfcr);
+               if (*status != BT_BFCR_STATUS_OK ||
+                               bfcr->state == BFCR_STATE_DONE) {
+                       break;
+               }
+       }
+
+       /* Update packet offset for next time */
+       update_packet_offset(bfcr);
+
+end:
+       return bfcr->buf.at;
+}
+
+BT_HIDDEN
+size_t bt_bfcr_continue(struct bt_bfcr *bfcr, const uint8_t *buf, size_t sz,
+               enum bt_bfcr_status *status)
+{
+       BT_ASSERT(bfcr);
+       BT_ASSERT(buf);
+       BT_ASSERT(sz > 0);
+       bfcr->buf.addr = buf;
+       bfcr->buf.offset = 0;
+       bfcr->buf.at = 0;
+       bfcr->buf.buf_sz = sz;
+       bfcr->buf.sz = BYTES_TO_BITS(sz);
+       *status = BT_BFCR_STATUS_OK;
+
+       BT_LOGV("Continuing decoding: bfcr-addr=%p, buf-addr=%p, buf-size=%zu",
+               bfcr, buf, sz);
+
+       /* Continue running the machine */
+       BT_LOGV_STR("Running the state machine.");
+
+       while (true) {
+               *status = handle_state(bfcr);
+               if (*status != BT_BFCR_STATUS_OK ||
+                               bfcr->state == BFCR_STATE_DONE) {
+                       break;
+               }
+       }
+
+       /* Update packet offset for next time */
+       update_packet_offset(bfcr);
+       return bfcr->buf.at;
+}
+
+BT_HIDDEN
+void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr,
+               bt_bfcr_unsigned_int_cb_func cb)
+{
+       BT_ASSERT(bfcr);
+       BT_ASSERT(cb);
+       bfcr->user.cbs.classes.unsigned_int = cb;
+}
diff --git a/src/plugins/ctf/common/bfcr/bfcr.h b/src/plugins/ctf/common/bfcr/bfcr.h
new file mode 100644 (file)
index 0000000..9cc5aad
--- /dev/null
@@ -0,0 +1,378 @@
+#ifndef CTF_BFCR_H
+#define CTF_BFCR_H
+
+/*
+ * Babeltrace - CTF binary field class reader (BFCR)
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+
+#include "../metadata/ctf-meta.h"
+
+/**
+ * @file bfcr.h
+ *
+ * Event-driven CTF binary field class reader (BFCR).
+ *
+ * This is a common, internal API used by CTF source plugins. It allows
+ * a binary CTF IR field class to be decoded from user-provided buffers.
+ * As the class is decoded (and, possibly, its nested classes),
+ * registered user callback functions are called.
+ *
+ * This API is only concerned with reading one CTF class at a time from
+ * one or more buffer of bytes. It does not know CTF dynamic scopes,
+ * events, or streams. Sequence lengths and selected variant classes are
+ * requested to the user when needed.
+ */
+
+/**
+ * Binary class reader API status codes.
+ */
+enum bt_bfcr_status {
+       /** Out of memory. */
+       BT_BFCR_STATUS_ENOMEM =         -5,
+       /**
+        * The binary stream reader reached the end of the user-provided
+        * buffer, but data is still needed to finish decoding the
+        * requested class.
+        *
+        * The user needs to call bt_bfcr_continue() as long as
+        * #BT_BFCR_STATUS_EOF is returned to complete the decoding
+        * process of a given class.
+        */
+       BT_BFCR_STATUS_EOF =            1,
+
+       /** Invalid argument. */
+       BT_BFCR_STATUS_INVAL =          -3,
+
+       /** General error. */
+       BT_BFCR_STATUS_ERROR =          -1,
+
+       /** Everything okay. */
+       BT_BFCR_STATUS_OK =             0,
+};
+
+/** Field class reader. */
+struct bt_bfcr;
+
+typedef enum bt_bfcr_status (* bt_bfcr_unsigned_int_cb_func)(uint64_t,
+               struct ctf_field_class *, void *);
+
+/*
+ * Field class reader user callback functions.
+ */
+struct bt_bfcr_cbs {
+       /**
+        * Field class callback functions.
+        *
+        * This CTF binary class reader is event-driven. The following
+        * functions are called during the decoding process, either when
+        * a compound class begins/ends, or when a basic class is
+        * completely decoded (along with its value).
+        *
+        * Each function also receives the CTF field class associated
+        * with the call, and user data (registered to the class reader
+        * calling them).
+        *
+        * Actual trace IR fields are \em not created here; this would
+        * be the responsibility of a class reader's user (the provider
+        * of those callback functions).
+        *
+        * All the class callback functions return one of the following
+        * values:
+        *
+        *   - <b>#BT_BFCR_STATUS_OK</b>: Everything is okay;
+        *     continue the decoding process.
+        *   - <b>#BT_BFCR_STATUS_ERROR</b>: General error (reported
+        *     to class reader's user).
+        *
+        * Any member of this structure may be set to \c NULL, should
+        * a specific message be not needed.
+        */
+       struct {
+               /**
+                * Called when a signed integer class is completely
+                * decoded. This could also be the supporting signed
+                * integer class of an enumeration class (\p class will
+                * indicate this).
+                *
+                * @param value         Signed integer value
+                * @param class         Integer or enumeration class
+                * @param data          User data
+                * @returns             #BT_BFCR_STATUS_OK or
+                *                      #BT_BFCR_STATUS_ERROR
+                */
+               enum bt_bfcr_status (* signed_int)(int64_t value,
+                               struct ctf_field_class *cls, void *data);
+
+               /**
+                * Called when an unsigned integer class is completely
+                * decoded. This could also be the supporting signed
+                * integer class of an enumeration class (\p class will
+                * indicate this).
+                *
+                * @param value         Unsigned integer value
+                * @param class         Integer or enumeration class
+                * @param data          User data
+                * @returns             #BT_BFCR_STATUS_OK or
+                *                      #BT_BFCR_STATUS_ERROR
+                */
+               bt_bfcr_unsigned_int_cb_func unsigned_int;
+
+               /**
+                * Called when a floating point number class is
+                * completely decoded.
+                *
+                * @param value         Floating point number value
+                * @param class         Floating point number class
+                * @param data          User data
+                * @returns             #BT_BFCR_STATUS_OK or
+                *                      #BT_BFCR_STATUS_ERROR
+                */
+               enum bt_bfcr_status (* floating_point)(double value,
+                               struct ctf_field_class *cls, void *data);
+
+               /**
+                * Called when a string class begins.
+                *
+                * All the following user callback function calls will
+                * be made to bt_bfcr_cbs::classes::string(), each of
+                * them providing one substring of the complete string
+                * class's value.
+                *
+                * @param class         Beginning string class
+                * @param data          User data
+                * @returns             #BT_BFCR_STATUS_OK or
+                *                      #BT_BFCR_STATUS_ERROR
+                */
+               enum bt_bfcr_status (* string_begin)(
+                               struct ctf_field_class *cls, void *data);
+
+               /**
+                * Called when a string class's substring is decoded
+                * (between a call to bt_bfcr_cbs::classes::string_begin()
+                * and a call to bt_bfcr_cbs::classes::string_end()).
+                *
+                * @param value         String value (\em not null-terminated)
+                * @param len           String value length
+                * @param class         String class
+                * @param data          User data
+                * @returns             #BT_BFCR_STATUS_OK or
+                *                      #BT_BFCR_STATUS_ERROR
+                */
+               enum bt_bfcr_status (* string)(const char *value,
+                               size_t len, struct ctf_field_class *cls,
+                               void *data);
+
+               /**
+                * Called when a string class ends.
+                *
+                * @param class         Ending string class
+                * @param data          User data
+                * @returns             #BT_BFCR_STATUS_OK or
+                *                      #BT_BFCR_STATUS_ERROR
+                */
+               enum bt_bfcr_status (* string_end)(
+                               struct ctf_field_class *cls, void *data);
+
+               /**
+                * Called when a compound class begins.
+                *
+                * All the following class callback function calls will
+                * signal sequential elements of this compound class,
+                * until the next corresponding
+                * bt_bfcr_cbs::classes::compound_end() is called.
+                *
+                * If \p class is a variant class, then only one class
+                * callback function call will follow before the call to
+                * bt_bfcr_cbs::classes::compound_end(). This single
+                * call indicates the selected class of this variant
+                * class.
+                *
+                * @param class         Beginning compound class
+                * @param data          User data
+                * @returns             #BT_BFCR_STATUS_OK or
+                *                      #BT_BFCR_STATUS_ERROR
+                */
+               enum bt_bfcr_status (* compound_begin)(
+                               struct ctf_field_class *cls, void *data);
+
+               /**
+                * Called when a compound class ends.
+                *
+                * @param class         Ending compound class
+                * @param data          User data
+                * @returns             #BT_BFCR_STATUS_OK or
+                *                      #BT_BFCR_STATUS_ERROR
+                */
+               enum bt_bfcr_status (* compound_end)(
+                               struct ctf_field_class *cls, void *data);
+       } classes;
+
+       /**
+        * Query callback functions are used when the class reader needs
+        * dynamic information, i.e. a sequence class's current length
+        * or a variant class's current selected class.
+        *
+        * Both functions need to be set unless it is known that no
+        * sequences or variants will have to be decoded.
+        */
+       struct {
+               /**
+                * Called to query the current length of a given sequence
+                * class.
+                *
+                * @param class         Sequence class
+                * @param data          User data
+                * @returns             Sequence length or
+                *                      #BT_BFCR_STATUS_ERROR on error
+                */
+               int64_t (* get_sequence_length)(struct ctf_field_class *cls,
+                               void *data);
+
+               /**
+                * Called to query the current selected class of a given
+                * variant class.
+                *
+                * @param class         Variant class
+                * @param data          User data
+                * @returns             Current selected class (owned by
+                *                      this) or \c NULL on error
+                */
+               struct ctf_field_class * (* borrow_variant_selected_field_class)(
+                               struct ctf_field_class *cls, void *data);
+       } query;
+};
+
+/**
+ * Creates a CTF binary class reader.
+ *
+ * @param cbs          User callback functions
+ * @param data         User data (passed to user callback functions)
+ * @returns            New binary class reader on success, or \c NULL on error
+ */
+BT_HIDDEN
+struct bt_bfcr *bt_bfcr_create(struct bt_bfcr_cbs cbs, void *data);
+
+/**
+ * Destroys a CTF binary class reader, freeing all internal resources.
+ *
+ * @param bfcr Binary class reader
+ */
+BT_HIDDEN
+void bt_bfcr_destroy(struct bt_bfcr *bfcr);
+
+/**
+ * Decodes a given CTF class from a buffer of bytes.
+ *
+ * The number of \em bits consumed by this function is returned.
+ *
+ * The \p status output parameter is where a status is written, amongst
+ * the following:
+ *
+ *   - <b>#BT_BFCR_STATUS_OK</b>: Decoding is done.
+ *   - <b>#BT_BFCR_STATUS_EOF</b>: The end of the buffer was reached,
+ *     but more data is needed to finish the decoding process of the
+ *     requested class. The user needs to call bt_bfcr_continue()
+ *     as long as #BT_BFCR_STATUS_EOF is returned to complete the
+ *     decoding process of the original class.
+ *   - <b>#BT_BFCR_STATUS_INVAL</b>: Invalid argument.
+ *   - <b>#BT_BFCR_STATUS_ERROR</b>: General error.
+ *
+ * Calling this function resets the class reader's internal state. If
+ * #BT_BFCR_STATUS_EOF is returned, bt_bfcr_continue() needs to
+ * be called next, \em not bt_bfcr_decode().
+ *
+ * @param bfcr                 Binary class reader
+ * @param class                        Field class to decode
+ * @param buf                  Buffer
+ * @param offset               Offset of first bit from \p buf (bits)
+ * @param packet_offset                Offset of \p offset within the CTF
+ *                             binary packet containing \p class (bits)
+ * @param sz                   Size of buffer in bytes (from \p buf)
+ * @param status               Returned status (see description above)
+ * @returns                    Number of consumed bits
+ */
+BT_HIDDEN
+size_t bt_bfcr_start(struct bt_bfcr *bfcr,
+               struct ctf_field_class *cls, const uint8_t *buf,
+               size_t offset, size_t packet_offset, size_t sz,
+               enum bt_bfcr_status *status);
+
+/**
+ * Continues the decoding process a given CTF class.
+ *
+ * The number of bits consumed by this function is returned.
+ *
+ * The \p status output parameter is where a status is placed, amongst
+ * the following:
+ *
+ *   - <b>#BT_BFCR_STATUS_OK</b>: decoding is done.
+ *   - <b>#BT_BFCR_STATUS_EOF</b>: the end of the buffer was reached,
+ *     but more data is needed to finish the decoding process of the
+ *     requested class. The user needs to call bt_bfcr_continue()
+ *     as long as #BT_BFCR_STATUS_EOF is returned to complete the
+ *     decoding process of the original class.
+ *   - <b>#BT_BFCR_STATUS_INVAL</b>: invalid argument.
+ *   - <b>#BT_BFCR_STATUS_ERROR</b>: general error.
+ *
+ * @param bfcr         Binary class reader
+ * @param buf          Buffer
+ * @param sz           Size of buffer in bytes (from \p offset)
+ * @param status       Returned status (see description above)
+ * @returns            Number of consumed bits
+ */
+BT_HIDDEN
+size_t bt_bfcr_continue(struct bt_bfcr *bfcr,
+               const uint8_t *buf, size_t sz,
+               enum bt_bfcr_status *status);
+
+BT_HIDDEN
+void bt_bfcr_set_unsigned_int_cb(struct bt_bfcr *bfcr,
+               bt_bfcr_unsigned_int_cb_func cb);
+
+static inline
+const char *bt_bfcr_status_string(enum bt_bfcr_status status)
+{
+       switch (status) {
+       case BT_BFCR_STATUS_ENOMEM:
+               return "BT_BFCR_STATUS_ENOMEM";
+       case BT_BFCR_STATUS_EOF:
+               return "BT_BFCR_STATUS_EOF";
+       case BT_BFCR_STATUS_INVAL:
+               return "BT_BFCR_STATUS_INVAL";
+       case BT_BFCR_STATUS_ERROR:
+               return "BT_BFCR_STATUS_ERROR";
+       case BT_BFCR_STATUS_OK:
+               return "BT_BFCR_STATUS_OK";
+       default:
+               return "(unknown)";
+       }
+}
+
+#endif /* CTF_BFCR_H */
diff --git a/src/plugins/ctf/common/bfcr/btr.gdb b/src/plugins/ctf/common/bfcr/btr.gdb
new file mode 100644 (file)
index 0000000..71cc0f6
--- /dev/null
@@ -0,0 +1,24 @@
+define ctf-btr-show-stack
+    if (stack_empty($arg0))
+        printf "stack is empty!\n"
+    else
+        set $stack_size = stack_size($arg0)
+        set $stack_at = (int) ($stack_size - 1)
+        printf "%3s    %10s   %4s    %3s\n", "pos", "base addr", "blen", "idx"
+
+        while ($stack_at >= 0)
+            set $stack_entry = (struct stack_entry *) g_ptr_array_index($arg0->entries, $stack_at)
+
+            if ($stack_at == $stack_size - 1)
+                printf "%3d    %10p    %3d    %3d  <-- top\n", $stack_at, \
+                    $stack_entry->base_class, $stack_entry->base_len, \
+                    $stack_entry->index
+            else
+                printf "%3d    %10p    %3d    %3d\n", $stack_at, \
+                    $stack_entry->base_class, $stack_entry->base_len, \
+                    $stack_entry->index
+            end
+            set $stack_at = $stack_at - 1
+        end
+    end
+end
diff --git a/src/plugins/ctf/common/bfcr/logging.c b/src/plugins/ctf/common/bfcr/logging.c
new file mode 100644 (file)
index 0000000..77ac65f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bfcr_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bfcr_log_level, "BABELTRACE_PLUGIN_CTF_BFCR_LOG_LEVEL");
diff --git a/src/plugins/ctf/common/bfcr/logging.h b/src/plugins/ctf/common/bfcr/logging.h
new file mode 100644 (file)
index 0000000..cb28468
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef CTF_BFCR_LOGGING_H
+#define CTF_BFCR_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bfcr_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bfcr_log_level);
+
+#endif /* CTF_BFCR_LOGGING_H */
diff --git a/src/plugins/ctf/common/metadata/Makefile.am b/src/plugins/ctf/common/metadata/Makefile.am
new file mode 100644 (file)
index 0000000..fa5b6f8
--- /dev/null
@@ -0,0 +1,80 @@
+AM_CPPFLAGS += -I$(builddir) -I$(srcdir)
+AM_YFLAGS = -t -d -v
+
+noinst_LTLIBRARIES = libctf-parser.la libctf-ast.la
+
+BUILT_SOURCES = parser.h
+
+libctf_parser_la_SOURCES = lexer.l parser.y objstack.c
+# scanner-symbols.h is included to prefix generated yy_* symbols
+# with bt_.
+libctf_parser_la_CPPFLAGS = $(AM_CPPFLAGS) \
+               -include $(srcdir)/scanner-symbols.h
+libctf_parser_la_CFLAGS = $(AM_CFLAGS) -Wno-unused-function
+
+libctf_ast_la_SOURCES = \
+       visitor-generate-ir.c \
+       visitor-semantic-validator.c \
+       visitor-parent-links.c \
+       ast.h \
+       objstack.h \
+       parser.h \
+       scanner.h \
+       scanner-symbols.h \
+       decoder.c \
+       decoder.h \
+       logging.c \
+       logging.h \
+       ctf-meta.h \
+       ctf-meta-visitors.h \
+       ctf-meta-validate.c \
+       ctf-meta-update-meanings.c \
+       ctf-meta-update-in-ir.c \
+       ctf-meta-update-default-clock-classes.c \
+       ctf-meta-update-text-array-sequence.c \
+       ctf-meta-update-value-storing-indexes.c \
+       ctf-meta-update-stream-class-config.c \
+       ctf-meta-warn-meaningless-header-fields.c \
+       ctf-meta-translate.c \
+       ctf-meta-resolve.c
+
+libctf_ast_la_LIBADD = $(UUID_LIBS)
+
+if BABELTRACE_BUILD_WITH_MINGW
+libctf_ast_la_LIBADD += -lrpcrt4 -lintl -liconv -lole32 $(POPT_LIBS)
+endif
+
+# start with empty files to clean
+CLEANFILES =
+
+if HAVE_BISON
+# we have bison: we can clean the generated parser files
+CLEANFILES += parser.c parser.h parser.output
+else # HAVE_BISON
+# create target used to stop the build if we want to build the parser,
+# but we don't have the necessary tool to do so
+ERR_MSG = "Error: Cannot build target because bison is missing."
+ERR_MSG += "Make sure bison is installed and run the configure script again."
+
+parser.c parser.h: parser.y
+       @echo $(ERR_MSG)
+       @false
+
+all-local: parser.c parser.h
+endif # HAVE_BISON
+
+if HAVE_FLEX
+# we have flex: we can clean the generated lexer files
+CLEANFILES += lexer.c
+else # HAVE_FLEX
+# create target used to stop the build if we want to build the lexer,
+# but we don't have the necessary tool to do so
+ERR_MSG = "Error: Cannot build target because flex is missing."
+ERR_MSG += "Make sure flex is installed and run the configure script again."
+
+filter-lexer.c: lexer.l
+       @echo $(ERR_MSG)
+       @false
+
+all-local: lexer.c
+endif # HAVE_FLEX
diff --git a/src/plugins/ctf/common/metadata/ast.h b/src/plugins/ctf/common/metadata/ast.h
new file mode 100644 (file)
index 0000000..6f6fbe7
--- /dev/null
@@ -0,0 +1,344 @@
+#ifndef _CTF_AST_H
+#define _CTF_AST_H
+
+/*
+ * ctf-ast.h
+ *
+ * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <glib.h>
+#include "common/list.h"
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+
+#include "decoder.h"
+#include "ctf-meta.h"
+
+// the parameter name (of the reentrant 'yyparse' function)
+// data is a pointer to a 'SParserParam' structure
+//#define YYPARSE_PARAM        scanner
+
+struct ctf_node;
+struct ctf_parser;
+struct ctf_visitor_generate_ir;
+
+#define EINCOMPLETE    1000
+
+#define FOREACH_CTF_NODES(F) \
+       F(NODE_UNKNOWN) \
+       F(NODE_ROOT) \
+       F(NODE_ERROR) \
+       F(NODE_EVENT) \
+       F(NODE_STREAM) \
+       F(NODE_ENV) \
+       F(NODE_TRACE) \
+       F(NODE_CLOCK) \
+       F(NODE_CALLSITE) \
+       F(NODE_CTF_EXPRESSION) \
+       F(NODE_UNARY_EXPRESSION) \
+       F(NODE_TYPEDEF) \
+       F(NODE_TYPEALIAS_TARGET) \
+       F(NODE_TYPEALIAS_ALIAS) \
+       F(NODE_TYPEALIAS) \
+       F(NODE_TYPE_SPECIFIER) \
+       F(NODE_TYPE_SPECIFIER_LIST) \
+       F(NODE_POINTER) \
+       F(NODE_TYPE_DECLARATOR) \
+       F(NODE_FLOATING_POINT) \
+       F(NODE_INTEGER) \
+       F(NODE_STRING) \
+       F(NODE_ENUMERATOR) \
+       F(NODE_ENUM) \
+       F(NODE_STRUCT_OR_VARIANT_DECLARATION) \
+       F(NODE_VARIANT) \
+       F(NODE_STRUCT)
+
+enum node_type {
+#define ENTRY(S)       S,
+       FOREACH_CTF_NODES(ENTRY)
+#undef ENTRY
+       NR_NODE_TYPES,
+};
+
+struct ctf_node {
+       /*
+        * Parent node is only set on demand by specific visitor.
+        */
+       struct ctf_node *parent;
+       struct bt_list_head siblings;
+       struct bt_list_head tmp_head;
+       unsigned int lineno;
+       /*
+        * We mark nodes visited in the generate-ir phase (last
+        * phase). We only mark the 1-depth level nodes as visited
+        * (never the root node, and not their sub-nodes). This allows
+        * skipping already visited nodes when doing incremental
+        * metadata append.
+        */
+       int visited;
+
+       enum node_type type;
+       union {
+               struct {
+               } unknown;
+               struct {
+                       /*
+                        * Children nodes are ctf_expression, field_class_def,
+                        * field_class_alias and field_class_specifier_list.
+                        */
+                       struct bt_list_head declaration_list;
+                       struct bt_list_head trace;
+                       struct bt_list_head env;
+                       struct bt_list_head stream;
+                       struct bt_list_head event;
+                       struct bt_list_head clock;
+                       struct bt_list_head callsite;
+               } root;
+               struct {
+                       /*
+                        * Children nodes are ctf_expression, field_class_def,
+                        * field_class_alias and field_class_specifier_list.
+                        */
+                       struct bt_list_head declaration_list;
+               } event;
+               struct {
+                       /*
+                        * Children nodes are ctf_expression, field_class_def,
+                        * field_class_alias and field_class_specifier_list.
+                        */
+                       struct bt_list_head declaration_list;
+               } stream;
+               struct {
+                       /*
+                        * Children nodes are ctf_expression, field_class_def,
+                        * field_class_alias and field_class_specifier_list.
+                        */
+                       struct bt_list_head declaration_list;
+               } env;
+               struct {
+                       /*
+                        * Children nodes are ctf_expression, field_class_def,
+                        * field_class_alias and field_class_specifier_list.
+                        */
+                       struct bt_list_head declaration_list;
+               } trace;
+               struct {
+                       /*
+                        * Children nodes are ctf_expression, field_class_def,
+                        * field_class_alias and field_class_specifier_list.
+                        */
+                       struct bt_list_head declaration_list;
+               } clock;
+               struct {
+                       /*
+                        * Children nodes are ctf_expression, field_class_def,
+                        * field_class_alias and field_class_specifier_list.
+                        */
+                       struct bt_list_head declaration_list;
+               } callsite;
+               struct {
+                       struct bt_list_head left;       /* Should be string */
+                       struct bt_list_head right;      /* Unary exp. or type */
+               } ctf_expression;
+               struct {
+                       enum {
+                               UNARY_UNKNOWN = 0,
+                               UNARY_STRING,
+                               UNARY_SIGNED_CONSTANT,
+                               UNARY_UNSIGNED_CONSTANT,
+                               UNARY_SBRAC,
+                       } type;
+                       union {
+                               /*
+                                * string for identifier, id_type, keywords,
+                                * string literals and character constants.
+                                */
+                               char *string;
+                               int64_t signed_constant;
+                               uint64_t unsigned_constant;
+                               struct ctf_node *sbrac_exp;
+                       } u;
+                       enum {
+                               UNARY_LINK_UNKNOWN = 0,
+                               UNARY_DOTLINK,
+                               UNARY_ARROWLINK,
+                               UNARY_DOTDOTDOT,
+                       } link;
+               } unary_expression;
+               struct {
+                       struct ctf_node *field_class_specifier_list;
+                       struct bt_list_head field_class_declarators;
+               } field_class_def;
+               /* new type is "alias", existing type "target" */
+               struct {
+                       struct ctf_node *field_class_specifier_list;
+                       struct bt_list_head field_class_declarators;
+               } field_class_alias_target;
+               struct {
+                       struct ctf_node *field_class_specifier_list;
+                       struct bt_list_head field_class_declarators;
+               } field_class_alias_name;
+               struct {
+                       struct ctf_node *target;
+                       struct ctf_node *alias;
+               } field_class_alias;
+               struct {
+                       enum {
+                               TYPESPEC_UNKNOWN = 0,
+                               TYPESPEC_VOID,
+                               TYPESPEC_CHAR,
+                               TYPESPEC_SHORT,
+                               TYPESPEC_INT,
+                               TYPESPEC_LONG,
+                               TYPESPEC_FLOAT,
+                               TYPESPEC_DOUBLE,
+                               TYPESPEC_SIGNED,
+                               TYPESPEC_UNSIGNED,
+                               TYPESPEC_BOOL,
+                               TYPESPEC_COMPLEX,
+                               TYPESPEC_IMAGINARY,
+                               TYPESPEC_CONST,
+                               TYPESPEC_ID_TYPE,
+                               TYPESPEC_FLOATING_POINT,
+                               TYPESPEC_INTEGER,
+                               TYPESPEC_STRING,
+                               TYPESPEC_STRUCT,
+                               TYPESPEC_VARIANT,
+                               TYPESPEC_ENUM,
+                       } type;
+                       /* For struct, variant and enum */
+                       struct ctf_node *node;
+                       const char *id_type;
+               } field_class_specifier;
+               struct {
+                       /* list of field_class_specifier */
+                       struct bt_list_head head;
+               } field_class_specifier_list;
+               struct {
+                       unsigned int const_qualifier;
+               } pointer;
+               struct {
+                       struct bt_list_head pointers;
+                       enum {
+                               TYPEDEC_UNKNOWN = 0,
+                               TYPEDEC_ID,     /* identifier */
+                               TYPEDEC_NESTED, /* (), array or sequence */
+                       } type;
+                       union {
+                               char *id;
+                               struct {
+                                       /* typedec has no pointer list */
+                                       struct ctf_node *field_class_declarator;
+                                       /*
+                                        * unary expression (value) or
+                                        * field_class_specifier_list.
+                                        */
+                                       struct bt_list_head length;
+                                       /* for abstract type declarator */
+                                       unsigned int abstract_array;
+                               } nested;
+                       } u;
+                       struct ctf_node *bitfield_len;
+               } field_class_declarator;
+               struct {
+                       /* Children nodes are ctf_expression. */
+                       struct bt_list_head expressions;
+               } floating_point;
+               struct {
+                       /* Children nodes are ctf_expression. */
+                       struct bt_list_head expressions;
+               } integer;
+               struct {
+                       /* Children nodes are ctf_expression. */
+                       struct bt_list_head expressions;
+               } string;
+               struct {
+                       char *id;
+                       /*
+                        * Range list or single value node. Contains unary
+                        * expressions.
+                        */
+                       struct bt_list_head values;
+               } enumerator;
+               struct {
+                       char *enum_id;
+                       /*
+                        * Either NULL, or points to unary expression or
+                        * field_class_specifier_list.
+                        */
+                       struct ctf_node *container_field_class;
+                       struct bt_list_head enumerator_list;
+                       int has_body;
+               } _enum;
+               struct {
+                       struct ctf_node *field_class_specifier_list;
+                       struct bt_list_head field_class_declarators;
+               } struct_or_variant_declaration;
+               struct {
+                       char *name;
+                       char *choice;
+                       /*
+                        * list of field_class_def, field_class_alias and
+                        * declarations
+                        */
+                       struct bt_list_head declaration_list;
+                       int has_body;
+               } variant;
+               struct {
+                       char *name;
+                       /*
+                        * list of field_class_def, field_class_alias and
+                        * declarations
+                        */
+                       struct bt_list_head declaration_list;
+                       int has_body;
+                       struct bt_list_head min_align;  /* align() attribute */
+               } _struct;
+       } u;
+};
+
+struct ctf_ast {
+       struct ctf_node root;
+};
+
+const char *node_type(struct ctf_node *node);
+
+BT_HIDDEN
+struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(
+               bt_self_component_source *self_comp,
+               const struct ctf_metadata_decoder_config *config);
+
+void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor);
+
+BT_HIDDEN
+bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(
+               struct ctf_visitor_generate_ir *visitor);
+
+BT_HIDDEN
+struct ctf_trace_class *ctf_visitor_generate_ir_borrow_ctf_trace_class(
+               struct ctf_visitor_generate_ir *visitor);
+
+BT_HIDDEN
+int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
+               struct ctf_node *node);
+
+BT_HIDDEN
+int ctf_visitor_semantic_check(int depth, struct ctf_node *node);
+
+BT_HIDDEN
+int ctf_visitor_parent_links(int depth, struct ctf_node *node);
+
+#endif /* _CTF_AST_H */
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-resolve.c b/src/plugins/ctf/common/metadata/ctf-meta-resolve.c
new file mode 100644 (file)
index 0000000..130ae61
--- /dev/null
@@ -0,0 +1,1316 @@
+/*
+ * Copyright 2016-2018 - Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-RESOLVE"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include "common/common.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include "ctf-meta-visitors.h"
+
+typedef GPtrArray field_class_stack;
+
+/*
+ * A stack frame.
+ *
+ * `fc` contains a compound field class (structure, variant, array,
+ * or sequence) and `index` indicates the index of the field class in
+ * the upper frame (-1 for array and sequence field classes). `name`
+ * indicates the name of the field class in the upper frame (empty
+ * string for array and sequence field classes).
+ */
+struct field_class_stack_frame {
+       struct ctf_field_class *fc;
+       int64_t index;
+};
+
+/*
+ * The current context of the resolving engine.
+ */
+struct resolve_context {
+       struct ctf_trace_class *tc;
+       struct ctf_stream_class *sc;
+       struct ctf_event_class *ec;
+
+       struct {
+               struct ctf_field_class *packet_header;
+               struct ctf_field_class *packet_context;
+               struct ctf_field_class *event_header;
+               struct ctf_field_class *event_common_context;
+               struct ctf_field_class *event_spec_context;
+               struct ctf_field_class *event_payload;
+       } scopes;
+
+       /* Root scope being visited */
+       enum ctf_scope root_scope;
+       field_class_stack *field_class_stack;
+       struct ctf_field_class *cur_fc;
+};
+
+/* TSDL dynamic scope prefixes as defined in CTF Section 7.3.2 */
+static const char * const absolute_path_prefixes[] = {
+       [CTF_SCOPE_PACKET_HEADER]               = "trace.packet.header.",
+       [CTF_SCOPE_PACKET_CONTEXT]              = "stream.packet.context.",
+       [CTF_SCOPE_EVENT_HEADER]                = "stream.event.header.",
+       [CTF_SCOPE_EVENT_COMMON_CONTEXT]        = "stream.event.context.",
+       [CTF_SCOPE_EVENT_SPECIFIC_CONTEXT]      = "event.context.",
+       [CTF_SCOPE_EVENT_PAYLOAD]               = "event.fields.",
+};
+
+/* Number of path tokens used for the absolute prefixes */
+static const uint64_t absolute_path_prefix_ptoken_counts[] = {
+       [CTF_SCOPE_PACKET_HEADER]               = 3,
+       [CTF_SCOPE_PACKET_CONTEXT]              = 3,
+       [CTF_SCOPE_EVENT_HEADER]                = 3,
+       [CTF_SCOPE_EVENT_COMMON_CONTEXT]        = 3,
+       [CTF_SCOPE_EVENT_SPECIFIC_CONTEXT]      = 2,
+       [CTF_SCOPE_EVENT_PAYLOAD]               = 2,
+};
+
+static
+void destroy_field_class_stack_frame(struct field_class_stack_frame *frame)
+{
+       if (!frame) {
+               return;
+       }
+
+       g_free(frame);
+}
+
+/*
+ * Creates a class stack.
+ */
+static
+field_class_stack *field_class_stack_create(void)
+{
+       return g_ptr_array_new_with_free_func(
+               (GDestroyNotify) destroy_field_class_stack_frame);
+}
+
+/*
+ * Destroys a class stack.
+ */
+static
+void field_class_stack_destroy(field_class_stack *stack)
+{
+       if (stack) {
+               g_ptr_array_free(stack, TRUE);
+       }
+}
+
+/*
+ * Pushes a field class onto a class stack.
+ */
+static
+int field_class_stack_push(field_class_stack *stack, struct ctf_field_class *fc)
+{
+       int ret = 0;
+       struct field_class_stack_frame *frame = NULL;
+
+       if (!stack || !fc) {
+               BT_LOGE("Invalid parameter: stack or field class is NULL.");
+               ret = -1;
+               goto end;
+       }
+
+       frame = g_new0(struct field_class_stack_frame, 1);
+       if (!frame) {
+               BT_LOGE_STR("Failed to allocate one field class stack frame.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_LOGV("Pushing field class on context's stack: "
+               "fc-addr=%p, stack-size-before=%u", fc, stack->len);
+       frame->fc = fc;
+       g_ptr_array_add(stack, frame);
+
+end:
+       return ret;
+}
+
+/*
+ * Checks whether or not `stack` is empty.
+ */
+static
+bool field_class_stack_empty(field_class_stack *stack)
+{
+       return stack->len == 0;
+}
+
+/*
+ * Returns the number of frames in `stack`.
+ */
+static
+size_t field_class_stack_size(field_class_stack *stack)
+{
+       return stack->len;
+}
+
+/*
+ * Returns the top frame of `stack`.
+ */
+static
+struct field_class_stack_frame *field_class_stack_peek(field_class_stack *stack)
+{
+       struct field_class_stack_frame *entry = NULL;
+
+       if (!stack || field_class_stack_empty(stack)) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, stack->len - 1);
+end:
+       return entry;
+}
+
+/*
+ * Returns the frame at index `index` in `stack`.
+ */
+static
+struct field_class_stack_frame *field_class_stack_at(field_class_stack *stack,
+               size_t index)
+{
+       struct field_class_stack_frame *entry = NULL;
+
+       if (!stack || index >= stack->len) {
+               goto end;
+       }
+
+       entry = g_ptr_array_index(stack, index);
+
+end:
+       return entry;
+}
+
+/*
+ * Removes the top frame of `stack`.
+ */
+static
+void field_class_stack_pop(field_class_stack *stack)
+{
+       if (!field_class_stack_empty(stack)) {
+               /*
+                * This will call the frame's destructor and free it, as
+                * well as put its contained field class.
+                */
+               BT_LOGV("Popping context's stack: stack-size-before=%u",
+                       stack->len);
+               g_ptr_array_set_size(stack, stack->len - 1);
+       }
+}
+
+/*
+ * Returns the scope field class of `scope` in the context `ctx`.
+ */
+static
+struct ctf_field_class *borrow_class_from_ctx(struct resolve_context *ctx,
+               enum ctf_scope scope)
+{
+       switch (scope) {
+       case CTF_SCOPE_PACKET_HEADER:
+               return ctx->scopes.packet_header;
+       case CTF_SCOPE_PACKET_CONTEXT:
+               return ctx->scopes.packet_context;
+       case CTF_SCOPE_EVENT_HEADER:
+               return ctx->scopes.event_header;
+       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
+               return ctx->scopes.event_common_context;
+       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               return ctx->scopes.event_spec_context;
+       case CTF_SCOPE_EVENT_PAYLOAD:
+               return ctx->scopes.event_payload;
+       default:
+               abort();
+       }
+
+       return NULL;
+}
+
+/*
+ * Returns the CTF scope from a path string. May return -1 if the path
+ * is found to be relative.
+ */
+static
+enum ctf_scope get_root_scope_from_absolute_pathstr(const char *pathstr)
+{
+       enum ctf_scope scope;
+       enum ctf_scope ret = -1;
+       const size_t prefixes_count = sizeof(absolute_path_prefixes) /
+               sizeof(*absolute_path_prefixes);
+
+       for (scope = CTF_SCOPE_PACKET_HEADER; scope < CTF_SCOPE_PACKET_HEADER +
+                       prefixes_count; scope++) {
+               /*
+                * Chech if path string starts with a known absolute
+                * path prefix.
+                *
+                * Refer to CTF 7.3.2 STATIC AND DYNAMIC SCOPES.
+                */
+               if (strncmp(pathstr, absolute_path_prefixes[scope],
+                               strlen(absolute_path_prefixes[scope]))) {
+                       /* Prefix does not match: try the next one */
+                       BT_LOGV("Prefix does not match: trying the next one: "
+                               "path=\"%s\", path-prefix=\"%s\", scope=%s",
+                               pathstr, absolute_path_prefixes[scope],
+                               ctf_scope_string(scope));
+                       continue;
+               }
+
+               /* Found it! */
+               ret = scope;
+               BT_LOGV("Found root scope from absolute path: "
+                       "path=\"%s\", scope=%s", pathstr,
+                       ctf_scope_string(scope));
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Destroys a path token.
+ */
+static
+void ptokens_destroy_func(gpointer ptoken, gpointer data)
+{
+       g_string_free(ptoken, TRUE);
+}
+
+/*
+ * Destroys a path token list.
+ */
+static
+void ptokens_destroy(GList *ptokens)
+{
+       if (!ptokens) {
+               return;
+       }
+
+       g_list_foreach(ptokens, ptokens_destroy_func, NULL);
+       g_list_free(ptokens);
+}
+
+/*
+ * Returns the string contained in a path token.
+ */
+static
+const char *ptoken_get_string(GList *ptoken)
+{
+       GString *tokenstr = (GString *) ptoken->data;
+
+       return tokenstr->str;
+}
+
+/*
+ * Converts a path string to a path token list, that is, splits the
+ * individual words of a path string into a list of individual
+ * strings.
+ */
+static
+GList *pathstr_to_ptokens(const char *pathstr)
+{
+       const char *at = pathstr;
+       const char *last = at;
+       GList *ptokens = NULL;
+
+       for (;;) {
+               if (*at == '.' || *at == '\0') {
+                       GString *tokenstr;
+
+                       if (at == last) {
+                               /* Error: empty token */
+                               BT_LOGE("Empty path token: path=\"%s\", pos=%u",
+                                       pathstr, (unsigned int) (at - pathstr));
+                               goto error;
+                       }
+
+                       tokenstr = g_string_new(NULL);
+                       g_string_append_len(tokenstr, last, at - last);
+                       ptokens = g_list_append(ptokens, tokenstr);
+                       last = at + 1;
+               }
+
+               if (*at == '\0') {
+                       break;
+               }
+
+               at++;
+       }
+
+       return ptokens;
+
+error:
+       ptokens_destroy(ptokens);
+       return NULL;
+}
+
+/*
+ * Converts a path token list to a field path object. The path token
+ * list is relative from `fc`. The index of the source looking for its
+ * target within `fc` is indicated by `src_index`. This can be `INT64_MAX`
+ * if the source is contained in `fc`.
+ *
+ * `field_path` is an output parameter owned by the caller that must be
+ * filled here.
+ */
+static
+int ptokens_to_field_path(GList *ptokens, struct ctf_field_path *field_path,
+               struct ctf_field_class *fc, int64_t src_index)
+{
+       int ret = 0;
+       GList *cur_ptoken = ptokens;
+       bool first_level_done = false;
+
+       /* Locate target */
+       while (cur_ptoken) {
+               int64_t child_index;
+               struct ctf_field_class *child_fc;
+               const char *ft_name = ptoken_get_string(cur_ptoken);
+
+               BT_LOGV("Current path token: token=\"%s\"", ft_name);
+
+               /* Find to which index corresponds the current path token */
+               if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY ||
+                               fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
+                       child_index = -1;
+               } else {
+                       child_index =
+                               ctf_field_class_compound_get_field_class_index_from_name(
+                                       fc, ft_name);
+                       if (child_index < 0) {
+                               /*
+                                * Error: field name does not exist or
+                                * wrong current class.
+                                */
+                               BT_LOGV("Cannot get index of field class: "
+                                       "field-name=\"%s\", "
+                                       "src-index=%" PRId64 ", "
+                                       "child-index=%" PRId64 ", "
+                                       "first-level-done=%d",
+                                       ft_name, src_index, child_index,
+                                       first_level_done);
+                               ret = -1;
+                               goto end;
+                       } else if (child_index > src_index &&
+                                       !first_level_done) {
+                               BT_LOGV("Child field class is located after source field class: "
+                                       "field-name=\"%s\", "
+                                       "src-index=%" PRId64 ", "
+                                       "child-index=%" PRId64 ", "
+                                       "first-level-done=%d",
+                                       ft_name, src_index, child_index,
+                                       first_level_done);
+                               ret = -1;
+                               goto end;
+                       }
+
+                       /* Next path token */
+                       cur_ptoken = g_list_next(cur_ptoken);
+                       first_level_done = true;
+               }
+
+               /* Create new field path entry */
+               ctf_field_path_append_index(field_path, child_index);
+
+               /* Get child field class */
+               child_fc = ctf_field_class_compound_borrow_field_class_by_index(
+                       fc, child_index);
+               BT_ASSERT(child_fc);
+
+               /* Move child class to current class */
+               fc = child_fc;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Converts a known absolute path token list to a field path object
+ * within the resolving context `ctx`.
+ *
+ * `field_path` is an output parameter owned by the caller that must be
+ * filled here.
+ */
+static
+int absolute_ptokens_to_field_path(GList *ptokens,
+               struct ctf_field_path *field_path,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       GList *cur_ptoken;
+       struct ctf_field_class *fc;
+
+       /*
+        * Make sure we're not referring to a scope within a translated
+        * object.
+        */
+       switch (field_path->root) {
+       case CTF_SCOPE_PACKET_HEADER:
+               if (ctx->tc->is_translated) {
+                       BT_LOGE("Trace class is already translated: "
+                               "root-scope=%s",
+                               ctf_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               break;
+       case CTF_SCOPE_PACKET_CONTEXT:
+       case CTF_SCOPE_EVENT_HEADER:
+       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
+               if (!ctx->sc) {
+                       BT_LOGE("No current stream class: "
+                               "root-scope=%s",
+                               ctf_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               if (ctx->sc->is_translated) {
+                       BT_LOGE("Stream class is already translated: "
+                               "root-scope=%s",
+                               ctf_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               break;
+       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
+       case CTF_SCOPE_EVENT_PAYLOAD:
+               if (!ctx->ec) {
+                       BT_LOGE("No current event class: "
+                               "root-scope=%s",
+                               ctf_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               if (ctx->ec->is_translated) {
+                       BT_LOGE("Event class is already translated: "
+                               "root-scope=%s",
+                               ctf_scope_string(field_path->root));
+                       ret = -1;
+                       goto end;
+               }
+
+               break;
+
+       default:
+               abort();
+       }
+
+       /* Skip absolute path tokens */
+       cur_ptoken = g_list_nth(ptokens,
+               absolute_path_prefix_ptoken_counts[field_path->root]);
+
+       /* Start with root class */
+       fc = borrow_class_from_ctx(ctx, field_path->root);
+       if (!fc) {
+               /* Error: root class is not available */
+               BT_LOGE("Root field class is not available: "
+                       "root-scope=%s",
+                       ctf_scope_string(field_path->root));
+               ret = -1;
+               goto end;
+       }
+
+       /* Locate target */
+       ret = ptokens_to_field_path(cur_ptoken, field_path, fc, INT64_MAX);
+
+end:
+       return ret;
+}
+
+/*
+ * Converts a known relative path token list to a field path object
+ * within the resolving context `ctx`.
+ *
+ * `field_path` is an output parameter owned by the caller that must be
+ * filled here.
+ */
+static
+int relative_ptokens_to_field_path(GList *ptokens,
+               struct ctf_field_path *field_path, struct resolve_context *ctx)
+{
+       int ret = 0;
+       int64_t parent_pos_in_stack;
+       struct ctf_field_path tail_field_path;
+
+       ctf_field_path_init(&tail_field_path);
+       parent_pos_in_stack = field_class_stack_size(ctx->field_class_stack) - 1;
+
+       while (parent_pos_in_stack >= 0) {
+               struct ctf_field_class *parent_class =
+                       field_class_stack_at(ctx->field_class_stack,
+                               parent_pos_in_stack)->fc;
+               int64_t cur_index = field_class_stack_at(ctx->field_class_stack,
+                       parent_pos_in_stack)->index;
+
+               BT_LOGV("Locating target field class from current parent field class: "
+                       "parent-pos=%" PRId64 ", parent-fc-addr=%p, "
+                       "cur-index=%" PRId64,
+                       parent_pos_in_stack, parent_class, cur_index);
+
+               /* Locate target from current parent class */
+               ret = ptokens_to_field_path(ptokens, &tail_field_path,
+                       parent_class, cur_index);
+               if (ret) {
+                       /* Not found... yet */
+                       BT_LOGV_STR("Not found at this point.");
+                       ctf_field_path_clear(&tail_field_path);
+               } else {
+                       /* Found: stitch tail field path to head field path */
+                       uint64_t i = 0;
+                       size_t tail_field_path_len =
+                               tail_field_path.path->len;
+
+                       while (BT_TRUE) {
+                               struct ctf_field_class *cur_class =
+                                       field_class_stack_at(
+                                               ctx->field_class_stack, i)->fc;
+                               int64_t index = field_class_stack_at(
+                                       ctx->field_class_stack, i)->index;
+
+                               if (cur_class == parent_class) {
+                                       break;
+                               }
+
+                               ctf_field_path_append_index(field_path,
+                                       index);
+                               i++;
+                       }
+
+                       for (i = 0; i < tail_field_path_len; i++) {
+                               int64_t index =
+                                       ctf_field_path_borrow_index_by_index(
+                                               &tail_field_path, i);
+
+                               ctf_field_path_append_index(field_path,
+                                       (int64_t) index);
+                       }
+                       break;
+               }
+
+               parent_pos_in_stack--;
+       }
+
+       if (parent_pos_in_stack < 0) {
+               /* Not found */
+               ret = -1;
+       }
+
+       ctf_field_path_fini(&tail_field_path);
+       return ret;
+}
+
+/*
+ * Converts a path string to a field path object within the resolving
+ * context `ctx`.
+ */
+static
+int pathstr_to_field_path(const char *pathstr,
+               struct ctf_field_path *field_path, struct resolve_context *ctx)
+{
+       int ret = 0;
+       enum ctf_scope root_scope;
+       GList *ptokens = NULL;
+
+       /* Convert path string to path tokens */
+       ptokens = pathstr_to_ptokens(pathstr);
+       if (!ptokens) {
+               BT_LOGE("Cannot convert path string to path tokens: "
+                       "path=\"%s\"", pathstr);
+               ret = -1;
+               goto end;
+       }
+
+       /* Absolute or relative path? */
+       root_scope = get_root_scope_from_absolute_pathstr(pathstr);
+
+       if (root_scope == -1) {
+               /* Relative path: start with current root scope */
+               field_path->root = ctx->root_scope;
+               BT_LOGV("Detected relative path: starting with current root scope: "
+                       "scope=%s", ctf_scope_string(field_path->root));
+               ret = relative_ptokens_to_field_path(ptokens, field_path, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot get relative field path of path string: "
+                               "path=\"%s\", start-scope=%s, end-scope=%s",
+                               pathstr, ctf_scope_string(ctx->root_scope),
+                               ctf_scope_string(field_path->root));
+                       goto end;
+               }
+       } else {
+               /* Absolute path: use found root scope */
+               field_path->root = root_scope;
+               BT_LOGV("Detected absolute path: using root scope: "
+                       "scope=%s", ctf_scope_string(field_path->root));
+               ret = absolute_ptokens_to_field_path(ptokens, field_path, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot get absolute field path of path string: "
+                               "path=\"%s\", root-scope=%s",
+                               pathstr, ctf_scope_string(root_scope));
+                       goto end;
+               }
+       }
+
+       if (BT_LOG_ON_VERBOSE && ret == 0) {
+               GString *field_path_pretty = ctf_field_path_string(field_path);
+               const char *field_path_pretty_str =
+                       field_path_pretty ? field_path_pretty->str : NULL;
+
+               BT_LOGV("Found field path: path=\"%s\", field-path=\"%s\"",
+                       pathstr, field_path_pretty_str);
+
+               if (field_path_pretty) {
+                       g_string_free(field_path_pretty, TRUE);
+               }
+       }
+
+end:
+       ptokens_destroy(ptokens);
+       return ret;
+}
+
+/*
+ * Retrieves a field class by following the field path `field_path` in
+ * the resolving context `ctx`.
+ */
+static
+struct ctf_field_class *field_path_to_field_class(
+               struct ctf_field_path *field_path, struct resolve_context *ctx)
+{
+       uint64_t i;
+       struct ctf_field_class *fc;
+
+       /* Start with root class */
+       fc = borrow_class_from_ctx(ctx, field_path->root);
+       if (!fc) {
+               /* Error: root class is not available */
+               BT_LOGE("Root field class is not available: root-scope=%s",
+                       ctf_scope_string(field_path->root));
+               goto end;
+       }
+
+       /* Locate target */
+       for (i = 0; i < field_path->path->len; i++) {
+               struct ctf_field_class *child_fc;
+               int64_t child_index =
+                       ctf_field_path_borrow_index_by_index(field_path, i);
+
+               /* Get child field class */
+               child_fc = ctf_field_class_compound_borrow_field_class_by_index(
+                       fc, child_index);
+               BT_ASSERT(child_fc);
+
+               /* Move child class to current class */
+               fc = child_fc;
+       }
+
+end:
+       return fc;
+}
+
+/*
+ * Fills the equivalent field path object of the context class stack.
+ */
+static
+void get_ctx_stack_field_path(struct resolve_context *ctx,
+               struct ctf_field_path *field_path)
+{
+       uint64_t i;
+
+       BT_ASSERT(field_path);
+       field_path->root = ctx->root_scope;
+       ctf_field_path_clear(field_path);
+
+       for (i = 0; i < field_class_stack_size(ctx->field_class_stack); i++) {
+               struct field_class_stack_frame *frame =
+                       field_class_stack_at(ctx->field_class_stack, i);
+
+               ctf_field_path_append_index(field_path, frame->index);
+       }
+}
+
+/*
+ * Returns the index of the lowest common ancestor of two field path
+ * objects having the same root scope.
+ */
+int64_t get_field_paths_lca_index(struct ctf_field_path *field_path1,
+               struct ctf_field_path *field_path2)
+{
+       int64_t lca_index = 0;
+       uint64_t field_path1_len, field_path2_len;
+
+       if (BT_LOG_ON_VERBOSE) {
+               GString *field_path1_pretty =
+                       ctf_field_path_string(field_path1);
+               GString *field_path2_pretty =
+                       ctf_field_path_string(field_path2);
+               const char *field_path1_pretty_str =
+                       field_path1_pretty ? field_path1_pretty->str : NULL;
+               const char *field_path2_pretty_str =
+                       field_path2_pretty ? field_path2_pretty->str : NULL;
+
+               BT_LOGV("Finding lowest common ancestor (LCA) between two field paths: "
+                       "field-path-1=\"%s\", field-path-2=\"%s\"",
+                       field_path1_pretty_str, field_path2_pretty_str);
+
+               if (field_path1_pretty) {
+                       g_string_free(field_path1_pretty, TRUE);
+               }
+
+               if (field_path2_pretty) {
+                       g_string_free(field_path2_pretty, TRUE);
+               }
+       }
+
+       /*
+        * Start from both roots and find the first mismatch.
+        */
+       BT_ASSERT(field_path1->root == field_path2->root);
+       field_path1_len = field_path1->path->len;
+       field_path2_len = field_path2->path->len;
+
+       while (true) {
+               int64_t target_index, ctx_index;
+
+               if (lca_index == (int64_t) field_path2_len ||
+                               lca_index == (int64_t) field_path1_len) {
+                       /*
+                        * This means that both field paths never split.
+                        * This is invalid because the target cannot be
+                        * an ancestor of the source.
+                        */
+                       BT_LOGE("Source field class is an ancestor of target field class or vice versa: "
+                               "lca-index=%" PRId64 ", "
+                               "field-path-1-len=%" PRIu64 ", "
+                               "field-path-2-len=%" PRIu64,
+                               lca_index, field_path1_len, field_path2_len);
+                       lca_index = -1;
+                       break;
+               }
+
+               target_index = ctf_field_path_borrow_index_by_index(field_path1,
+                       lca_index);
+               ctx_index = ctf_field_path_borrow_index_by_index(field_path2,
+                       lca_index);
+
+               if (target_index != ctx_index) {
+                       /* LCA index is the previous */
+                       break;
+               }
+
+               lca_index++;
+       }
+
+       BT_LOGV("Found LCA: lca-index=%" PRId64, lca_index);
+       return lca_index;
+}
+
+/*
+ * Validates a target field path.
+ */
+static
+int validate_target_field_path(struct ctf_field_path *target_field_path,
+               struct ctf_field_class *target_fc,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       struct ctf_field_path ctx_field_path;
+       uint64_t target_field_path_len = target_field_path->path->len;
+       int64_t lca_index;
+
+       /* Get context field path */
+       ctf_field_path_init(&ctx_field_path);
+       get_ctx_stack_field_path(ctx, &ctx_field_path);
+
+       /*
+        * Make sure the target is not a root.
+        */
+       if (target_field_path_len == 0) {
+               BT_LOGE_STR("Target field path's length is 0 (targeting the root).");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Make sure the root of the target field path is not located
+        * after the context field path's root.
+        */
+       if (target_field_path->root > ctx_field_path.root) {
+               BT_LOGE("Target field class is located after source field class: "
+                       "target-root=%s, source-root=%s",
+                       ctf_scope_string(target_field_path->root),
+                       ctf_scope_string(ctx_field_path.root));
+               ret = -1;
+               goto end;
+       }
+
+       if (target_field_path->root == ctx_field_path.root) {
+               int64_t target_index, ctx_index;
+
+               /*
+                * Find the index of the lowest common ancestor of both field
+                * paths.
+                */
+               lca_index = get_field_paths_lca_index(target_field_path,
+                       &ctx_field_path);
+               if (lca_index < 0) {
+                       BT_LOGE_STR("Cannot get least common ancestor.");
+                       ret = -1;
+                       goto end;
+               }
+
+               /*
+                * Make sure the target field path is located before the
+                * context field path.
+                */
+               target_index = ctf_field_path_borrow_index_by_index(
+                       target_field_path, (uint64_t) lca_index);
+               ctx_index = ctf_field_path_borrow_index_by_index(
+                       &ctx_field_path, (uint64_t) lca_index);
+
+               if (target_index >= ctx_index) {
+                       BT_LOGE("Target field class's index is greater than or equal to source field class's index in LCA: "
+                               "lca-index=%" PRId64 ", "
+                               "target-index=%" PRId64 ", "
+                               "source-index=%" PRId64,
+                               lca_index, target_index, ctx_index);
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /*
+        * Make sure the target class has the right class and properties.
+        */
+       switch (ctx->cur_fc->type) {
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+               if (target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE("Variant field class's tag field class is not an enumeration field class: "
+                               "tag-fc-addr=%p, tag-fc-id=%d",
+                               target_fc, target_fc->type);
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_int *int_fc = (void *) target_fc;
+
+               if (target_fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               target_fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE("Sequence field class's length field class is not an unsigned integer field class: "
+                               "length-fc-addr=%p, length-fc-id=%d",
+                               target_fc, target_fc->type);
+                       ret = -1;
+                       goto end;
+               }
+
+               if (int_fc->is_signed) {
+                       BT_LOGE("Sequence field class's length field class is not an unsigned integer field class: "
+                               "length-fc-addr=%p, length-fc-id=%d",
+                               target_fc, target_fc->type);
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       }
+       default:
+               abort();
+       }
+
+end:
+       ctf_field_path_fini(&ctx_field_path);
+       return ret;
+}
+
+/*
+ * Resolves a variant or sequence field class `fc`.
+ */
+static
+int resolve_sequence_or_variant_field_class(struct ctf_field_class *fc,
+               struct resolve_context *ctx)
+{
+       int ret = 0;
+       const char *pathstr;
+       struct ctf_field_path target_field_path;
+       struct ctf_field_class *target_fc = NULL;
+       GString *target_field_path_pretty = NULL;
+       const char *target_field_path_pretty_str;
+
+       ctf_field_path_init(&target_field_path);
+
+       /* Get path string */
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_sequence *seq_fc = (void *) fc;
+               pathstr = seq_fc->length_ref->str;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+               pathstr = var_fc->tag_ref->str;
+               break;
+       }
+       default:
+               abort();
+       }
+
+       if (!pathstr) {
+               BT_LOGE_STR("Cannot get path string.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Get target field path out of path string */
+       ret = pathstr_to_field_path(pathstr, &target_field_path, ctx);
+       if (ret) {
+               BT_LOGE("Cannot get target field path for path string: "
+                       "path=\"%s\"", pathstr);
+               goto end;
+       }
+
+       target_field_path_pretty = ctf_field_path_string(
+               &target_field_path);
+       target_field_path_pretty_str =
+               target_field_path_pretty ? target_field_path_pretty->str : NULL;
+
+       /* Get target field class */
+       target_fc = field_path_to_field_class(&target_field_path, ctx);
+       if (!target_fc) {
+               BT_LOGE("Cannot get target field class for path string: "
+                       "path=\"%s\", target-field-path=\"%s\"",
+                       pathstr, target_field_path_pretty_str);
+               ret = -1;
+               goto end;
+       }
+
+       ret = validate_target_field_path(&target_field_path,
+               target_fc, ctx);
+       if (ret) {
+               BT_LOGE("Invalid target field path for path string: "
+                       "path=\"%s\", target-field-path=\"%s\"",
+                       pathstr, target_field_path_pretty_str);
+               goto end;
+       }
+
+       /* Set target field path and target field class */
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_sequence *seq_fc = (void *) fc;
+
+               ctf_field_path_copy_content(&seq_fc->length_path,
+                       &target_field_path);
+               seq_fc->length_fc = (void *) target_fc;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               ctf_field_path_copy_content(&var_fc->tag_path,
+                       &target_field_path);
+               ctf_field_class_variant_set_tag_field_class(var_fc,
+                       (void *) target_fc);
+               break;
+       }
+       default:
+               abort();
+       }
+
+end:
+       if (target_field_path_pretty) {
+               g_string_free(target_field_path_pretty, TRUE);
+       }
+
+       ctf_field_path_fini(&target_field_path);
+       return ret;
+}
+
+/*
+ * Resolves a field class `fc`.
+ */
+static
+int resolve_field_class(struct ctf_field_class *fc, struct resolve_context *ctx)
+{
+       int ret = 0;
+
+       if (!fc) {
+               /* Field class is not available; still valid */
+               goto end;
+       }
+
+       ctx->cur_fc = fc;
+
+       /* Resolve sequence/variant field class */
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+               ret = resolve_sequence_or_variant_field_class(fc, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve sequence field class's length or variant field class's tag: "
+                               "ret=%d, fc-addr=%p", ret, fc);
+                       goto end;
+               }
+
+               break;
+       default:
+               break;
+       }
+
+       /* Recurse into compound classes */
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       {
+               uint64_t i;
+               uint64_t field_count =
+                       ctf_field_class_compound_get_field_class_count(fc);
+
+               ret = field_class_stack_push(ctx->field_class_stack, fc);
+               if (ret) {
+                       BT_LOGE("Cannot push field class on context's stack: "
+                               "fc-addr=%p", fc);
+                       goto end;
+               }
+
+               for (i = 0; i < field_count; i++) {
+                       struct ctf_field_class *child_fc =
+                               ctf_field_class_compound_borrow_field_class_by_index(
+                                       fc, i);
+
+                       BT_ASSERT(child_fc);
+
+                       if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY||
+                                       fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
+                               field_class_stack_peek(
+                                       ctx->field_class_stack)->index = -1;
+                       } else {
+                               field_class_stack_peek(
+                                       ctx->field_class_stack)->index =
+                                               (int64_t) i;
+                       }
+
+                       BT_LOGV("Resolving field class's child field class: "
+                               "parent-fc-addr=%p, child-fc-addr=%p, "
+                               "index=%" PRIu64 ", count=%" PRIu64,
+                               fc, child_fc, i, field_count);
+                       ret = resolve_field_class(child_fc, ctx);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               field_class_stack_pop(ctx->field_class_stack);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Resolves the root field class corresponding to the scope `root_scope`.
+ */
+static
+int resolve_root_class(enum ctf_scope root_scope, struct resolve_context *ctx)
+{
+       int ret;
+
+       BT_ASSERT(field_class_stack_size(ctx->field_class_stack) == 0);
+       ctx->root_scope = root_scope;
+       ret = resolve_field_class(borrow_class_from_ctx(ctx, root_scope), ctx);
+       ctx->root_scope = -1;
+       return ret;
+}
+
+static
+int resolve_event_class_field_classes(struct resolve_context *ctx,
+               struct ctf_event_class *ec)
+{
+       int ret = 0;
+
+       BT_ASSERT(!ctx->scopes.event_spec_context);
+       BT_ASSERT(!ctx->scopes.event_payload);
+
+       if (ec->is_translated) {
+               goto end;
+       }
+
+       ctx->ec = ec;
+       ctx->scopes.event_spec_context = ec->spec_context_fc;
+       ret = resolve_root_class(CTF_SCOPE_EVENT_COMMON_CONTEXT, ctx);
+       if (ret) {
+               BT_LOGE("Cannot resolve event specific context field class: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       ctx->scopes.event_payload = ec->payload_fc;
+       ret = resolve_root_class(CTF_SCOPE_EVENT_PAYLOAD, ctx);
+       if (ret) {
+               BT_LOGE("Cannot resolve event payload field class: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+end:
+       ctx->scopes.event_spec_context = NULL;
+       ctx->scopes.event_payload = NULL;
+       ctx->ec = NULL;
+       return ret;
+}
+
+static
+int resolve_stream_class_field_classes(struct resolve_context *ctx,
+               struct ctf_stream_class *sc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       BT_ASSERT(!ctx->scopes.packet_context);
+       BT_ASSERT(!ctx->scopes.event_header);
+       BT_ASSERT(!ctx->scopes.event_common_context);
+       ctx->sc = sc;
+
+       if (!sc->is_translated) {
+               ctx->scopes.packet_context = sc->packet_context_fc;
+               ret = resolve_root_class(CTF_SCOPE_PACKET_CONTEXT, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve packet context field class: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+
+               ctx->scopes.event_header = sc->event_header_fc;
+               ret = resolve_root_class(CTF_SCOPE_EVENT_HEADER, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve event header field class: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+
+               ctx->scopes.event_common_context = sc->event_common_context_fc;
+               ret = resolve_root_class(CTF_SCOPE_EVENT_SPECIFIC_CONTEXT, ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve event common context field class: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       ctx->scopes.packet_context = sc->packet_context_fc;
+       ctx->scopes.event_header = sc->event_header_fc;
+       ctx->scopes.event_common_context = sc->event_common_context_fc;
+
+       for (i = 0; i < sc->event_classes->len; i++) {
+               struct ctf_event_class *ec = sc->event_classes->pdata[i];
+
+               ret = resolve_event_class_field_classes(ctx, ec);
+               if (ret) {
+                       BT_LOGE("Cannot resolve event class's field classes: "
+                               "ec-id=%" PRIu64 ", ec-name=\"%s\"",
+                               ec->id, ec->name->str);
+                       goto end;
+               }
+       }
+
+end:
+       ctx->scopes.packet_context = NULL;
+       ctx->scopes.event_header = NULL;
+       ctx->scopes.event_common_context = NULL;
+       ctx->sc = NULL;
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc)
+{
+       int ret = 0;
+       uint64_t i;
+       struct resolve_context ctx = {
+               .tc = tc,
+               .sc = NULL,
+               .ec = NULL,
+               .scopes = {
+                       .packet_header = tc->packet_header_fc,
+                       .packet_context = NULL,
+                       .event_header = NULL,
+                       .event_common_context = NULL,
+                       .event_spec_context = NULL,
+                       .event_payload = NULL,
+               },
+               .root_scope = CTF_SCOPE_PACKET_HEADER,
+               .cur_fc = NULL,
+       };
+
+       /* Initialize class stack */
+       ctx.field_class_stack = field_class_stack_create();
+       if (!ctx.field_class_stack) {
+               BT_LOGE_STR("Cannot create field class stack.");
+               ret = -1;
+               goto end;
+       }
+
+       if (!tc->is_translated) {
+               ctx.scopes.packet_header = tc->packet_header_fc;
+               ret = resolve_root_class(CTF_SCOPE_PACKET_HEADER, &ctx);
+               if (ret) {
+                       BT_LOGE("Cannot resolve packet header field class: "
+                               "ret=%d", ret);
+                       goto end;
+               }
+       }
+
+       ctx.scopes.packet_header = tc->packet_header_fc;
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = tc->stream_classes->pdata[i];
+
+               ret = resolve_stream_class_field_classes(&ctx, sc);
+               if (ret) {
+                       BT_LOGE("Cannot resolve stream class's field classes: "
+                               "sc-id=%" PRIu64, sc->id);
+                       goto end;
+               }
+       }
+
+end:
+       field_class_stack_destroy(ctx.field_class_stack);
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-translate.c b/src/plugins/ctf/common/metadata/ctf-meta-translate.c
new file mode 100644 (file)
index 0000000..287cc25
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-TRANSLATE"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+struct ctx {
+       bt_self_component_source *self_comp;
+       bt_trace_class *ir_tc;
+       bt_stream_class *ir_sc;
+       struct ctf_trace_class *tc;
+       struct ctf_stream_class *sc;
+       struct ctf_event_class *ec;
+       enum ctf_scope scope;
+};
+
+static inline
+bt_field_class *ctf_field_class_to_ir(struct ctx *ctx,
+               struct ctf_field_class *fc);
+
+static inline
+void ctf_field_class_int_set_props(struct ctf_field_class_int *fc,
+               bt_field_class *ir_fc)
+{
+       bt_field_class_integer_set_field_value_range(ir_fc,
+               fc->base.size);
+       bt_field_class_integer_set_preferred_display_base(ir_fc,
+               fc->disp_base);
+}
+
+static inline
+bt_field_class *ctf_field_class_int_to_ir(struct ctx *ctx,
+               struct ctf_field_class_int *fc)
+{
+       bt_field_class *ir_fc;
+
+       if (fc->is_signed) {
+               ir_fc = bt_field_class_signed_integer_create(ctx->ir_tc);
+       } else {
+               ir_fc = bt_field_class_unsigned_integer_create(ctx->ir_tc);
+       }
+
+       BT_ASSERT(ir_fc);
+       ctf_field_class_int_set_props(fc, ir_fc);
+       return ir_fc;
+}
+
+static inline
+bt_field_class *ctf_field_class_enum_to_ir(struct ctx *ctx,
+               struct ctf_field_class_enum *fc)
+{
+       int ret;
+       bt_field_class *ir_fc;
+       uint64_t i;
+
+       if (fc->base.is_signed) {
+               ir_fc = bt_field_class_signed_enumeration_create(ctx->ir_tc);
+       } else {
+               ir_fc = bt_field_class_unsigned_enumeration_create(ctx->ir_tc);
+       }
+
+       BT_ASSERT(ir_fc);
+       ctf_field_class_int_set_props((void *) fc, ir_fc);
+
+       for (i = 0; i < fc->mappings->len; i++) {
+               struct ctf_field_class_enum_mapping *mapping =
+                       ctf_field_class_enum_borrow_mapping_by_index(fc, i);
+
+               if (fc->base.is_signed) {
+                       ret = bt_field_class_signed_enumeration_map_range(
+                               ir_fc, mapping->label->str,
+                               mapping->range.lower.i, mapping->range.upper.i);
+               } else {
+                       ret = bt_field_class_unsigned_enumeration_map_range(
+                               ir_fc, mapping->label->str,
+                               mapping->range.lower.u, mapping->range.upper.u);
+               }
+
+               BT_ASSERT(ret == 0);
+       }
+
+       return ir_fc;
+}
+
+static inline
+bt_field_class *ctf_field_class_float_to_ir(struct ctx *ctx,
+               struct ctf_field_class_float *fc)
+{
+       bt_field_class *ir_fc;
+
+       ir_fc = bt_field_class_real_create(ctx->ir_tc);
+       BT_ASSERT(ir_fc);
+
+       if (fc->base.size == 32) {
+               bt_field_class_real_set_is_single_precision(ir_fc,
+                       BT_TRUE);
+       }
+
+       return ir_fc;
+}
+
+static inline
+bt_field_class *ctf_field_class_string_to_ir(struct ctx *ctx,
+               struct ctf_field_class_string *fc)
+{
+       bt_field_class *ir_fc = bt_field_class_string_create(ctx->ir_tc);
+
+       BT_ASSERT(ir_fc);
+       return ir_fc;
+}
+
+static inline
+void translate_struct_field_class_members(struct ctx *ctx,
+               struct ctf_field_class_struct *fc, bt_field_class *ir_fc,
+               bool with_header_prefix,
+               struct ctf_field_class_struct *context_fc)
+{
+       uint64_t i;
+       int ret;
+
+       for (i = 0; i < fc->members->len; i++) {
+               struct ctf_named_field_class *named_fc =
+                       ctf_field_class_struct_borrow_member_by_index(fc, i);
+               bt_field_class *member_ir_fc;
+               const char *name = named_fc->name->str;
+
+               if (!named_fc->fc->in_ir) {
+                       continue;
+               }
+
+               member_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc);
+               BT_ASSERT(member_ir_fc);
+               ret = bt_field_class_structure_append_member(ir_fc, name,
+                       member_ir_fc);
+               BT_ASSERT(ret == 0);
+               bt_field_class_put_ref(member_ir_fc);
+       }
+}
+
+static inline
+bt_field_class *ctf_field_class_struct_to_ir(struct ctx *ctx,
+               struct ctf_field_class_struct *fc)
+{
+       bt_field_class *ir_fc = bt_field_class_structure_create(ctx->ir_tc);
+
+       BT_ASSERT(ir_fc);
+       translate_struct_field_class_members(ctx, fc, ir_fc, false, NULL);
+       return ir_fc;
+}
+
+static inline
+bt_field_class *borrow_ir_fc_from_field_path(struct ctx *ctx,
+               struct ctf_field_path *field_path)
+{
+       bt_field_class *ir_fc = NULL;
+       struct ctf_field_class *fc = ctf_field_path_borrow_field_class(
+               field_path, ctx->tc, ctx->sc, ctx->ec);
+
+       BT_ASSERT(fc);
+
+       if (fc->in_ir) {
+               ir_fc = fc->ir_fc;
+       }
+
+       return ir_fc;
+}
+
+static inline
+bt_field_class *ctf_field_class_variant_to_ir(struct ctx *ctx,
+               struct ctf_field_class_variant *fc)
+{
+       int ret;
+       bt_field_class *ir_fc = bt_field_class_variant_create(ctx->ir_tc);
+       uint64_t i;
+
+       BT_ASSERT(ir_fc);
+
+       if (fc->tag_path.root != CTF_SCOPE_PACKET_HEADER &&
+                       fc->tag_path.root != CTF_SCOPE_EVENT_HEADER) {
+               ret = bt_field_class_variant_set_selector_field_class(
+                       ir_fc, borrow_ir_fc_from_field_path(ctx,
+                               &fc->tag_path));
+               BT_ASSERT(ret == 0);
+       }
+
+       for (i = 0; i < fc->options->len; i++) {
+               struct ctf_named_field_class *named_fc =
+                       ctf_field_class_variant_borrow_option_by_index(fc, i);
+               bt_field_class *option_ir_fc;
+
+               BT_ASSERT(named_fc->fc->in_ir);
+               option_ir_fc = ctf_field_class_to_ir(ctx, named_fc->fc);
+               BT_ASSERT(option_ir_fc);
+               ret = bt_field_class_variant_append_option(
+                       ir_fc, named_fc->name->str, option_ir_fc);
+               BT_ASSERT(ret == 0);
+               bt_field_class_put_ref(option_ir_fc);
+       }
+
+       return ir_fc;
+}
+
+static inline
+bt_field_class *ctf_field_class_array_to_ir(struct ctx *ctx,
+               struct ctf_field_class_array *fc)
+{
+       bt_field_class *ir_fc;
+       bt_field_class *elem_ir_fc;
+
+       if (fc->base.is_text) {
+               ir_fc = bt_field_class_string_create(ctx->ir_tc);
+               BT_ASSERT(ir_fc);
+               goto end;
+       }
+
+       elem_ir_fc = ctf_field_class_to_ir(ctx, fc->base.elem_fc);
+       BT_ASSERT(elem_ir_fc);
+       ir_fc = bt_field_class_static_array_create(ctx->ir_tc, elem_ir_fc,
+               fc->length);
+       BT_ASSERT(ir_fc);
+       bt_field_class_put_ref(elem_ir_fc);
+
+end:
+       return ir_fc;
+}
+
+static inline
+bt_field_class *ctf_field_class_sequence_to_ir(struct ctx *ctx,
+               struct ctf_field_class_sequence *fc)
+{
+       int ret;
+       bt_field_class *ir_fc;
+       bt_field_class *elem_ir_fc;
+
+       if (fc->base.is_text) {
+               ir_fc = bt_field_class_string_create(ctx->ir_tc);
+               BT_ASSERT(ir_fc);
+               goto end;
+       }
+
+       elem_ir_fc = ctf_field_class_to_ir(ctx, fc->base.elem_fc);
+       BT_ASSERT(elem_ir_fc);
+       ir_fc = bt_field_class_dynamic_array_create(ctx->ir_tc, elem_ir_fc);
+       BT_ASSERT(ir_fc);
+       bt_field_class_put_ref(elem_ir_fc);
+       BT_ASSERT(ir_fc);
+
+       if (fc->length_path.root != CTF_SCOPE_PACKET_HEADER &&
+                       fc->length_path.root != CTF_SCOPE_EVENT_HEADER) {
+               ret = bt_field_class_dynamic_array_set_length_field_class(
+                       ir_fc, borrow_ir_fc_from_field_path(ctx, &fc->length_path));
+               BT_ASSERT(ret == 0);
+       }
+
+end:
+       return ir_fc;
+}
+
+static inline
+bt_field_class *ctf_field_class_to_ir(struct ctx *ctx,
+               struct ctf_field_class *fc)
+{
+       bt_field_class *ir_fc = NULL;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(fc->in_ir);
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_INT:
+               ir_fc = ctf_field_class_int_to_ir(ctx, (void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+               ir_fc = ctf_field_class_enum_to_ir(ctx, (void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_FLOAT:
+               ir_fc = ctf_field_class_float_to_ir(ctx, (void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_STRING:
+               ir_fc = ctf_field_class_string_to_ir(ctx, (void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+               ir_fc = ctf_field_class_struct_to_ir(ctx, (void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+               ir_fc = ctf_field_class_array_to_ir(ctx, (void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+               ir_fc = ctf_field_class_sequence_to_ir(ctx, (void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+               ir_fc = ctf_field_class_variant_to_ir(ctx, (void *) fc);
+               break;
+       default:
+               abort();
+       }
+
+       fc->ir_fc = ir_fc;
+       return ir_fc;
+}
+
+static inline
+bool ctf_field_class_struct_has_immediate_member_in_ir(
+               struct ctf_field_class_struct *fc)
+{
+       uint64_t i;
+       bool has_immediate_member_in_ir = false;
+
+       /*
+        * If the structure field class has no members at all, then it
+        * was an empty structure in the beginning, so leave it existing
+        * and empty.
+        */
+       if (fc->members->len == 0) {
+               has_immediate_member_in_ir = true;
+               goto end;
+       }
+
+       for (i = 0; i < fc->members->len; i++) {
+               struct ctf_named_field_class *named_fc =
+                       ctf_field_class_struct_borrow_member_by_index(fc, i);
+
+               if (named_fc->fc->in_ir) {
+                       has_immediate_member_in_ir = true;
+                       goto end;
+               }
+       }
+
+end:
+       return has_immediate_member_in_ir;
+}
+
+static inline
+bt_field_class *scope_ctf_field_class_to_ir(struct ctx *ctx)
+{
+       bt_field_class *ir_fc = NULL;
+       struct ctf_field_class *fc = NULL;
+
+       switch (ctx->scope) {
+       case CTF_SCOPE_PACKET_CONTEXT:
+               fc = ctx->sc->packet_context_fc;
+               break;
+       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
+               fc = ctx->sc->event_common_context_fc;
+               break;
+       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               fc = ctx->ec->spec_context_fc;
+               break;
+       case CTF_SCOPE_EVENT_PAYLOAD:
+               fc = ctx->ec->payload_fc;
+               break;
+       default:
+               abort();
+       }
+
+       if (fc && ctf_field_class_struct_has_immediate_member_in_ir(
+                       (void *) fc)) {
+               ir_fc = ctf_field_class_to_ir(ctx, fc);
+       }
+
+       return ir_fc;
+}
+
+static inline
+void ctf_event_class_to_ir(struct ctx *ctx)
+{
+       int ret;
+       bt_event_class *ir_ec = NULL;
+       bt_field_class *ir_fc;
+
+       BT_ASSERT(ctx->ec);
+
+       if (ctx->ec->is_translated) {
+               ir_ec = bt_stream_class_borrow_event_class_by_id(
+                       ctx->ir_sc, ctx->ec->id);
+               BT_ASSERT(ir_ec);
+               goto end;
+       }
+
+       ir_ec = bt_event_class_create_with_id(ctx->ir_sc, ctx->ec->id);
+       BT_ASSERT(ir_ec);
+       bt_event_class_put_ref(ir_ec);
+       ctx->scope = CTF_SCOPE_EVENT_SPECIFIC_CONTEXT;
+       ir_fc = scope_ctf_field_class_to_ir(ctx);
+       if (ir_fc) {
+               ret = bt_event_class_set_specific_context_field_class(
+                       ir_ec, ir_fc);
+               BT_ASSERT(ret == 0);
+               bt_field_class_put_ref(ir_fc);
+       }
+
+       ctx->scope = CTF_SCOPE_EVENT_PAYLOAD;
+       ir_fc = scope_ctf_field_class_to_ir(ctx);
+       if (ir_fc) {
+               ret = bt_event_class_set_payload_field_class(ir_ec,
+                       ir_fc);
+               BT_ASSERT(ret == 0);
+               bt_field_class_put_ref(ir_fc);
+       }
+
+       if (ctx->ec->name->len > 0) {
+               ret = bt_event_class_set_name(ir_ec, ctx->ec->name->str);
+               BT_ASSERT(ret == 0);
+       }
+
+       if (ctx->ec->emf_uri->len > 0) {
+               ret = bt_event_class_set_emf_uri(ir_ec, ctx->ec->emf_uri->str);
+               BT_ASSERT(ret == 0);
+       }
+
+       if (ctx->ec->log_level != -1) {
+               bt_event_class_set_log_level(ir_ec, ctx->ec->log_level);
+       }
+
+       ctx->ec->is_translated = true;
+       ctx->ec->ir_ec = ir_ec;
+
+end:
+       return;
+}
+
+
+static inline
+void ctf_stream_class_to_ir(struct ctx *ctx)
+{
+       int ret;
+       bt_field_class *ir_fc;
+
+       BT_ASSERT(ctx->sc);
+
+       if (ctx->sc->is_translated) {
+               ctx->ir_sc = bt_trace_class_borrow_stream_class_by_id(
+                       ctx->ir_tc, ctx->sc->id);
+               BT_ASSERT(ctx->ir_sc);
+               goto end;
+       }
+
+       ctx->ir_sc = bt_stream_class_create_with_id(ctx->ir_tc, ctx->sc->id);
+       BT_ASSERT(ctx->ir_sc);
+       bt_stream_class_put_ref(ctx->ir_sc);
+       ctx->scope = CTF_SCOPE_PACKET_CONTEXT;
+       ir_fc = scope_ctf_field_class_to_ir(ctx);
+       if (ir_fc) {
+               ret = bt_stream_class_set_packet_context_field_class(
+                       ctx->ir_sc, ir_fc);
+               BT_ASSERT(ret == 0);
+               bt_field_class_put_ref(ir_fc);
+       }
+
+       ctx->scope = CTF_SCOPE_EVENT_COMMON_CONTEXT;
+       ir_fc = scope_ctf_field_class_to_ir(ctx);
+       if (ir_fc) {
+               ret = bt_stream_class_set_event_common_context_field_class(
+                       ctx->ir_sc, ir_fc);
+               BT_ASSERT(ret == 0);
+               bt_field_class_put_ref(ir_fc);
+       }
+
+       bt_stream_class_set_assigns_automatic_event_class_id(ctx->ir_sc,
+               BT_FALSE);
+       bt_stream_class_set_assigns_automatic_stream_id(ctx->ir_sc, BT_FALSE);
+
+       if (ctx->sc->default_clock_class) {
+               BT_ASSERT(ctx->sc->default_clock_class->ir_cc);
+               ret = bt_stream_class_set_default_clock_class(ctx->ir_sc,
+                       ctx->sc->default_clock_class->ir_cc);
+               BT_ASSERT(ret == 0);
+       }
+
+       bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
+               ctx->ir_sc, ctx->sc->packets_have_ts_begin);
+       bt_stream_class_set_packets_have_end_default_clock_snapshot(
+               ctx->ir_sc, ctx->sc->packets_have_ts_end);
+       bt_stream_class_set_supports_discarded_events(ctx->ir_sc,
+               ctx->sc->has_discarded_events,
+               ctx->sc->discarded_events_have_default_cs);
+       bt_stream_class_set_supports_discarded_packets(ctx->ir_sc,
+               ctx->sc->has_discarded_packets,
+               ctx->sc->discarded_packets_have_default_cs);
+       ctx->sc->is_translated = true;
+       ctx->sc->ir_sc = ctx->ir_sc;
+
+end:
+       return;
+}
+
+static inline
+void ctf_clock_class_to_ir(bt_clock_class *ir_cc, struct ctf_clock_class *cc)
+{
+       int ret;
+
+       if (strlen(cc->name->str) > 0) {
+               ret = bt_clock_class_set_name(ir_cc, cc->name->str);
+               BT_ASSERT(ret == 0);
+       }
+
+       if (strlen(cc->description->str) > 0) {
+               ret = bt_clock_class_set_description(ir_cc, cc->description->str);
+               BT_ASSERT(ret == 0);
+       }
+
+       bt_clock_class_set_frequency(ir_cc, cc->frequency);
+       bt_clock_class_set_precision(ir_cc, cc->precision);
+       bt_clock_class_set_offset(ir_cc, cc->offset_seconds, cc->offset_cycles);
+
+       if (cc->has_uuid) {
+               bt_clock_class_set_uuid(ir_cc, cc->uuid);
+       }
+
+       bt_clock_class_set_origin_is_unix_epoch(ir_cc, cc->is_absolute);
+}
+
+static inline
+int ctf_trace_class_to_ir(struct ctx *ctx)
+{
+       int ret = 0;
+       uint64_t i;
+
+       BT_ASSERT(ctx->tc);
+       BT_ASSERT(ctx->ir_tc);
+
+       if (ctx->tc->is_translated) {
+               goto end;
+       }
+
+       if (ctx->tc->is_uuid_set) {
+               bt_trace_class_set_uuid(ctx->ir_tc, ctx->tc->uuid);
+       }
+
+       for (i = 0; i < ctx->tc->env_entries->len; i++) {
+               struct ctf_trace_class_env_entry *env_entry =
+                       ctf_trace_class_borrow_env_entry_by_index(ctx->tc, i);
+
+               switch (env_entry->type) {
+               case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT:
+                       ret = bt_trace_class_set_environment_entry_integer(
+                               ctx->ir_tc, env_entry->name->str,
+                               env_entry->value.i);
+                       break;
+               case CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR:
+                       ret = bt_trace_class_set_environment_entry_string(
+                               ctx->ir_tc, env_entry->name->str,
+                               env_entry->value.str->str);
+                       break;
+               default:
+                       abort();
+               }
+
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < ctx->tc->clock_classes->len; i++) {
+               struct ctf_clock_class *cc = ctx->tc->clock_classes->pdata[i];
+
+               cc->ir_cc = bt_clock_class_create(
+                               bt_self_component_source_as_self_component(
+                                       ctx->self_comp));
+               ctf_clock_class_to_ir(cc->ir_cc, cc);
+       }
+
+       bt_trace_class_set_assigns_automatic_stream_class_id(ctx->ir_tc,
+               BT_FALSE);
+       ctx->tc->is_translated = true;
+       ctx->tc->ir_tc = ctx->ir_tc;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_translate(bt_self_component_source *self_comp,
+               bt_trace_class *ir_tc, struct ctf_trace_class *tc)
+{
+       int ret = 0;
+       uint64_t i;
+       struct ctx ctx = { 0 };
+
+       ctx.self_comp = self_comp;
+       ctx.tc = tc;
+       ctx.ir_tc = ir_tc;
+       ret = ctf_trace_class_to_ir(&ctx);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               uint64_t j;
+               ctx.sc = tc->stream_classes->pdata[i];
+
+               ctf_stream_class_to_ir(&ctx);
+
+               for (j = 0; j < ctx.sc->event_classes->len; j++) {
+                       ctx.ec = ctx.sc->event_classes->pdata[j];
+
+                       ctf_event_class_to_ir(&ctx);
+                       ctx.ec = NULL;
+               }
+
+               ctx.sc = NULL;
+       }
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c b/src/plugins/ctf/common/metadata/ctf-meta-update-default-clock-classes.c
new file mode 100644 (file)
index 0000000..f114d80
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-DEF-CC"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static inline
+int find_mapped_clock_class(struct ctf_field_class *fc,
+               struct ctf_clock_class **clock_class)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (!fc) {
+               goto end;
+       }
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_INT:
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+       {
+               struct ctf_field_class_int *int_fc = (void *) fc;
+
+               if (int_fc->mapped_clock_class) {
+                       if (*clock_class && *clock_class !=
+                                       int_fc->mapped_clock_class) {
+                               BT_LOGE("Stream class contains more than one "
+                                       "clock class: expected-cc-name=\"%s\", "
+                                       "other-cc-name=\"%s\"",
+                                       (*clock_class)->name->str,
+                                       int_fc->mapped_clock_class->name->str);
+                               ret = -1;
+                               goto end;
+                       }
+
+                       *clock_class = int_fc->mapped_clock_class;
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               for (i = 0; i < struct_fc->members->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+
+                       ret = find_mapped_clock_class(named_fc->fc,
+                               clock_class);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               for (i = 0; i < var_fc->options->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+
+                       ret = find_mapped_clock_class(named_fc->fc,
+                               clock_class);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               ret = find_mapped_clock_class(array_fc->elem_fc, clock_class);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static inline
+int update_stream_class_default_clock_class(
+               struct ctf_stream_class *stream_class)
+{
+       int ret = 0;
+       struct ctf_clock_class *clock_class =
+               stream_class->default_clock_class;
+       uint64_t i;
+
+       ret = find_mapped_clock_class(stream_class->packet_context_fc,
+               &clock_class);
+       if (ret) {
+               goto end;
+       }
+
+       ret = find_mapped_clock_class(stream_class->event_header_fc,
+               &clock_class);
+       if (ret) {
+               goto end;
+       }
+
+       ret = find_mapped_clock_class(stream_class->event_common_context_fc,
+               &clock_class);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < stream_class->event_classes->len; i++) {
+               struct ctf_event_class *event_class =
+                       stream_class->event_classes->pdata[i];
+
+               ret = find_mapped_clock_class(event_class->spec_context_fc,
+                       &clock_class);
+               if (ret) {
+                       goto end;
+               }
+
+               ret = find_mapped_clock_class(event_class->payload_fc,
+                       &clock_class);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       if (!stream_class->default_clock_class) {
+               stream_class->default_clock_class = clock_class;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_update_default_clock_classes(struct ctf_trace_class *ctf_tc)
+{
+       uint64_t i;
+       int ret = 0;
+       struct ctf_clock_class *clock_class = NULL;
+
+       ret = find_mapped_clock_class(ctf_tc->packet_header_fc, &clock_class);
+       if (ret) {
+               goto end;
+       }
+
+       if (clock_class) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc =
+                       ctf_tc->stream_classes->pdata[i];
+
+               ret = update_stream_class_default_clock_class(
+                       ctf_tc->stream_classes->pdata[i]);
+               if (ret) {
+                       BT_LOGE("Stream class contains more than one "
+                               "clock class: stream-class-id=%" PRIu64,
+                               sc->id);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.c b/src/plugins/ctf/common/metadata/ctf-meta-update-in-ir.c
new file mode 100644 (file)
index 0000000..e634294
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-IN-IR"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include "compat/glib.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+#include "common/assert.h"
+
+#include "ctf-meta-visitors.h"
+
+static
+void force_update_field_class_in_ir(struct ctf_field_class *fc, bool in_ir)
+{
+       uint64_t i;
+
+       if (!fc) {
+               goto end;
+       }
+
+       fc->in_ir = in_ir;
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               for (i = 0; i < struct_fc->members->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+
+                       force_update_field_class_in_ir(named_fc->fc, in_ir);
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_named_field_class *named_fc;
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               for (i = 0; i < var_fc->options->len; i++) {
+                       named_fc =
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+
+                       force_update_field_class_in_ir(named_fc->fc, in_ir);
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               force_update_field_class_in_ir(array_fc->elem_fc, in_ir);
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return;
+}
+
+static
+void update_field_class_in_ir(struct ctf_field_class *fc,
+               GHashTable *ft_dependents)
+{
+       int64_t i;
+
+       if (!fc) {
+               goto end;
+       }
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_INT:
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+       {
+               struct ctf_field_class_int *int_fc = (void *) fc;
+
+               /*
+                * Conditions to be in trace IR; one of:
+                *
+                * 1. Does NOT have a mapped clock class AND does not
+                *    have a special meaning.
+                * 2. Another field class depends on it.
+                */
+               if ((!int_fc->mapped_clock_class &&
+                               int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE) ||
+                               bt_g_hash_table_contains(ft_dependents, fc)) {
+                       fc->in_ir = true;
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               /*
+                * Make it part of IR if it's empty because it was
+                * originally empty.
+                */
+               if (struct_fc->members->len == 0) {
+                       fc->in_ir = true;
+               }
+
+               /* Reverse order */
+               for (i = (int64_t) struct_fc->members->len - 1; i >= 0; i--) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+
+                       update_field_class_in_ir(named_fc->fc, ft_dependents);
+
+                       if (named_fc->fc->in_ir) {
+                               /* At least one member is part of IR */
+                               fc->in_ir = true;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_named_field_class *named_fc;
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               /*
+                * Reverse order, although it is not important for this
+                * loop because a field class within a variant field
+                * type's option cannot depend on a field class in
+                * another option of the same variant field class.
+                */
+               for (i = (int64_t) var_fc->options->len - 1; i >= 0; i--) {
+                       named_fc =
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+
+                       update_field_class_in_ir(named_fc->fc, ft_dependents);
+
+                       if (named_fc->fc->in_ir) {
+                               /* At least one option is part of IR */
+                               fc->in_ir = true;
+                       }
+               }
+
+               if (fc->in_ir) {
+                       /*
+                        * At least one option will make it to IR. In
+                        * this case, make all options part of IR
+                        * because the variant's tag could still select
+                        * (dynamically) a removed option. This can mean
+                        * having an empty structure as an option, for
+                        * example, but at least all the options are
+                        * selectable.
+                        */
+                       for (i = 0; i < var_fc->options->len; i++) {
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i)->fc->in_ir = true;
+                       }
+
+                       /*
+                        * This variant field class is part of IR and
+                        * depends on a tag field class (which must also
+                        * be part of IR).
+                        */
+                       g_hash_table_insert(ft_dependents, var_fc->tag_fc,
+                               var_fc->tag_fc);
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               update_field_class_in_ir(array_fc->elem_fc, ft_dependents);
+               fc->in_ir = array_fc->elem_fc->in_ir;
+
+               if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) {
+                       struct ctf_field_class_array *arr_fc = (void *) fc;
+
+                       assert(arr_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE ||
+                               arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID);
+
+                       /*
+                        * UUID field class: nothing depends on this, so
+                        * it's not part of IR.
+                        */
+                       if (arr_fc->meaning == CTF_FIELD_CLASS_MEANING_UUID) {
+                               fc->in_ir = false;
+                               array_fc->elem_fc->in_ir = false;
+                       }
+               } else if (fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
+                       if (fc->in_ir) {
+                               struct ctf_field_class_sequence *seq_fc = (void *) fc;
+
+                               /*
+                                * This sequence field class is part of
+                                * IR and depends on a length field class
+                                * (which must also be part of IR).
+                                */
+                               g_hash_table_insert(ft_dependents,
+                                       seq_fc->length_fc, seq_fc->length_fc);
+                       }
+               }
+
+               break;
+       }
+       default:
+               fc->in_ir = true;
+               break;
+       }
+
+end:
+       return;
+}
+
+/*
+ * Scopes and field classes are processed in reverse order because we need
+ * to know if a given integer field class has dependents (sequence or
+ * variant field classes) when we reach it. Dependents can only be located
+ * after the length/tag field class in the metadata tree.
+ */
+BT_HIDDEN
+int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       GHashTable *ft_dependents = g_hash_table_new(g_direct_hash,
+               g_direct_equal);
+
+       BT_ASSERT(ft_dependents);
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
+               uint64_t j;
+
+               for (j = 0; j < sc->event_classes->len; j++) {
+                       struct ctf_event_class *ec = sc->event_classes->pdata[j];
+
+                       if (ec->is_translated) {
+                               continue;
+                       }
+
+                       update_field_class_in_ir(ec->payload_fc, ft_dependents);
+                       update_field_class_in_ir(ec->spec_context_fc,
+                               ft_dependents);
+               }
+
+               if (!sc->is_translated) {
+                       update_field_class_in_ir(sc->event_common_context_fc,
+                               ft_dependents);
+                       force_update_field_class_in_ir(sc->event_header_fc,
+                               false);
+                       update_field_class_in_ir(sc->packet_context_fc,
+                               ft_dependents);
+               }
+       }
+
+       if (!ctf_tc->is_translated) {
+               force_update_field_class_in_ir(ctf_tc->packet_header_fc,
+                       false);
+       }
+
+       g_hash_table_destroy(ft_dependents);
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-meanings.c b/src/plugins/ctf/common/metadata/ctf-meta-update-meanings.c
new file mode 100644 (file)
index 0000000..bd80197
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-MEANINGS"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static
+int set_int_field_class_meaning_by_name(struct ctf_field_class *fc,
+               const char *field_name, const char *id_name,
+               enum ctf_field_class_meaning meaning)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (!fc) {
+               goto end;
+       }
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_INT:
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+       {
+               struct ctf_field_class_int *int_fc = (void *) fc;
+
+               if (field_name && strcmp(field_name, id_name) == 0) {
+                       int_fc->meaning = meaning;
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               for (i = 0; i < struct_fc->members->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+
+                       ret = set_int_field_class_meaning_by_name(named_fc->fc,
+                               named_fc->name->str, id_name, meaning);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               for (i = 0; i < var_fc->options->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+
+                       ret = set_int_field_class_meaning_by_name(named_fc->fc,
+                               NULL, id_name, meaning);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               ret = set_int_field_class_meaning_by_name(array_fc->elem_fc,
+                       NULL, id_name, meaning);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+static
+int update_stream_class_meanings(struct ctf_stream_class *sc)
+{
+       int ret = 0;
+       struct ctf_field_class_int *int_fc;
+       uint64_t i;
+
+       if (!sc->is_translated) {
+               if (sc->packet_context_fc) {
+                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                               (void *) sc->packet_context_fc, "timestamp_begin");
+                       if (int_fc) {
+                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME;
+                       }
+
+                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                               (void *) sc->packet_context_fc, "timestamp_end");
+                       if (int_fc) {
+                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_END_TIME;
+
+                               /*
+                                * Remove mapped clock class to avoid updating
+                                * the clock immediately when decoding.
+                                */
+                               int_fc->mapped_clock_class = NULL;
+                       }
+
+                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                               (void *) sc->packet_context_fc, "events_discarded");
+                       if (int_fc) {
+                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT;
+                       }
+
+                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                               (void *) sc->packet_context_fc, "packet_seq_num");
+                       if (int_fc) {
+                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT;
+
+                       }
+
+                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                               (void *) sc->packet_context_fc, "packet_size");
+                       if (int_fc) {
+                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE;
+                       }
+
+                       int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                               (void *) sc->packet_context_fc, "content_size");
+                       if (int_fc) {
+                               int_fc->meaning = CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE;
+                       }
+               }
+
+               if (sc->event_header_fc) {
+                       ret = set_int_field_class_meaning_by_name(
+                               sc->event_header_fc, NULL, "id",
+                               CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+       }
+
+       for (i = 0; i < sc->event_classes->len; i++) {
+               struct ctf_event_class *ec = sc->event_classes->pdata[i];
+
+               if (ec->is_translated) {
+                       continue;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc)
+{
+       int ret = 0;
+       struct ctf_field_class_int *int_fc;
+       struct ctf_named_field_class *named_fc;
+       uint64_t i;
+
+       if (!ctf_tc->is_translated && ctf_tc->packet_header_fc) {
+               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                       (void *) ctf_tc->packet_header_fc, "magic");
+               if (int_fc) {
+                       int_fc->meaning = CTF_FIELD_CLASS_MEANING_MAGIC;
+               }
+
+               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                       (void *) ctf_tc->packet_header_fc, "stream_id");
+               if (int_fc) {
+                       int_fc->meaning = CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID;
+               }
+
+               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                       (void *) ctf_tc->packet_header_fc,
+                       "stream_instance_id");
+               if (int_fc) {
+                       int_fc->meaning = CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID;
+               }
+
+               named_fc = ctf_field_class_struct_borrow_member_by_name(
+                       (void *) ctf_tc->packet_header_fc, "uuid");
+               if (named_fc && named_fc->fc->type == CTF_FIELD_CLASS_TYPE_ARRAY) {
+                       struct ctf_field_class_array *array_fc =
+                               (void *) named_fc->fc;
+
+                       array_fc->meaning = CTF_FIELD_CLASS_MEANING_UUID;
+               }
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               ret = update_stream_class_meanings(
+                       ctf_tc->stream_classes->pdata[i]);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.c b/src/plugins/ctf/common/metadata/ctf-meta-update-stream-class-config.c
new file mode 100644 (file)
index 0000000..d5dd9d9
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-SC-CONFIG"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+BT_HIDDEN
+int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc)
+{
+       struct ctf_field_class_int *int_fc;
+       uint64_t i;
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc =
+                       ctf_tc->stream_classes->pdata[i];
+
+               if (sc->is_translated) {
+                       continue;
+               }
+
+               if (!sc->packet_context_fc) {
+                       continue;
+               }
+
+               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                       (void *) sc->packet_context_fc, "timestamp_begin");
+               if (int_fc && int_fc->meaning ==
+                               CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME) {
+                       sc->packets_have_ts_begin = true;
+               }
+
+               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                       (void *) sc->packet_context_fc, "timestamp_end");
+               if (int_fc && int_fc->meaning ==
+                               CTF_FIELD_CLASS_MEANING_PACKET_END_TIME) {
+                       sc->packets_have_ts_end = true;
+               }
+
+               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                       (void *) sc->packet_context_fc, "events_discarded");
+               if (int_fc && int_fc->meaning ==
+                               CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT) {
+                       sc->has_discarded_events = true;
+               }
+
+               sc->discarded_events_have_default_cs =
+                       sc->has_discarded_events && sc->packets_have_ts_begin &&
+                       sc->packets_have_ts_end;
+               int_fc = ctf_field_class_struct_borrow_member_int_field_class_by_name(
+                       (void *) sc->packet_context_fc, "packet_seq_num");
+               if (int_fc && int_fc->meaning ==
+                               CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT) {
+                       sc->has_discarded_packets = true;
+               }
+
+               sc->discarded_packets_have_default_cs =
+                       sc->has_discarded_packets &&
+                       sc->packets_have_ts_begin && sc->packets_have_ts_end;
+       }
+
+       return 0;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c b/src/plugins/ctf/common/metadata/ctf-meta-update-text-array-sequence.c
new file mode 100644 (file)
index 0000000..8201954
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-TEXT-ARRAY-SEQ"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static inline
+int set_text_array_sequence_field_class(struct ctf_field_class *fc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (!fc) {
+               goto end;
+       }
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               for (i = 0; i < struct_fc->members->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+
+                       ret = set_text_array_sequence_field_class(named_fc->fc);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               for (i = 0; i < var_fc->options->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+
+                       ret = set_text_array_sequence_field_class(named_fc->fc);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               if (array_fc->elem_fc->type == CTF_FIELD_CLASS_TYPE_INT ||
+                               array_fc->elem_fc->type == CTF_FIELD_CLASS_TYPE_ENUM) {
+                       struct ctf_field_class_int *int_fc =
+                               (void *) array_fc->elem_fc;
+
+                       if (int_fc->base.base.alignment == 8 &&
+                                       int_fc->base.size == 8 &&
+                                       int_fc->encoding == CTF_ENCODING_UTF8) {
+                               array_fc->is_text = true;
+
+                               /*
+                                * Force integer element to be unsigned;
+                                * this makes the decoder enter a single
+                                * path when reading a text
+                                * array/sequence and we can safely
+                                * decode bytes as characters anyway.
+                                */
+                               int_fc->is_signed = false;
+                       }
+               }
+
+               ret = set_text_array_sequence_field_class(array_fc->elem_fc);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (!ctf_tc->is_translated) {
+               ret = set_text_array_sequence_field_class(
+                       ctf_tc->packet_header_fc);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
+               uint64_t j;
+
+               if (!sc->is_translated) {
+                       ret = set_text_array_sequence_field_class(
+                               sc->packet_context_fc);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       ret = set_text_array_sequence_field_class(
+                               sc->event_header_fc);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       ret = set_text_array_sequence_field_class(
+                               sc->event_common_context_fc);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               for (j = 0; j < sc->event_classes->len; j++) {
+                       struct ctf_event_class *ec =
+                               sc->event_classes->pdata[j];
+
+                       if (ec->is_translated) {
+                               continue;
+                       }
+
+                       ret = set_text_array_sequence_field_class(
+                               ec->spec_context_fc);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       ret = set_text_array_sequence_field_class(
+                               ec->payload_fc);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c b/src/plugins/ctf/common/metadata/ctf-meta-update-value-storing-indexes.c
new file mode 100644 (file)
index 0000000..81f7638
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-UPDATE-VALUE-STORING-INDEXES"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static
+int update_field_class_stored_value_index(struct ctf_field_class *fc,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       int ret = 0;
+       uint64_t i;
+       struct ctf_field_path *field_path = NULL;
+       struct ctf_field_class_int *tgt_fc = NULL;
+       uint64_t *stored_value_index = NULL;
+
+       if (!fc) {
+               goto end;
+       }
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               field_path = &var_fc->tag_path;
+               stored_value_index = &var_fc->stored_tag_index;
+               tgt_fc = (void *) var_fc->tag_fc;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_sequence *seq_fc = (void *) fc;
+
+               field_path = &seq_fc->length_path;
+               stored_value_index = &seq_fc->stored_length_index;
+               tgt_fc = seq_fc->length_fc;
+               break;
+       }
+       default:
+               break;
+       }
+
+       if (field_path) {
+               BT_ASSERT(tgt_fc);
+               BT_ASSERT(tgt_fc->base.base.type == CTF_FIELD_CLASS_TYPE_INT ||
+                       tgt_fc->base.base.type == CTF_FIELD_CLASS_TYPE_ENUM);
+               if (tgt_fc->storing_index >= 0) {
+                       /* Already storing its value */
+                       *stored_value_index = (uint64_t) tgt_fc->storing_index;
+               } else {
+                       /* Not storing its value: allocate new index */
+                       tgt_fc->storing_index = tc->stored_value_count;
+                       *stored_value_index = (uint64_t) tgt_fc->storing_index;
+                       tc->stored_value_count++;
+               }
+       }
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               for (i = 0; i < struct_fc->members->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+
+                       ret = update_field_class_stored_value_index(named_fc->fc,
+                               tc, sc, ec);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               for (i = 0; i < var_fc->options->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+
+                       ret = update_field_class_stored_value_index(named_fc->fc,
+                               tc, sc, ec);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               ret = update_field_class_stored_value_index(array_fc->elem_fc,
+                       tc, sc, ec);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc)
+{
+       uint64_t i;
+
+       if (!ctf_tc->is_translated) {
+               update_field_class_stored_value_index(
+                       ctf_tc->packet_header_fc, ctf_tc, NULL, NULL);
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               uint64_t j;
+               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
+
+               if (!sc->is_translated) {
+                       update_field_class_stored_value_index(sc->packet_context_fc,
+                               ctf_tc, sc, NULL);
+                       update_field_class_stored_value_index(sc->event_header_fc,
+                               ctf_tc, sc, NULL);
+                       update_field_class_stored_value_index(
+                               sc->event_common_context_fc, ctf_tc, sc, NULL);
+               }
+
+               for (j = 0; j < sc->event_classes->len; j++) {
+                       struct ctf_event_class *ec =
+                               sc->event_classes->pdata[j];
+
+                       if (!ec->is_translated) {
+                               update_field_class_stored_value_index(
+                                       ec->spec_context_fc, ctf_tc, sc, ec);
+                               update_field_class_stored_value_index(
+                                       ec->payload_fc, ctf_tc, sc, ec);
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-validate.c b/src/plugins/ctf/common/metadata/ctf-meta-validate.c
new file mode 100644 (file)
index 0000000..bb1aac0
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-VALIDATE"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static
+int validate_stream_class(struct ctf_stream_class *sc)
+{
+       int ret = 0;
+       struct ctf_field_class_int *int_fc;
+       struct ctf_field_class *fc;
+
+       if (sc->is_translated) {
+               goto end;
+       }
+
+       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+               (void *) sc->packet_context_fc, "timestamp_begin");
+       if (fc) {
+               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`timestamp_begin` member is not an integer field class.");
+                       goto invalid;
+               }
+
+               int_fc = (void *) fc;
+
+               if (int_fc->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`timestamp_begin` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+               (void *) sc->packet_context_fc, "timestamp_end");
+       if (fc) {
+               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`timestamp_end` member is not an integer field class.");
+                       goto invalid;
+               }
+
+               int_fc = (void *) fc;
+
+               if (int_fc->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`timestamp_end` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+               (void *) sc->packet_context_fc, "events_discarded");
+       if (fc) {
+               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`events_discarded` member is not an integer field class.");
+                       goto invalid;
+               }
+
+               int_fc = (void *) fc;
+
+               if (int_fc->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`events_discarded` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+               (void *) sc->packet_context_fc, "packet_seq_num");
+       if (fc) {
+               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`packet_seq_num` member is not an integer field class.");
+                       goto invalid;
+               }
+
+               int_fc = (void *) fc;
+
+               if (int_fc->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`packet_seq_num` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+               (void *) sc->packet_context_fc, "packet_size");
+       if (fc) {
+               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`packet_size` member is not an integer field class.");
+                       goto invalid;
+               }
+
+               int_fc = (void *) fc;
+
+               if (int_fc->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`packet_size` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+               (void *) sc->packet_context_fc, "content_size");
+       if (fc) {
+               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`content_size` member is not an integer field class.");
+                       goto invalid;
+               }
+
+               int_fc = (void *) fc;
+
+               if (int_fc->is_signed) {
+                       BT_LOGE_STR("Invalid packet context field class: "
+                               "`content_size` member is signed.");
+                       goto invalid;
+               }
+       }
+
+       fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+               (void *) sc->event_header_fc, "id");
+       if (fc) {
+               if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       BT_LOGE_STR("Invalid event header field class: "
+                               "`id` member is not an integer field class.");
+                       goto invalid;
+               }
+
+               int_fc = (void *) fc;
+
+               if (int_fc->is_signed) {
+                       BT_LOGE_STR("Invalid event header field class: "
+                               "`id` member is signed.");
+                       goto invalid;
+               }
+       } else {
+               if (sc->event_classes->len > 1) {
+                       BT_LOGE_STR("Invalid event header field class: "
+                               "missing `id` member as there's "
+                               "more than one event class.");
+                       goto invalid;
+               }
+       }
+
+       goto end;
+
+invalid:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc)
+{
+       int ret = 0;
+       struct ctf_field_class_int *int_fc;
+       uint64_t i;
+
+       if (!ctf_tc->is_translated) {
+               struct ctf_field_class *fc;
+
+               fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+                       (void *) ctf_tc->packet_header_fc, "magic");
+               if (fc) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       (void *) ctf_tc->packet_header_fc,
+                                       0);
+
+                       if (named_fc->fc != fc) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`magic` member is not the first member.");
+                               goto invalid;
+                       }
+
+                       if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                                       fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`magic` member is not an integer field class.");
+                               goto invalid;
+                       }
+
+                       int_fc = (void *) fc;
+
+                       if (int_fc->is_signed) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`magic` member is signed.");
+                               goto invalid;
+                       }
+
+                       if (int_fc->base.size != 32) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`magic` member is not 32-bit.");
+                               goto invalid;
+                       }
+               }
+
+               fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+                       (void *) ctf_tc->packet_header_fc, "stream_id");
+               if (fc) {
+                       if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                                       fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`stream_id` member is not an integer field class.");
+                               goto invalid;
+                       }
+
+                       int_fc = (void *) fc;
+
+                       if (int_fc->is_signed) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`stream_id` member is signed.");
+                               goto invalid;
+                       }
+               } else {
+                       if (ctf_tc->stream_classes->len > 1) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "missing `stream_id` member as there's "
+                                       "more than one stream class.");
+                               goto invalid;
+                       }
+               }
+
+               fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+                       (void *) ctf_tc->packet_header_fc,
+                       "stream_instance_id");
+               if (fc) {
+                       if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                                       fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`stream_instance_id` member is not an integer field class.");
+                               goto invalid;
+                       }
+
+                       int_fc = (void *) fc;
+
+                       if (int_fc->is_signed) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`stream_instance_id` member is signed.");
+                               goto invalid;
+                       }
+               }
+
+               fc = ctf_field_class_struct_borrow_member_field_class_by_name(
+                       (void *) ctf_tc->packet_header_fc, "uuid");
+               if (fc) {
+                       struct ctf_field_class_array *array_fc = (void *) fc;
+
+                       if (fc->type != CTF_FIELD_CLASS_TYPE_ARRAY) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`uuid` member is not an array field class.");
+                               goto invalid;
+                       }
+
+                       array_fc = (void *) fc;
+
+                       if (array_fc->length != 16) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`uuid` member is not a 16-element array field class.");
+                               goto invalid;
+                       }
+
+                       if (array_fc->base.elem_fc->type != CTF_FIELD_CLASS_TYPE_INT) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`uuid` member's element field class is not "
+                                       "an integer field class.");
+                               goto invalid;
+                       }
+
+                       int_fc = (void *) array_fc->base.elem_fc;
+
+                       if (int_fc->is_signed) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`uuid` member's element field class "
+                                       "is a signed integer field class.");
+                               goto invalid;
+                       }
+
+                       if (int_fc->base.size != 8) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`uuid` member's element field class "
+                                       "is not an 8-bit integer field class.");
+                               goto invalid;
+                       }
+
+                       if (int_fc->base.base.alignment != 8) {
+                               BT_LOGE_STR("Invalid packet header field class: "
+                                       "`uuid` member's element field class's "
+                                       "alignment is not 8.");
+                               goto invalid;
+                       }
+               }
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc =
+                       ctf_tc->stream_classes->pdata[i];
+
+               ret = validate_stream_class(sc);
+               if (ret) {
+                       BT_LOGE("Invalid stream class: sc-id=%" PRIu64, sc->id);
+                       goto invalid;
+               }
+       }
+
+       goto end;
+
+invalid:
+       ret = -1;
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-visitors.h b/src/plugins/ctf/common/metadata/ctf-meta-visitors.h
new file mode 100644 (file)
index 0000000..9eb3cf3
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef _CTF_META_VISITORS_H
+#define _CTF_META_VISITORS_H
+
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+
+#include "ctf-meta.h"
+
+BT_HIDDEN
+int ctf_trace_class_resolve_field_classes(struct ctf_trace_class *tc);
+
+BT_HIDDEN
+int ctf_trace_class_translate(bt_self_component_source *self_comp,
+               bt_trace_class *ir_tc, struct ctf_trace_class *tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_default_clock_classes(
+               struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_in_ir(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_meanings(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_text_array_sequence(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_value_storing_indexes(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_update_stream_class_config(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+int ctf_trace_class_validate(struct ctf_trace_class *ctf_tc);
+
+BT_HIDDEN
+void ctf_trace_class_warn_meaningless_header_fields(
+               struct ctf_trace_class *ctf_tc);
+
+#endif /* _CTF_META_VISITORS_H */
diff --git a/src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.c b/src/plugins/ctf/common/metadata/ctf-meta-warn-meaningless-header-fields.c
new file mode 100644 (file)
index 0000000..73b6fe9
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-META-WARN-MEANINGLESS-HEADER-FIELDS"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "ctf-meta-visitors.h"
+
+static inline
+void warn_meaningless_field(const char *name, const char *scope_name)
+{
+       BT_LOGW("User field found in %s: ignoring: name=\"%s\"",
+               scope_name, name);
+}
+
+static inline
+void warn_meaningless_fields(struct ctf_field_class *fc, const char *name,
+               const char *scope_name)
+{
+       uint64_t i;
+
+       if (!fc) {
+               goto end;
+       }
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_FLOAT:
+       case CTF_FIELD_CLASS_TYPE_STRING:
+               warn_meaningless_field(name, scope_name);
+               break;
+       case CTF_FIELD_CLASS_TYPE_INT:
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+       {
+               struct ctf_field_class_int *int_fc = (void *) fc;
+
+               if (int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE &&
+                               !int_fc->mapped_clock_class) {
+                       warn_meaningless_field(name, scope_name);
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               for (i = 0; i < struct_fc->members->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+
+                       warn_meaningless_fields(named_fc->fc,
+                               named_fc->name->str, scope_name);
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               for (i = 0; i < var_fc->options->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+
+                       warn_meaningless_fields(named_fc->fc,
+                               named_fc->name->str, scope_name);
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       {
+               struct ctf_field_class_array *array_fc = (void *) fc;
+
+               if (array_fc->meaning != CTF_FIELD_CLASS_MEANING_NONE) {
+                       goto end;
+               }
+
+       }
+       /* fall-through */
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               warn_meaningless_fields(array_fc->elem_fc, name, scope_name);
+               break;
+       }
+       default:
+               abort();
+       }
+
+end:
+       return;
+}
+
+BT_HIDDEN
+void ctf_trace_class_warn_meaningless_header_fields(
+               struct ctf_trace_class *ctf_tc)
+{
+       uint64_t i;
+
+       if (!ctf_tc->is_translated) {
+               warn_meaningless_fields(
+                       ctf_tc->packet_header_fc, NULL, "packet header");
+       }
+
+       for (i = 0; i < ctf_tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = ctf_tc->stream_classes->pdata[i];
+
+               if (!sc->is_translated) {
+                       warn_meaningless_fields(sc->event_header_fc, NULL,
+                               "event header");
+               }
+       }
+}
diff --git a/src/plugins/ctf/common/metadata/ctf-meta.h b/src/plugins/ctf/common/metadata/ctf-meta.h
new file mode 100644 (file)
index 0000000..29c5e17
--- /dev/null
@@ -0,0 +1,1680 @@
+#ifndef _CTF_META_H
+#define _CTF_META_H
+
+/*
+ * Copyright 2018 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "common/common.h"
+#include "common/assert.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+
+enum ctf_field_class_type {
+       CTF_FIELD_CLASS_TYPE_INT,
+       CTF_FIELD_CLASS_TYPE_ENUM,
+       CTF_FIELD_CLASS_TYPE_FLOAT,
+       CTF_FIELD_CLASS_TYPE_STRING,
+       CTF_FIELD_CLASS_TYPE_STRUCT,
+       CTF_FIELD_CLASS_TYPE_ARRAY,
+       CTF_FIELD_CLASS_TYPE_SEQUENCE,
+       CTF_FIELD_CLASS_TYPE_VARIANT,
+};
+
+enum ctf_field_class_meaning {
+       CTF_FIELD_CLASS_MEANING_NONE,
+       CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME,
+       CTF_FIELD_CLASS_MEANING_PACKET_END_TIME,
+       CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID,
+       CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID,
+       CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID,
+       CTF_FIELD_CLASS_MEANING_MAGIC,
+       CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT,
+       CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT,
+       CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE,
+       CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE,
+       CTF_FIELD_CLASS_MEANING_UUID,
+};
+
+enum ctf_byte_order {
+       CTF_BYTE_ORDER_DEFAULT,
+       CTF_BYTE_ORDER_LITTLE,
+       CTF_BYTE_ORDER_BIG,
+};
+
+enum ctf_encoding {
+       CTF_ENCODING_NONE,
+       CTF_ENCODING_UTF8,
+};
+
+enum ctf_scope {
+       CTF_SCOPE_PACKET_HEADER,
+       CTF_SCOPE_PACKET_CONTEXT,
+       CTF_SCOPE_EVENT_HEADER,
+       CTF_SCOPE_EVENT_COMMON_CONTEXT,
+       CTF_SCOPE_EVENT_SPECIFIC_CONTEXT,
+       CTF_SCOPE_EVENT_PAYLOAD,
+};
+
+struct ctf_clock_class {
+       GString *name;
+       GString *description;
+       uint64_t frequency;
+       uint64_t precision;
+       int64_t offset_seconds;
+       uint64_t offset_cycles;
+       uint8_t uuid[16];
+       bool has_uuid;
+       bool is_absolute;
+
+       /* Weak, set during translation */
+       bt_clock_class *ir_cc;
+};
+
+struct ctf_field_class {
+       enum ctf_field_class_type type;
+       unsigned int alignment;
+       bool is_compound;
+       bool in_ir;
+
+       /* Weak, set during translation. NULL if `in_ir` is false below. */
+       bt_field_class *ir_fc;
+};
+
+struct ctf_field_class_bit_array {
+       struct ctf_field_class base;
+       enum ctf_byte_order byte_order;
+       unsigned int size;
+};
+
+struct ctf_field_class_int {
+       struct ctf_field_class_bit_array base;
+       enum ctf_field_class_meaning meaning;
+       bool is_signed;
+       bt_field_class_integer_preferred_display_base disp_base;
+       enum ctf_encoding encoding;
+       int64_t storing_index;
+
+       /* Weak */
+       struct ctf_clock_class *mapped_clock_class;
+};
+
+struct ctf_range {
+       union {
+               uint64_t u;
+               int64_t i;
+       } lower;
+
+       union {
+               uint64_t u;
+               int64_t i;
+       } upper;
+};
+
+struct ctf_field_class_enum_mapping {
+       GString *label;
+       struct ctf_range range;
+};
+
+struct ctf_field_class_enum {
+       struct ctf_field_class_int base;
+
+       /* Array of `struct ctf_field_class_enum_mapping` */
+       GArray *mappings;
+};
+
+struct ctf_field_class_float {
+       struct ctf_field_class_bit_array base;
+};
+
+struct ctf_field_class_string {
+       struct ctf_field_class base;
+       enum ctf_encoding encoding;
+};
+
+struct ctf_named_field_class {
+       GString *name;
+
+       /* Owned by this */
+       struct ctf_field_class *fc;
+};
+
+struct ctf_field_class_struct {
+       struct ctf_field_class base;
+
+       /* Array of `struct ctf_named_field_class` */
+       GArray *members;
+};
+
+struct ctf_field_path {
+       enum ctf_scope root;
+
+       /* Array of `int64_t` */
+       GArray *path;
+};
+
+struct ctf_field_class_variant_range {
+       struct ctf_range range;
+       uint64_t option_index;
+};
+
+struct ctf_field_class_variant {
+       struct ctf_field_class base;
+       GString *tag_ref;
+       struct ctf_field_path tag_path;
+       uint64_t stored_tag_index;
+
+       /* Array of `struct ctf_named_field_class` */
+       GArray *options;
+
+       /* Array of `struct ctf_field_class_variant_range` */
+       GArray *ranges;
+
+       /* Weak */
+       struct ctf_field_class_enum *tag_fc;
+};
+
+struct ctf_field_class_array_base {
+       struct ctf_field_class base;
+       struct ctf_field_class *elem_fc;
+       bool is_text;
+};
+
+struct ctf_field_class_array {
+       struct ctf_field_class_array_base base;
+       enum ctf_field_class_meaning meaning;
+       uint64_t length;
+};
+
+struct ctf_field_class_sequence {
+       struct ctf_field_class_array_base base;
+       GString *length_ref;
+       struct ctf_field_path length_path;
+       uint64_t stored_length_index;
+
+       /* Weak */
+       struct ctf_field_class_int *length_fc;
+};
+
+struct ctf_event_class {
+       GString *name;
+       uint64_t id;
+       GString *emf_uri;
+       bt_event_class_log_level log_level;
+       bool is_translated;
+
+       /* Owned by this */
+       struct ctf_field_class *spec_context_fc;
+
+       /* Owned by this */
+       struct ctf_field_class *payload_fc;
+
+       /* Weak, set during translation */
+       bt_event_class *ir_ec;
+};
+
+struct ctf_stream_class {
+       uint64_t id;
+       bool is_translated;
+       bool packets_have_ts_begin;
+       bool packets_have_ts_end;
+       bool has_discarded_events;
+       bool has_discarded_packets;
+       bool discarded_events_have_default_cs;
+       bool discarded_packets_have_default_cs;
+
+       /* Owned by this */
+       struct ctf_field_class *packet_context_fc;
+
+       /* Owned by this */
+       struct ctf_field_class *event_header_fc;
+
+       /* Owned by this */
+       struct ctf_field_class *event_common_context_fc;
+
+       /* Array of `struct ctf_event_class *`, owned by this */
+       GPtrArray *event_classes;
+
+       /*
+        * Hash table mapping event class IDs to `struct ctf_event_class *`,
+        * weak.
+        */
+       GHashTable *event_classes_by_id;
+
+       /* Weak */
+       struct ctf_clock_class *default_clock_class;
+
+       /* Weak, set during translation */
+       bt_stream_class *ir_sc;
+};
+
+enum ctf_trace_class_env_entry_type {
+       CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT,
+       CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR,
+};
+
+struct ctf_trace_class_env_entry {
+       enum ctf_trace_class_env_entry_type type;
+       GString *name;
+
+       struct {
+               int64_t i;
+               GString *str;
+       } value;
+};
+
+struct ctf_trace_class {
+       unsigned int major;
+       unsigned int minor;
+       uint8_t uuid[16];
+       bool is_uuid_set;
+       enum ctf_byte_order default_byte_order;
+
+       /* Owned by this */
+       struct ctf_field_class *packet_header_fc;
+
+       uint64_t stored_value_count;
+
+       /* Array of `struct ctf_clock_class *` (owned by this) */
+       GPtrArray *clock_classes;
+
+       /* Array of `struct ctf_stream_class *` */
+       GPtrArray *stream_classes;
+
+       /* Array of `struct ctf_trace_class_env_entry` */
+       GArray *env_entries;
+
+       bool is_translated;
+
+       /* Weak, set during translation */
+       bt_trace_class *ir_tc;
+};
+
+static inline
+void ctf_field_class_destroy(struct ctf_field_class *fc);
+
+static inline
+void _ctf_field_class_init(struct ctf_field_class *fc,
+               enum ctf_field_class_type type, unsigned int alignment)
+{
+       BT_ASSERT(fc);
+       fc->type = type;
+       fc->alignment = alignment;
+       fc->in_ir = false;
+}
+
+static inline
+void _ctf_field_class_bit_array_init(struct ctf_field_class_bit_array *fc,
+               enum ctf_field_class_type type)
+{
+       _ctf_field_class_init((void *) fc, type, 1);
+}
+
+static inline
+void _ctf_field_class_int_init(struct ctf_field_class_int *fc,
+               enum ctf_field_class_type type)
+{
+       _ctf_field_class_bit_array_init((void *) fc, type);
+       fc->meaning = CTF_FIELD_CLASS_MEANING_NONE;
+       fc->storing_index = -1;
+}
+
+static inline
+void ctf_field_path_init(struct ctf_field_path *field_path)
+{
+       BT_ASSERT(field_path);
+       field_path->path = g_array_new(FALSE, TRUE, sizeof(int64_t));
+       BT_ASSERT(field_path->path);
+}
+
+static inline
+void ctf_field_path_fini(struct ctf_field_path *field_path)
+{
+       BT_ASSERT(field_path);
+
+       if (field_path->path) {
+               g_array_free(field_path->path, TRUE);
+       }
+}
+
+static inline
+void _ctf_named_field_class_init(struct ctf_named_field_class *named_fc)
+{
+       BT_ASSERT(named_fc);
+       named_fc->name = g_string_new(NULL);
+       BT_ASSERT(named_fc->name);
+}
+
+static inline
+void _ctf_named_field_class_fini(struct ctf_named_field_class *named_fc)
+{
+       BT_ASSERT(named_fc);
+
+       if (named_fc->name) {
+               g_string_free(named_fc->name, TRUE);
+       }
+
+       ctf_field_class_destroy(named_fc->fc);
+}
+
+static inline
+void _ctf_field_class_enum_mapping_init(
+               struct ctf_field_class_enum_mapping *mapping)
+{
+       BT_ASSERT(mapping);
+       mapping->label = g_string_new(NULL);
+       BT_ASSERT(mapping->label);
+}
+
+static inline
+void _ctf_field_class_enum_mapping_fini(
+               struct ctf_field_class_enum_mapping *mapping)
+{
+       BT_ASSERT(mapping);
+
+       if (mapping->label) {
+               g_string_free(mapping->label, TRUE);
+       }
+}
+
+static inline
+struct ctf_field_class_int *ctf_field_class_int_create(void)
+{
+       struct ctf_field_class_int *fc = g_new0(struct ctf_field_class_int, 1);
+
+       BT_ASSERT(fc);
+       _ctf_field_class_int_init(fc, CTF_FIELD_CLASS_TYPE_INT);
+       return fc;
+}
+
+static inline
+struct ctf_field_class_float *ctf_field_class_float_create(void)
+{
+       struct ctf_field_class_float *fc =
+               g_new0(struct ctf_field_class_float, 1);
+
+       BT_ASSERT(fc);
+       _ctf_field_class_bit_array_init((void *) fc, CTF_FIELD_CLASS_TYPE_FLOAT);
+       return fc;
+}
+
+static inline
+struct ctf_field_class_string *ctf_field_class_string_create(void)
+{
+       struct ctf_field_class_string *fc =
+               g_new0(struct ctf_field_class_string, 1);
+
+       BT_ASSERT(fc);
+       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_STRING, 8);
+       return fc;
+}
+
+static inline
+struct ctf_field_class_enum *ctf_field_class_enum_create(void)
+{
+       struct ctf_field_class_enum *fc = g_new0(struct ctf_field_class_enum, 1);
+
+       BT_ASSERT(fc);
+       _ctf_field_class_int_init((void *) fc, CTF_FIELD_CLASS_TYPE_ENUM);
+       fc->mappings = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_field_class_enum_mapping));
+       BT_ASSERT(fc->mappings);
+       return fc;
+}
+
+static inline
+struct ctf_field_class_struct *ctf_field_class_struct_create(void)
+{
+       struct ctf_field_class_struct *fc =
+               g_new0(struct ctf_field_class_struct, 1);
+
+       BT_ASSERT(fc);
+       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_STRUCT, 1);
+       fc->members = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_named_field_class));
+       BT_ASSERT(fc->members);
+       fc->base.is_compound = true;
+       return fc;
+}
+
+static inline
+struct ctf_field_class_variant *ctf_field_class_variant_create(void)
+{
+       struct ctf_field_class_variant *fc =
+               g_new0(struct ctf_field_class_variant, 1);
+
+       BT_ASSERT(fc);
+       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_VARIANT, 1);
+       fc->options = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_named_field_class));
+       BT_ASSERT(fc->options);
+       fc->ranges = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_field_class_variant_range));
+       BT_ASSERT(fc->ranges);
+       fc->tag_ref = g_string_new(NULL);
+       BT_ASSERT(fc->tag_ref);
+       ctf_field_path_init(&fc->tag_path);
+       fc->base.is_compound = true;
+       return fc;
+}
+
+static inline
+struct ctf_field_class_array *ctf_field_class_array_create(void)
+{
+       struct ctf_field_class_array *fc =
+               g_new0(struct ctf_field_class_array, 1);
+
+       BT_ASSERT(fc);
+       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_ARRAY, 1);
+       fc->base.base.is_compound = true;
+       return fc;
+}
+
+static inline
+struct ctf_field_class_sequence *ctf_field_class_sequence_create(void)
+{
+       struct ctf_field_class_sequence *fc =
+               g_new0(struct ctf_field_class_sequence, 1);
+
+       BT_ASSERT(fc);
+       _ctf_field_class_init((void *) fc, CTF_FIELD_CLASS_TYPE_SEQUENCE, 1);
+       fc->length_ref = g_string_new(NULL);
+       BT_ASSERT(fc->length_ref);
+       ctf_field_path_init(&fc->length_path);
+       fc->base.base.is_compound = true;
+       return fc;
+}
+
+static inline
+void _ctf_field_class_int_destroy(struct ctf_field_class_int *fc)
+{
+       BT_ASSERT(fc);
+       g_free(fc);
+}
+
+static inline
+void _ctf_field_class_enum_destroy(struct ctf_field_class_enum *fc)
+{
+       BT_ASSERT(fc);
+
+       if (fc->mappings) {
+               uint64_t i;
+
+               for (i = 0; i < fc->mappings->len; i++) {
+                       struct ctf_field_class_enum_mapping *mapping =
+                               &g_array_index(fc->mappings,
+                                       struct ctf_field_class_enum_mapping, i);
+
+                       _ctf_field_class_enum_mapping_fini(mapping);
+               }
+
+               g_array_free(fc->mappings, TRUE);
+       }
+
+       g_free(fc);
+}
+
+static inline
+void _ctf_field_class_float_destroy(struct ctf_field_class_float *fc)
+{
+       BT_ASSERT(fc);
+       g_free(fc);
+}
+
+static inline
+void _ctf_field_class_string_destroy(struct ctf_field_class_string *fc)
+{
+       BT_ASSERT(fc);
+       g_free(fc);
+}
+
+static inline
+void _ctf_field_class_struct_destroy(struct ctf_field_class_struct *fc)
+{
+       BT_ASSERT(fc);
+
+       if (fc->members) {
+               uint64_t i;
+
+               for (i = 0; i < fc->members->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               &g_array_index(fc->members,
+                                       struct ctf_named_field_class, i);
+
+                       _ctf_named_field_class_fini(named_fc);
+               }
+
+               g_array_free(fc->members, TRUE);
+       }
+
+       g_free(fc);
+}
+
+static inline
+void _ctf_field_class_array_base_fini(struct ctf_field_class_array_base *fc)
+{
+       BT_ASSERT(fc);
+       ctf_field_class_destroy(fc->elem_fc);
+}
+
+static inline
+void _ctf_field_class_array_destroy(struct ctf_field_class_array *fc)
+{
+       BT_ASSERT(fc);
+       _ctf_field_class_array_base_fini((void *) fc);
+       g_free(fc);
+}
+
+static inline
+void _ctf_field_class_sequence_destroy(struct ctf_field_class_sequence *fc)
+{
+       BT_ASSERT(fc);
+       _ctf_field_class_array_base_fini((void *) fc);
+
+       if (fc->length_ref) {
+               g_string_free(fc->length_ref, TRUE);
+       }
+
+       ctf_field_path_fini(&fc->length_path);
+       g_free(fc);
+}
+
+static inline
+void _ctf_field_class_variant_destroy(struct ctf_field_class_variant *fc)
+{
+       BT_ASSERT(fc);
+
+       if (fc->options) {
+               uint64_t i;
+
+               for (i = 0; i < fc->options->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               &g_array_index(fc->options,
+                                       struct ctf_named_field_class, i);
+
+                       _ctf_named_field_class_fini(named_fc);
+               }
+
+               g_array_free(fc->options, TRUE);
+       }
+
+       if (fc->ranges) {
+               g_array_free(fc->ranges, TRUE);
+       }
+
+       if (fc->tag_ref) {
+               g_string_free(fc->tag_ref, TRUE);
+       }
+
+       ctf_field_path_fini(&fc->tag_path);
+       g_free(fc);
+}
+
+static inline
+void ctf_field_class_destroy(struct ctf_field_class *fc)
+{
+       if (!fc) {
+               return;
+       }
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_INT:
+               _ctf_field_class_int_destroy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+               _ctf_field_class_enum_destroy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_FLOAT:
+               _ctf_field_class_float_destroy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_STRING:
+               _ctf_field_class_string_destroy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+               _ctf_field_class_struct_destroy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+               _ctf_field_class_array_destroy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+               _ctf_field_class_sequence_destroy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+               _ctf_field_class_variant_destroy((void *) fc);
+               break;
+       default:
+               abort();
+       }
+}
+
+static inline
+void ctf_field_class_enum_append_mapping(struct ctf_field_class_enum *fc,
+               const char *label, uint64_t u_lower, uint64_t u_upper)
+{
+       struct ctf_field_class_enum_mapping *mapping;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(label);
+       g_array_set_size(fc->mappings, fc->mappings->len + 1);
+
+       mapping = &g_array_index(fc->mappings,
+               struct ctf_field_class_enum_mapping, fc->mappings->len - 1);
+       _ctf_field_class_enum_mapping_init(mapping);
+       g_string_assign(mapping->label, label);
+       mapping->range.lower.u = u_lower;
+       mapping->range.upper.u = u_upper;
+}
+
+static inline
+struct ctf_field_class_enum_mapping *ctf_field_class_enum_borrow_mapping_by_index(
+               struct ctf_field_class_enum *fc, uint64_t index)
+{
+       BT_ASSERT(fc);
+       BT_ASSERT(index < fc->mappings->len);
+       return &g_array_index(fc->mappings, struct ctf_field_class_enum_mapping,
+               index);
+}
+
+static inline
+struct ctf_named_field_class *ctf_field_class_struct_borrow_member_by_index(
+               struct ctf_field_class_struct *fc, uint64_t index)
+{
+       BT_ASSERT(fc);
+       BT_ASSERT(index < fc->members->len);
+       return &g_array_index(fc->members, struct ctf_named_field_class,
+               index);
+}
+
+static inline
+struct ctf_named_field_class *ctf_field_class_struct_borrow_member_by_name(
+               struct ctf_field_class_struct *fc, const char *name)
+{
+       uint64_t i;
+       struct ctf_named_field_class *ret_named_fc = NULL;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(name);
+
+       for (i = 0; i < fc->members->len; i++) {
+               struct ctf_named_field_class *named_fc =
+                       ctf_field_class_struct_borrow_member_by_index(fc, i);
+
+               if (strcmp(name, named_fc->name->str) == 0) {
+                       ret_named_fc = named_fc;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_named_fc;
+}
+
+static inline
+struct ctf_field_class *ctf_field_class_struct_borrow_member_field_class_by_name(
+               struct ctf_field_class_struct *struct_fc, const char *name)
+{
+       struct ctf_named_field_class *named_fc = NULL;
+       struct ctf_field_class *fc = NULL;
+
+       if (!struct_fc) {
+               goto end;
+       }
+
+       named_fc = ctf_field_class_struct_borrow_member_by_name(struct_fc, name);
+       if (!named_fc) {
+               goto end;
+       }
+
+       fc = named_fc->fc;
+
+end:
+       return fc;
+}
+
+static inline
+struct ctf_field_class_int *
+ctf_field_class_struct_borrow_member_int_field_class_by_name(
+               struct ctf_field_class_struct *struct_fc, const char *name)
+{
+       struct ctf_field_class_int *int_fc = NULL;
+
+       int_fc = (void *)
+               ctf_field_class_struct_borrow_member_field_class_by_name(
+                       struct_fc, name);
+       if (!int_fc) {
+               goto end;
+       }
+
+       if (int_fc->base.base.type != CTF_FIELD_CLASS_TYPE_INT &&
+                       int_fc->base.base.type != CTF_FIELD_CLASS_TYPE_ENUM) {
+               int_fc = NULL;
+               goto end;
+       }
+
+end:
+       return int_fc;
+}
+
+
+static inline
+void ctf_field_class_struct_append_member(struct ctf_field_class_struct *fc,
+               const char *name, struct ctf_field_class *member_fc)
+{
+       struct ctf_named_field_class *named_fc;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(name);
+       g_array_set_size(fc->members, fc->members->len + 1);
+
+       named_fc = &g_array_index(fc->members, struct ctf_named_field_class,
+               fc->members->len - 1);
+       _ctf_named_field_class_init(named_fc);
+       g_string_assign(named_fc->name, name);
+       named_fc->fc = member_fc;
+
+       if (member_fc->alignment > fc->base.alignment) {
+               fc->base.alignment = member_fc->alignment;
+       }
+}
+
+static inline
+struct ctf_named_field_class *ctf_field_class_variant_borrow_option_by_index(
+               struct ctf_field_class_variant *fc, uint64_t index)
+{
+       BT_ASSERT(fc);
+       BT_ASSERT(index < fc->options->len);
+       return &g_array_index(fc->options, struct ctf_named_field_class,
+               index);
+}
+
+static inline
+struct ctf_named_field_class *ctf_field_class_variant_borrow_option_by_name(
+               struct ctf_field_class_variant *fc, const char *name)
+{
+       uint64_t i;
+       struct ctf_named_field_class *ret_named_fc = NULL;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(name);
+
+       for (i = 0; i < fc->options->len; i++) {
+               struct ctf_named_field_class *named_fc =
+                       ctf_field_class_variant_borrow_option_by_index(fc, i);
+
+               if (strcmp(name, named_fc->name->str) == 0) {
+                       ret_named_fc = named_fc;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_named_fc;
+}
+
+static inline
+struct ctf_field_class_variant_range *
+ctf_field_class_variant_borrow_range_by_index(
+               struct ctf_field_class_variant *fc, uint64_t index)
+{
+       BT_ASSERT(fc);
+       BT_ASSERT(index < fc->ranges->len);
+       return &g_array_index(fc->ranges, struct ctf_field_class_variant_range,
+               index);
+}
+
+static inline
+void ctf_field_class_variant_append_option(struct ctf_field_class_variant *fc,
+               const char *name, struct ctf_field_class *option_fc)
+{
+       struct ctf_named_field_class *named_fc;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(name);
+       g_array_set_size(fc->options, fc->options->len + 1);
+
+       named_fc = &g_array_index(fc->options, struct ctf_named_field_class,
+               fc->options->len - 1);
+       _ctf_named_field_class_init(named_fc);
+       g_string_assign(named_fc->name, name);
+       named_fc->fc = option_fc;
+}
+
+static inline
+void ctf_field_class_variant_set_tag_field_class(
+               struct ctf_field_class_variant *fc,
+               struct ctf_field_class_enum *tag_fc)
+{
+       uint64_t option_i;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(tag_fc);
+       fc->tag_fc = tag_fc;
+
+       for (option_i = 0; option_i < fc->options->len; option_i++) {
+               uint64_t mapping_i;
+               struct ctf_named_field_class *named_fc =
+                       ctf_field_class_variant_borrow_option_by_index(
+                               fc, option_i);
+
+               for (mapping_i = 0; mapping_i < tag_fc->mappings->len;
+                               mapping_i++) {
+                       struct ctf_field_class_enum_mapping *mapping =
+                               ctf_field_class_enum_borrow_mapping_by_index(
+                                       tag_fc, mapping_i);
+
+                       if (strcmp(named_fc->name->str,
+                                       mapping->label->str) == 0) {
+                               struct ctf_field_class_variant_range range;
+
+                               range.range = mapping->range;
+                               range.option_index = option_i;
+                               g_array_append_val(fc->ranges, range);
+                       }
+               }
+       }
+}
+
+static inline
+struct ctf_field_class *ctf_field_class_compound_borrow_field_class_by_index(
+               struct ctf_field_class *comp_fc, uint64_t index)
+{
+       struct ctf_field_class *fc = NULL;
+
+       switch (comp_fc->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_named_field_class *named_fc =
+                       ctf_field_class_struct_borrow_member_by_index(
+                               (void *) comp_fc, index);
+
+               BT_ASSERT(named_fc);
+               fc = named_fc->fc;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_named_field_class *named_fc =
+                       ctf_field_class_variant_borrow_option_by_index(
+                               (void *) comp_fc, index);
+
+               BT_ASSERT(named_fc);
+               fc = named_fc->fc;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct ctf_field_class_array_base *array_fc = (void *) comp_fc;
+
+               fc = array_fc->elem_fc;
+               break;
+       }
+       default:
+               break;
+       }
+
+       return fc;
+}
+
+static inline
+uint64_t ctf_field_class_compound_get_field_class_count(struct ctf_field_class *fc)
+{
+       uint64_t field_count;
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               field_count = struct_fc->members->len;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               field_count = var_fc->options->len;
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+               /*
+                * Array and sequence types always contain a single
+                * member (the element type).
+                */
+               field_count = 1;
+               break;
+       default:
+               abort();
+       }
+
+       return field_count;
+}
+
+static inline
+int64_t ctf_field_class_compound_get_field_class_index_from_name(
+               struct ctf_field_class *fc, const char *name)
+{
+       int64_t ret_index = -1;
+       uint64_t i;
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+       {
+               struct ctf_field_class_struct *struct_fc = (void *) fc;
+
+               for (i = 0; i < struct_fc->members->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+
+                       if (strcmp(name, named_fc->name->str) == 0) {
+                               ret_index = (int64_t) i;
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct ctf_field_class_variant *var_fc = (void *) fc;
+
+               for (i = 0; i < var_fc->options->len; i++) {
+                       struct ctf_named_field_class *named_fc =
+                               ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+
+                       if (strcmp(name, named_fc->name->str) == 0) {
+                               ret_index = (int64_t) i;
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret_index;
+}
+
+static inline
+void ctf_field_path_append_index(struct ctf_field_path *fp, int64_t index)
+{
+       BT_ASSERT(fp);
+       g_array_append_val(fp->path, index);
+}
+
+static inline
+int64_t ctf_field_path_borrow_index_by_index(struct ctf_field_path *fp,
+               uint64_t index)
+{
+       BT_ASSERT(fp);
+       BT_ASSERT(index < fp->path->len);
+       return g_array_index(fp->path, int64_t, index);
+}
+
+static inline
+void ctf_field_path_clear(struct ctf_field_path *fp)
+{
+       BT_ASSERT(fp);
+       g_array_set_size(fp->path, 0);
+}
+
+static inline
+const char *ctf_scope_string(enum ctf_scope scope)
+{
+       switch (scope) {
+       case CTF_SCOPE_PACKET_HEADER:
+               return "CTF_SCOPE_PACKET_HEADER";
+       case CTF_SCOPE_PACKET_CONTEXT:
+               return "CTF_SCOPE_PACKET_CONTEXT";
+       case CTF_SCOPE_EVENT_HEADER:
+               return "CTF_SCOPE_EVENT_HEADER";
+       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
+               return "CTF_SCOPE_EVENT_COMMON_CONTEXT";
+       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               return "CTF_SCOPE_EVENT_SPECIFIC_CONTEXT";
+       case CTF_SCOPE_EVENT_PAYLOAD:
+               return "CTF_SCOPE_EVENT_PAYLOAD";
+       default:
+               abort();
+       }
+}
+
+static inline
+GString *ctf_field_path_string(struct ctf_field_path *path)
+{
+       GString *str = g_string_new(NULL);
+       uint64_t i;
+
+       BT_ASSERT(path);
+
+       if (!str) {
+               goto end;
+       }
+
+       g_string_append_printf(str, "[%s", ctf_scope_string(path->root));
+
+       for (i = 0; i < path->path->len; i++) {
+               g_string_append_printf(str, ", %" PRId64,
+                       ctf_field_path_borrow_index_by_index(path, i));
+       }
+
+       g_string_append(str, "]");
+
+end:
+       return str;
+}
+
+static inline
+struct ctf_field_class *ctf_field_path_borrow_field_class(
+               struct ctf_field_path *field_path,
+               struct ctf_trace_class *tc,
+               struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       uint64_t i;
+       struct ctf_field_class *fc;
+
+       switch (field_path->root) {
+       case CTF_SCOPE_PACKET_HEADER:
+               fc = tc->packet_header_fc;
+               break;
+       case CTF_SCOPE_PACKET_CONTEXT:
+               fc = sc->packet_context_fc;
+               break;
+       case CTF_SCOPE_EVENT_HEADER:
+               fc = sc->event_header_fc;
+               break;
+       case CTF_SCOPE_EVENT_COMMON_CONTEXT:
+               fc = sc->event_common_context_fc;
+               break;
+       case CTF_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               fc = ec->spec_context_fc;
+               break;
+       case CTF_SCOPE_EVENT_PAYLOAD:
+               fc = ec->payload_fc;
+               break;
+       default:
+               abort();
+       }
+
+       BT_ASSERT(fc);
+
+       for (i = 0; i < field_path->path->len; i++) {
+               int64_t child_index =
+                       ctf_field_path_borrow_index_by_index(field_path, i);
+               struct ctf_field_class *child_fc =
+                       ctf_field_class_compound_borrow_field_class_by_index(
+                               fc, child_index);
+               BT_ASSERT(child_fc);
+               fc = child_fc;
+       }
+
+       BT_ASSERT(fc);
+       return fc;
+}
+
+static inline
+struct ctf_field_class *ctf_field_class_copy(struct ctf_field_class *fc);
+
+static inline
+void ctf_field_class_bit_array_copy_content(
+               struct ctf_field_class_bit_array *dst_fc,
+               struct ctf_field_class_bit_array *src_fc)
+{
+       BT_ASSERT(dst_fc);
+       BT_ASSERT(src_fc);
+       dst_fc->byte_order = src_fc->byte_order;
+       dst_fc->size = src_fc->size;
+}
+
+static inline
+void ctf_field_class_int_copy_content(
+               struct ctf_field_class_int *dst_fc,
+               struct ctf_field_class_int *src_fc)
+{
+       ctf_field_class_bit_array_copy_content((void *) dst_fc, (void *) src_fc);
+       dst_fc->meaning = src_fc->meaning;
+       dst_fc->is_signed = src_fc->is_signed;
+       dst_fc->disp_base = src_fc->disp_base;
+       dst_fc->encoding = src_fc->encoding;
+       dst_fc->mapped_clock_class = src_fc->mapped_clock_class;
+       dst_fc->storing_index = src_fc->storing_index;
+}
+
+static inline
+struct ctf_field_class_int *_ctf_field_class_int_copy(
+               struct ctf_field_class_int *fc)
+{
+       struct ctf_field_class_int *copy_fc = ctf_field_class_int_create();
+
+       BT_ASSERT(copy_fc);
+       ctf_field_class_int_copy_content(copy_fc, fc);
+       return copy_fc;
+}
+
+static inline
+struct ctf_field_class_enum *_ctf_field_class_enum_copy(
+               struct ctf_field_class_enum *fc)
+{
+       struct ctf_field_class_enum *copy_fc = ctf_field_class_enum_create();
+       uint64_t i;
+
+       BT_ASSERT(copy_fc);
+       ctf_field_class_int_copy_content((void *) copy_fc, (void *) fc);
+
+       for (i = 0; i < fc->mappings->len; i++) {
+               struct ctf_field_class_enum_mapping *mapping =
+                       &g_array_index(fc->mappings,
+                               struct ctf_field_class_enum_mapping, i);
+
+               ctf_field_class_enum_append_mapping(copy_fc, mapping->label->str,
+                       mapping->range.lower.u, mapping->range.upper.u);
+       }
+
+       return copy_fc;
+}
+
+static inline
+struct ctf_field_class_float *_ctf_field_class_float_copy(
+               struct ctf_field_class_float *fc)
+{
+       struct ctf_field_class_float *copy_fc = ctf_field_class_float_create();
+
+       BT_ASSERT(copy_fc);
+       ctf_field_class_bit_array_copy_content((void *) copy_fc, (void *) fc);
+       return copy_fc;
+}
+
+static inline
+struct ctf_field_class_string *_ctf_field_class_string_copy(
+               struct ctf_field_class_string *fc)
+{
+       struct ctf_field_class_string *copy_fc = ctf_field_class_string_create();
+
+       BT_ASSERT(copy_fc);
+       return copy_fc;
+}
+
+static inline
+struct ctf_field_class_struct *_ctf_field_class_struct_copy(
+               struct ctf_field_class_struct *fc)
+{
+       struct ctf_field_class_struct *copy_fc = ctf_field_class_struct_create();
+       uint64_t i;
+
+       BT_ASSERT(copy_fc);
+
+       for (i = 0; i < fc->members->len; i++) {
+               struct ctf_named_field_class *named_fc =
+                       &g_array_index(fc->members,
+                               struct ctf_named_field_class, i);
+
+               ctf_field_class_struct_append_member(copy_fc,
+                       named_fc->name->str,
+                       ctf_field_class_copy(named_fc->fc));
+       }
+
+       return copy_fc;
+}
+
+static inline
+void ctf_field_path_copy_content(struct ctf_field_path *dst_fp,
+               struct ctf_field_path *src_fp)
+{
+       uint64_t i;
+
+       BT_ASSERT(dst_fp);
+       BT_ASSERT(src_fp);
+       dst_fp->root = src_fp->root;
+       ctf_field_path_clear(dst_fp);
+
+       for (i = 0; i < src_fp->path->len; i++) {
+               int64_t index = ctf_field_path_borrow_index_by_index(
+                       src_fp, i);
+
+               ctf_field_path_append_index(dst_fp, index);
+       }
+}
+
+static inline
+struct ctf_field_class_variant *_ctf_field_class_variant_copy(
+               struct ctf_field_class_variant *fc)
+{
+       struct ctf_field_class_variant *copy_fc =
+               ctf_field_class_variant_create();
+       uint64_t i;
+
+       BT_ASSERT(copy_fc);
+
+       for (i = 0; i < fc->options->len; i++) {
+               struct ctf_named_field_class *named_fc =
+                       &g_array_index(fc->options,
+                               struct ctf_named_field_class, i);
+
+               ctf_field_class_variant_append_option(copy_fc,
+                       named_fc->name->str,
+                       ctf_field_class_copy(named_fc->fc));
+       }
+
+       for (i = 0; i < fc->ranges->len; i++) {
+               struct ctf_field_class_variant_range *range =
+                       &g_array_index(fc->ranges,
+                               struct ctf_field_class_variant_range, i);
+
+               g_array_append_val(copy_fc->ranges, *range);
+       }
+
+       ctf_field_path_copy_content(&copy_fc->tag_path, &fc->tag_path);
+       g_string_assign(copy_fc->tag_ref, fc->tag_ref->str);
+       copy_fc->stored_tag_index = fc->stored_tag_index;
+       return copy_fc;
+}
+
+static inline
+void ctf_field_class_array_base_copy_content(
+               struct ctf_field_class_array_base *dst_fc,
+               struct ctf_field_class_array_base *src_fc)
+{
+       BT_ASSERT(dst_fc);
+       BT_ASSERT(src_fc);
+       dst_fc->elem_fc = ctf_field_class_copy(src_fc->elem_fc);
+       dst_fc->is_text = src_fc->is_text;
+}
+
+static inline
+struct ctf_field_class_array *_ctf_field_class_array_copy(
+               struct ctf_field_class_array *fc)
+{
+       struct ctf_field_class_array *copy_fc = ctf_field_class_array_create();
+
+       BT_ASSERT(copy_fc);
+       ctf_field_class_array_base_copy_content((void *) copy_fc, (void *) fc);
+       copy_fc->length = fc->length;
+       return copy_fc;
+}
+
+static inline
+struct ctf_field_class_sequence *_ctf_field_class_sequence_copy(
+               struct ctf_field_class_sequence *fc)
+{
+       struct ctf_field_class_sequence *copy_fc =
+               ctf_field_class_sequence_create();
+
+       BT_ASSERT(copy_fc);
+       ctf_field_class_array_base_copy_content((void *) copy_fc, (void *) fc);
+       ctf_field_path_copy_content(&copy_fc->length_path, &fc->length_path);
+       g_string_assign(copy_fc->length_ref, fc->length_ref->str);
+       copy_fc->stored_length_index = fc->stored_length_index;
+       return copy_fc;
+}
+
+static inline
+struct ctf_field_class *ctf_field_class_copy(struct ctf_field_class *fc)
+{
+       struct ctf_field_class *copy_fc = NULL;
+
+       if (!fc) {
+               goto end;
+       }
+
+       /*
+        * Translation should not have happened yet.
+        */
+       BT_ASSERT(!fc->ir_fc);
+
+       switch (fc->type) {
+       case CTF_FIELD_CLASS_TYPE_INT:
+               copy_fc = (void *) _ctf_field_class_int_copy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_ENUM:
+               copy_fc = (void *) _ctf_field_class_enum_copy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_FLOAT:
+               copy_fc = (void *) _ctf_field_class_float_copy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_STRING:
+               copy_fc = (void *) _ctf_field_class_string_copy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_STRUCT:
+               copy_fc = (void *) _ctf_field_class_struct_copy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_ARRAY:
+               copy_fc = (void *) _ctf_field_class_array_copy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_SEQUENCE:
+               copy_fc = (void *) _ctf_field_class_sequence_copy((void *) fc);
+               break;
+       case CTF_FIELD_CLASS_TYPE_VARIANT:
+               copy_fc = (void *) _ctf_field_class_variant_copy((void *) fc);
+               break;
+       default:
+               abort();
+       }
+
+       copy_fc->type = fc->type;
+       copy_fc->alignment = fc->alignment;
+       copy_fc->in_ir = fc->in_ir;
+
+end:
+       return copy_fc;
+}
+
+static inline
+struct ctf_event_class *ctf_event_class_create(void)
+{
+       struct ctf_event_class *ec = g_new0(struct ctf_event_class, 1);
+
+       BT_ASSERT(ec);
+       ec->name = g_string_new(NULL);
+       BT_ASSERT(ec->name);
+       ec->emf_uri = g_string_new(NULL);
+       BT_ASSERT(ec->emf_uri);
+       ec->log_level = -1;
+       return ec;
+}
+
+static inline
+void ctf_event_class_destroy(struct ctf_event_class *ec)
+{
+       if (!ec) {
+               return;
+       }
+
+       if (ec->name) {
+               g_string_free(ec->name, TRUE);
+       }
+
+       if (ec->emf_uri) {
+               g_string_free(ec->emf_uri, TRUE);
+       }
+
+       ctf_field_class_destroy(ec->spec_context_fc);
+       ctf_field_class_destroy(ec->payload_fc);
+       g_free(ec);
+}
+
+static inline
+struct ctf_stream_class *ctf_stream_class_create(void)
+{
+       struct ctf_stream_class *sc = g_new0(struct ctf_stream_class, 1);
+
+       BT_ASSERT(sc);
+       sc->event_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) ctf_event_class_destroy);
+       BT_ASSERT(sc->event_classes);
+       sc->event_classes_by_id = g_hash_table_new(g_direct_hash,
+               g_direct_equal);
+       BT_ASSERT(sc->event_classes_by_id);
+       return sc;
+}
+
+static inline
+void ctf_stream_class_destroy(struct ctf_stream_class *sc)
+{
+       if (!sc) {
+               return;
+       }
+
+       if (sc->event_classes) {
+               g_ptr_array_free(sc->event_classes, TRUE);
+       }
+
+       if (sc->event_classes_by_id) {
+               g_hash_table_destroy(sc->event_classes_by_id);
+       }
+
+       ctf_field_class_destroy(sc->packet_context_fc);
+       ctf_field_class_destroy(sc->event_header_fc);
+       ctf_field_class_destroy(sc->event_common_context_fc);
+       g_free(sc);
+}
+
+static inline
+void ctf_stream_class_append_event_class(struct ctf_stream_class *sc,
+               struct ctf_event_class *ec)
+{
+       g_ptr_array_add(sc->event_classes, ec);
+       g_hash_table_insert(sc->event_classes_by_id,
+               GUINT_TO_POINTER((guint) ec->id), ec);
+}
+
+static inline
+struct ctf_event_class *ctf_stream_class_borrow_event_class_by_id(
+               struct ctf_stream_class *sc, uint64_t type)
+{
+       BT_ASSERT(sc);
+       return g_hash_table_lookup(sc->event_classes_by_id,
+               GUINT_TO_POINTER((guint) type));
+}
+
+static inline
+void _ctf_trace_class_env_entry_init(struct ctf_trace_class_env_entry *entry)
+{
+       BT_ASSERT(entry);
+       entry->name = g_string_new(NULL);
+       BT_ASSERT(entry->name);
+       entry->value.str = g_string_new(NULL);
+       BT_ASSERT(entry->value.str);
+}
+
+static inline
+void _ctf_trace_class_env_entry_fini(struct ctf_trace_class_env_entry *entry)
+{
+       BT_ASSERT(entry);
+
+       if (entry->name) {
+               g_string_free(entry->name, TRUE);
+       }
+
+       if (entry->value.str) {
+               g_string_free(entry->value.str, TRUE);
+       }
+}
+
+static inline
+struct ctf_clock_class *ctf_clock_class_create(void)
+{
+       struct ctf_clock_class *cc = g_new0(struct ctf_clock_class, 1);
+
+       BT_ASSERT(cc);
+       cc->name = g_string_new(NULL);
+       BT_ASSERT(cc->name);
+       cc->description = g_string_new(NULL);
+       BT_ASSERT(cc->description);
+       return cc;
+}
+
+static inline
+void ctf_clock_class_destroy(struct ctf_clock_class *cc)
+{
+       if (!cc) {
+               return;
+       }
+
+       if (cc->name) {
+               g_string_free(cc->name, TRUE);
+       }
+
+       if (cc->description) {
+               g_string_free(cc->description, TRUE);
+       }
+
+       bt_clock_class_put_ref(cc->ir_cc);
+       g_free(cc);
+}
+
+static inline
+struct ctf_trace_class *ctf_trace_class_create(void)
+{
+       struct ctf_trace_class *tc = g_new0(struct ctf_trace_class, 1);
+
+       BT_ASSERT(tc);
+       tc->default_byte_order = -1;
+       tc->clock_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) ctf_clock_class_destroy);
+       BT_ASSERT(tc->clock_classes);
+       tc->stream_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) ctf_stream_class_destroy);
+       BT_ASSERT(tc->stream_classes);
+       tc->env_entries = g_array_new(FALSE, TRUE,
+               sizeof(struct ctf_trace_class_env_entry));
+       return tc;
+}
+
+static inline
+void ctf_trace_class_destroy(struct ctf_trace_class *tc)
+{
+       if (!tc) {
+               return;
+       }
+
+       ctf_field_class_destroy(tc->packet_header_fc);
+
+       if (tc->clock_classes) {
+               g_ptr_array_free(tc->clock_classes, TRUE);
+       }
+
+       if (tc->stream_classes) {
+               g_ptr_array_free(tc->stream_classes, TRUE);
+       }
+
+       if (tc->env_entries) {
+               uint64_t i;
+
+               for (i = 0; i < tc->env_entries->len; i++) {
+                       struct ctf_trace_class_env_entry *entry =
+                               &g_array_index(tc->env_entries,
+                                       struct ctf_trace_class_env_entry, i);
+
+                       _ctf_trace_class_env_entry_fini(entry);
+               }
+
+               g_array_free(tc->env_entries, TRUE);
+       }
+
+       g_free(tc);
+}
+
+static inline
+void ctf_trace_class_append_env_entry(struct ctf_trace_class *tc,
+               const char *name, enum ctf_trace_class_env_entry_type type,
+               const char *str_value, int64_t i_value)
+{
+       struct ctf_trace_class_env_entry *entry;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(name);
+       g_array_set_size(tc->env_entries, tc->env_entries->len + 1);
+
+       entry = &g_array_index(tc->env_entries,
+               struct ctf_trace_class_env_entry, tc->env_entries->len - 1);
+       entry->type = type;
+       _ctf_trace_class_env_entry_init(entry);
+       g_string_assign(entry->name, name);
+
+       if (str_value) {
+               g_string_assign(entry->value.str, str_value);
+       }
+
+       entry->value.i = i_value;
+}
+
+static inline
+struct ctf_stream_class *ctf_trace_class_borrow_stream_class_by_id(
+               struct ctf_trace_class *tc, uint64_t id)
+{
+       uint64_t i;
+       struct ctf_stream_class *ret_sc = NULL;
+
+       BT_ASSERT(tc);
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = tc->stream_classes->pdata[i];
+
+               if (sc->id == id) {
+                       ret_sc = sc;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_sc;
+}
+
+static inline
+struct ctf_clock_class *ctf_trace_class_borrow_clock_class_by_name(
+               struct ctf_trace_class *tc, const char *name)
+{
+       uint64_t i;
+       struct ctf_clock_class *ret_cc = NULL;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(name);
+
+       for (i = 0; i < tc->clock_classes->len; i++) {
+               struct ctf_clock_class *cc = tc->clock_classes->pdata[i];
+
+               BT_ASSERT(cc->name);
+               if (strcmp(cc->name->str, name) == 0) {
+                       ret_cc = cc;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_cc;
+}
+
+static inline
+struct ctf_trace_class_env_entry *ctf_trace_class_borrow_env_entry_by_index(
+               struct ctf_trace_class *tc, uint64_t index)
+{
+       BT_ASSERT(tc);
+       BT_ASSERT(index < tc->env_entries->len);
+       return &g_array_index(tc->env_entries, struct ctf_trace_class_env_entry,
+               index);
+}
+
+static inline
+struct ctf_trace_class_env_entry *ctf_trace_class_borrow_env_entry_by_name(
+               struct ctf_trace_class *tc, const char *name)
+{
+       struct ctf_trace_class_env_entry *ret_entry = NULL;
+       uint64_t i;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(name);
+
+       for (i = 0; i < tc->env_entries->len; i++) {
+               struct ctf_trace_class_env_entry *env_entry =
+                       ctf_trace_class_borrow_env_entry_by_index(tc, i);
+
+               if (strcmp(env_entry->name->str, name) == 0) {
+                       ret_entry = env_entry;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_entry;
+}
+
+#endif /* _CTF_META_H */
diff --git a/src/plugins/ctf/common/metadata/decoder.c b/src/plugins/ctf/common/metadata/decoder.c
new file mode 100644 (file)
index 0000000..53749a7
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-DECODER"
+#include "logging.h"
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "common/assert.h"
+#include "compat/uuid.h"
+#include "compat/memstream.h"
+#include <babeltrace2/babeltrace.h>
+#include <glib.h>
+#include <string.h>
+
+#include "ast.h"
+#include "decoder.h"
+#include "scanner.h"
+
+#define TSDL_MAGIC     0x75d11d57
+
+extern
+int yydebug;
+
+struct ctf_metadata_decoder {
+       struct ctf_visitor_generate_ir *visitor;
+       uint8_t uuid[16];
+       bool is_uuid_set;
+       int bo;
+       struct ctf_metadata_decoder_config config;
+};
+
+struct packet_header {
+       uint32_t magic;
+       uint8_t  uuid[16];
+       uint32_t checksum;
+       uint32_t content_size;
+       uint32_t packet_size;
+       uint8_t  compression_scheme;
+       uint8_t  encryption_scheme;
+       uint8_t  checksum_scheme;
+       uint8_t  major;
+       uint8_t  minor;
+} __attribute__((__packed__));
+
+BT_HIDDEN
+bool ctf_metadata_decoder_is_packetized(FILE *fp, int *byte_order)
+{
+       uint32_t magic;
+       size_t len;
+       int ret = 0;
+
+       len = fread(&magic, sizeof(magic), 1, fp);
+       if (len != 1) {
+               BT_LOGD_STR("Cannot reade first metadata packet header: assuming the stream is not packetized.");
+               goto end;
+       }
+
+       if (byte_order) {
+               if (magic == TSDL_MAGIC) {
+                       ret = 1;
+                       *byte_order = BYTE_ORDER;
+               } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
+                       ret = 1;
+                       *byte_order = BYTE_ORDER == BIG_ENDIAN ?
+                               LITTLE_ENDIAN : BIG_ENDIAN;
+               }
+       }
+
+end:
+       rewind(fp);
+
+       return ret;
+}
+
+static
+bool is_version_valid(unsigned int major, unsigned int minor)
+{
+       return major == 1 && minor == 8;
+}
+
+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;
+}
+
+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
+int ctf_metadata_decoder_packetized_file_stream_to_buf(
+               FILE *fp, char **buf, int byte_order)
+{
+       return ctf_metadata_decoder_packetized_file_stream_to_buf_with_mdec(
+               NULL, fp, buf, byte_order);
+}
+
+BT_HIDDEN
+struct ctf_metadata_decoder *ctf_metadata_decoder_create(
+               bt_self_component_source *self_comp,
+               const struct ctf_metadata_decoder_config *config)
+{
+       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,
+               config->clock_class_offset_s, config->clock_class_offset_ns);
+
+       if (!mdec) {
+               BT_LOGE_STR("Failed to allocate one CTF metadata decoder.");
+               goto end;
+       }
+
+       mdec->config = *config;
+       mdec->visitor = ctf_visitor_generate_ir_create(self_comp, config);
+       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 ", addr=%p",
+               config->clock_class_offset_s, config->clock_class_offset_ns,
+               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;
+
+       BT_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;
+       }
+
+       BT_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
+bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(
+               struct ctf_metadata_decoder *mdec)
+{
+       return ctf_visitor_generate_ir_get_ir_trace_class(mdec->visitor);
+}
+
+BT_HIDDEN
+struct ctf_trace_class *ctf_metadata_decoder_borrow_ctf_trace_class(
+               struct ctf_metadata_decoder *mdec)
+{
+       return ctf_visitor_generate_ir_borrow_ctf_trace_class(mdec->visitor);
+}
diff --git a/src/plugins/ctf/common/metadata/decoder.h b/src/plugins/ctf/common/metadata/decoder.h
new file mode 100644 (file)
index 0000000..b0f179b
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef _METADATA_DECODER_H
+#define _METADATA_DECODER_H
+
+/*
+ * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <babeltrace2/babeltrace.h>
+
+/* A CTF metadata decoder object */
+struct ctf_metadata_decoder;
+
+/* CTF metadata decoder status */
+enum ctf_metadata_decoder_status {
+       CTF_METADATA_DECODER_STATUS_OK                  = 0,
+       CTF_METADATA_DECODER_STATUS_ERROR               = -1,
+       CTF_METADATA_DECODER_STATUS_INCOMPLETE          = -2,
+       CTF_METADATA_DECODER_STATUS_INVAL_VERSION       = -3,
+       CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR    = -4,
+};
+
+/* Decoding configuration */
+struct ctf_metadata_decoder_config {
+       int64_t clock_class_offset_s;
+       int64_t clock_class_offset_ns;
+};
+
+/*
+ * Creates a CTF metadata decoder.
+ *
+ * Returns `NULL` on error.
+ */
+BT_HIDDEN
+struct ctf_metadata_decoder *ctf_metadata_decoder_create(
+               bt_self_component_source *self_comp,
+               const struct ctf_metadata_decoder_config *config);
+
+/*
+ * Destroys a CTF metadata decoder that you created with
+ * ctf_metadata_decoder_create().
+ */
+BT_HIDDEN
+void ctf_metadata_decoder_destroy(
+               struct ctf_metadata_decoder *metadata_decoder);
+
+/*
+ * Decodes a new chunk of CTF metadata.
+ *
+ * This function reads the metadata from the current position of `fp`
+ * until the end of this file stream. If it finds new information (new
+ * event class, new stream class, or new clock class), it appends this
+ * information to the decoder's trace object (as returned by
+ * ctf_metadata_decoder_get_ir_trace_class()), or it creates this trace.
+ *
+ * The metadata can be packetized or not.
+ *
+ * The metadata chunk needs to be complete and scannable, that is,
+ * zero or more complete top-level blocks. If it's incomplete, this
+ * function returns `CTF_METADATA_DECODER_STATUS_INCOMPLETE`. If this
+ * function returns `CTF_METADATA_DECODER_STATUS_INCOMPLETE`, then you
+ * need to call it again with the same metadata and more to make it
+ * complete. For example:
+ *
+ *     First call:  event { name = hell
+ *     Second call: event { name = hello_world; ... };
+ *
+ * If the conversion from the metadata text to CTF IR objects fails,
+ * this function returns `CTF_METADATA_DECODER_STATUS_IR_VISITOR_ERROR`.
+ *
+ * If everything goes as expected, this function returns
+ * `CTF_METADATA_DECODER_STATUS_OK`.
+ */
+BT_HIDDEN
+enum ctf_metadata_decoder_status ctf_metadata_decoder_decode(
+               struct ctf_metadata_decoder *metadata_decoder, FILE *fp);
+
+BT_HIDDEN
+bt_trace_class *ctf_metadata_decoder_get_ir_trace_class(
+               struct ctf_metadata_decoder *mdec);
+
+BT_HIDDEN
+struct ctf_trace_class *ctf_metadata_decoder_borrow_ctf_trace_class(
+               struct ctf_metadata_decoder *mdec);
+
+/*
+ * Checks whether or not a given metadata file stream is packetized, and
+ * if so, sets `*byte_order` to the byte order of the first packet.
+ */
+BT_HIDDEN
+bool ctf_metadata_decoder_is_packetized(FILE *fp, int *byte_order);
+
+/*
+ * Decodes a packetized metadata file stream to a NULL-terminated
+ * text buffer using the given byte order.
+ */
+BT_HIDDEN
+int ctf_metadata_decoder_packetized_file_stream_to_buf(
+               FILE *fp, char **buf, int byte_order);
+
+#endif /* _METADATA_DECODER_H */
diff --git a/src/plugins/ctf/common/metadata/lexer.l b/src/plugins/ctf/common/metadata/lexer.l
new file mode 100644 (file)
index 0000000..694ddc3
--- /dev/null
@@ -0,0 +1,148 @@
+%{
+/*
+ * lexer.l
+ *
+ * Common Trace Formal Lexer
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-LEXER"
+#include "logging.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+
+#define YY_FATAL_ERROR(_msg)   BT_LOGF_STR(_msg)
+
+#define PARSE_INTEGER_LITERAL(base)                                    \
+       do {                                                            \
+               errno = 0;                                              \
+               yylval->ull = strtoull(yytext, NULL, base);             \
+               if (errno) {                                            \
+                       _BT_LOGE_LINENO(yylineno,                       \
+                               "Cannot parser constant integer: "      \
+                               "base=%d, text=\"%s\"", base, yytext);  \
+                       return CTF_ERROR;                               \
+               }                                                       \
+       } while (0)
+
+BT_HIDDEN
+void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src);
+
+static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
+       __attribute__((unused));
+static int input (yyscan_t yyscanner) __attribute__((unused));
+
+BT_HIDDEN
+int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src, char delim);
+
+%}
+
+%x comment_ml comment_sl string_lit char_const
+%option reentrant yylineno noyywrap bison-bridge
+%option extra-type="struct ctf_scanner *"
+       /* bison-locations */
+INTEGER_SUFFIX                 (U|UL|ULL|LU|LLU|Ul|Ull|lU|llU|u|uL|uLL|Lu|LLu|ul|ull|lu|llu)
+DIGIT                          [0-9]
+NONDIGIT                       [a-zA-Z_]
+HEXDIGIT                       [0-9A-Fa-f]
+OCTALDIGIT                     [0-7]
+UCHARLOWERCASE                 \\u{HEXDIGIT}{4}
+UCHARUPPERCASE                 \\U{HEXDIGIT}{8}
+ID_NONDIGIT                    {NONDIGIT}|{UCHARLOWERCASE}|{UCHARUPPERCASE}
+IDENTIFIER                     {ID_NONDIGIT}({ID_NONDIGIT}|{DIGIT})*
+%%
+
+                               /*
+                                * Using start conditions to deal with comments
+                                * and strings.
+                                */
+
+"/*"                           BEGIN(comment_ml);
+<comment_ml>[^*\n]*            /* eat anything that's not a '*' */
+<comment_ml>"*"+[^*/\n]*       /* eat up '*'s not followed by '/'s */
+<comment_ml>\n
+<comment_ml>"*"+"/"            BEGIN(INITIAL);
+
+"//"[^\n]*\n                   /* skip comment */
+
+L?\"(\\.|[^\\"])*\"            { if (import_string(yyextra, yylval, yytext, '\"') < 0) return CTF_ERROR; else return CTF_STRING_LITERAL; }
+L?\'(\\.|[^\\'])*\'            { if (import_string(yyextra, yylval, yytext, '\'') < 0) return CTF_ERROR; else return CTF_CHARACTER_LITERAL; }
+
+"["                            return CTF_LSBRAC;
+"]"                            return CTF_RSBRAC;
+"("                            return CTF_LPAREN;
+")"                            return CTF_RPAREN;
+"{"                            return CTF_LBRAC;
+"}"                            return CTF_RBRAC;
+"->"                           return CTF_RARROW;
+"*"                            return CTF_STAR;
+"+"                            return CTF_PLUS;
+"-"                            return CTF_MINUS;
+"<"                            return CTF_LT;
+">"                            return CTF_GT;
+:=                             return CTF_TYPEASSIGN;
+:                              return CTF_COLON;
+;                              return CTF_SEMICOLON;
+"..."                          return CTF_DOTDOTDOT;
+"."                            return CTF_DOT;
+=                              return CTF_EQUAL;
+","                            return CTF_COMMA;
+align                          setstring(yyextra, yylval, yytext); return CTF_TOK_ALIGN;
+const                          setstring(yyextra, yylval, yytext); return CTF_CONST;
+char                           setstring(yyextra, yylval, yytext); return CTF_CHAR;
+clock                          setstring(yyextra, yylval, yytext); return CTF_CLOCK;
+double                         setstring(yyextra, yylval, yytext); return CTF_DOUBLE;
+enum                           setstring(yyextra, yylval, yytext); return CTF_ENUM;
+env                            setstring(yyextra, yylval, yytext); return CTF_ENV;
+event                          setstring(yyextra, yylval, yytext); return CTF_EVENT;
+floating_point                 setstring(yyextra, yylval, yytext); return CTF_FLOATING_POINT;
+float                          setstring(yyextra, yylval, yytext); return CTF_FLOAT;
+integer                                setstring(yyextra, yylval, yytext); return CTF_INTEGER;
+int                            setstring(yyextra, yylval, yytext); return CTF_INT;
+long                           setstring(yyextra, yylval, yytext); return CTF_LONG;
+short                          setstring(yyextra, yylval, yytext); return CTF_SHORT;
+signed                         setstring(yyextra, yylval, yytext); return CTF_SIGNED;
+stream                         setstring(yyextra, yylval, yytext); return CTF_STREAM;
+string                         setstring(yyextra, yylval, yytext); return CTF_STRING;
+struct                         setstring(yyextra, yylval, yytext); return CTF_STRUCT;
+trace                          setstring(yyextra, yylval, yytext); return CTF_TRACE;
+callsite                       setstring(yyextra, yylval, yytext); return CTF_CALLSITE;
+typealias                      setstring(yyextra, yylval, yytext); return CTF_TYPEALIAS;
+typedef                                setstring(yyextra, yylval, yytext); return CTF_TYPEDEF;
+unsigned                       setstring(yyextra, yylval, yytext); return CTF_UNSIGNED;
+variant                                setstring(yyextra, yylval, yytext); return CTF_VARIANT;
+void                           setstring(yyextra, yylval, yytext); return CTF_VOID;
+_Bool                          setstring(yyextra, yylval, yytext); return CTF_BOOL;
+_Complex                       setstring(yyextra, yylval, yytext); return CTF_COMPLEX;
+_Imaginary                     setstring(yyextra, yylval, yytext); return CTF_IMAGINARY;
+[1-9]{DIGIT}*{INTEGER_SUFFIX}? PARSE_INTEGER_LITERAL(10); return CTF_INTEGER_LITERAL;
+0{OCTALDIGIT}*{INTEGER_SUFFIX}?        PARSE_INTEGER_LITERAL(8); return CTF_INTEGER_LITERAL;
+0[xX]{HEXDIGIT}+{INTEGER_SUFFIX}?      PARSE_INTEGER_LITERAL(16); return CTF_INTEGER_LITERAL;
+
+{IDENTIFIER}                   BT_LOGV("Got identifier: id=\"%s\"", yytext); setstring(yyextra, yylval, yytext); if (is_type(yyextra, yytext)) return ID_TYPE; else return IDENTIFIER;
+[ \t\r\n]                      ; /* ignore */
+.                              _BT_LOGE_LINENO(yylineno, "Invalid character: char=\"%c\", val=0x%02x", isprint(yytext[0]) ? yytext[0] : '\0', yytext[0]); return CTF_ERROR;
+%%
diff --git a/src/plugins/ctf/common/metadata/logging.c b/src/plugins/ctf/common/metadata/logging.c
new file mode 100644 (file)
index 0000000..c7b514f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL metadata_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(metadata_log_level, "BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL");
diff --git a/src/plugins/ctf/common/metadata/logging.h b/src/plugins/ctf/common/metadata/logging.h
new file mode 100644 (file)
index 0000000..81f76a2
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef CTF_METADATA_LOGGING_H
+#define CTF_METADATA_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL metadata_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(metadata_log_level);
+
+#define _BT_LOGV_LINENO(_lineno, _msg, args...) \
+       BT_LOGV("At line %u in metadata stream: " _msg, _lineno, ## args)
+
+#define _BT_LOGW_LINENO(_lineno, _msg, args...) \
+       BT_LOGW("At line %u in metadata stream: " _msg, _lineno, ## args)
+
+#define _BT_LOGE_LINENO(_lineno, _msg, args...) \
+       BT_LOGE("At line %u in metadata stream: " _msg, _lineno, ## args)
+
+#endif /* CTF_METADATA_LOGGING_H */
diff --git a/src/plugins/ctf/common/metadata/objstack.c b/src/plugins/ctf/common/metadata/objstack.c
new file mode 100644 (file)
index 0000000..15b6d26
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * objstack.c
+ *
+ * Common Trace Format Object Stack.
+ *
+ * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-OBJSTACK"
+#include "logging.h"
+
+#include <stdlib.h>
+#include "common/list.h"
+#include "common/babeltrace.h"
+#include "common/align.h"
+
+#define OBJSTACK_ALIGN                 8       /* Object stack alignment */
+#define OBJSTACK_INIT_LEN              128
+#define OBJSTACK_POISON                        0xcc
+
+struct objstack {
+       struct bt_list_head head;       /* list of struct objstack_node */
+};
+
+struct objstack_node {
+       struct bt_list_head node;
+       size_t len;
+       size_t used_len;
+       char __attribute__ ((aligned (OBJSTACK_ALIGN))) data[];
+};
+
+BT_HIDDEN
+struct objstack *objstack_create(void)
+{
+       struct objstack *objstack;
+       struct objstack_node *node;
+
+       objstack = calloc(1, sizeof(*objstack));
+       if (!objstack) {
+               BT_LOGE_STR("Failed to allocate one object stack.");
+               return NULL;
+       }
+       node = calloc(sizeof(struct objstack_node) + OBJSTACK_INIT_LEN,
+                       sizeof(char));
+       if (!node) {
+               BT_LOGE_STR("Failed to allocate one object stack node.");
+               free(objstack);
+               return NULL;
+       }
+       BT_INIT_LIST_HEAD(&objstack->head);
+       bt_list_add_tail(&node->node, &objstack->head);
+       node->len = OBJSTACK_INIT_LEN;
+       return objstack;
+}
+
+static
+void objstack_node_free(struct objstack_node *node)
+{
+       size_t offset, len;
+       char *p;
+
+       if (!node)
+               return;
+       p = (char *) node;
+       len = sizeof(*node) + node->len;
+       for (offset = 0; offset < len; offset++)
+               p[offset] = OBJSTACK_POISON;
+       free(node);
+}
+
+BT_HIDDEN
+void objstack_destroy(struct objstack *objstack)
+{
+       struct objstack_node *node, *p;
+
+       if (!objstack)
+               return;
+       bt_list_for_each_entry_safe(node, p, &objstack->head, node) {
+               bt_list_del(&node->node);
+               objstack_node_free(node);
+       }
+       free(objstack);
+}
+
+static
+struct objstack_node *objstack_append_node(struct objstack *objstack)
+{
+       struct objstack_node *last_node, *new_node;
+
+       /* Get last node */
+       last_node = bt_list_entry(objstack->head.prev,
+                       struct objstack_node, node);
+
+       /* Allocate new node with double of size of last node */
+       new_node = calloc(sizeof(struct objstack_node) + (last_node->len << 1),
+                       sizeof(char));
+       if (!new_node) {
+               BT_LOGE_STR("Failed to allocate one object stack node.");
+               return NULL;
+       }
+       bt_list_add_tail(&new_node->node, &objstack->head);
+       new_node->len = last_node->len << 1;
+       return new_node;
+}
+
+BT_HIDDEN
+void *objstack_alloc(struct objstack *objstack, size_t len)
+{
+       struct objstack_node *last_node;
+       void *p;
+
+       len = ALIGN(len, OBJSTACK_ALIGN);
+
+       /* Get last node */
+       last_node = bt_list_entry(objstack->head.prev,
+                       struct objstack_node, node);
+       while (last_node->len - last_node->used_len < len) {
+               last_node = objstack_append_node(objstack);
+               if (!last_node) {
+                       return NULL;
+               }
+       }
+       p = &last_node->data[last_node->used_len];
+       last_node->used_len += len;
+       return p;
+}
diff --git a/src/plugins/ctf/common/metadata/objstack.h b/src/plugins/ctf/common/metadata/objstack.h
new file mode 100644 (file)
index 0000000..c026eb5
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _OBJSTACK_H
+#define _OBJSTACK_H
+
+/*
+ * objstack.h
+ *
+ * Common Trace Format Object Stack.
+ *
+ * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+struct objstack;
+
+BT_HIDDEN
+struct objstack *objstack_create(void);
+BT_HIDDEN
+void objstack_destroy(struct objstack *objstack);
+
+/*
+ * Allocate len bytes of zeroed memory.
+ * Return NULL on error.
+ */
+BT_HIDDEN
+void *objstack_alloc(struct objstack *objstack, size_t len);
+
+#endif /* _OBJSTACK_H */
diff --git a/src/plugins/ctf/common/metadata/parser.y b/src/plugins/ctf/common/metadata/parser.y
new file mode 100644 (file)
index 0000000..8082a0b
--- /dev/null
@@ -0,0 +1,2592 @@
+%{
+/*
+ * ctf-parser.y
+ *
+ * Common Trace Format Metadata Grammar.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-PARSER"
+#include "logging.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <glib.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "common/list.h"
+#include "common/assert.h"
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+#include "objstack.h"
+
+#if BT_LOG_ENABLED_VERBOSE
+# define YYDEBUG 1
+# define YYFPRINTF(_stream, _fmt, args...) BT_LOGV(_fmt, ## args)
+#else
+# define YYDEBUG 0
+#endif
+
+/* Join two lists, put "add" at the end of "head".  */
+static inline void
+_bt_list_splice_tail (struct bt_list_head *add, struct bt_list_head *head)
+{
+       /* Do nothing if the list which gets added is empty.  */
+       if (add != add->next) {
+               add->next->prev = head->prev;
+               add->prev->next = head;
+               head->prev->next = add->next;
+               head->prev = add->prev;
+       }
+}
+
+BT_HIDDEN
+int yyparse(struct ctf_scanner *scanner, yyscan_t yyscanner);
+BT_HIDDEN
+int yylex(union YYSTYPE *yyval, yyscan_t yyscanner);
+BT_HIDDEN
+int yylex_init_extra(struct ctf_scanner *scanner, yyscan_t * ptr_yy_globals);
+BT_HIDDEN
+int yylex_destroy(yyscan_t yyscanner);
+BT_HIDDEN
+void yyrestart(FILE * in_str, yyscan_t yyscanner);
+BT_HIDDEN
+int yyget_lineno(yyscan_t yyscanner);
+BT_HIDDEN
+char *yyget_text(yyscan_t yyscanner);
+
+static const char *node_type_to_str[] = {
+#define ENTRY(S)       [S] = #S,
+       FOREACH_CTF_NODES(ENTRY)
+#undef ENTRY
+};
+
+/*
+ * Static node for out of memory errors. Only "type" is used. lineno is
+ * always left at 0. The rest of the node content can be overwritten,
+ * but is never used.
+ */
+static struct ctf_node error_node = {
+       .type = NODE_ERROR,
+};
+
+BT_HIDDEN
+const char *node_type(struct ctf_node *node)
+{
+       if (node->type < NR_NODE_TYPES)
+               return node_type_to_str[node->type];
+       else
+               return NULL;
+}
+
+void setstring(struct ctf_scanner *scanner, YYSTYPE *lvalp, const char *src)
+{
+       lvalp->s = objstack_alloc(scanner->objstack, strlen(src) + 1);
+       strcpy(lvalp->s, src);
+}
+
+static
+int str_check(size_t str_len, size_t offset, size_t len)
+{
+       /* check overflow */
+       if (offset + len < offset)
+               return -1;
+       if (offset + len > str_len)
+               return -1;
+       return 0;
+}
+
+static
+int bt_isodigit(int c)
+{
+       switch (c) {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static
+int parse_base_sequence(const char *src, size_t len, size_t pos,
+               char *buffer, size_t *buf_len, int base)
+{
+       const size_t max_char = 3;
+       int nr_char = 0;
+
+       while (!str_check(len, pos, 1) && nr_char < max_char) {
+               char c = src[pos++];
+
+               if (base == 8) {
+                       if (bt_isodigit(c))
+                               buffer[nr_char++] = c;
+                       else
+                               break;
+               } else if (base == 16) {
+                       if (isxdigit(c))
+                               buffer[nr_char++] = c;
+                       else
+                               break;
+
+               } else {
+                       /* Unsupported base */
+                       return -1;
+               }
+       }
+       BT_ASSERT(nr_char > 0);
+       buffer[nr_char] = '\0';
+       *buf_len = nr_char;
+       return 0;
+}
+
+static
+int import_basic_string(struct ctf_scanner *scanner, YYSTYPE *lvalp,
+               size_t len, const char *src, char delim)
+{
+       size_t pos = 0, dpos = 0;
+
+       if (str_check(len, pos, 1))
+               return -1;
+       if (src[pos++] != delim)
+               return -1;
+
+       while (src[pos] != delim) {
+               char c;
+
+               if (str_check(len, pos, 1))
+                       return -1;
+               c = src[pos++];
+               if (c == '\\') {
+                       if (str_check(len, pos, 1))
+                               return -1;
+                       c = src[pos++];
+
+                       switch (c) {
+                       case 'a':
+                               c = '\a';
+                               break;
+                       case 'b':
+                               c = '\b';
+                               break;
+                       case 'f':
+                               c = '\f';
+                               break;
+                       case 'n':
+                               c = '\n';
+                               break;
+                       case 'r':
+                               c = '\r';
+                               break;
+                       case 't':
+                               c = '\t';
+                               break;
+                       case 'v':
+                               c = '\v';
+                               break;
+                       case '\\':
+                               c = '\\';
+                               break;
+                       case '\'':
+                               c = '\'';
+                               break;
+                       case '\"':
+                               c = '\"';
+                               break;
+                       case '?':
+                               c = '?';
+                               break;
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       {
+                               char oct_buffer[4];
+                               size_t oct_len;
+
+                               if (parse_base_sequence(src, len, pos - 1,
+                                               oct_buffer, &oct_len, 8))
+                                       return -1;
+                               c = strtoul(&oct_buffer[0], NULL, 8);
+                               pos += oct_len - 1;
+                               break;
+                       }
+                       case 'x':
+                       {
+                               char hex_buffer[4];
+                               size_t hex_len;
+
+                               if (parse_base_sequence(src, len, pos,
+                                               hex_buffer, &hex_len, 16))
+                                       return -1;
+                               c = strtoul(&hex_buffer[0], NULL, 16);
+                               pos += hex_len;
+                               break;
+                       }
+                       default:
+                               return -1;
+                       }
+               }
+               if (str_check(len, dpos, 1))
+                       return -1;
+               lvalp->s[dpos++] = c;
+       }
+
+       if (str_check(len, dpos, 1))
+               return -1;
+       lvalp->s[dpos++] = '\0';
+
+       if (str_check(len, pos, 1))
+               return -1;
+       if (src[pos++] != delim)
+               return -1;
+
+       if (str_check(len, pos, 1))
+               return -1;
+       if (src[pos] != '\0')
+               return -1;
+       return 0;
+}
+
+int import_string(struct ctf_scanner *scanner, YYSTYPE *lvalp,
+               const char *src, char delim)
+{
+       size_t len;
+
+       len = strlen(src) + 1;
+       lvalp->s = objstack_alloc(scanner->objstack, len);
+       if (src[0] == 'L') {
+               // TODO: import wide string
+               _BT_LOGE_LINENO(yyget_lineno(scanner),
+                       "wide characters are not supported as of this version: "
+                       "scanner-addr=%p", scanner);
+               return -1;
+       } else {
+               return import_basic_string(scanner, lvalp, len, src, delim);
+       }
+}
+
+static void init_scope(struct ctf_scanner_scope *scope,
+                      struct ctf_scanner_scope *parent)
+{
+       scope->parent = parent;
+       scope->classes = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                            NULL, NULL);
+}
+
+static void finalize_scope(struct ctf_scanner_scope *scope)
+{
+       g_hash_table_destroy(scope->classes);
+}
+
+static void push_scope(struct ctf_scanner *scanner)
+{
+       struct ctf_scanner_scope *ns;
+
+       BT_LOGV("Pushing scope: scanner-addr=%p", scanner);
+       ns = malloc(sizeof(struct ctf_scanner_scope));
+       init_scope(ns, scanner->cs);
+       scanner->cs = ns;
+}
+
+static void pop_scope(struct ctf_scanner *scanner)
+{
+       struct ctf_scanner_scope *os;
+
+       BT_LOGV("Popping scope: scanner-addr=%p", scanner);
+       os = scanner->cs;
+       scanner->cs = os->parent;
+       finalize_scope(os);
+       free(os);
+}
+
+static int lookup_type(struct ctf_scanner_scope *s, const char *id)
+{
+       int ret;
+
+       ret = GPOINTER_TO_INT(g_hash_table_lookup(s->classes, id));
+       BT_LOGV("Looked up type: scanner-addr=%p, id=\"%s\", ret=%d",
+               s, id, ret);
+       return ret;
+}
+
+BT_HIDDEN
+int is_type(struct ctf_scanner *scanner, const char *id)
+{
+       struct ctf_scanner_scope *it;
+       int ret = 0;
+
+       for (it = scanner->cs; it != NULL; it = it->parent) {
+               if (lookup_type(it, id)) {
+                       ret = 1;
+                       break;
+               }
+       }
+       BT_LOGV("Found if ID is type: scanner-addr=%p, id=\"%s\", ret=%d",
+               scanner, id, ret);
+       return ret;
+}
+
+static void add_type(struct ctf_scanner *scanner, char *id)
+{
+       BT_LOGV("Adding type: scanner-addr=%p, id=\"%s\"",
+               scanner, id);
+       if (lookup_type(scanner->cs, id))
+               return;
+       g_hash_table_insert(scanner->cs->classes, id, id);
+}
+
+static struct ctf_node *make_node(struct ctf_scanner *scanner,
+                                 enum node_type type)
+{
+       struct ctf_node *node;
+
+       node = objstack_alloc(scanner->objstack, sizeof(*node));
+       if (!node) {
+               _BT_LOGE_LINENO(yyget_lineno(scanner->scanner),
+                       "failed to allocate one stack entry: "
+                       "scanner-addr=%p", scanner);
+               return &error_node;
+       }
+       node->type = type;
+       node->lineno = yyget_lineno(scanner->scanner);
+       BT_INIT_LIST_HEAD(&node->tmp_head);
+       bt_list_add(&node->siblings, &node->tmp_head);
+
+       switch (type) {
+       case NODE_ROOT:
+               node->type = NODE_ERROR;
+               BT_LOGE("Trying to create root node: scanner-addr=%p",
+                       scanner);
+               break;
+       case NODE_EVENT:
+               BT_INIT_LIST_HEAD(&node->u.event.declaration_list);
+               break;
+       case NODE_STREAM:
+               BT_INIT_LIST_HEAD(&node->u.stream.declaration_list);
+               break;
+       case NODE_ENV:
+               BT_INIT_LIST_HEAD(&node->u.env.declaration_list);
+               break;
+       case NODE_TRACE:
+               BT_INIT_LIST_HEAD(&node->u.trace.declaration_list);
+               break;
+       case NODE_CLOCK:
+               BT_INIT_LIST_HEAD(&node->u.clock.declaration_list);
+               break;
+       case NODE_CALLSITE:
+               BT_INIT_LIST_HEAD(&node->u.callsite.declaration_list);
+               break;
+       case NODE_CTF_EXPRESSION:
+               BT_INIT_LIST_HEAD(&node->u.ctf_expression.left);
+               BT_INIT_LIST_HEAD(&node->u.ctf_expression.right);
+               break;
+       case NODE_UNARY_EXPRESSION:
+               break;
+       case NODE_TYPEDEF:
+               BT_INIT_LIST_HEAD(&node->u.field_class_def.field_class_declarators);
+               break;
+       case NODE_TYPEALIAS_TARGET:
+               BT_INIT_LIST_HEAD(&node->u.field_class_alias_target.field_class_declarators);
+               break;
+       case NODE_TYPEALIAS_ALIAS:
+               BT_INIT_LIST_HEAD(&node->u.field_class_alias_name.field_class_declarators);
+               break;
+       case NODE_TYPEALIAS:
+               break;
+       case NODE_TYPE_SPECIFIER:
+               break;
+       case NODE_TYPE_SPECIFIER_LIST:
+               BT_INIT_LIST_HEAD(&node->u.field_class_specifier_list.head);
+               break;
+       case NODE_POINTER:
+               break;
+       case NODE_TYPE_DECLARATOR:
+               BT_INIT_LIST_HEAD(&node->u.field_class_declarator.pointers);
+               break;
+       case NODE_FLOATING_POINT:
+               BT_INIT_LIST_HEAD(&node->u.floating_point.expressions);
+               break;
+       case NODE_INTEGER:
+               BT_INIT_LIST_HEAD(&node->u.integer.expressions);
+               break;
+       case NODE_STRING:
+               BT_INIT_LIST_HEAD(&node->u.string.expressions);
+               break;
+       case NODE_ENUMERATOR:
+               BT_INIT_LIST_HEAD(&node->u.enumerator.values);
+               break;
+       case NODE_ENUM:
+               BT_INIT_LIST_HEAD(&node->u._enum.enumerator_list);
+               break;
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               BT_INIT_LIST_HEAD(&node->u.struct_or_variant_declaration.field_class_declarators);
+               break;
+       case NODE_VARIANT:
+               BT_INIT_LIST_HEAD(&node->u.variant.declaration_list);
+               break;
+       case NODE_STRUCT:
+               BT_INIT_LIST_HEAD(&node->u._struct.declaration_list);
+               BT_INIT_LIST_HEAD(&node->u._struct.min_align);
+               break;
+       case NODE_UNKNOWN:
+       default:
+               node->type = NODE_ERROR;
+               BT_LOGE("Unknown node type: scanner-addr=%p, node-type=%d",
+                       scanner, type);
+               break;
+       }
+
+       return node;
+}
+
+static int reparent_ctf_expression(struct ctf_node *node,
+                                  struct ctf_node *parent)
+{
+       switch (parent->type) {
+       case NODE_EVENT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list);
+               break;
+       case NODE_STREAM:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list);
+               break;
+       case NODE_ENV:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list);
+               break;
+       case NODE_TRACE:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list);
+               break;
+       case NODE_CLOCK:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
+               break;
+       case NODE_CALLSITE:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
+               break;
+       case NODE_FLOATING_POINT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.floating_point.expressions);
+               break;
+       case NODE_INTEGER:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.integer.expressions);
+               break;
+       case NODE_STRING:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.string.expressions);
+               break;
+
+       case NODE_ROOT:
+       case NODE_CTF_EXPRESSION:
+       case NODE_TYPEDEF:
+       case NODE_TYPEALIAS_TARGET:
+       case NODE_TYPEALIAS_ALIAS:
+       case NODE_TYPEALIAS:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_TYPE_SPECIFIER_LIST:
+       case NODE_POINTER:
+       case NODE_TYPE_DECLARATOR:
+       case NODE_ENUMERATOR:
+       case NODE_ENUM:
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+       case NODE_VARIANT:
+       case NODE_STRUCT:
+       case NODE_UNARY_EXPRESSION:
+               return -EPERM;
+
+       case NODE_UNKNOWN:
+       default:
+               BT_LOGE("Unknown node type: node-type=%d", parent->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int reparent_typedef(struct ctf_node *node, struct ctf_node *parent)
+{
+       switch (parent->type) {
+       case NODE_ROOT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list);
+               break;
+       case NODE_EVENT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list);
+               break;
+       case NODE_STREAM:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list);
+               break;
+       case NODE_ENV:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list);
+               break;
+       case NODE_TRACE:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list);
+               break;
+       case NODE_CLOCK:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
+               break;
+       case NODE_CALLSITE:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
+               break;
+       case NODE_VARIANT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list);
+               break;
+       case NODE_STRUCT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list);
+               break;
+
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_CTF_EXPRESSION:
+       case NODE_TYPEDEF:
+       case NODE_TYPEALIAS_TARGET:
+       case NODE_TYPEALIAS_ALIAS:
+       case NODE_TYPEALIAS:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_TYPE_SPECIFIER_LIST:
+       case NODE_POINTER:
+       case NODE_TYPE_DECLARATOR:
+       case NODE_ENUMERATOR:
+       case NODE_ENUM:
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+       case NODE_UNARY_EXPRESSION:
+               return -EPERM;
+
+       case NODE_UNKNOWN:
+       default:
+               BT_LOGE("Unknown node type: node-type=%d", parent->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int reparent_field_class_alias(struct ctf_node *node, struct ctf_node *parent)
+{
+       switch (parent->type) {
+       case NODE_ROOT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.root.declaration_list);
+               break;
+       case NODE_EVENT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.event.declaration_list);
+               break;
+       case NODE_STREAM:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.stream.declaration_list);
+               break;
+       case NODE_ENV:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.env.declaration_list);
+               break;
+       case NODE_TRACE:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.trace.declaration_list);
+               break;
+       case NODE_CLOCK:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.clock.declaration_list);
+               break;
+       case NODE_CALLSITE:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.callsite.declaration_list);
+               break;
+       case NODE_VARIANT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list);
+               break;
+       case NODE_STRUCT:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list);
+               break;
+
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_CTF_EXPRESSION:
+       case NODE_TYPEDEF:
+       case NODE_TYPEALIAS_TARGET:
+       case NODE_TYPEALIAS_ALIAS:
+       case NODE_TYPEALIAS:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_TYPE_SPECIFIER_LIST:
+       case NODE_POINTER:
+       case NODE_TYPE_DECLARATOR:
+       case NODE_ENUMERATOR:
+       case NODE_ENUM:
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+       case NODE_UNARY_EXPRESSION:
+               return -EPERM;
+
+       case NODE_UNKNOWN:
+       default:
+               BT_LOGE("Unknown node type: node-type=%d", parent->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int reparent_field_class_specifier(struct ctf_node *node,
+                                  struct ctf_node *parent)
+{
+       switch (parent->type) {
+       case NODE_TYPE_SPECIFIER_LIST:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_specifier_list.head);
+               break;
+
+       case NODE_TYPE_SPECIFIER:
+       case NODE_EVENT:
+       case NODE_STREAM:
+       case NODE_ENV:
+       case NODE_TRACE:
+       case NODE_CLOCK:
+       case NODE_CALLSITE:
+       case NODE_VARIANT:
+       case NODE_STRUCT:
+       case NODE_TYPEDEF:
+       case NODE_TYPEALIAS_TARGET:
+       case NODE_TYPEALIAS_ALIAS:
+       case NODE_TYPE_DECLARATOR:
+       case NODE_ENUM:
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+       case NODE_TYPEALIAS:
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_CTF_EXPRESSION:
+       case NODE_POINTER:
+       case NODE_ENUMERATOR:
+       case NODE_UNARY_EXPRESSION:
+               return -EPERM;
+
+       case NODE_UNKNOWN:
+       default:
+               BT_LOGE("Unknown node type: node-type=%d", parent->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int reparent_field_class_specifier_list(struct ctf_node *node,
+                                       struct ctf_node *parent)
+{
+       switch (parent->type) {
+       case NODE_ROOT:
+               bt_list_add_tail(&node->siblings, &parent->u.root.declaration_list);
+               break;
+       case NODE_EVENT:
+               bt_list_add_tail(&node->siblings, &parent->u.event.declaration_list);
+               break;
+       case NODE_STREAM:
+               bt_list_add_tail(&node->siblings, &parent->u.stream.declaration_list);
+               break;
+       case NODE_ENV:
+               bt_list_add_tail(&node->siblings, &parent->u.env.declaration_list);
+               break;
+       case NODE_TRACE:
+               bt_list_add_tail(&node->siblings, &parent->u.trace.declaration_list);
+               break;
+       case NODE_CLOCK:
+               bt_list_add_tail(&node->siblings, &parent->u.clock.declaration_list);
+               break;
+       case NODE_CALLSITE:
+               bt_list_add_tail(&node->siblings, &parent->u.callsite.declaration_list);
+               break;
+       case NODE_VARIANT:
+               bt_list_add_tail(&node->siblings, &parent->u.variant.declaration_list);
+               break;
+       case NODE_STRUCT:
+               bt_list_add_tail(&node->siblings, &parent->u._struct.declaration_list);
+               break;
+       case NODE_TYPEDEF:
+               parent->u.field_class_def.field_class_specifier_list = node;
+               break;
+       case NODE_TYPEALIAS_TARGET:
+               parent->u.field_class_alias_target.field_class_specifier_list = node;
+               break;
+       case NODE_TYPEALIAS_ALIAS:
+               parent->u.field_class_alias_name.field_class_specifier_list = node;
+               break;
+       case NODE_ENUM:
+               parent->u._enum.container_field_class = node;
+               break;
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               parent->u.struct_or_variant_declaration.field_class_specifier_list = node;
+               break;
+       case NODE_TYPE_DECLARATOR:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_TYPEALIAS:
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_CTF_EXPRESSION:
+       case NODE_POINTER:
+       case NODE_ENUMERATOR:
+       case NODE_UNARY_EXPRESSION:
+               return -EPERM;
+
+       case NODE_UNKNOWN:
+       default:
+               BT_LOGE("Unknown node type: node-type=%d", parent->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int reparent_field_class_declarator(struct ctf_node *node,
+                                   struct ctf_node *parent)
+{
+       switch (parent->type) {
+       case NODE_TYPE_DECLARATOR:
+               parent->u.field_class_declarator.type = TYPEDEC_NESTED;
+               parent->u.field_class_declarator.u.nested.field_class_declarator = node;
+               break;
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.struct_or_variant_declaration.field_class_declarators);
+               break;
+       case NODE_TYPEDEF:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_def.field_class_declarators);
+               break;
+       case NODE_TYPEALIAS_TARGET:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_target.field_class_declarators);
+               break;
+       case NODE_TYPEALIAS_ALIAS:
+               _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_alias_name.field_class_declarators);
+               break;
+
+       case NODE_ROOT:
+       case NODE_EVENT:
+       case NODE_STREAM:
+       case NODE_ENV:
+       case NODE_TRACE:
+       case NODE_CLOCK:
+       case NODE_CALLSITE:
+       case NODE_VARIANT:
+       case NODE_STRUCT:
+       case NODE_TYPEALIAS:
+       case NODE_ENUM:
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_CTF_EXPRESSION:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_TYPE_SPECIFIER_LIST:
+       case NODE_POINTER:
+       case NODE_ENUMERATOR:
+       case NODE_UNARY_EXPRESSION:
+               return -EPERM;
+
+       case NODE_UNKNOWN:
+       default:
+               BT_LOGE("Unknown node type: node-type=%d", parent->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * set_parent_node
+ *
+ * Link node to parent. Returns 0 on success, -EPERM if it is not permitted to
+ * create the link declared by the input, -ENOENT if node or parent is NULL,
+ * -EINVAL if there is an internal structure problem.
+ */
+static int set_parent_node(struct ctf_node *node,
+                        struct ctf_node *parent)
+{
+       if (!node || !parent)
+               return -ENOENT;
+
+       /* Note: Linking to parent will be done only by an external visitor */
+
+       switch (node->type) {
+       case NODE_ROOT:
+               BT_LOGE_STR("Trying to reparent root node.");
+               return -EINVAL;
+
+       case NODE_EVENT:
+               if (parent->type == NODE_ROOT) {
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.event);
+               } else {
+                       return -EPERM;
+               }
+               break;
+       case NODE_STREAM:
+               if (parent->type == NODE_ROOT) {
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.stream);
+               } else {
+                       return -EPERM;
+               }
+               break;
+       case NODE_ENV:
+               if (parent->type == NODE_ROOT) {
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.env);
+               } else {
+                       return -EPERM;
+               }
+               break;
+       case NODE_TRACE:
+               if (parent->type == NODE_ROOT) {
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.trace);
+               } else {
+                       return -EPERM;
+               }
+               break;
+       case NODE_CLOCK:
+               if (parent->type == NODE_ROOT) {
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.clock);
+               } else {
+                       return -EPERM;
+               }
+               break;
+       case NODE_CALLSITE:
+               if (parent->type == NODE_ROOT) {
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u.root.callsite);
+               } else {
+                       return -EPERM;
+               }
+               break;
+
+       case NODE_CTF_EXPRESSION:
+               return reparent_ctf_expression(node, parent);
+       case NODE_UNARY_EXPRESSION:
+               if (parent->type == NODE_TYPE_DECLARATOR)
+                       parent->u.field_class_declarator.bitfield_len = node;
+               else
+                       return -EPERM;
+               break;
+
+       case NODE_TYPEDEF:
+               return reparent_typedef(node, parent);
+       case NODE_TYPEALIAS_TARGET:
+               if (parent->type == NODE_TYPEALIAS)
+                       parent->u.field_class_alias.target = node;
+               else
+                       return -EINVAL;
+               /* fall-through */
+       case NODE_TYPEALIAS_ALIAS:
+               if (parent->type == NODE_TYPEALIAS)
+                       parent->u.field_class_alias.alias = node;
+               else
+                       return -EINVAL;
+               /* fall-through */
+       case NODE_TYPEALIAS:
+               return reparent_field_class_alias(node, parent);
+
+       case NODE_POINTER:
+               if (parent->type == NODE_TYPE_DECLARATOR) {
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u.field_class_declarator.pointers);
+               } else
+                       return -EPERM;
+               break;
+       case NODE_TYPE_DECLARATOR:
+               return reparent_field_class_declarator(node, parent);
+
+       case NODE_TYPE_SPECIFIER_LIST:
+               return reparent_field_class_specifier_list(node, parent);
+
+       case NODE_TYPE_SPECIFIER:
+               return reparent_field_class_specifier(node, parent);
+
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_ENUM:
+       case NODE_VARIANT:
+       case NODE_STRUCT:
+               return -EINVAL; /* Dealt with internally within grammar */
+
+       case NODE_ENUMERATOR:
+               if (parent->type == NODE_ENUM) {
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u._enum.enumerator_list);
+               } else {
+                       return -EPERM;
+               }
+               break;
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               switch (parent->type) {
+               case NODE_STRUCT:
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u._struct.declaration_list);
+                       break;
+               case NODE_VARIANT:
+                       _bt_list_splice_tail(&node->tmp_head, &parent->u.variant.declaration_list);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case NODE_UNKNOWN:
+       default:
+               BT_LOGE("Unknown node type: node-type=%d", parent->type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+BT_HIDDEN
+void yyerror(struct ctf_scanner *scanner, yyscan_t yyscanner, const char *str)
+{
+       _BT_LOGE_LINENO(yyget_lineno(scanner->scanner),
+               "%s: token=\"%s\"", str, yyget_text(scanner->scanner));
+}
+
+BT_HIDDEN
+int yywrap(void)
+{
+       return 1;
+}
+
+#define reparent_error(scanner, str)                           \
+do {                                                           \
+       yyerror(scanner, scanner->scanner, YY_("reparent_error: " str)); \
+       YYERROR;                                                \
+} while (0)
+
+static struct ctf_ast *ctf_ast_alloc(struct ctf_scanner *scanner)
+{
+       struct ctf_ast *ast;
+
+       ast = objstack_alloc(scanner->objstack, sizeof(*ast));
+       if (!ast)
+               return NULL;
+       ast->root.type = NODE_ROOT;
+       BT_INIT_LIST_HEAD(&ast->root.tmp_head);
+       BT_INIT_LIST_HEAD(&ast->root.u.root.declaration_list);
+       BT_INIT_LIST_HEAD(&ast->root.u.root.trace);
+       BT_INIT_LIST_HEAD(&ast->root.u.root.env);
+       BT_INIT_LIST_HEAD(&ast->root.u.root.stream);
+       BT_INIT_LIST_HEAD(&ast->root.u.root.event);
+       BT_INIT_LIST_HEAD(&ast->root.u.root.clock);
+       BT_INIT_LIST_HEAD(&ast->root.u.root.callsite);
+       return ast;
+}
+
+int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input)
+{
+       /* Start processing new stream */
+       yyrestart(input, scanner->scanner);
+       return yyparse(scanner, scanner->scanner);
+}
+
+struct ctf_scanner *ctf_scanner_alloc(void)
+{
+       struct ctf_scanner *scanner;
+       int ret;
+
+       scanner = malloc(sizeof(*scanner));
+       if (!scanner)
+               return NULL;
+       memset(scanner, 0, sizeof(*scanner));
+       ret = yylex_init_extra(scanner, &scanner->scanner);
+       if (ret) {
+               BT_LOGE("yylex_init_extra() failed: ret=%d", ret);
+               goto cleanup_scanner;
+       }
+       scanner->objstack = objstack_create();
+       if (!scanner->objstack)
+               goto cleanup_lexer;
+       scanner->ast = ctf_ast_alloc(scanner);
+       if (!scanner->ast)
+               goto cleanup_objstack;
+       init_scope(&scanner->root_scope, NULL);
+       scanner->cs = &scanner->root_scope;
+
+       return scanner;
+
+cleanup_objstack:
+       objstack_destroy(scanner->objstack);
+cleanup_lexer:
+       ret = yylex_destroy(scanner->scanner);
+       if (!ret)
+               BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d",
+                       scanner, ret);
+cleanup_scanner:
+       free(scanner);
+       return NULL;
+}
+
+void ctf_scanner_free(struct ctf_scanner *scanner)
+{
+       int ret;
+
+       if (!scanner)
+               return;
+       finalize_scope(&scanner->root_scope);
+       objstack_destroy(scanner->objstack);
+       ret = yylex_destroy(scanner->scanner);
+       if (ret)
+               BT_LOGE("yylex_destroy() failed: scanner-addr=%p, ret=%d",
+                       scanner, ret);
+       free(scanner);
+}
+
+%}
+
+%define api.pure
+       /* %locations */
+%error-verbose
+%parse-param {struct ctf_scanner *scanner}
+%parse-param {yyscan_t yyscanner}
+%lex-param {yyscan_t yyscanner}
+/*
+ * Expect two shift-reduce conflicts. Caused by enum name-opt : type {}
+ * vs struct { int :value; } (unnamed bit-field). The default is to
+ * shift, so whenever we encounter an enumeration, we are doing the
+ * proper thing (shift). It is illegal to declare an enumeration
+ * "bit-field", so it is OK if this situation ends up in a parsing
+ * error.
+ */
+%expect 2
+%start file
+%token CTF_INTEGER_LITERAL CTF_STRING_LITERAL CTF_CHARACTER_LITERAL CTF_LSBRAC CTF_RSBRAC CTF_LPAREN CTF_RPAREN CTF_LBRAC CTF_RBRAC CTF_RARROW CTF_STAR CTF_PLUS CTF_MINUS CTF_LT CTF_GT CTF_TYPEASSIGN CTF_COLON CTF_SEMICOLON CTF_DOTDOTDOT CTF_DOT CTF_EQUAL CTF_COMMA CTF_CONST CTF_CHAR CTF_DOUBLE CTF_ENUM CTF_ENV CTF_EVENT CTF_FLOATING_POINT CTF_FLOAT CTF_INTEGER CTF_INT CTF_LONG CTF_SHORT CTF_SIGNED CTF_STREAM CTF_STRING CTF_STRUCT CTF_TRACE CTF_CALLSITE CTF_CLOCK CTF_TYPEALIAS CTF_TYPEDEF CTF_UNSIGNED CTF_VARIANT CTF_VOID CTF_BOOL CTF_COMPLEX CTF_IMAGINARY CTF_TOK_ALIGN
+%token <s> IDENTIFIER ID_TYPE
+%token CTF_ERROR
+%union
+{
+       long long ll;
+       unsigned long long ull;
+       char c;
+       char *s;
+       struct ctf_node *n;
+}
+
+%type <s> CTF_STRING_LITERAL CTF_CHARACTER_LITERAL
+
+%type <s> keywords
+
+%type <ull> CTF_INTEGER_LITERAL
+%type <n> postfix_expression unary_expression unary_expression_or_range
+
+%type <n> declaration
+%type <n> event_declaration
+%type <n> stream_declaration
+%type <n> env_declaration
+%type <n> trace_declaration
+%type <n> clock_declaration
+%type <n> callsite_declaration
+%type <n> integer_declaration_specifiers
+%type <n> declaration_specifiers
+%type <n> alias_declaration_specifiers
+
+%type <n> field_class_declarator_list
+%type <n> integer_field_class_specifier
+%type <n> field_class_specifier
+%type <n> struct_class_specifier
+%type <n> variant_field_class_specifier
+%type <n> enum_field_class_specifier
+%type <n> struct_or_variant_declaration_list
+%type <n> struct_or_variant_declaration
+%type <n> struct_or_variant_declarator_list
+%type <n> struct_or_variant_declarator
+%type <n> enumerator_list
+%type <n> enumerator
+%type <n> abstract_declarator_list
+%type <n> abstract_declarator
+%type <n> direct_abstract_declarator
+%type <n> alias_abstract_declarator_list
+%type <n> alias_abstract_declarator
+%type <n> direct_alias_abstract_declarator
+%type <n> declarator
+%type <n> direct_declarator
+%type <n> field_class_declarator
+%type <n> direct_field_class_declarator
+%type <n> pointer
+%type <n> ctf_assignment_expression_list
+%type <n> ctf_assignment_expression
+
+%%
+
+file:
+               declaration
+               {
+                       if (set_parent_node($1, &ctf_scanner_get_ast(scanner)->root))
+                               reparent_error(scanner, "error reparenting to root");
+               }
+       |       file declaration
+               {
+                       if (set_parent_node($2, &ctf_scanner_get_ast(scanner)->root))
+                               reparent_error(scanner, "error reparenting to root");
+               }
+       ;
+
+keywords:
+               CTF_VOID
+               {       $$ = yylval.s;          }
+       |       CTF_CHAR
+               {       $$ = yylval.s;          }
+       |       CTF_SHORT
+               {       $$ = yylval.s;          }
+       |       CTF_INT
+               {       $$ = yylval.s;          }
+       |       CTF_LONG
+               {       $$ = yylval.s;          }
+       |       CTF_FLOAT
+               {       $$ = yylval.s;          }
+       |       CTF_DOUBLE
+               {       $$ = yylval.s;          }
+       |       CTF_SIGNED
+               {       $$ = yylval.s;          }
+       |       CTF_UNSIGNED
+               {       $$ = yylval.s;          }
+       |       CTF_BOOL
+               {       $$ = yylval.s;          }
+       |       CTF_COMPLEX
+               {       $$ = yylval.s;          }
+       |       CTF_IMAGINARY
+               {       $$ = yylval.s;          }
+       |       CTF_FLOATING_POINT
+               {       $$ = yylval.s;          }
+       |       CTF_INTEGER
+               {       $$ = yylval.s;          }
+       |       CTF_STRING
+               {       $$ = yylval.s;          }
+       |       CTF_ENUM
+               {       $$ = yylval.s;          }
+       |       CTF_VARIANT
+               {       $$ = yylval.s;          }
+       |       CTF_STRUCT
+               {       $$ = yylval.s;          }
+       |       CTF_CONST
+               {       $$ = yylval.s;          }
+       |       CTF_TYPEDEF
+               {       $$ = yylval.s;          }
+       |       CTF_EVENT
+               {       $$ = yylval.s;          }
+       |       CTF_STREAM
+               {       $$ = yylval.s;          }
+       |       CTF_ENV
+               {       $$ = yylval.s;          }
+       |       CTF_TRACE
+               {       $$ = yylval.s;          }
+       |       CTF_CLOCK
+               {       $$ = yylval.s;          }
+       |       CTF_CALLSITE
+               {       $$ = yylval.s;          }
+       |       CTF_TOK_ALIGN
+               {       $$ = yylval.s;          }
+       ;
+
+
+/* 2: Phrase structure grammar */
+
+postfix_expression:
+               IDENTIFIER
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = yylval.s;
+               }
+       |       ID_TYPE
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = yylval.s;
+               }
+       |       keywords
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = yylval.s;
+               }
+       |       CTF_INTEGER_LITERAL
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_UNSIGNED_CONSTANT;
+                       $$->u.unary_expression.u.unsigned_constant = $1;
+               }
+       |       CTF_STRING_LITERAL
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = $1;
+               }
+       |       CTF_CHARACTER_LITERAL
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = $1;
+               }
+       |       CTF_LPAREN unary_expression CTF_RPAREN
+               {
+                       $$ = $2;
+               }
+       |       postfix_expression CTF_LSBRAC unary_expression CTF_RSBRAC
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_SBRAC;
+                       $$->u.unary_expression.u.sbrac_exp = $3;
+                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
+                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
+               }
+       |       postfix_expression CTF_DOT IDENTIFIER
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = yylval.s;
+                       $$->u.unary_expression.link = UNARY_DOTLINK;
+                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
+                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
+               }
+       |       postfix_expression CTF_DOT ID_TYPE
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = yylval.s;
+                       $$->u.unary_expression.link = UNARY_DOTLINK;
+                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
+                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
+               }
+       |       postfix_expression CTF_DOT keywords
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = yylval.s;
+                       $$->u.unary_expression.link = UNARY_DOTLINK;
+                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
+                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
+               }
+       |       postfix_expression CTF_RARROW IDENTIFIER
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = yylval.s;
+                       $$->u.unary_expression.link = UNARY_ARROWLINK;
+                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
+                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
+               }
+       |       postfix_expression CTF_RARROW ID_TYPE
+               {
+                       $$ = make_node(scanner, NODE_UNARY_EXPRESSION);
+                       $$->u.unary_expression.type = UNARY_STRING;
+                       $$->u.unary_expression.u.string = yylval.s;
+                       $$->u.unary_expression.link = UNARY_ARROWLINK;
+                       bt_list_splice(&($1)->tmp_head, &($$)->tmp_head);
+                       bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
+               }
+       ;
+
+unary_expression:
+               postfix_expression
+               {       $$ = $1;                                }
+       |       CTF_PLUS postfix_expression
+               {
+                       $$ = $2;
+                       if ($$->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT
+                               && $$->u.unary_expression.type != UNARY_SIGNED_CONSTANT) {
+                               reparent_error(scanner, "expecting numeric constant");
+                       }
+               }
+       |       CTF_MINUS postfix_expression
+               {
+                       $$ = $2;
+                       if ($$->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT) {
+                               $$->u.unary_expression.type = UNARY_SIGNED_CONSTANT;
+                               $$->u.unary_expression.u.signed_constant =
+                                       -($$->u.unary_expression.u.unsigned_constant);
+                       } else if ($$->u.unary_expression.type == UNARY_UNSIGNED_CONSTANT) {
+                               $$->u.unary_expression.u.signed_constant =
+                                       -($$->u.unary_expression.u.signed_constant);
+                       } else {
+                               reparent_error(scanner, "expecting numeric constant");
+                       }
+               }
+       ;
+
+unary_expression_or_range:
+               unary_expression CTF_DOTDOTDOT unary_expression
+               {
+                       $$ = $1;
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->tmp_head);
+                       $3->u.unary_expression.link = UNARY_DOTDOTDOT;
+               }
+       |       unary_expression
+               {       $$ = $1;                }
+       ;
+
+/* 2.2: Declarations */
+
+declaration:
+               declaration_specifiers CTF_SEMICOLON
+               {       $$ = $1;        }
+       |       event_declaration
+               {       $$ = $1;        }
+       |       stream_declaration
+               {       $$ = $1;        }
+       |       env_declaration
+               {       $$ = $1;        }
+       |       trace_declaration
+               {       $$ = $1;        }
+       |       clock_declaration
+               {       $$ = $1;        }
+       |       callsite_declaration
+               {       $$ = $1;        }
+       |       declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_def.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_def.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_def.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEALIAS);
+                       $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
+                       $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators);
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators);
+               }
+       ;
+
+event_declaration:
+               event_declaration_begin event_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_EVENT);
+               }
+       |       event_declaration_begin ctf_assignment_expression_list event_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_EVENT);
+                       if (set_parent_node($2, $$))
+                               reparent_error(scanner, "event_declaration");
+               }
+       ;
+
+event_declaration_begin:
+               CTF_EVENT CTF_LBRAC
+               {       push_scope(scanner);    }
+       ;
+
+event_declaration_end:
+               CTF_RBRAC CTF_SEMICOLON
+               {       pop_scope(scanner);     }
+       ;
+
+
+stream_declaration:
+               stream_declaration_begin stream_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_STREAM);
+               }
+       |       stream_declaration_begin ctf_assignment_expression_list stream_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_STREAM);
+                       if (set_parent_node($2, $$))
+                               reparent_error(scanner, "stream_declaration");
+               }
+       ;
+
+stream_declaration_begin:
+               CTF_STREAM CTF_LBRAC
+               {       push_scope(scanner);    }
+       ;
+
+stream_declaration_end:
+               CTF_RBRAC CTF_SEMICOLON
+               {       pop_scope(scanner);     }
+       ;
+
+env_declaration:
+               env_declaration_begin env_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_ENV);
+               }
+       |       env_declaration_begin ctf_assignment_expression_list env_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_ENV);
+                       if (set_parent_node($2, $$))
+                               reparent_error(scanner, "env declaration");
+               }
+       ;
+
+env_declaration_begin:
+               CTF_ENV CTF_LBRAC
+               {       push_scope(scanner);    }
+       ;
+
+env_declaration_end:
+               CTF_RBRAC CTF_SEMICOLON
+               {       pop_scope(scanner);     }
+       ;
+
+trace_declaration:
+               trace_declaration_begin trace_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_TRACE);
+               }
+       |       trace_declaration_begin ctf_assignment_expression_list trace_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_TRACE);
+                       if (set_parent_node($2, $$))
+                               reparent_error(scanner, "trace_declaration");
+               }
+       ;
+
+trace_declaration_begin:
+               CTF_TRACE CTF_LBRAC
+               {       push_scope(scanner);    }
+       ;
+
+trace_declaration_end:
+               CTF_RBRAC CTF_SEMICOLON
+               {       pop_scope(scanner);     }
+       ;
+
+clock_declaration:
+               CTF_CLOCK clock_declaration_begin clock_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_CLOCK);
+               }
+       |       CTF_CLOCK clock_declaration_begin ctf_assignment_expression_list clock_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_CLOCK);
+                       if (set_parent_node($3, $$))
+                               reparent_error(scanner, "trace_declaration");
+               }
+       ;
+
+clock_declaration_begin:
+               CTF_LBRAC
+               {       push_scope(scanner);    }
+       ;
+
+clock_declaration_end:
+               CTF_RBRAC CTF_SEMICOLON
+               {       pop_scope(scanner);     }
+       ;
+
+callsite_declaration:
+               CTF_CALLSITE callsite_declaration_begin callsite_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_CALLSITE);
+               }
+       |       CTF_CALLSITE callsite_declaration_begin ctf_assignment_expression_list callsite_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_CALLSITE);
+                       if (set_parent_node($3, $$))
+                               reparent_error(scanner, "trace_declaration");
+               }
+       ;
+
+callsite_declaration_begin:
+               CTF_LBRAC
+               {       push_scope(scanner);    }
+       ;
+
+callsite_declaration_end:
+               CTF_RBRAC CTF_SEMICOLON
+               {       pop_scope(scanner);     }
+       ;
+
+integer_declaration_specifiers:
+               CTF_CONST
+               {
+                       struct ctf_node *node;
+
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       node->u.field_class_specifier.type = TYPESPEC_CONST;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       integer_field_class_specifier
+               {
+                       struct ctf_node *node;
+
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       node = $1;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       integer_declaration_specifiers CTF_CONST
+               {
+                       struct ctf_node *node;
+
+                       $$ = $1;
+                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       node->u.field_class_specifier.type = TYPESPEC_CONST;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       integer_declaration_specifiers integer_field_class_specifier
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       ;
+
+declaration_specifiers:
+               CTF_CONST
+               {
+                       struct ctf_node *node;
+
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       node->u.field_class_specifier.type = TYPESPEC_CONST;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       field_class_specifier
+               {
+                       struct ctf_node *node;
+
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       node = $1;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       declaration_specifiers CTF_CONST
+               {
+                       struct ctf_node *node;
+
+                       $$ = $1;
+                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       node->u.field_class_specifier.type = TYPESPEC_CONST;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       declaration_specifiers field_class_specifier
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       ;
+
+field_class_declarator_list:
+               field_class_declarator
+               {       $$ = $1;        }
+       |       field_class_declarator_list CTF_COMMA field_class_declarator
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
+               }
+       ;
+
+integer_field_class_specifier:
+               CTF_CHAR
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_CHAR;
+               }
+       |       CTF_SHORT
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_SHORT;
+               }
+       |       CTF_INT
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_INT;
+               }
+       |       CTF_LONG
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_LONG;
+               }
+       |       CTF_SIGNED
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_SIGNED;
+               }
+       |       CTF_UNSIGNED
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED;
+               }
+       |       CTF_BOOL
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_BOOL;
+               }
+       |       ID_TYPE
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE;
+                       $$->u.field_class_specifier.id_type = yylval.s;
+               }
+       |       CTF_INTEGER CTF_LBRAC CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_INTEGER;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER);
+               }
+       |       CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_INTEGER;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER);
+                       if (set_parent_node($3, $$->u.field_class_specifier.node))
+                               reparent_error(scanner, "integer reparent error");
+               }
+       ;
+
+field_class_specifier:
+               CTF_VOID
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_VOID;
+               }
+       |       CTF_CHAR
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_CHAR;
+               }
+       |       CTF_SHORT
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_SHORT;
+               }
+       |       CTF_INT
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_INT;
+               }
+       |       CTF_LONG
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_LONG;
+               }
+       |       CTF_FLOAT
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_FLOAT;
+               }
+       |       CTF_DOUBLE
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_DOUBLE;
+               }
+       |       CTF_SIGNED
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_SIGNED;
+               }
+       |       CTF_UNSIGNED
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_UNSIGNED;
+               }
+       |       CTF_BOOL
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_BOOL;
+               }
+       |       CTF_COMPLEX
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_COMPLEX;
+               }
+       |       CTF_IMAGINARY
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_IMAGINARY;
+               }
+       |       ID_TYPE
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_ID_TYPE;
+                       $$->u.field_class_specifier.id_type = yylval.s;
+               }
+       |       CTF_FLOATING_POINT CTF_LBRAC CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT);
+               }
+       |       CTF_FLOATING_POINT CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_FLOATING_POINT;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_FLOATING_POINT);
+                       if (set_parent_node($3, $$->u.field_class_specifier.node))
+                               reparent_error(scanner, "floating point reparent error");
+               }
+       |       CTF_INTEGER CTF_LBRAC CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_INTEGER;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER);
+               }
+       |       CTF_INTEGER CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_INTEGER;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_INTEGER);
+                       if (set_parent_node($3, $$->u.field_class_specifier.node))
+                               reparent_error(scanner, "integer reparent error");
+               }
+       |       CTF_STRING
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_STRING;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING);
+               }
+       |       CTF_STRING CTF_LBRAC CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_STRING;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING);
+               }
+       |       CTF_STRING CTF_LBRAC ctf_assignment_expression_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_STRING;
+                       $$->u.field_class_specifier.node = make_node(scanner, NODE_STRING);
+                       if (set_parent_node($3, $$->u.field_class_specifier.node))
+                               reparent_error(scanner, "string reparent error");
+               }
+       |       CTF_ENUM enum_field_class_specifier
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_ENUM;
+                       $$->u.field_class_specifier.node = $2;
+               }
+       |       CTF_VARIANT variant_field_class_specifier
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_VARIANT;
+                       $$->u.field_class_specifier.node = $2;
+               }
+       |       CTF_STRUCT struct_class_specifier
+               {
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       $$->u.field_class_specifier.type = TYPESPEC_STRUCT;
+                       $$->u.field_class_specifier.node = $2;
+               }
+       ;
+
+struct_class_specifier:
+               struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_STRUCT);
+                       $$->u._struct.has_body = 1;
+                       if ($2 && set_parent_node($2, $$))
+                               reparent_error(scanner, "struct reparent error");
+               }
+       |       IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_STRUCT);
+                       $$->u._struct.has_body = 1;
+                       $$->u._struct.name = $1;
+                       if ($3 && set_parent_node($3, $$))
+                               reparent_error(scanner, "struct reparent error");
+               }
+       |       ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_STRUCT);
+                       $$->u._struct.has_body = 1;
+                       $$->u._struct.name = $1;
+                       if ($3 && set_parent_node($3, $$))
+                               reparent_error(scanner, "struct reparent error");
+               }
+       |       IDENTIFIER
+               {
+                       $$ = make_node(scanner, NODE_STRUCT);
+                       $$->u._struct.has_body = 0;
+                       $$->u._struct.name = $1;
+               }
+       |       ID_TYPE
+               {
+                       $$ = make_node(scanner, NODE_STRUCT);
+                       $$->u._struct.has_body = 0;
+                       $$->u._struct.name = $1;
+               }
+       |       struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN
+               {
+                       $$ = make_node(scanner, NODE_STRUCT);
+                       $$->u._struct.has_body = 1;
+                       bt_list_add_tail(&($6)->siblings, &$$->u._struct.min_align);
+                       if ($2 && set_parent_node($2, $$))
+                               reparent_error(scanner, "struct reparent error");
+               }
+       |       IDENTIFIER struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN
+               {
+                       $$ = make_node(scanner, NODE_STRUCT);
+                       $$->u._struct.has_body = 1;
+                       $$->u._struct.name = $1;
+                       bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align);
+                       if ($3 && set_parent_node($3, $$))
+                               reparent_error(scanner, "struct reparent error");
+               }
+       |       ID_TYPE struct_declaration_begin struct_or_variant_declaration_list struct_declaration_end CTF_TOK_ALIGN CTF_LPAREN unary_expression CTF_RPAREN
+               {
+                       $$ = make_node(scanner, NODE_STRUCT);
+                       $$->u._struct.has_body = 1;
+                       $$->u._struct.name = $1;
+                       bt_list_add_tail(&($7)->siblings, &$$->u._struct.min_align);
+                       if ($3 && set_parent_node($3, $$))
+                               reparent_error(scanner, "struct reparent error");
+               }
+       ;
+
+struct_declaration_begin:
+               CTF_LBRAC
+               {       push_scope(scanner);    }
+       ;
+
+struct_declaration_end:
+               CTF_RBRAC
+               {       pop_scope(scanner);     }
+       ;
+
+variant_field_class_specifier:
+               variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       if ($2 && set_parent_node($2, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       $$->u.variant.choice = $2;
+                       if ($5 && set_parent_node($5, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       $$->u.variant.choice = $2;
+                       if ($5 && set_parent_node($5, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       IDENTIFIER variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       $$->u.variant.name = $1;
+                       if ($3 && set_parent_node($3, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       IDENTIFIER CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       $$->u.variant.name = $1;
+                       $$->u.variant.choice = $3;
+                       if ($6 && set_parent_node($6, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       IDENTIFIER CTF_LT IDENTIFIER CTF_GT
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 0;
+                       $$->u.variant.name = $1;
+                       $$->u.variant.choice = $3;
+               }
+       |       IDENTIFIER CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       $$->u.variant.name = $1;
+                       $$->u.variant.choice = $3;
+                       if ($6 && set_parent_node($6, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       IDENTIFIER CTF_LT ID_TYPE CTF_GT
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 0;
+                       $$->u.variant.name = $1;
+                       $$->u.variant.choice = $3;
+               }
+       |       ID_TYPE variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       $$->u.variant.name = $1;
+                       if ($3 && set_parent_node($3, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       ID_TYPE CTF_LT IDENTIFIER CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       $$->u.variant.name = $1;
+                       $$->u.variant.choice = $3;
+                       if ($6 && set_parent_node($6, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       ID_TYPE CTF_LT IDENTIFIER CTF_GT
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 0;
+                       $$->u.variant.name = $1;
+                       $$->u.variant.choice = $3;
+               }
+       |       ID_TYPE CTF_LT ID_TYPE CTF_GT variant_declaration_begin struct_or_variant_declaration_list variant_declaration_end
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 1;
+                       $$->u.variant.name = $1;
+                       $$->u.variant.choice = $3;
+                       if ($6 && set_parent_node($6, $$))
+                               reparent_error(scanner, "variant reparent error");
+               }
+       |       ID_TYPE CTF_LT ID_TYPE CTF_GT
+               {
+                       $$ = make_node(scanner, NODE_VARIANT);
+                       $$->u.variant.has_body = 0;
+                       $$->u.variant.name = $1;
+                       $$->u.variant.choice = $3;
+               }
+       ;
+
+variant_declaration_begin:
+               CTF_LBRAC
+               {       push_scope(scanner);    }
+       ;
+
+variant_declaration_end:
+               CTF_RBRAC
+               {       pop_scope(scanner);     }
+       ;
+
+enum_field_class_specifier:
+               CTF_LBRAC enumerator_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       ($$)->u._enum.container_field_class = $2;
+                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       IDENTIFIER CTF_LBRAC enumerator_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       $$->u._enum.enum_id = $1;
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       $$->u._enum.enum_id = $1;
+                       ($$)->u._enum.container_field_class = $3;
+                       _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       ID_TYPE CTF_LBRAC enumerator_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       $$->u._enum.enum_id = $1;
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       $$->u._enum.enum_id = $1;
+                       ($$)->u._enum.container_field_class = $3;
+                       _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       _bt_list_splice_tail(&($2)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       ($$)->u._enum.container_field_class = $2;
+                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       IDENTIFIER CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       $$->u._enum.enum_id = $1;
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       IDENTIFIER CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       $$->u._enum.enum_id = $1;
+                       ($$)->u._enum.container_field_class = $3;
+                       _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       IDENTIFIER
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 0;
+                       $$->u._enum.enum_id = $1;
+               }
+       |       ID_TYPE CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       $$->u._enum.enum_id = $1;
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       ID_TYPE CTF_COLON integer_declaration_specifiers CTF_LBRAC enumerator_list CTF_COMMA CTF_RBRAC
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 1;
+                       $$->u._enum.enum_id = $1;
+                       ($$)->u._enum.container_field_class = $3;
+                       _bt_list_splice_tail(&($5)->tmp_head, &($$)->u._enum.enumerator_list);
+               }
+       |       ID_TYPE
+               {
+                       $$ = make_node(scanner, NODE_ENUM);
+                       $$->u._enum.has_body = 0;
+                       $$->u._enum.enum_id = $1;
+               }
+       ;
+
+struct_or_variant_declaration_list:
+               /* empty */
+               {       $$ = NULL;      }
+       |       struct_or_variant_declaration_list struct_or_variant_declaration
+               {
+                       if ($1) {
+                               $$ = $1;
+                               bt_list_add_tail(&($2)->siblings, &($$)->tmp_head);
+                       } else {
+                               $$ = $2;
+                               bt_list_add_tail(&($$)->siblings, &($$)->tmp_head);
+                       }
+               }
+       ;
+
+struct_or_variant_declaration:
+               declaration_specifiers struct_or_variant_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       $$ = make_node(scanner, NODE_STRUCT_OR_VARIANT_DECLARATION);
+                       ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($2)->tmp_head, &($$)->u.struct_or_variant_declaration.field_class_declarators);
+               }
+       |       declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_def.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       CTF_TYPEDEF declaration_specifiers field_class_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_def.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       declaration_specifiers CTF_TYPEDEF field_class_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list CTF_SEMICOLON
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEALIAS);
+                       $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
+                       $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators);
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators);
+               }
+       ;
+
+alias_declaration_specifiers:
+               CTF_CONST
+               {
+                       struct ctf_node *node;
+
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       node->u.field_class_specifier.type = TYPESPEC_CONST;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       field_class_specifier
+               {
+                       struct ctf_node *node;
+
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       node = $1;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       IDENTIFIER
+               {
+                       struct ctf_node *node;
+
+                       add_type(scanner, $1);
+                       $$ = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       node->u.field_class_specifier.type = TYPESPEC_ID_TYPE;
+                       node->u.field_class_specifier.id_type = yylval.s;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       alias_declaration_specifiers CTF_CONST
+               {
+                       struct ctf_node *node;
+
+                       $$ = $1;
+                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       node->u.field_class_specifier.type = TYPESPEC_CONST;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       alias_declaration_specifiers field_class_specifier
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($2)->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       |       alias_declaration_specifiers IDENTIFIER
+               {
+                       struct ctf_node *node;
+
+                       add_type(scanner, $2);
+                       $$ = $1;
+                       node = make_node(scanner, NODE_TYPE_SPECIFIER);
+                       node->u.field_class_specifier.type = TYPESPEC_ID_TYPE;
+                       node->u.field_class_specifier.id_type = yylval.s;
+                       bt_list_add_tail(&node->siblings, &($$)->u.field_class_specifier_list.head);
+               }
+       ;
+
+struct_or_variant_declarator_list:
+               struct_or_variant_declarator
+               {       $$ = $1;        }
+       |       struct_or_variant_declarator_list CTF_COMMA struct_or_variant_declarator
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
+               }
+       ;
+
+struct_or_variant_declarator:
+               declarator
+               {       $$ = $1;        }
+       |       CTF_COLON unary_expression
+               {       $$ = $2;        }
+       |       declarator CTF_COLON unary_expression
+               {
+                       $$ = $1;
+                       if (set_parent_node($3, $1))
+                               reparent_error(scanner, "struct_or_variant_declarator");
+               }
+       ;
+
+enumerator_list:
+               enumerator
+               {       $$ = $1;        }
+       |       enumerator_list CTF_COMMA enumerator
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
+               }
+       ;
+
+enumerator:
+               IDENTIFIER
+               {
+                       $$ = make_node(scanner, NODE_ENUMERATOR);
+                       $$->u.enumerator.id = $1;
+               }
+       |       ID_TYPE
+               {
+                       $$ = make_node(scanner, NODE_ENUMERATOR);
+                       $$->u.enumerator.id = $1;
+               }
+       |       keywords
+               {
+                       $$ = make_node(scanner, NODE_ENUMERATOR);
+                       $$->u.enumerator.id = $1;
+               }
+       |       CTF_STRING_LITERAL
+               {
+                       $$ = make_node(scanner, NODE_ENUMERATOR);
+                       $$->u.enumerator.id = $1;
+               }
+       |       IDENTIFIER CTF_EQUAL unary_expression_or_range
+               {
+                       $$ = make_node(scanner, NODE_ENUMERATOR);
+                       $$->u.enumerator.id = $1;
+                       bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
+               }
+       |       ID_TYPE CTF_EQUAL unary_expression_or_range
+               {
+                       $$ = make_node(scanner, NODE_ENUMERATOR);
+                       $$->u.enumerator.id = $1;
+                       bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
+               }
+       |       keywords CTF_EQUAL unary_expression_or_range
+               {
+                       $$ = make_node(scanner, NODE_ENUMERATOR);
+                       $$->u.enumerator.id = $1;
+                       bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
+               }
+       |       CTF_STRING_LITERAL CTF_EQUAL unary_expression_or_range
+               {
+                       $$ = make_node(scanner, NODE_ENUMERATOR);
+                       $$->u.enumerator.id = $1;
+                       bt_list_splice(&($3)->tmp_head, &($$)->u.enumerator.values);
+               }
+       ;
+
+abstract_declarator_list:
+               abstract_declarator
+               {       $$ = $1;        }
+       |       abstract_declarator_list CTF_COMMA abstract_declarator
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
+               }
+       ;
+
+abstract_declarator:
+               direct_abstract_declarator
+               {       $$ = $1;        }
+       |       pointer direct_abstract_declarator
+               {
+                       $$ = $2;
+                       bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers);
+               }
+       ;
+
+direct_abstract_declarator:
+               /* empty */
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                        $$->u.field_class_declarator.type = TYPEDEC_ID;
+                       /* id is NULL */
+               }
+       |       IDENTIFIER
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_ID;
+                       $$->u.field_class_declarator.u.id = $1;
+               }
+       |       CTF_LPAREN abstract_declarator CTF_RPAREN
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $2;
+               }
+       |       direct_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
+                       BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length);
+               }
+       |       direct_abstract_declarator CTF_LSBRAC CTF_RSBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
+                       $$->u.field_class_declarator.u.nested.abstract_array = 1;
+               }
+       ;
+
+alias_abstract_declarator_list:
+               alias_abstract_declarator
+               {       $$ = $1;        }
+       |       alias_abstract_declarator_list CTF_COMMA alias_abstract_declarator
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($3)->siblings, &($$)->tmp_head);
+               }
+       ;
+
+alias_abstract_declarator:
+               direct_alias_abstract_declarator
+               {       $$ = $1;        }
+       |       pointer direct_alias_abstract_declarator
+               {
+                       $$ = $2;
+                       bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers);
+               }
+       ;
+
+direct_alias_abstract_declarator:
+               /* empty */
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                        $$->u.field_class_declarator.type = TYPEDEC_ID;
+                       /* id is NULL */
+               }
+       |       CTF_LPAREN alias_abstract_declarator CTF_RPAREN
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $2;
+               }
+       |       direct_alias_abstract_declarator CTF_LSBRAC unary_expression CTF_RSBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
+                       BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length);
+               }
+       |       direct_alias_abstract_declarator CTF_LSBRAC CTF_RSBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
+                       $$->u.field_class_declarator.u.nested.abstract_array = 1;
+               }
+       ;
+
+declarator:
+               direct_declarator
+               {       $$ = $1;        }
+       |       pointer direct_declarator
+               {
+                       $$ = $2;
+                       bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers);
+               }
+       ;
+
+direct_declarator:
+               IDENTIFIER
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_ID;
+                       $$->u.field_class_declarator.u.id = $1;
+               }
+       |       CTF_LPAREN declarator CTF_RPAREN
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $2;
+               }
+       |       direct_declarator CTF_LSBRAC unary_expression CTF_RSBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
+                       BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length);
+               }
+       ;
+
+field_class_declarator:
+               direct_field_class_declarator
+               {       $$ = $1;        }
+       |       pointer direct_field_class_declarator
+               {
+                       $$ = $2;
+                       bt_list_splice(&($1)->tmp_head, &($$)->u.field_class_declarator.pointers);
+               }
+       ;
+
+direct_field_class_declarator:
+               IDENTIFIER
+               {
+                       add_type(scanner, $1);
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_ID;
+                       $$->u.field_class_declarator.u.id = $1;
+               }
+       |       CTF_LPAREN field_class_declarator CTF_RPAREN
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $2;
+               }
+       |       direct_field_class_declarator CTF_LSBRAC unary_expression CTF_RSBRAC
+               {
+                       $$ = make_node(scanner, NODE_TYPE_DECLARATOR);
+                       $$->u.field_class_declarator.type = TYPEDEC_NESTED;
+                       $$->u.field_class_declarator.u.nested.field_class_declarator = $1;
+                       BT_INIT_LIST_HEAD(&($$)->u.field_class_declarator.u.nested.length);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_declarator.u.nested.length);
+               }
+       ;
+
+pointer:
+               CTF_STAR
+               {
+                       $$ = make_node(scanner, NODE_POINTER);
+               }
+       |       CTF_STAR pointer
+               {
+                       $$ = make_node(scanner, NODE_POINTER);
+                       bt_list_splice(&($2)->tmp_head, &($$)->tmp_head);
+               }
+       |       CTF_STAR type_qualifier_list pointer
+               {
+                       $$ = make_node(scanner, NODE_POINTER);
+                       $$->u.pointer.const_qualifier = 1;
+                       bt_list_splice(&($3)->tmp_head, &($$)->tmp_head);
+               }
+       ;
+
+type_qualifier_list:
+               /* pointer assumes only const type qualifier */
+               CTF_CONST
+       |       type_qualifier_list CTF_CONST
+       ;
+
+/* 2.3: CTF-specific declarations */
+
+ctf_assignment_expression_list:
+               ctf_assignment_expression CTF_SEMICOLON
+               {       $$ = $1;        }
+       |       ctf_assignment_expression_list ctf_assignment_expression CTF_SEMICOLON
+               {
+                       $$ = $1;
+                       bt_list_add_tail(&($2)->siblings, &($$)->tmp_head);
+               }
+       ;
+
+ctf_assignment_expression:
+               unary_expression CTF_EQUAL unary_expression
+               {
+                       /*
+                        * Because we have left and right, cannot use
+                        * set_parent_node.
+                        */
+                       $$ = make_node(scanner, NODE_CTF_EXPRESSION);
+                       _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left);
+                       if ($1->u.unary_expression.type != UNARY_STRING)
+                               reparent_error(scanner, "ctf_assignment_expression left expects string");
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.ctf_expression.right);
+               }
+       |       unary_expression CTF_TYPEASSIGN declaration_specifiers  /* Only allow struct */
+               {
+                       /*
+                        * Because we have left and right, cannot use
+                        * set_parent_node.
+                        */
+                       $$ = make_node(scanner, NODE_CTF_EXPRESSION);
+                       _bt_list_splice_tail(&($1)->tmp_head, &($$)->u.ctf_expression.left);
+                       if ($1->u.unary_expression.type != UNARY_STRING)
+                               reparent_error(scanner, "ctf_assignment_expression left expects string");
+                       bt_list_add_tail(&($3)->siblings, &($$)->u.ctf_expression.right);
+               }
+       |       declaration_specifiers CTF_TYPEDEF declaration_specifiers field_class_declarator_list
+               {
+                       struct ctf_node *list;
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($4)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       CTF_TYPEDEF declaration_specifiers field_class_declarator_list
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_def.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       declaration_specifiers CTF_TYPEDEF field_class_declarator_list
+               {
+                       struct ctf_node *list;
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       _bt_list_splice_tail(&($1)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       $$ = make_node(scanner, NODE_TYPEDEF);
+                       ($$)->u.struct_or_variant_declaration.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_def.field_class_declarators);
+               }
+       |       CTF_TYPEALIAS declaration_specifiers abstract_declarator_list CTF_TYPEASSIGN alias_declaration_specifiers alias_abstract_declarator_list
+               {
+                       struct ctf_node *list;
+
+                       $$ = make_node(scanner, NODE_TYPEALIAS);
+                       $$->u.field_class_alias.target = make_node(scanner, NODE_TYPEALIAS_TARGET);
+                       $$->u.field_class_alias.alias = make_node(scanner, NODE_TYPEALIAS_ALIAS);
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_alias.target->u.field_class_alias_target.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($2)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($3)->tmp_head, &($$)->u.field_class_alias.target->u.field_class_alias_target.field_class_declarators);
+
+                       list = make_node(scanner, NODE_TYPE_SPECIFIER_LIST);
+                       $$->u.field_class_alias.alias->u.field_class_alias_name.field_class_specifier_list = list;
+                       _bt_list_splice_tail(&($5)->u.field_class_specifier_list.head, &list->u.field_class_specifier_list.head);
+                       _bt_list_splice_tail(&($6)->tmp_head, &($$)->u.field_class_alias.alias->u.field_class_alias_name.field_class_declarators);
+               }
+       ;
diff --git a/src/plugins/ctf/common/metadata/scanner-symbols.h b/src/plugins/ctf/common/metadata/scanner-symbols.h
new file mode 100644 (file)
index 0000000..9b9e363
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _CTF_SCANNER_SYMBOLS
+#define _CTF_SCANNER_SYMBOLS
+
+/*
+ * ctf-scanner-symbols.h
+ *
+ * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#define yy_create_buffer bt_yy_create_buffer
+#define yy_delete_buffer bt_yy_delete_buffer
+#define yy_flush_buffer bt_yy_flush_buffer
+#define yy_scan_buffer bt_yy_scan_buffer
+#define yy_scan_bytes bt_yy_scan_bytes
+#define yy_scan_string bt_yy_scan_string
+#define yy_switch_to_buffer bt_yy_switch_to_buffer
+#define yyalloc bt_yyalloc
+#define yyfree bt_yyfree
+#define yyget_column bt_yyget_column
+#define yyget_debug bt_yyget_debug
+#define yyget_extra bt_yyget_extra
+#define yyget_in bt_yyget_in
+#define yyget_leng bt_yyget_leng
+#define yyget_lineno bt_yyget_lineno
+#define yyget_lval bt_yyget_lval
+#define yyget_out bt_yyget_out
+#define yyget_text bt_yyget_text
+#define yylex_init bt_yylex_init
+#define yypop_buffer_state bt_yypop_buffer_state
+#define yypush_buffer_state bt_yypush_buffer_state
+#define yyrealloc bt_yyrealloc
+#define yyset_column bt_yyset_column
+#define yyset_debug bt_yyset_debug
+#define yyset_extra bt_yyset_extra
+#define yyset_in bt_yyset_in
+#define yyset_lineno bt_yyset_lineno
+#define yyset_lval bt_yyset_lval
+#define yyset_out bt_yyset_out
+
+#endif /* _CTF_SCANNER_SYMBOLS */
diff --git a/src/plugins/ctf/common/metadata/scanner.h b/src/plugins/ctf/common/metadata/scanner.h
new file mode 100644 (file)
index 0000000..34d6c46
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _CTF_SCANNER_H
+#define _CTF_SCANNER_H
+
+/*
+ * ctf-scanner.h
+ *
+ * Copyright 2011-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <stdio.h>
+#include "ast.h"
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+struct ctf_scanner_scope;
+struct ctf_scanner_scope {
+       struct ctf_scanner_scope *parent;
+       GHashTable *classes;
+};
+
+struct ctf_scanner {
+       yyscan_t scanner;
+       struct ctf_ast *ast;
+       struct ctf_scanner_scope root_scope;
+       struct ctf_scanner_scope *cs;
+       struct objstack *objstack;
+};
+
+struct ctf_scanner *ctf_scanner_alloc(void);
+void ctf_scanner_free(struct ctf_scanner *scanner);
+int ctf_scanner_append_ast(struct ctf_scanner *scanner, FILE *input);
+
+static inline
+struct ctf_ast *ctf_scanner_get_ast(struct ctf_scanner *scanner)
+{
+       return scanner->ast;
+}
+
+BT_HIDDEN
+int is_type(struct ctf_scanner *scanner, const char *id);
+
+#endif /* _CTF_SCANNER_H */
diff --git a/src/plugins/ctf/common/metadata/visitor-generate-ir.c b/src/plugins/ctf/common/metadata/visitor-generate-ir.c
new file mode 100644 (file)
index 0000000..d2f80d0
--- /dev/null
@@ -0,0 +1,5090 @@
+/*
+ * ctf-visitor-generate-ir.c
+ *
+ * Common Trace Format metadata visitor (generates CTF IR objects).
+ *
+ * Based on older ctf-visitor-generate-io-struct.c.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright 2015-2018 - Philippe Proulx <philippe.proulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-IR-VISITOR"
+#include "logging.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "common/assert.h"
+#include <glib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "common/common.h"
+#include "compat/uuid.h"
+#include "compat/endian.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+#include "decoder.h"
+#include "ctf-meta.h"
+#include "ctf-meta-visitors.h"
+
+/* Bit value (left shift) */
+#define _BV(_val)              (1 << (_val))
+
+/* Bit is set in a set of bits */
+#define _IS_SET(_set, _mask)   (*(_set) & (_mask))
+
+/* Set bit in a set of bits */
+#define _SET(_set, _mask)      (*(_set) |= (_mask))
+
+/* Try to push scope, or go to the `error` label */
+#define _TRY_PUSH_SCOPE_OR_GOTO_ERROR()                                        \
+       do {                                                            \
+               ret = ctx_push_scope(ctx);                              \
+               if (ret) {                                              \
+                       BT_LOGE_STR("Cannot push scope.");              \
+                       goto error;                                     \
+               }                                                       \
+       } while (0)
+
+/* Bits for verifying existing attributes in various declarations */
+enum {
+       _CLOCK_NAME_SET =               _BV(0),
+       _CLOCK_UUID_SET =               _BV(1),
+       _CLOCK_FREQ_SET =               _BV(2),
+       _CLOCK_PRECISION_SET =          _BV(3),
+       _CLOCK_OFFSET_S_SET =           _BV(4),
+       _CLOCK_OFFSET_SET =             _BV(5),
+       _CLOCK_ABSOLUTE_SET =           _BV(6),
+       _CLOCK_DESCRIPTION_SET =        _BV(7),
+};
+
+enum {
+       _INTEGER_ALIGN_SET =            _BV(0),
+       _INTEGER_SIZE_SET =             _BV(1),
+       _INTEGER_BASE_SET =             _BV(2),
+       _INTEGER_ENCODING_SET =         _BV(3),
+       _INTEGER_BYTE_ORDER_SET =       _BV(4),
+       _INTEGER_SIGNED_SET =           _BV(5),
+       _INTEGER_MAP_SET =              _BV(6),
+};
+
+enum {
+       _FLOAT_ALIGN_SET =              _BV(0),
+       _FLOAT_MANT_DIG_SET =           _BV(1),
+       _FLOAT_EXP_DIG_SET =            _BV(2),
+       _FLOAT_BYTE_ORDER_SET =         _BV(3),
+};
+
+enum {
+       _STRING_ENCODING_SET =          _BV(0),
+};
+
+enum {
+       _TRACE_MINOR_SET =              _BV(0),
+       _TRACE_MAJOR_SET =              _BV(1),
+       _TRACE_BYTE_ORDER_SET =         _BV(2),
+       _TRACE_UUID_SET =               _BV(3),
+       _TRACE_PACKET_HEADER_SET =      _BV(4),
+};
+
+enum {
+       _STREAM_ID_SET =                _BV(0),
+       _STREAM_PACKET_CONTEXT_SET =    _BV(1),
+       _STREAM_EVENT_HEADER_SET =      _BV(2),
+       _STREAM_EVENT_CONTEXT_SET =     _BV(3),
+};
+
+enum {
+       _EVENT_NAME_SET =               _BV(0),
+       _EVENT_ID_SET =                 _BV(1),
+       _EVENT_MODEL_EMF_URI_SET =      _BV(2),
+       _EVENT_STREAM_ID_SET =          _BV(3),
+       _EVENT_LOG_LEVEL_SET =          _BV(4),
+       _EVENT_CONTEXT_SET =            _BV(5),
+       _EVENT_FIELDS_SET =             _BV(6),
+};
+
+enum loglevel {
+        LOG_LEVEL_EMERG                  = 0,
+        LOG_LEVEL_ALERT                  = 1,
+        LOG_LEVEL_CRIT                   = 2,
+        LOG_LEVEL_ERR                    = 3,
+        LOG_LEVEL_WARNING                = 4,
+        LOG_LEVEL_NOTICE                 = 5,
+        LOG_LEVEL_INFO                   = 6,
+        LOG_LEVEL_DEBUG_SYSTEM           = 7,
+        LOG_LEVEL_DEBUG_PROGRAM          = 8,
+        LOG_LEVEL_DEBUG_PROCESS          = 9,
+        LOG_LEVEL_DEBUG_MODULE           = 10,
+        LOG_LEVEL_DEBUG_UNIT             = 11,
+        LOG_LEVEL_DEBUG_FUNCTION         = 12,
+        LOG_LEVEL_DEBUG_LINE             = 13,
+        LOG_LEVEL_DEBUG                  = 14,
+       _NR_LOGLEVELS                   = 15,
+};
+
+/* Prefixes of class aliases */
+#define _PREFIX_ALIAS                  'a'
+#define _PREFIX_ENUM                   'e'
+#define _PREFIX_STRUCT                 's'
+#define _PREFIX_VARIANT                        'v'
+
+/* First entry in a BT list */
+#define _BT_LIST_FIRST_ENTRY(_ptr, _class, _member)                    \
+       bt_list_entry((_ptr)->next, _class, _member)
+
+#define _BT_LOGE_DUP_ATTR(_node, _attr, _entity)                       \
+       _BT_LOGE_LINENO((_node)->lineno,                                \
+               "Duplicate attribute in %s: attr-name=\"%s\"",          \
+               _entity, _attr)
+
+#define _BT_LOGE_NODE(_node, _msg, args...)                            \
+       _BT_LOGE_LINENO((_node)->lineno, _msg, ## args)
+
+#define _BT_LOGW_NODE(_node, _msg, args...)                            \
+       _BT_LOGW_LINENO((_node)->lineno, _msg, ## args)
+
+#define _BT_LOGV_NODE(_node, _msg, args...)                            \
+       _BT_LOGV_LINENO((_node)->lineno, _msg, ## args)
+
+/*
+ * Declaration scope of a visitor context. This represents a TSDL
+ * lexical scope, so that aliases and named structures, variants,
+ * and enumerations may be registered and looked up hierarchically.
+ */
+struct ctx_decl_scope {
+       /*
+        * Alias name to field class.
+        *
+        * GQuark -> struct ctf_field_class * (owned by this)
+        */
+       GHashTable *decl_map;
+
+       /* Parent scope; NULL if this is the root declaration scope */
+       struct ctx_decl_scope *parent_scope;
+};
+
+/*
+ * Visitor context (private).
+ */
+struct ctx {
+       bt_self_component_source *self_comp;
+       /* Trace IR trace class being filled (owned by this) */
+       bt_trace_class *trace_class;
+
+       /* CTF meta trace being filled (owned by this) */
+       struct ctf_trace_class *ctf_tc;
+
+       /* Current declaration scope (top of the stack) (owned by this) */
+       struct ctx_decl_scope *current_scope;
+
+       /* True if trace declaration is visited */
+       bool is_trace_visited;
+
+       /* True if this is an LTTng trace */
+       bool is_lttng;
+
+       /* Config passed by the user */
+       struct ctf_metadata_decoder_config decoder_config;
+};
+
+/*
+ * Visitor (public).
+ */
+struct ctf_visitor_generate_ir;
+
+/**
+ * Creates a new declaration scope.
+ *
+ * @param par_scope    Parent scope (NULL if creating a root scope)
+ * @returns            New declaration scope, or NULL on error
+ */
+static
+struct ctx_decl_scope *ctx_decl_scope_create(struct ctx_decl_scope *par_scope)
+{
+       struct ctx_decl_scope *scope;
+
+       scope = g_new(struct ctx_decl_scope, 1);
+       if (!scope) {
+               BT_LOGE_STR("Failed to allocate one declaration scope.");
+               goto end;
+       }
+
+       scope->decl_map = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+               NULL, (GDestroyNotify) ctf_field_class_destroy);
+       scope->parent_scope = par_scope;
+
+end:
+       return scope;
+}
+
+/**
+ * Destroys a declaration scope.
+ *
+ * This function does not destroy the parent scope.
+ *
+ * @param scope        Scope to destroy
+ */
+static
+void ctx_decl_scope_destroy(struct ctx_decl_scope *scope)
+{
+       if (!scope) {
+               goto end;
+       }
+
+       g_hash_table_destroy(scope->decl_map);
+       g_free(scope);
+
+end:
+       return;
+}
+
+/**
+ * Returns the GQuark of a prefixed alias.
+ *
+ * @param prefix       Prefix character
+ * @param name         Name
+ * @returns            Associated GQuark, or 0 on error
+ */
+static
+GQuark get_prefixed_named_quark(char prefix, const char *name)
+{
+       GQuark qname = 0;
+
+       BT_ASSERT(name);
+
+       /* Prefix character + original string + '\0' */
+       char *prname = g_new(char, strlen(name) + 2);
+       if (!prname) {
+               BT_LOGE_STR("Failed to allocate a string.");
+               goto end;
+       }
+
+       sprintf(prname, "%c%s", prefix, name);
+       qname = g_quark_from_string(prname);
+       g_free(prname);
+
+end:
+       return qname;
+}
+
+/**
+ * Looks up a prefixed class alias within a declaration scope.
+ *
+ * @param scope                Declaration scope
+ * @param prefix       Prefix character
+ * @param name         Alias name
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
+ */
+static
+struct ctf_field_class *ctx_decl_scope_lookup_prefix_alias(
+               struct ctx_decl_scope *scope, char prefix, const char *name,
+               int levels, bool copy)
+{
+       GQuark qname = 0;
+       int cur_levels = 0;
+       struct ctf_field_class *decl = NULL;
+       struct ctx_decl_scope *cur_scope = scope;
+
+       BT_ASSERT(scope);
+       BT_ASSERT(name);
+       qname = get_prefixed_named_quark(prefix, name);
+       if (!qname) {
+               goto end;
+       }
+
+       if (levels < 0) {
+               levels = INT_MAX;
+       }
+
+       while (cur_scope && cur_levels < levels) {
+               decl = g_hash_table_lookup(cur_scope->decl_map,
+                       (gconstpointer) GUINT_TO_POINTER(qname));
+               if (decl) {
+                       /* Caller's reference */
+                       if (copy) {
+                               decl = ctf_field_class_copy(decl);
+                               BT_ASSERT(decl);
+                       }
+
+                       goto end;
+               }
+
+               cur_scope = cur_scope->parent_scope;
+               cur_levels++;
+       }
+
+end:
+       return decl;
+}
+
+/**
+ * Looks up a class alias within a declaration scope.
+ *
+ * @param scope                Declaration scope
+ * @param name         Alias name
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
+ */
+static
+struct ctf_field_class *ctx_decl_scope_lookup_alias(
+               struct ctx_decl_scope *scope, const char *name, int levels,
+               bool copy)
+{
+       return ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ALIAS,
+               name, levels, copy);
+}
+
+/**
+ * Looks up an enumeration within a declaration scope.
+ *
+ * @param scope                Declaration scope
+ * @param name         Enumeration name
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
+ */
+static
+struct ctf_field_class_enum *ctx_decl_scope_lookup_enum(
+               struct ctx_decl_scope *scope, const char *name, int levels,
+               bool copy)
+{
+       return (void *) ctx_decl_scope_lookup_prefix_alias(scope, _PREFIX_ENUM,
+               name, levels, copy);
+}
+
+/**
+ * Looks up a structure within a declaration scope.
+ *
+ * @param scope                Declaration scope
+ * @param name         Structure name
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
+ */
+static
+struct ctf_field_class_struct *ctx_decl_scope_lookup_struct(
+               struct ctx_decl_scope *scope, const char *name, int levels,
+               bool copy)
+{
+       return (void *) ctx_decl_scope_lookup_prefix_alias(scope,
+               _PREFIX_STRUCT, name, levels, copy);
+}
+
+/**
+ * Looks up a variant within a declaration scope.
+ *
+ * @param scope                Declaration scope
+ * @param name         Variant name
+ * @param levels       Number of levels to dig into (-1 means infinite)
+ * @param copy         True to return a copy
+ * @returns            Declaration (owned by caller if \p copy is true),
+ *                     or NULL if not found
+ */
+static
+struct ctf_field_class_variant *ctx_decl_scope_lookup_variant(
+               struct ctx_decl_scope *scope, const char *name, int levels,
+               bool copy)
+{
+       return (void *) ctx_decl_scope_lookup_prefix_alias(scope,
+               _PREFIX_VARIANT, name, levels, copy);
+}
+
+/**
+ * Registers a prefixed class alias within a declaration scope.
+ *
+ * @param scope                Declaration scope
+ * @param prefix       Prefix character
+ * @param name         Alias name (non-NULL)
+ * @param decl         Field class to register (copied)
+ * @returns            0 if registration went okay, negative value otherwise
+ */
+static
+int ctx_decl_scope_register_prefix_alias(struct ctx_decl_scope *scope,
+               char prefix, const char *name, struct ctf_field_class *decl)
+{
+       int ret = 0;
+       GQuark qname = 0;
+
+       BT_ASSERT(scope);
+       BT_ASSERT(name);
+       BT_ASSERT(decl);
+       qname = get_prefixed_named_quark(prefix, name);
+       if (!qname) {
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       /* Make sure alias does not exist in local scope */
+       if (ctx_decl_scope_lookup_prefix_alias(scope, prefix, name, 1,
+                       false)) {
+               ret = -EEXIST;
+               goto end;
+       }
+
+       decl = ctf_field_class_copy(decl);
+       BT_ASSERT(decl);
+       g_hash_table_insert(scope->decl_map, GUINT_TO_POINTER(qname), decl);
+
+end:
+       return ret;
+}
+
+/**
+ * Registers a class alias within a declaration scope.
+ *
+ * @param scope        Declaration scope
+ * @param name Alias name (non-NULL)
+ * @param decl Field class to register (copied)
+ * @returns    0 if registration went okay, negative value otherwise
+ */
+static
+int ctx_decl_scope_register_alias(struct ctx_decl_scope *scope,
+               const char *name, struct ctf_field_class *decl)
+{
+       return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ALIAS,
+               name, (void *) decl);
+}
+
+/**
+ * Registers an enumeration declaration within a declaration scope.
+ *
+ * @param scope        Declaration scope
+ * @param name Enumeration name (non-NULL)
+ * @param decl Enumeration field class to register (copied)
+ * @returns    0 if registration went okay, negative value otherwise
+ */
+static
+int ctx_decl_scope_register_enum(struct ctx_decl_scope *scope,
+               const char *name, struct ctf_field_class_enum *decl)
+{
+       return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_ENUM,
+               name, (void *) decl);
+}
+
+/**
+ * Registers a structure declaration within a declaration scope.
+ *
+ * @param scope        Declaration scope
+ * @param name Structure name (non-NULL)
+ * @param decl Structure field class to register (copied)
+ * @returns    0 if registration went okay, negative value otherwise
+ */
+static
+int ctx_decl_scope_register_struct(struct ctx_decl_scope *scope,
+               const char *name, struct ctf_field_class_struct *decl)
+{
+       return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_STRUCT,
+               name, (void *) decl);
+}
+
+/**
+ * Registers a variant declaration within a declaration scope.
+ *
+ * @param scope        Declaration scope
+ * @param name Variant name (non-NULL)
+ * @param decl Variant field class to register
+ * @returns    0 if registration went okay, negative value otherwise
+ */
+static
+int ctx_decl_scope_register_variant(struct ctx_decl_scope *scope,
+               const char *name, struct ctf_field_class_variant *decl)
+{
+       return ctx_decl_scope_register_prefix_alias(scope, _PREFIX_VARIANT,
+               name, (void *) decl);
+}
+
+/**
+ * Destroys a visitor context.
+ *
+ * @param ctx  Visitor context to destroy
+ */
+static
+void ctx_destroy(struct ctx *ctx)
+{
+       struct ctx_decl_scope *scope;
+
+       if (!ctx) {
+               goto end;
+       }
+
+       scope = ctx->current_scope;
+
+       /*
+        * Destroy all scopes, from current one to the root scope.
+        */
+       while (scope) {
+               struct ctx_decl_scope *parent_scope = scope->parent_scope;
+
+               ctx_decl_scope_destroy(scope);
+               scope = parent_scope;
+       }
+
+       bt_trace_class_put_ref(ctx->trace_class);
+
+       if (ctx->ctf_tc) {
+               ctf_trace_class_destroy(ctx->ctf_tc);
+       }
+
+       g_free(ctx);
+
+end:
+       return;
+}
+
+/**
+ * Creates a new visitor context.
+ *
+ * @param trace        Associated trace
+ * @returns    New visitor context, or NULL on error
+ */
+static
+struct ctx *ctx_create(bt_self_component_source *self_comp,
+               const struct ctf_metadata_decoder_config *decoder_config)
+{
+       struct ctx *ctx = NULL;
+
+       BT_ASSERT(decoder_config);
+
+       ctx = g_new0(struct ctx, 1);
+       if (!ctx) {
+               BT_LOGE_STR("Failed to allocate one visitor context.");
+               goto error;
+       }
+
+       if (self_comp) {
+               ctx->trace_class = bt_trace_class_create(
+                       bt_self_component_source_as_self_component(self_comp));
+               if (!ctx->trace_class) {
+                       BT_LOGE_STR("Cannot create empty trace class.");
+                       goto error;
+               }
+               ctx->self_comp = self_comp;
+       }
+
+       ctx->ctf_tc = ctf_trace_class_create();
+       if (!ctx->ctf_tc) {
+               BT_LOGE_STR("Cannot create CTF trace class.");
+               goto error;
+       }
+
+       /* Root declaration scope */
+       ctx->current_scope = ctx_decl_scope_create(NULL);
+       if (!ctx->current_scope) {
+               BT_LOGE_STR("Cannot create declaration scope.");
+               goto error;
+       }
+
+       ctx->decoder_config = *decoder_config;
+       goto end;
+
+error:
+       ctx_destroy(ctx);
+       ctx = NULL;
+
+end:
+       return ctx;
+}
+
+/**
+ * Pushes a new declaration scope on top of a visitor context's
+ * declaration scope stack.
+ *
+ * @param ctx  Visitor context
+ * @returns    0 on success, or a negative value on error
+ */
+static
+int ctx_push_scope(struct ctx *ctx)
+{
+       int ret = 0;
+       struct ctx_decl_scope *new_scope;
+
+       BT_ASSERT(ctx);
+       new_scope = ctx_decl_scope_create(ctx->current_scope);
+       if (!new_scope) {
+               BT_LOGE_STR("Cannot create declaration scope.");
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       ctx->current_scope = new_scope;
+
+end:
+       return ret;
+}
+
+static
+void ctx_pop_scope(struct ctx *ctx)
+{
+       struct ctx_decl_scope *parent_scope = NULL;
+
+       BT_ASSERT(ctx);
+
+       if (!ctx->current_scope) {
+               goto end;
+       }
+
+       parent_scope = ctx->current_scope->parent_scope;
+       ctx_decl_scope_destroy(ctx->current_scope);
+       ctx->current_scope = parent_scope;
+
+end:
+       return;
+}
+
+static
+int visit_field_class_specifier_list(struct ctx *ctx, struct ctf_node *ts_list,
+               struct ctf_field_class **decl);
+
+static
+char *remove_underscores_from_field_ref(const char *field_ref)
+{
+       const char *in_ch;
+       char *out_ch;
+       char *ret;
+       enum {
+               UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE,
+               UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE,
+       } state = UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE;
+
+       BT_ASSERT(field_ref);
+       ret = calloc(strlen(field_ref) + 1, 1);
+       if (!ret) {
+               BT_LOGE("Failed to allocate a string: size=%zu",
+                       strlen(field_ref) + 1);
+               goto end;
+       }
+
+       in_ch = field_ref;
+       out_ch = ret;
+
+       while (*in_ch != '\0') {
+               switch (*in_ch) {
+               case ' ':
+               case '\t':
+                       /* Remove whitespace */
+                       in_ch++;
+                       continue;
+               case '_':
+                       if (state == UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE) {
+                               in_ch++;
+                               state = UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE;
+                               continue;
+                       }
+
+                       goto copy;
+               case '.':
+                       state = UNDERSCORE_REMOVE_STATE_REMOVE_NEXT_UNDERSCORE;
+                       goto copy;
+               default:
+                       state = UNDERSCORE_REMOVE_STATE_DO_NOT_REMOVE_NEXT_UNDERSCORE;
+                       goto copy;
+               }
+
+copy:
+               *out_ch = *in_ch;
+               in_ch++;
+               out_ch++;
+       }
+
+end:
+       return ret;
+}
+
+static
+int is_unary_string(struct bt_list_head *head)
+{
+       int ret = TRUE;
+       struct ctf_node *node;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               if (node->type != NODE_UNARY_EXPRESSION) {
+                       ret = FALSE;
+               }
+
+               if (node->u.unary_expression.type != UNARY_STRING) {
+                       ret = FALSE;
+               }
+       }
+
+       return ret;
+}
+
+static
+char *concatenate_unary_strings(struct bt_list_head *head)
+{
+       int i = 0;
+       GString *str;
+       struct ctf_node *node;
+
+       str = g_string_new(NULL);
+       BT_ASSERT(str);
+
+       bt_list_for_each_entry(node, head, siblings) {
+               char *src_string;
+
+               if (
+                       node->type != NODE_UNARY_EXPRESSION ||
+                       node->u.unary_expression.type != UNARY_STRING ||
+                       !(
+                               (
+                                       node->u.unary_expression.link !=
+                                       UNARY_LINK_UNKNOWN
+                               ) ^ (i == 0)
+                       )
+               ) {
+                       goto error;
+               }
+
+               switch (node->u.unary_expression.link) {
+               case UNARY_DOTLINK:
+                       g_string_append(str, ".");
+                       break;
+               case UNARY_ARROWLINK:
+                       g_string_append(str, "->");
+                       break;
+               case UNARY_DOTDOTDOT:
+                       g_string_append(str, "...");
+                       break;
+               default:
+                       break;
+               }
+
+               src_string = node->u.unary_expression.u.string;
+               g_string_append(str, src_string);
+               i++;
+       }
+
+       /* Destroys the container, returns the underlying string */
+       return g_string_free(str, FALSE);
+
+error:
+       /* This always returns NULL */
+       return g_string_free(str, TRUE);
+}
+
+static
+const char *get_map_clock_name_value(struct bt_list_head *head)
+{
+       int i = 0;
+       struct ctf_node *node;
+       const char *name = NULL;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               char *src_string;
+               int uexpr_type = node->u.unary_expression.type;
+               int uexpr_link = node->u.unary_expression.link;
+               int cond = node->type != NODE_UNARY_EXPRESSION ||
+                       uexpr_type != UNARY_STRING ||
+                       !((uexpr_link != UNARY_LINK_UNKNOWN) ^ (i == 0));
+               if (cond) {
+                       goto error;
+               }
+
+               /* Needs to be chained with . */
+               switch (node->u.unary_expression.link) {
+               case UNARY_DOTLINK:
+                       break;
+               case UNARY_ARROWLINK:
+               case UNARY_DOTDOTDOT:
+                       goto error;
+               default:
+                       break;
+               }
+
+               src_string = node->u.unary_expression.u.string;
+
+               switch (i) {
+               case 0:
+                       if (strcmp("clock", src_string)) {
+                               goto error;
+                       }
+                       break;
+               case 1:
+                       name = src_string;
+                       break;
+               case 2:
+                       if (strcmp("value", src_string)) {
+                               goto error;
+                       }
+                       break;
+               default:
+                       /* Extra identifier, unknown */
+                       goto error;
+               }
+
+               i++;
+       }
+
+       return name;
+
+error:
+       return NULL;
+}
+
+static
+int is_unary_unsigned(struct bt_list_head *head)
+{
+       int ret = TRUE;
+       struct ctf_node *node;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               if (node->type != NODE_UNARY_EXPRESSION) {
+                       ret = FALSE;
+               }
+
+               if (node->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT) {
+                       ret = FALSE;
+               }
+       }
+
+       return ret;
+}
+
+static
+int get_unary_unsigned(struct bt_list_head *head, uint64_t *value)
+{
+       int i = 0;
+       int ret = 0;
+       struct ctf_node *node;
+
+       *value = 0;
+
+       if (bt_list_empty(head)) {
+               ret = -1;
+               goto end;
+       }
+
+       bt_list_for_each_entry(node, head, siblings) {
+               int uexpr_type = node->u.unary_expression.type;
+               int uexpr_link = node->u.unary_expression.link;
+               int cond = node->type != NODE_UNARY_EXPRESSION ||
+                       uexpr_type != UNARY_UNSIGNED_CONSTANT ||
+                       uexpr_link != UNARY_LINK_UNKNOWN || i != 0;
+               if (cond) {
+                       _BT_LOGE_NODE(node, "Invalid constant unsigned integer.");
+                       ret = -EINVAL;
+                       goto end;
+               }
+
+               *value = node->u.unary_expression.u.unsigned_constant;
+               i++;
+       }
+
+end:
+       return ret;
+}
+
+static
+int is_unary_signed(struct bt_list_head *head)
+{
+       int ret = TRUE;
+       struct ctf_node *node;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               if (node->type != NODE_UNARY_EXPRESSION) {
+                       ret = FALSE;
+               }
+
+               if (node->u.unary_expression.type != UNARY_SIGNED_CONSTANT) {
+                       ret = FALSE;
+               }
+       }
+
+       return ret;
+}
+
+static
+int get_unary_signed(struct bt_list_head *head, int64_t *value)
+{
+       int i = 0;
+       int ret = 0;
+       struct ctf_node *node;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               int uexpr_type = node->u.unary_expression.type;
+               int uexpr_link = node->u.unary_expression.link;
+               int cond = node->type != NODE_UNARY_EXPRESSION ||
+                       (uexpr_type != UNARY_UNSIGNED_CONSTANT &&
+                               uexpr_type != UNARY_SIGNED_CONSTANT) ||
+                       uexpr_link != UNARY_LINK_UNKNOWN || i != 0;
+               if (cond) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+
+               switch (uexpr_type) {
+               case UNARY_UNSIGNED_CONSTANT:
+                       *value = (int64_t)
+                               node->u.unary_expression.u.unsigned_constant;
+                       break;
+               case UNARY_SIGNED_CONSTANT:
+                       *value = node->u.unary_expression.u.signed_constant;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto end;
+               }
+
+               i++;
+       }
+
+end:
+       return ret;
+}
+
+static
+int get_unary_uuid(struct bt_list_head *head, unsigned char *uuid)
+{
+       int i = 0;
+       int ret = 0;
+       struct ctf_node *node;
+
+       bt_list_for_each_entry(node, head, siblings) {
+               int uexpr_type = node->u.unary_expression.type;
+               int uexpr_link = node->u.unary_expression.link;
+               const char *src_string;
+
+               if (node->type != NODE_UNARY_EXPRESSION ||
+                               uexpr_type != UNARY_STRING ||
+                               uexpr_link != UNARY_LINK_UNKNOWN ||
+                               i != 0) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+
+               src_string = node->u.unary_expression.u.string;
+               ret = bt_uuid_parse(src_string, uuid);
+               if (ret) {
+                       _BT_LOGE_NODE(node,
+                               "Cannot parse UUID: uuid=\"%s\"", src_string);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int get_boolean(struct ctf_node *unary_expr)
+{
+       int ret = 0;
+
+       if (unary_expr->type != NODE_UNARY_EXPRESSION) {
+               _BT_LOGE_NODE(unary_expr,
+                       "Expecting unary expression: node-type=%d",
+                       unary_expr->type);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       switch (unary_expr->u.unary_expression.type) {
+       case UNARY_UNSIGNED_CONSTANT:
+               ret = (unary_expr->u.unary_expression.u.unsigned_constant != 0);
+               break;
+       case UNARY_SIGNED_CONSTANT:
+               ret = (unary_expr->u.unary_expression.u.signed_constant != 0);
+               break;
+       case UNARY_STRING:
+       {
+               const char *str = unary_expr->u.unary_expression.u.string;
+
+               if (!strcmp(str, "true") || !strcmp(str, "TRUE")) {
+                       ret = TRUE;
+               } else if (!strcmp(str, "false") || !strcmp(str, "FALSE")) {
+                       ret = FALSE;
+               } else {
+                       _BT_LOGE_NODE(unary_expr,
+                               "Unexpected boolean value: value=\"%s\"", str);
+                       ret = -EINVAL;
+                       goto end;
+               }
+               break;
+       }
+       default:
+               _BT_LOGE_NODE(unary_expr,
+                       "Unexpected unary expression type: node-type=%d",
+                       unary_expr->u.unary_expression.type);
+               ret = -EINVAL;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+enum ctf_byte_order byte_order_from_unary_expr(struct ctf_node *unary_expr)
+{
+       const char *str;
+       enum ctf_byte_order bo = -1;
+
+       if (unary_expr->u.unary_expression.type != UNARY_STRING) {
+               _BT_LOGE_NODE(unary_expr,
+                       "\"byte_order\" attribute: expecting `be`, `le`, `network`, or `native`.");
+               goto end;
+       }
+
+       str = unary_expr->u.unary_expression.u.string;
+
+       if (!strcmp(str, "be") || !strcmp(str, "network")) {
+               bo = CTF_BYTE_ORDER_BIG;
+       } else if (!strcmp(str, "le")) {
+               bo = CTF_BYTE_ORDER_LITTLE;
+       } else if (!strcmp(str, "native")) {
+               bo = CTF_BYTE_ORDER_DEFAULT;
+       } else {
+               _BT_LOGE_NODE(unary_expr,
+                       "Unexpected \"byte_order\" attribute value: "
+                       "expecting `be`, `le`, `network`, or `native`: value=\"%s\"",
+                       str);
+               goto end;
+       }
+
+end:
+       return bo;
+}
+
+static
+enum ctf_byte_order get_real_byte_order(struct ctx *ctx,
+               struct ctf_node *uexpr)
+{
+       enum ctf_byte_order bo = byte_order_from_unary_expr(uexpr);
+
+       if (bo == CTF_BYTE_ORDER_DEFAULT) {
+               bo = ctx->ctf_tc->default_byte_order;
+       }
+
+       return bo;
+}
+
+static
+int is_align_valid(uint64_t align)
+{
+       return (align != 0) && !(align & (align - UINT64_C(1)));
+}
+
+static
+int get_class_specifier_name(struct ctx *ctx, struct ctf_node *cls_specifier,
+               GString *str)
+{
+       int ret = 0;
+
+       if (cls_specifier->type != NODE_TYPE_SPECIFIER) {
+               _BT_LOGE_NODE(cls_specifier,
+                       "Unexpected node type: node-type=%d",
+                       cls_specifier->type);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       switch (cls_specifier->u.field_class_specifier.type) {
+       case TYPESPEC_VOID:
+               g_string_append(str, "void");
+               break;
+       case TYPESPEC_CHAR:
+               g_string_append(str, "char");
+               break;
+       case TYPESPEC_SHORT:
+               g_string_append(str, "short");
+               break;
+       case TYPESPEC_INT:
+               g_string_append(str, "int");
+               break;
+       case TYPESPEC_LONG:
+               g_string_append(str, "long");
+               break;
+       case TYPESPEC_FLOAT:
+               g_string_append(str, "float");
+               break;
+       case TYPESPEC_DOUBLE:
+               g_string_append(str, "double");
+               break;
+       case TYPESPEC_SIGNED:
+               g_string_append(str, "signed");
+               break;
+       case TYPESPEC_UNSIGNED:
+               g_string_append(str, "unsigned");
+               break;
+       case TYPESPEC_BOOL:
+               g_string_append(str, "bool");
+               break;
+       case TYPESPEC_COMPLEX:
+               g_string_append(str, "_Complex");
+               break;
+       case TYPESPEC_IMAGINARY:
+               g_string_append(str, "_Imaginary");
+               break;
+       case TYPESPEC_CONST:
+               g_string_append(str, "const");
+               break;
+       case TYPESPEC_ID_TYPE:
+               if (cls_specifier->u.field_class_specifier.id_type) {
+                       g_string_append(str,
+                               cls_specifier->u.field_class_specifier.id_type);
+               }
+               break;
+       case TYPESPEC_STRUCT:
+       {
+               struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
+
+               if (!node->u._struct.name) {
+                       _BT_LOGE_NODE(node, "Unexpected empty structure field class name.");
+                       ret = -EINVAL;
+                       goto end;
+               }
+
+               g_string_append(str, "struct ");
+               g_string_append(str, node->u._struct.name);
+               break;
+       }
+       case TYPESPEC_VARIANT:
+       {
+               struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
+
+               if (!node->u.variant.name) {
+                       _BT_LOGE_NODE(node, "Unexpected empty variant field class name.");
+                       ret = -EINVAL;
+                       goto end;
+               }
+
+               g_string_append(str, "variant ");
+               g_string_append(str, node->u.variant.name);
+               break;
+       }
+       case TYPESPEC_ENUM:
+       {
+               struct ctf_node *node = cls_specifier->u.field_class_specifier.node;
+
+               if (!node->u._enum.enum_id) {
+                       _BT_LOGE_NODE(node,
+                               "Unexpected empty enumeration field class (`enum`) name.");
+                       ret = -EINVAL;
+                       goto end;
+               }
+
+               g_string_append(str, "enum ");
+               g_string_append(str, node->u._enum.enum_id);
+               break;
+       }
+       case TYPESPEC_FLOATING_POINT:
+       case TYPESPEC_INTEGER:
+       case TYPESPEC_STRING:
+       default:
+               _BT_LOGE_NODE(cls_specifier->u.field_class_specifier.node,
+                       "Unexpected field class specifier type: %d",
+                       cls_specifier->u.field_class_specifier.type);
+               ret = -EINVAL;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int get_class_specifier_list_name(struct ctx *ctx,
+               struct ctf_node *cls_specifier_list, GString *str)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+       int alias_item_nr = 0;
+       struct bt_list_head *head =
+               &cls_specifier_list->u.field_class_specifier_list.head;
+
+       bt_list_for_each_entry(iter, head, siblings) {
+               if (alias_item_nr != 0) {
+                       g_string_append(str, " ");
+               }
+
+               alias_item_nr++;
+               ret = get_class_specifier_name(ctx, iter, str);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+GQuark create_class_alias_identifier(struct ctx *ctx,
+               struct ctf_node *cls_specifier_list,
+               struct ctf_node *node_field_class_declarator)
+{
+       int ret;
+       char *str_c;
+       GString *str;
+       GQuark qalias = 0;
+       struct ctf_node *iter;
+       struct bt_list_head *pointers =
+               &node_field_class_declarator->u.field_class_declarator.pointers;
+
+       str = g_string_new("");
+       ret = get_class_specifier_list_name(ctx, cls_specifier_list, str);
+       if (ret) {
+               g_string_free(str, TRUE);
+               goto end;
+       }
+
+       bt_list_for_each_entry(iter, pointers, siblings) {
+               g_string_append(str, " *");
+
+               if (iter->u.pointer.const_qualifier) {
+                       g_string_append(str, " const");
+               }
+       }
+
+       str_c = g_string_free(str, FALSE);
+       qalias = g_quark_from_string(str_c);
+       g_free(str_c);
+
+end:
+       return qalias;
+}
+
+static
+int visit_field_class_declarator(struct ctx *ctx,
+               struct ctf_node *cls_specifier_list,
+               GQuark *field_name, struct ctf_node *node_field_class_declarator,
+               struct ctf_field_class **field_decl,
+               struct ctf_field_class *nested_decl)
+{
+       /*
+        * During this whole function, nested_decl is always OURS,
+        * whereas field_decl is an output which we create, but
+        * belongs to the caller (it is moved).
+        */
+       int ret = 0;
+       *field_decl = NULL;
+
+       /* Validate field class declarator node */
+       if (node_field_class_declarator) {
+               if (node_field_class_declarator->u.field_class_declarator.type ==
+                               TYPEDEC_UNKNOWN) {
+                       _BT_LOGE_NODE(node_field_class_declarator,
+                               "Unexpected field class declarator type: type=%d",
+                               node_field_class_declarator->u.field_class_declarator.type);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               /* TODO: GCC bitfields not supported yet */
+               if (node_field_class_declarator->u.field_class_declarator.bitfield_len !=
+                               NULL) {
+                       _BT_LOGE_NODE(node_field_class_declarator,
+                               "GCC bitfields are not supported as of this version.");
+                       ret = -EPERM;
+                       goto error;
+               }
+       }
+
+       /* Find the right nested declaration if not provided */
+       if (!nested_decl) {
+               struct bt_list_head *pointers =
+                       &node_field_class_declarator->u.field_class_declarator.pointers;
+
+               if (node_field_class_declarator && !bt_list_empty(pointers)) {
+                       GQuark qalias;
+
+                       /*
+                        * If we have a pointer declarator, it HAS to
+                        * be present in the field class aliases (else
+                        * fail).
+                        */
+                       qalias = create_class_alias_identifier(ctx,
+                               cls_specifier_list, node_field_class_declarator);
+                       nested_decl =
+                               ctx_decl_scope_lookup_alias(ctx->current_scope,
+                                       g_quark_to_string(qalias), -1, true);
+                       if (!nested_decl) {
+                               _BT_LOGE_NODE(node_field_class_declarator,
+                                       "Cannot find class alias: name=\"%s\"",
+                                       g_quark_to_string(qalias));
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (nested_decl->type == CTF_FIELD_CLASS_TYPE_INT) {
+                               /* Pointer: force integer's base to 16 */
+                               struct ctf_field_class_int *int_fc =
+                                       (void *) nested_decl;
+
+                               int_fc->disp_base =
+                                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
+                       }
+               } else {
+                       ret = visit_field_class_specifier_list(ctx,
+                               cls_specifier_list, &nested_decl);
+                       if (ret) {
+                               BT_ASSERT(!nested_decl);
+                               goto error;
+                       }
+               }
+       }
+
+       BT_ASSERT(nested_decl);
+
+       if (!node_field_class_declarator) {
+               *field_decl = nested_decl;
+               nested_decl = NULL;
+               goto end;
+       }
+
+       if (node_field_class_declarator->u.field_class_declarator.type == TYPEDEC_ID) {
+               if (node_field_class_declarator->u.field_class_declarator.u.id) {
+                       const char *id =
+                               node_field_class_declarator->u.field_class_declarator.u.id;
+
+                       if (id[0] == '_') {
+                               id++;
+                       }
+
+                       *field_name = g_quark_from_string(id);
+               } else {
+                       *field_name = 0;
+               }
+
+               *field_decl = nested_decl;
+               nested_decl = NULL;
+               goto end;
+       } else {
+               struct ctf_node *first;
+               struct ctf_field_class *decl = NULL;
+               struct ctf_field_class *outer_field_decl = NULL;
+               struct bt_list_head *length =
+                       &node_field_class_declarator->
+                               u.field_class_declarator.u.nested.length;
+
+               /* Create array/sequence, pass nested_decl as child */
+               if (bt_list_empty(length)) {
+                       _BT_LOGE_NODE(node_field_class_declarator,
+                               "Expecting length field reference or value.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               first = _BT_LIST_FIRST_ENTRY(length, struct ctf_node, siblings);
+               if (first->type != NODE_UNARY_EXPRESSION) {
+                       _BT_LOGE_NODE(first,
+                               "Unexpected node type: node-type=%d",
+                               first->type);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               switch (first->u.unary_expression.type) {
+               case UNARY_UNSIGNED_CONSTANT:
+               {
+                       struct ctf_field_class_array *array_decl = NULL;
+
+                       array_decl = ctf_field_class_array_create();
+                       BT_ASSERT(array_decl);
+                       array_decl->length =
+                               first->u.unary_expression.u.unsigned_constant;
+                       array_decl->base.elem_fc = nested_decl;
+                       nested_decl = NULL;
+                       decl = (void *) array_decl;
+                       break;
+               }
+               case UNARY_STRING:
+               {
+                       /* Lookup unsigned integer definition, create seq. */
+                       struct ctf_field_class_sequence *seq_decl = NULL;
+                       char *length_name = concatenate_unary_strings(length);
+
+                       if (!length_name) {
+                               _BT_LOGE_NODE(node_field_class_declarator,
+                                       "Cannot concatenate unary strings.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (strncmp(length_name, "env.", 4) == 0) {
+                               /* This is, in fact, an array */
+                               const char *env_entry_name = &length_name[4];
+                               struct ctf_trace_class_env_entry *env_entry =
+                                       ctf_trace_class_borrow_env_entry_by_name(
+                                               ctx->ctf_tc, env_entry_name);
+                               struct ctf_field_class_array *array_decl;
+
+                               if (!env_entry) {
+                                       _BT_LOGE_NODE(node_field_class_declarator,
+                                               "Cannot find environment entry: "
+                                               "name=\"%s\"", env_entry_name);
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               if (env_entry->type != CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT) {
+                                       _BT_LOGE_NODE(node_field_class_declarator,
+                                               "Wrong environment entry type "
+                                               "(expecting integer): "
+                                               "name=\"%s\"", env_entry_name);
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               if (env_entry->value.i < 0) {
+                                       _BT_LOGE_NODE(node_field_class_declarator,
+                                               "Invalid, negative array length: "
+                                               "env-entry-name=\"%s\", "
+                                               "value=%" PRId64,
+                                               env_entry_name,
+                                               env_entry->value.i);
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               array_decl = ctf_field_class_array_create();
+                               BT_ASSERT(array_decl);
+                               array_decl->length =
+                                       (uint64_t) env_entry->value.i;
+                               array_decl->base.elem_fc = nested_decl;
+                               nested_decl = NULL;
+                               decl = (void *) array_decl;
+                       } else {
+                               char *length_name_no_underscore =
+                                       remove_underscores_from_field_ref(
+                                               length_name);
+                               if (!length_name_no_underscore) {
+                                       /*
+                                        * remove_underscores_from_field_ref()
+                                        * logs errors
+                                        */
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+                               seq_decl = ctf_field_class_sequence_create();
+                               BT_ASSERT(seq_decl);
+                               seq_decl->base.elem_fc = nested_decl;
+                               nested_decl = NULL;
+                               g_string_assign(seq_decl->length_ref,
+                                       length_name_no_underscore);
+                               free(length_name_no_underscore);
+                               decl = (void *) seq_decl;
+                       }
+
+                       g_free(length_name);
+                       break;
+               }
+               default:
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               BT_ASSERT(!nested_decl);
+               BT_ASSERT(decl);
+               BT_ASSERT(!*field_decl);
+
+               /*
+                * At this point, we found the next nested declaration.
+                * We currently own this (and lost the ownership of
+                * nested_decl in the meantime). Pass this next
+                * nested declaration as the content of the outer
+                * container, MOVING its ownership.
+                */
+               ret = visit_field_class_declarator(ctx, cls_specifier_list,
+                       field_name,
+                       node_field_class_declarator->
+                               u.field_class_declarator.u.nested.field_class_declarator,
+                       &outer_field_decl, decl);
+               decl = NULL;
+               if (ret) {
+                       BT_ASSERT(!outer_field_decl);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               BT_ASSERT(outer_field_decl);
+               *field_decl = outer_field_decl;
+               outer_field_decl = NULL;
+       }
+
+       BT_ASSERT(*field_decl);
+       goto end;
+
+error:
+       ctf_field_class_destroy(*field_decl);
+       *field_decl = NULL;
+
+       if (ret >= 0) {
+               ret = -1;
+       }
+
+end:
+       ctf_field_class_destroy(nested_decl);
+       nested_decl = NULL;
+       return ret;
+}
+
+static
+int visit_struct_decl_field(struct ctx *ctx,
+               struct ctf_field_class_struct *struct_decl,
+               struct ctf_node *cls_specifier_list,
+               struct bt_list_head *field_class_declarators)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+       struct ctf_field_class *field_decl = NULL;
+
+       bt_list_for_each_entry(iter, field_class_declarators, siblings) {
+               field_decl = NULL;
+               GQuark qfield_name;
+               const char *field_name;
+
+               ret = visit_field_class_declarator(ctx, cls_specifier_list,
+                       &qfield_name, iter, &field_decl, NULL);
+               if (ret) {
+                       BT_ASSERT(!field_decl);
+                       _BT_LOGE_NODE(cls_specifier_list,
+                               "Cannot visit field class declarator: ret=%d", ret);
+                       goto error;
+               }
+
+               BT_ASSERT(field_decl);
+               field_name = g_quark_to_string(qfield_name);
+
+               /* Check if field with same name already exists */
+               if (ctf_field_class_struct_borrow_member_by_name(
+                               struct_decl, field_name)) {
+                       _BT_LOGE_NODE(cls_specifier_list,
+                               "Duplicate field in structure field class: "
+                               "field-name=\"%s\"", field_name);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               /* Add field to structure */
+               ctf_field_class_struct_append_member(struct_decl,
+                       field_name, field_decl);
+               field_decl = NULL;
+       }
+
+       return 0;
+
+error:
+       ctf_field_class_destroy(field_decl);
+       field_decl = NULL;
+       return ret;
+}
+
+static
+int visit_variant_decl_field(struct ctx *ctx,
+               struct ctf_field_class_variant *variant_decl,
+               struct ctf_node *cls_specifier_list,
+               struct bt_list_head *field_class_declarators)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+       struct ctf_field_class *field_decl = NULL;
+
+       bt_list_for_each_entry(iter, field_class_declarators, siblings) {
+               field_decl = NULL;
+               GQuark qfield_name;
+               const char *field_name;
+
+               ret = visit_field_class_declarator(ctx, cls_specifier_list,
+                       &qfield_name, iter, &field_decl, NULL);
+               if (ret) {
+                       BT_ASSERT(!field_decl);
+                       _BT_LOGE_NODE(cls_specifier_list,
+                               "Cannot visit field class declarator: ret=%d", ret);
+                       goto error;
+               }
+
+               BT_ASSERT(field_decl);
+               field_name = g_quark_to_string(qfield_name);
+
+               /* Check if field with same name already exists */
+               if (ctf_field_class_variant_borrow_option_by_name(
+                               variant_decl, field_name)) {
+                       _BT_LOGE_NODE(cls_specifier_list,
+                               "Duplicate field in variant field class: "
+                               "field-name=\"%s\"", field_name);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               /* Add field to structure */
+               ctf_field_class_variant_append_option(variant_decl,
+                       field_name, field_decl);
+               field_decl = NULL;
+       }
+
+       return 0;
+
+error:
+       ctf_field_class_destroy(field_decl);
+       field_decl = NULL;
+       return ret;
+}
+
+static
+int visit_field_class_def(struct ctx *ctx, struct ctf_node *cls_specifier_list,
+               struct bt_list_head *field_class_declarators)
+{
+       int ret = 0;
+       GQuark qidentifier;
+       struct ctf_node *iter;
+       struct ctf_field_class *class_decl = NULL;
+
+       bt_list_for_each_entry(iter, field_class_declarators, siblings) {
+               ret = visit_field_class_declarator(ctx, cls_specifier_list,
+                       &qidentifier, iter, &class_decl, NULL);
+               if (ret) {
+                       _BT_LOGE_NODE(iter,
+                               "Cannot visit field class declarator: ret=%d", ret);
+                       ret = -EINVAL;
+                       goto end;
+               }
+
+               /* Do not allow field class def and alias of untagged variants */
+               if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
+                       struct ctf_field_class_variant *var_fc =
+                               (void *) class_decl;
+
+                       if (var_fc->tag_path.path->len == 0) {
+                               _BT_LOGE_NODE(iter,
+                                       "Type definition of untagged variant field class is not allowed.");
+                               ret = -EPERM;
+                               goto end;
+                       }
+               }
+
+               ret = ctx_decl_scope_register_alias(ctx->current_scope,
+                       g_quark_to_string(qidentifier), class_decl);
+               if (ret) {
+                       _BT_LOGE_NODE(iter,
+                               "Cannot register field class alias: name=\"%s\"",
+                               g_quark_to_string(qidentifier));
+                       goto end;
+               }
+       }
+
+end:
+       ctf_field_class_destroy(class_decl);
+       class_decl = NULL;
+       return ret;
+}
+
+static
+int visit_field_class_alias(struct ctx *ctx, struct ctf_node *target,
+               struct ctf_node *alias)
+{
+       int ret = 0;
+       GQuark qalias;
+       struct ctf_node *node;
+       GQuark qdummy_field_name;
+       struct ctf_field_class *class_decl = NULL;
+
+       /* Create target field class */
+       if (bt_list_empty(&target->u.field_class_alias_target.field_class_declarators)) {
+               node = NULL;
+       } else {
+               node = _BT_LIST_FIRST_ENTRY(
+                       &target->u.field_class_alias_target.field_class_declarators,
+                       struct ctf_node, siblings);
+       }
+
+       ret = visit_field_class_declarator(ctx,
+               target->u.field_class_alias_target.field_class_specifier_list,
+               &qdummy_field_name, node, &class_decl, NULL);
+       if (ret) {
+               BT_ASSERT(!class_decl);
+               _BT_LOGE_NODE(node,
+                       "Cannot visit field class declarator: ret=%d", ret);
+               goto end;
+       }
+
+       /* Do not allow field class def and alias of untagged variants */
+       if (class_decl->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
+               struct ctf_field_class_variant *var_fc = (void *) class_decl;
+
+               if (var_fc->tag_path.path->len == 0) {
+                       _BT_LOGE_NODE(target,
+                               "Type definition of untagged variant field class is not allowed.");
+                       ret = -EPERM;
+                       goto end;
+               }
+       }
+
+       /*
+        * The semantic validator does not check whether the target is
+        * abstract or not (if it has an identifier). Check it here.
+        */
+       if (qdummy_field_name != 0) {
+               _BT_LOGE_NODE(target,
+                       "Expecting empty identifier: id=\"%s\"",
+                       g_quark_to_string(qdummy_field_name));
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Create alias identifier */
+       node = _BT_LIST_FIRST_ENTRY(&alias->u.field_class_alias_name.field_class_declarators,
+               struct ctf_node, siblings);
+       qalias = create_class_alias_identifier(ctx,
+               alias->u.field_class_alias_name.field_class_specifier_list, node);
+       ret = ctx_decl_scope_register_alias(ctx->current_scope,
+               g_quark_to_string(qalias), class_decl);
+       if (ret) {
+               _BT_LOGE_NODE(node,
+                       "Cannot register class alias: name=\"%s\"",
+                       g_quark_to_string(qalias));
+               goto end;
+       }
+
+end:
+       ctf_field_class_destroy(class_decl);
+       class_decl = NULL;
+       return ret;
+}
+
+static
+int visit_struct_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
+               struct ctf_field_class_struct *struct_decl)
+{
+       int ret = 0;
+
+       switch (entry_node->type) {
+       case NODE_TYPEDEF:
+               ret = visit_field_class_def(ctx,
+                       entry_node->u.field_class_def.field_class_specifier_list,
+                       &entry_node->u.field_class_def.field_class_declarators);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Cannot add field class found in structure field class: ret=%d",
+                               ret);
+                       goto end;
+               }
+               break;
+       case NODE_TYPEALIAS:
+               ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target,
+                       entry_node->u.field_class_alias.alias);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Cannot add field class alias found in structure field class: ret=%d",
+                               ret);
+                       goto end;
+               }
+               break;
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               /* Field */
+               ret = visit_struct_decl_field(ctx, struct_decl,
+                       entry_node->u.struct_or_variant_declaration.
+                               field_class_specifier_list,
+                       &entry_node->u.struct_or_variant_declaration.
+                               field_class_declarators);
+               if (ret) {
+                       goto end;
+               }
+               break;
+       default:
+               _BT_LOGE_NODE(entry_node,
+                       "Unexpected node type: node-type=%d", entry_node->type);
+               ret = -EINVAL;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int visit_variant_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
+               struct ctf_field_class_variant *variant_decl)
+{
+       int ret = 0;
+
+       switch (entry_node->type) {
+       case NODE_TYPEDEF:
+               ret = visit_field_class_def(ctx,
+                       entry_node->u.field_class_def.field_class_specifier_list,
+                       &entry_node->u.field_class_def.field_class_declarators);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Cannot add field class found in variant field class: ret=%d",
+                               ret);
+                       goto end;
+               }
+               break;
+       case NODE_TYPEALIAS:
+               ret = visit_field_class_alias(ctx, entry_node->u.field_class_alias.target,
+                       entry_node->u.field_class_alias.alias);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Cannot add field class alias found in variant field class: ret=%d",
+                               ret);
+                       goto end;
+               }
+               break;
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               /* Field */
+               ret = visit_variant_decl_field(ctx, variant_decl,
+                       entry_node->u.struct_or_variant_declaration.
+                               field_class_specifier_list,
+                       &entry_node->u.struct_or_variant_declaration.
+                               field_class_declarators);
+               if (ret) {
+                       goto end;
+               }
+               break;
+       default:
+               _BT_LOGE_NODE(entry_node,
+                       "Unexpected node type: node-type=%d",
+                       entry_node->type);
+               ret = -EINVAL;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int visit_struct_decl(struct ctx *ctx, const char *name,
+               struct bt_list_head *decl_list, int has_body,
+               struct bt_list_head *min_align,
+               struct ctf_field_class_struct **struct_decl)
+{
+       int ret = 0;
+
+       BT_ASSERT(struct_decl);
+       *struct_decl = NULL;
+
+       /* For named struct (without body), lookup in declaration scope */
+       if (!has_body) {
+               if (!name) {
+                       BT_LOGE_STR("Bodyless structure field class: missing name.");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               *struct_decl = ctx_decl_scope_lookup_struct(ctx->current_scope,
+                       name, -1, true);
+               if (!*struct_decl) {
+                       BT_LOGE("Cannot find structure field class: name=\"struct %s\"",
+                               name);
+                       ret = -EINVAL;
+                       goto error;
+               }
+       } else {
+               struct ctf_node *entry_node;
+               uint64_t min_align_value = 0;
+
+               if (name) {
+                       if (ctx_decl_scope_lookup_struct(
+                                       ctx->current_scope, name, 1, false)) {
+                               BT_LOGE("Structure field class already declared in local scope: "
+                                       "name=\"struct %s\"", name);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               }
+
+               if (!bt_list_empty(min_align)) {
+                       ret = get_unary_unsigned(min_align, &min_align_value);
+                       if (ret) {
+                               BT_LOGE("Unexpected unary expression for structure field class's `align` attribute: "
+                                       "ret=%d", ret);
+                               goto error;
+                       }
+               }
+
+               *struct_decl = ctf_field_class_struct_create();
+               BT_ASSERT(*struct_decl);
+
+               if (min_align_value != 0) {
+                       (*struct_decl)->base.alignment = min_align_value;
+               }
+
+               _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
+
+               bt_list_for_each_entry(entry_node, decl_list, siblings) {
+                       ret = visit_struct_decl_entry(ctx, entry_node,
+                               *struct_decl);
+                       if (ret) {
+                               _BT_LOGE_NODE(entry_node,
+                                       "Cannot visit structure field class entry: "
+                                       "ret=%d", ret);
+                               ctx_pop_scope(ctx);
+                               goto error;
+                       }
+               }
+
+               ctx_pop_scope(ctx);
+
+               if (name) {
+                       ret = ctx_decl_scope_register_struct(ctx->current_scope,
+                               name, *struct_decl);
+                       if (ret) {
+                               BT_LOGE("Cannot register structure field class in declaration scope: "
+                                       "name=\"struct %s\", ret=%d", name, ret);
+                               goto error;
+                       }
+               }
+       }
+
+       return 0;
+
+error:
+       ctf_field_class_destroy((void *) *struct_decl);
+       *struct_decl = NULL;
+       return ret;
+}
+
+static
+int visit_variant_decl(struct ctx *ctx, const char *name,
+       const char *tag, struct bt_list_head *decl_list,
+       int has_body, struct ctf_field_class_variant **variant_decl)
+{
+       int ret = 0;
+       struct ctf_field_class_variant *untagged_variant_decl = NULL;
+
+       BT_ASSERT(variant_decl);
+       *variant_decl = NULL;
+
+       /* For named variant (without body), lookup in declaration scope */
+       if (!has_body) {
+               if (!name) {
+                       BT_LOGE_STR("Bodyless variant field class: missing name.");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               untagged_variant_decl =
+                       ctx_decl_scope_lookup_variant(ctx->current_scope,
+                               name, -1, true);
+               if (!untagged_variant_decl) {
+                       BT_LOGE("Cannot find variant field class: name=\"variant %s\"",
+                               name);
+                       ret = -EINVAL;
+                       goto error;
+               }
+       } else {
+               struct ctf_node *entry_node;
+
+               if (name) {
+                       if (ctx_decl_scope_lookup_variant(ctx->current_scope,
+                                       name, 1, false)) {
+                               BT_LOGE("Variant field class already declared in local scope: "
+                                       "name=\"variant %s\"", name);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               }
+
+               untagged_variant_decl = ctf_field_class_variant_create();
+               BT_ASSERT(untagged_variant_decl);
+               _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
+
+               bt_list_for_each_entry(entry_node, decl_list, siblings) {
+                       ret = visit_variant_decl_entry(ctx, entry_node,
+                               untagged_variant_decl);
+                       if (ret) {
+                               _BT_LOGE_NODE(entry_node,
+                                       "Cannot visit variant field class entry: "
+                                       "ret=%d", ret);
+                               ctx_pop_scope(ctx);
+                               goto error;
+                       }
+               }
+
+               ctx_pop_scope(ctx);
+
+               if (name) {
+                       ret = ctx_decl_scope_register_variant(
+                               ctx->current_scope, name,
+                               untagged_variant_decl);
+                       if (ret) {
+                               BT_LOGE("Cannot register variant field class in declaration scope: "
+                                       "name=\"variant %s\", ret=%d", name, ret);
+                               goto error;
+                       }
+               }
+       }
+
+       /*
+        * If tagged, create tagged variant and return; otherwise
+        * return untagged variant.
+        */
+       if (!tag) {
+               *variant_decl = untagged_variant_decl;
+               untagged_variant_decl = NULL;
+       } else {
+               /*
+                * At this point, we have a fresh untagged variant; nobody
+                * else owns it. Set its tag now.
+                */
+               char *tag_no_underscore =
+                       remove_underscores_from_field_ref(tag);
+
+               if (!tag_no_underscore) {
+                       /* remove_underscores_from_field_ref() logs errors */
+                       goto error;
+               }
+
+               g_string_assign(untagged_variant_decl->tag_ref,
+                       tag_no_underscore);
+               free(tag_no_underscore);
+               *variant_decl = untagged_variant_decl;
+               untagged_variant_decl = NULL;
+       }
+
+       BT_ASSERT(!untagged_variant_decl);
+       BT_ASSERT(*variant_decl);
+       return 0;
+
+error:
+       ctf_field_class_destroy((void *) untagged_variant_decl);
+       untagged_variant_decl = NULL;
+       ctf_field_class_destroy((void *) *variant_decl);
+       *variant_decl = NULL;
+       return ret;
+}
+
+struct uori {
+       bool is_signed;
+       union {
+               uint64_t u;
+               uint64_t i;
+       } value;
+};
+
+static
+int visit_enum_decl_entry(struct ctx *ctx, struct ctf_node *enumerator,
+               struct ctf_field_class_enum *enum_decl, struct uori *last)
+{
+       int ret = 0;
+       int nr_vals = 0;
+       struct ctf_node *iter;
+       struct uori start = {
+               .is_signed = false,
+               .value.u = 0,
+       };
+       struct uori end = {
+               .is_signed = false,
+               .value.u = 0,
+       };
+       const char *label = enumerator->u.enumerator.id;
+       const char *effective_label = label;
+       struct bt_list_head *values = &enumerator->u.enumerator.values;
+
+       bt_list_for_each_entry(iter, values, siblings) {
+               struct uori *target;
+
+               if (iter->type != NODE_UNARY_EXPRESSION) {
+                       _BT_LOGE_NODE(iter,
+                               "Wrong expression for enumeration field class label: "
+                               "node-type=%d, label=\"%s\"", iter->type,
+                               label);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (nr_vals == 0) {
+                       target = &start;
+               } else {
+                       target = &end;
+               }
+
+               switch (iter->u.unary_expression.type) {
+               case UNARY_SIGNED_CONSTANT:
+                       target->is_signed = true;
+                       target->value.i =
+                               iter->u.unary_expression.u.signed_constant;
+                       break;
+               case UNARY_UNSIGNED_CONSTANT:
+                       target->is_signed = false;
+                       target->value.u =
+                               iter->u.unary_expression.u.unsigned_constant;
+                       break;
+               default:
+                       _BT_LOGE_NODE(iter,
+                               "Invalid enumeration field class entry: "
+                               "expecting constant signed or unsigned integer: "
+                               "node-type=%d, label=\"%s\"",
+                               iter->u.unary_expression.type, label);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (nr_vals > 1) {
+                       _BT_LOGE_NODE(iter,
+                               "Invalid enumeration field class entry: label=\"%s\"",
+                               label);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               nr_vals++;
+       }
+
+       if (nr_vals == 0) {
+               start = *last;
+       }
+
+       if (nr_vals <= 1) {
+               end = start;
+       }
+
+       if (end.is_signed) {
+               last->value.i = end.value.i + 1;
+       } else {
+               last->value.u = end.value.u + 1;
+       }
+
+       if (label[0] == '_') {
+               /*
+                * Strip the first underscore of any enumeration field
+                * class's label in case this enumeration FC is used as
+                * a variant FC tag later. The variant FC choice names
+                * could also start with `_`, in which case the prefix
+                * is removed, and it the resulting choice name needs to
+                * match tag labels.
+                */
+               effective_label = &label[1];
+       }
+
+       ctf_field_class_enum_append_mapping(enum_decl, effective_label,
+               start.value.u, end.value.u);
+       return 0;
+
+error:
+       return ret;
+}
+
+static
+int visit_enum_decl(struct ctx *ctx, const char *name,
+               struct ctf_node *container_cls,
+               struct bt_list_head *enumerator_list,
+               int has_body, struct ctf_field_class_enum **enum_decl)
+{
+       int ret = 0;
+       GQuark qdummy_id;
+       struct ctf_field_class_int *integer_decl = NULL;
+
+       BT_ASSERT(enum_decl);
+       *enum_decl = NULL;
+
+       /* For named enum (without body), lookup in declaration scope */
+       if (!has_body) {
+               if (!name) {
+                       BT_LOGE_STR("Bodyless enumeration field class: missing name.");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               *enum_decl = ctx_decl_scope_lookup_enum(ctx->current_scope,
+                       name, -1, true);
+               if (!*enum_decl) {
+                       BT_LOGE("Cannot find enumeration field class: "
+                               "name=\"enum %s\"", name);
+                       ret = -EINVAL;
+                       goto error;
+               }
+       } else {
+               struct ctf_node *iter;
+               struct uori last_value = {
+                       .is_signed = false,
+                       .value.u = 0,
+               };
+
+               if (name) {
+                       if (ctx_decl_scope_lookup_enum(ctx->current_scope,
+                                       name, 1, false)) {
+                               BT_LOGE("Enumeration field class already declared in local scope: "
+                                       "name=\"enum %s\"", name);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               }
+
+               if (!container_cls) {
+                       integer_decl = (void *) ctx_decl_scope_lookup_alias(
+                               ctx->current_scope, "int", -1, true);
+                       if (!integer_decl) {
+                               BT_LOGE_STR("Cannot find implicit `int` field class alias for enumeration field class.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               } else {
+                       ret = visit_field_class_declarator(ctx, container_cls,
+                               &qdummy_id, NULL, (void *) &integer_decl,
+                               NULL);
+                       if (ret) {
+                               BT_ASSERT(!integer_decl);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               }
+
+               BT_ASSERT(integer_decl);
+
+               if (integer_decl->base.base.type != CTF_FIELD_CLASS_TYPE_INT) {
+                       BT_LOGE("Container field class for enumeration field class is not an integer field class: "
+                               "fc-type=%d", integer_decl->base.base.type);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               *enum_decl = ctf_field_class_enum_create();
+               BT_ASSERT(*enum_decl);
+               (*enum_decl)->base.base.base.alignment =
+                       integer_decl->base.base.alignment;
+               ctf_field_class_int_copy_content((void *) *enum_decl,
+                               (void *) integer_decl);
+               last_value.is_signed = (*enum_decl)->base.is_signed;
+
+               bt_list_for_each_entry(iter, enumerator_list, siblings) {
+                       ret = visit_enum_decl_entry(ctx, iter, *enum_decl,
+                               &last_value);
+                       if (ret) {
+                               _BT_LOGE_NODE(iter,
+                                       "Cannot visit enumeration field class entry: "
+                                       "ret=%d", ret);
+                               goto error;
+                       }
+               }
+
+               if (name) {
+                       ret = ctx_decl_scope_register_enum(ctx->current_scope,
+                               name, *enum_decl);
+                       if (ret) {
+                               BT_LOGE("Cannot register enumeration field class in declaration scope: "
+                                       "ret=%d", ret);
+                               goto error;
+                       }
+               }
+       }
+
+       goto end;
+
+error:
+       ctf_field_class_destroy((void *) *enum_decl);
+       *enum_decl = NULL;
+
+end:
+       ctf_field_class_destroy((void *) integer_decl);
+       integer_decl = NULL;
+       return ret;
+}
+
+static
+int visit_field_class_specifier(struct ctx *ctx,
+               struct ctf_node *cls_specifier_list,
+               struct ctf_field_class **decl)
+{
+       int ret = 0;
+       GString *str = NULL;
+
+       *decl = NULL;
+       str = g_string_new("");
+       ret = get_class_specifier_list_name(ctx, cls_specifier_list, str);
+       if (ret) {
+               _BT_LOGE_NODE(cls_specifier_list,
+                       "Cannot get field class specifier list's name: ret=%d", ret);
+               goto error;
+       }
+
+       *decl = ctx_decl_scope_lookup_alias(ctx->current_scope, str->str, -1,
+               true);
+       if (!*decl) {
+               _BT_LOGE_NODE(cls_specifier_list,
+                       "Cannot find field class alias: name=\"%s\"", str->str);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ctf_field_class_destroy(*decl);
+       *decl = NULL;
+
+end:
+       if (str) {
+               g_string_free(str, TRUE);
+       }
+
+       return ret;
+}
+
+static
+int visit_integer_decl(struct ctx *ctx,
+               struct bt_list_head *expressions,
+               struct ctf_field_class_int **integer_decl)
+{
+       int set = 0;
+       int ret = 0;
+       int signedness = 0;
+       struct ctf_node *expression;
+       uint64_t alignment = 0, size = 0;
+       struct ctf_clock_class *mapped_clock_class = NULL;
+       enum ctf_encoding encoding = CTF_ENCODING_NONE;
+       bt_field_class_integer_preferred_display_base base =
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
+       enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order;
+
+       *integer_decl = NULL;
+
+       bt_list_for_each_entry(expression, expressions, siblings) {
+               struct ctf_node *left, *right;
+
+               left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left,
+                       struct ctf_node, siblings);
+               right = _BT_LIST_FIRST_ENTRY(
+                       &expression->u.ctf_expression.right, struct ctf_node,
+                       siblings);
+
+               if (left->u.unary_expression.type != UNARY_STRING) {
+                       _BT_LOGE_NODE(left,
+                               "Unexpected unary expression type: type=%d",
+                               left->u.unary_expression.type);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (!strcmp(left->u.unary_expression.u.string, "signed")) {
+                       if (_IS_SET(&set, _INTEGER_SIGNED_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "signed",
+                                       "integer field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       signedness = get_boolean(right);
+                       if (signedness < 0) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid boolean value for integer field class's `signed` attribute: "
+                                       "ret=%d", ret);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(&set, _INTEGER_SIGNED_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string,
+                               "byte_order")) {
+                       if (_IS_SET(&set, _INTEGER_BYTE_ORDER_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "byte_order",
+                                       "integer field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       byte_order = get_real_byte_order(ctx, right);
+                       if (byte_order == -1) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `byte_order` attribute in integer field class: "
+                                       "ret=%d", ret);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(&set, _INTEGER_BYTE_ORDER_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string, "size")) {
+                       if (_IS_SET(&set, _INTEGER_SIZE_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "size",
+                                       "integer field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       if (right->u.unary_expression.type !=
+                                       UNARY_UNSIGNED_CONSTANT) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `size` attribute in integer field class: "
+                                       "expecting unsigned constant integer: "
+                                       "node-type=%d",
+                                       right->u.unary_expression.type);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       size = right->u.unary_expression.u.unsigned_constant;
+                       if (size == 0) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `size` attribute in integer field class: "
+                                       "expecting positive constant integer: "
+                                       "size=%" PRIu64, size);
+                               ret = -EINVAL;
+                               goto error;
+                       } else if (size > 64) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `size` attribute in integer field class: "
+                                       "integer fields over 64 bits are not supported as of this version: "
+                                       "size=%" PRIu64, size);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(&set, _INTEGER_SIZE_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string,
+                               "align")) {
+                       if (_IS_SET(&set, _INTEGER_ALIGN_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "align",
+                                       "integer field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       if (right->u.unary_expression.type !=
+                                       UNARY_UNSIGNED_CONSTANT) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `align` attribute in integer field class: "
+                                       "expecting unsigned constant integer: "
+                                       "node-type=%d",
+                                       right->u.unary_expression.type);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       alignment =
+                               right->u.unary_expression.u.unsigned_constant;
+                       if (!is_align_valid(alignment)) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `align` attribute in integer field class: "
+                                       "expecting power of two: "
+                                       "align=%" PRIu64, alignment);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(&set, _INTEGER_ALIGN_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string, "base")) {
+                       if (_IS_SET(&set, _INTEGER_BASE_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "base",
+                                       "integer field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       switch (right->u.unary_expression.type) {
+                       case UNARY_UNSIGNED_CONSTANT:
+                       {
+                               uint64_t constant = right->u.unary_expression.
+                                       u.unsigned_constant;
+
+                               switch (constant) {
+                               case 2:
+                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
+                                       break;
+                               case 8:
+                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
+                                       break;
+                               case 10:
+                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
+                                       break;
+                               case 16:
+                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
+                                       break;
+                               default:
+                                       _BT_LOGE_NODE(right,
+                                               "Invalid `base` attribute in integer field class: "
+                                               "base=%" PRIu64,
+                                               right->u.unary_expression.u.unsigned_constant);
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+                               break;
+                       }
+                       case UNARY_STRING:
+                       {
+                               char *s_right = concatenate_unary_strings(
+                                       &expression->u.ctf_expression.right);
+                               if (!s_right) {
+                                       _BT_LOGE_NODE(right,
+                                               "Unexpected unary expression for integer field class's `base` attribute.");
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               if (!strcmp(s_right, "decimal") ||
+                                               !strcmp(s_right, "dec") ||
+                                               !strcmp(s_right, "d") ||
+                                               !strcmp(s_right, "i") ||
+                                               !strcmp(s_right, "u")) {
+                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL;
+                               } else if (!strcmp(s_right, "hexadecimal") ||
+                                               !strcmp(s_right, "hex") ||
+                                               !strcmp(s_right, "x") ||
+                                               !strcmp(s_right, "X") ||
+                                               !strcmp(s_right, "p")) {
+                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL;
+                               } else if (!strcmp(s_right, "octal") ||
+                                               !strcmp(s_right, "oct") ||
+                                               !strcmp(s_right, "o")) {
+                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL;
+                               } else if (!strcmp(s_right, "binary") ||
+                                               !strcmp(s_right, "b")) {
+                                       base = BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY;
+                               } else {
+                                       _BT_LOGE_NODE(right,
+                                               "Unexpected unary expression for integer field class's `base` attribute: "
+                                               "base=\"%s\"", s_right);
+                                       g_free(s_right);
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               g_free(s_right);
+                               break;
+                       }
+                       default:
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `base` attribute in integer field class: "
+                                       "expecting unsigned constant integer or unary string.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(&set, _INTEGER_BASE_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string,
+                               "encoding")) {
+                       char *s_right;
+
+                       if (_IS_SET(&set, _INTEGER_ENCODING_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "encoding",
+                                       "integer field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       if (right->u.unary_expression.type != UNARY_STRING) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `encoding` attribute in integer field class: "
+                                       "expecting unary string.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       s_right = concatenate_unary_strings(
+                               &expression->u.ctf_expression.right);
+                       if (!s_right) {
+                               _BT_LOGE_NODE(right,
+                                       "Unexpected unary expression for integer field class's `encoding` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (!strcmp(s_right, "UTF8") ||
+                                       !strcmp(s_right, "utf8") ||
+                                       !strcmp(s_right, "utf-8") ||
+                                       !strcmp(s_right, "UTF-8") ||
+                                       !strcmp(s_right, "ASCII") ||
+                                       !strcmp(s_right, "ascii")) {
+                               encoding = CTF_ENCODING_UTF8;
+                       } else if (!strcmp(s_right, "none")) {
+                               encoding = CTF_ENCODING_NONE;
+                       } else {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `encoding` attribute in integer field class: "
+                                       "unknown encoding: encoding=\"%s\"",
+                                       s_right);
+                               g_free(s_right);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       g_free(s_right);
+                       _SET(&set, _INTEGER_ENCODING_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string, "map")) {
+                       const char *clock_name;
+
+                       if (_IS_SET(&set, _INTEGER_MAP_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "map",
+                                       "integer field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       if (right->u.unary_expression.type != UNARY_STRING) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `map` attribute in integer field class: "
+                                       "expecting unary string.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       clock_name =
+                               get_map_clock_name_value(
+                                       &expression->u.ctf_expression.right);
+                       if (!clock_name) {
+                               char *s_right = concatenate_unary_strings(
+                                       &expression->u.ctf_expression.right);
+
+                               if (!s_right) {
+                                       _BT_LOGE_NODE(right,
+                                               "Unexpected unary expression for integer field class's `map` attribute.");
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `map` attribute in integer field class: "
+                                       "cannot find clock class at this point: name=\"%s\"",
+                                       s_right);
+                               _SET(&set, _INTEGER_MAP_SET);
+                               g_free(s_right);
+                               continue;
+                       }
+
+                       mapped_clock_class =
+                               ctf_trace_class_borrow_clock_class_by_name(
+                                       ctx->ctf_tc, clock_name);
+                       if (!mapped_clock_class) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `map` attribute in integer field class: "
+                                       "cannot find clock class at this point: name=\"%s\"",
+                                       clock_name);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(&set, _INTEGER_MAP_SET);
+               } else {
+                       _BT_LOGW_NODE(left,
+                               "Unknown attribute in integer field class: "
+                               "attr-name=\"%s\"",
+                               left->u.unary_expression.u.string);
+               }
+       }
+
+       if (!_IS_SET(&set, _INTEGER_SIZE_SET)) {
+               BT_LOGE_STR("Missing `size` attribute in integer field class.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) {
+               if (size % CHAR_BIT) {
+                       /* Bit-packed alignment */
+                       alignment = 1;
+               } else {
+                       /* Byte-packed alignment */
+                       alignment = CHAR_BIT;
+               }
+       }
+
+       *integer_decl = ctf_field_class_int_create();
+       BT_ASSERT(*integer_decl);
+       (*integer_decl)->base.base.alignment = alignment;
+       (*integer_decl)->base.byte_order = byte_order;
+       (*integer_decl)->base.size = size;
+       (*integer_decl)->is_signed = (signedness > 0);
+       (*integer_decl)->disp_base = base;
+       (*integer_decl)->encoding = encoding;
+       (*integer_decl)->mapped_clock_class = mapped_clock_class;
+       return 0;
+
+error:
+       ctf_field_class_destroy((void *) *integer_decl);
+       *integer_decl = NULL;
+       return ret;
+}
+
+static
+int visit_floating_point_number_decl(struct ctx *ctx,
+               struct bt_list_head *expressions,
+               struct ctf_field_class_float **float_decl)
+{
+       int set = 0;
+       int ret = 0;
+       struct ctf_node *expression;
+       uint64_t alignment = 1, exp_dig = 0, mant_dig = 0;
+       enum ctf_byte_order byte_order = ctx->ctf_tc->default_byte_order;
+
+       *float_decl = NULL;
+
+       bt_list_for_each_entry(expression, expressions, siblings) {
+               struct ctf_node *left, *right;
+
+               left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left,
+                       struct ctf_node, siblings);
+               right = _BT_LIST_FIRST_ENTRY(
+                       &expression->u.ctf_expression.right, struct ctf_node,
+                       siblings);
+
+               if (left->u.unary_expression.type != UNARY_STRING) {
+                       _BT_LOGE_NODE(left,
+                               "Unexpected unary expression type: type=%d",
+                               left->u.unary_expression.type);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (!strcmp(left->u.unary_expression.u.string, "byte_order")) {
+                       if (_IS_SET(&set, _FLOAT_BYTE_ORDER_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "byte_order",
+                                       "floating point number field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       byte_order = get_real_byte_order(ctx, right);
+                       if (byte_order == -1) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `byte_order` attribute in floating point number field class: "
+                                       "ret=%d", ret);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(&set, _FLOAT_BYTE_ORDER_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string,
+                               "exp_dig")) {
+                       if (_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "exp_dig",
+                                       "floating point number field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       if (right->u.unary_expression.type !=
+                                       UNARY_UNSIGNED_CONSTANT) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `exp_dig` attribute in floating point number field class: "
+                                       "expecting unsigned constant integer: "
+                                       "node-type=%d",
+                                       right->u.unary_expression.type);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       exp_dig = right->u.unary_expression.u.unsigned_constant;
+                       _SET(&set, _FLOAT_EXP_DIG_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string,
+                               "mant_dig")) {
+                       if (_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "mant_dig",
+                                       "floating point number field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       if (right->u.unary_expression.type !=
+                                       UNARY_UNSIGNED_CONSTANT) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `mant_dig` attribute in floating point number field class: "
+                                       "expecting unsigned constant integer: "
+                                       "node-type=%d",
+                                       right->u.unary_expression.type);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       mant_dig = right->u.unary_expression.u.
+                               unsigned_constant;
+                       _SET(&set, _FLOAT_MANT_DIG_SET);
+               } else if (!strcmp(left->u.unary_expression.u.string,
+                               "align")) {
+                       if (_IS_SET(&set, _FLOAT_ALIGN_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "align",
+                                       "floating point number field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       if (right->u.unary_expression.type !=
+                                       UNARY_UNSIGNED_CONSTANT) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `align` attribute in floating point number field class: "
+                                       "expecting unsigned constant integer: "
+                                       "node-type=%d",
+                                       right->u.unary_expression.type);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       alignment = right->u.unary_expression.u.
+                               unsigned_constant;
+
+                       if (!is_align_valid(alignment)) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `align` attribute in floating point number field class: "
+                                       "expecting power of two: "
+                                       "align=%" PRIu64, alignment);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(&set, _FLOAT_ALIGN_SET);
+               } else {
+                       _BT_LOGW_NODE(left,
+                               "Unknown attribute in floating point number field class: "
+                               "attr-name=\"%s\"",
+                               left->u.unary_expression.u.string);
+               }
+       }
+
+       if (!_IS_SET(&set, _FLOAT_MANT_DIG_SET)) {
+               BT_LOGE_STR("Missing `mant_dig` attribute in floating point number field class.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (!_IS_SET(&set, _FLOAT_EXP_DIG_SET)) {
+               BT_LOGE_STR("Missing `exp_dig` attribute in floating point number field class.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (mant_dig != 24 && mant_dig != 53) {
+               BT_LOGE_STR("`mant_dig` attribute: expecting 24 or 53.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (mant_dig == 24 && exp_dig != 8) {
+               BT_LOGE_STR("`exp_dig` attribute: expecting 8 because `mant_dig` is 24.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (mant_dig == 53 && exp_dig != 11) {
+               BT_LOGE_STR("`exp_dig` attribute: expecting 11 because `mant_dig` is 53.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (!_IS_SET(&set, _INTEGER_ALIGN_SET)) {
+               if ((mant_dig + exp_dig) % CHAR_BIT) {
+                       /* Bit-packed alignment */
+                       alignment = 1;
+               } else {
+                       /* Byte-packed alignment */
+                       alignment = CHAR_BIT;
+               }
+       }
+
+       *float_decl = ctf_field_class_float_create();
+       BT_ASSERT(*float_decl);
+       (*float_decl)->base.base.alignment = alignment;
+       (*float_decl)->base.byte_order = byte_order;
+       (*float_decl)->base.size = mant_dig + exp_dig;
+       return 0;
+
+error:
+       ctf_field_class_destroy((void *) *float_decl);
+       *float_decl = NULL;
+       return ret;
+}
+
+static
+int visit_string_decl(struct ctx *ctx,
+               struct bt_list_head *expressions,
+               struct ctf_field_class_string **string_decl)
+{
+       int set = 0;
+       int ret = 0;
+       struct ctf_node *expression;
+       enum ctf_encoding encoding = CTF_ENCODING_UTF8;
+
+       *string_decl = NULL;
+
+       bt_list_for_each_entry(expression, expressions, siblings) {
+               struct ctf_node *left, *right;
+
+               left = _BT_LIST_FIRST_ENTRY(&expression->u.ctf_expression.left,
+                       struct ctf_node, siblings);
+               right = _BT_LIST_FIRST_ENTRY(
+                       &expression->u.ctf_expression.right, struct ctf_node,
+                       siblings);
+
+               if (left->u.unary_expression.type != UNARY_STRING) {
+                       _BT_LOGE_NODE(left,
+                               "Unexpected unary expression type: type=%d",
+                               left->u.unary_expression.type);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (!strcmp(left->u.unary_expression.u.string, "encoding")) {
+                       char *s_right;
+
+                       if (_IS_SET(&set, _STRING_ENCODING_SET)) {
+                               _BT_LOGE_DUP_ATTR(left, "encoding",
+                                       "string field class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       if (right->u.unary_expression.type != UNARY_STRING) {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `encoding` attribute in string field class: "
+                                       "expecting unary string.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       s_right = concatenate_unary_strings(
+                               &expression->u.ctf_expression.right);
+                       if (!s_right) {
+                               _BT_LOGE_NODE(right,
+                                       "Unexpected unary expression for string field class's `encoding` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (!strcmp(s_right, "UTF8") ||
+                                       !strcmp(s_right, "utf8") ||
+                                       !strcmp(s_right, "utf-8") ||
+                                       !strcmp(s_right, "UTF-8") ||
+                                       !strcmp(s_right, "ASCII") ||
+                                       !strcmp(s_right, "ascii")) {
+                               encoding = CTF_ENCODING_UTF8;
+                       } else if (!strcmp(s_right, "none")) {
+                               encoding = CTF_ENCODING_NONE;
+                       } else {
+                               _BT_LOGE_NODE(right,
+                                       "Invalid `encoding` attribute in string field class: "
+                                       "unknown encoding: encoding=\"%s\"",
+                                       s_right);
+                               g_free(s_right);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       g_free(s_right);
+                       _SET(&set, _STRING_ENCODING_SET);
+               } else {
+                       _BT_LOGW_NODE(left,
+                               "Unknown attribute in string field class: "
+                               "attr-name=\"%s\"",
+                               left->u.unary_expression.u.string);
+               }
+       }
+
+       *string_decl = ctf_field_class_string_create();
+       BT_ASSERT(*string_decl);
+       (*string_decl)->encoding = encoding;
+       return 0;
+
+error:
+       ctf_field_class_destroy((void *) *string_decl);
+       *string_decl = NULL;
+       return ret;
+}
+
+static
+int visit_field_class_specifier_list(struct ctx *ctx,
+               struct ctf_node *ts_list, struct ctf_field_class **decl)
+{
+       int ret = 0;
+       struct ctf_node *first, *node;
+
+       *decl = NULL;
+
+       if (ts_list->type != NODE_TYPE_SPECIFIER_LIST) {
+               _BT_LOGE_NODE(ts_list,
+                       "Unexpected node type: node-type=%d", ts_list->type);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       first = _BT_LIST_FIRST_ENTRY(&ts_list->u.field_class_specifier_list.head,
+               struct ctf_node, siblings);
+       if (first->type != NODE_TYPE_SPECIFIER) {
+               _BT_LOGE_NODE(first,
+                       "Unexpected node type: node-type=%d", first->type);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       node = first->u.field_class_specifier.node;
+
+       switch (first->u.field_class_specifier.type) {
+       case TYPESPEC_INTEGER:
+               ret = visit_integer_decl(ctx, &node->u.integer.expressions,
+                       (void *) decl);
+               if (ret) {
+                       BT_ASSERT(!*decl);
+                       goto error;
+               }
+               break;
+       case TYPESPEC_FLOATING_POINT:
+               ret = visit_floating_point_number_decl(ctx,
+                       &node->u.floating_point.expressions, (void *) decl);
+               if (ret) {
+                       BT_ASSERT(!*decl);
+                       goto error;
+               }
+               break;
+       case TYPESPEC_STRING:
+               ret = visit_string_decl(ctx,
+                       &node->u.string.expressions, (void *) decl);
+               if (ret) {
+                       BT_ASSERT(!*decl);
+                       goto error;
+               }
+               break;
+       case TYPESPEC_STRUCT:
+               ret = visit_struct_decl(ctx, node->u._struct.name,
+                       &node->u._struct.declaration_list,
+                       node->u._struct.has_body,
+                       &node->u._struct.min_align, (void *) decl);
+               if (ret) {
+                       BT_ASSERT(!*decl);
+                       goto error;
+               }
+               break;
+       case TYPESPEC_VARIANT:
+               ret = visit_variant_decl(ctx, node->u.variant.name,
+                       node->u.variant.choice,
+                       &node->u.variant.declaration_list,
+                       node->u.variant.has_body, (void *) decl);
+               if (ret) {
+                       BT_ASSERT(!*decl);
+                       goto error;
+               }
+               break;
+       case TYPESPEC_ENUM:
+               ret = visit_enum_decl(ctx, node->u._enum.enum_id,
+                       node->u._enum.container_field_class,
+                       &node->u._enum.enumerator_list,
+                       node->u._enum.has_body, (void *) decl);
+               if (ret) {
+                       BT_ASSERT(!*decl);
+                       goto error;
+               }
+               break;
+       case TYPESPEC_VOID:
+       case TYPESPEC_CHAR:
+       case TYPESPEC_SHORT:
+       case TYPESPEC_INT:
+       case TYPESPEC_LONG:
+       case TYPESPEC_FLOAT:
+       case TYPESPEC_DOUBLE:
+       case TYPESPEC_SIGNED:
+       case TYPESPEC_UNSIGNED:
+       case TYPESPEC_BOOL:
+       case TYPESPEC_COMPLEX:
+       case TYPESPEC_IMAGINARY:
+       case TYPESPEC_CONST:
+       case TYPESPEC_ID_TYPE:
+               ret = visit_field_class_specifier(ctx, ts_list, decl);
+               if (ret) {
+                       _BT_LOGE_NODE(first,
+                               "Cannot visit field class specifier: ret=%d",
+                               ret);
+                       BT_ASSERT(!*decl);
+                       goto error;
+               }
+               break;
+       default:
+               _BT_LOGE_NODE(first,
+                       "Unexpected field class specifier type: node-type=%d",
+                       first->u.field_class_specifier.type);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       BT_ASSERT(*decl);
+       return 0;
+
+error:
+       ctf_field_class_destroy((void *) *decl);
+       *decl = NULL;
+       return ret;
+}
+
+static
+int visit_event_decl_entry(struct ctx *ctx, struct ctf_node *node,
+               struct ctf_event_class *event_class, uint64_t *stream_id,
+               int *set)
+{
+       int ret = 0;
+       char *left = NULL;
+
+       switch (node->type) {
+       case NODE_TYPEDEF:
+               ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
+                       &node->u.field_class_def.field_class_declarators);
+               if (ret) {
+                       _BT_LOGE_NODE(node,
+                               "Cannot add field class found in event class.");
+                       goto error;
+               }
+               break;
+       case NODE_TYPEALIAS:
+               ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
+                       node->u.field_class_alias.alias);
+               if (ret) {
+                       _BT_LOGE_NODE(node,
+                               "Cannot add field class alias found in event class.");
+                       goto error;
+               }
+               break;
+       case NODE_CTF_EXPRESSION:
+       {
+               left = concatenate_unary_strings(&node->u.ctf_expression.left);
+               if (!left) {
+                       _BT_LOGE_NODE(node, "Cannot concatenate unary strings.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (!strcmp(left, "name")) {
+                       /* This is already known at this stage */
+                       if (_IS_SET(set, _EVENT_NAME_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "name", "event class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       _SET(set, _EVENT_NAME_SET);
+               } else if (!strcmp(left, "id")) {
+                       int64_t id = -1;
+
+                       if (_IS_SET(set, _EVENT_ID_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "id", "event class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
+                               (uint64_t *) &id);
+                       /* Only read "id" if get_unary_unsigned() succeeded. */
+                       if (ret || (!ret && id < 0)) {
+                               _BT_LOGE_NODE(node,
+                                       "Unexpected unary expression for event class's `id` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       event_class->id = id;
+                       _SET(set, _EVENT_ID_SET);
+               } else if (!strcmp(left, "stream_id")) {
+                       if (_IS_SET(set, _EVENT_STREAM_ID_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "stream_id",
+                                       "event class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
+                               stream_id);
+
+                       /*
+                        * Only read "stream_id" if get_unary_unsigned()
+                        * succeeded.
+                        */
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Unexpected unary expression for event class's `stream_id` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       _SET(set, _EVENT_STREAM_ID_SET);
+               } else if (!strcmp(left, "context")) {
+                       if (_IS_SET(set, _EVENT_CONTEXT_SET)) {
+                               _BT_LOGE_NODE(node,
+                                       "Duplicate `context` entry in event class.");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = visit_field_class_specifier_list(ctx,
+                               _BT_LIST_FIRST_ENTRY(
+                                       &node->u.ctf_expression.right,
+                                       struct ctf_node, siblings),
+                               &event_class->spec_context_fc);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot create event class's context field class.");
+                               goto error;
+                       }
+
+                       BT_ASSERT(event_class->spec_context_fc);
+                       _SET(set, _EVENT_CONTEXT_SET);
+               } else if (!strcmp(left, "fields")) {
+                       if (_IS_SET(set, _EVENT_FIELDS_SET)) {
+                               _BT_LOGE_NODE(node,
+                                       "Duplicate `fields` entry in event class.");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = visit_field_class_specifier_list(ctx,
+                               _BT_LIST_FIRST_ENTRY(
+                                       &node->u.ctf_expression.right,
+                                       struct ctf_node, siblings),
+                               &event_class->payload_fc);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot create event class's payload field class.");
+                               goto error;
+                       }
+
+                       BT_ASSERT(event_class->payload_fc);
+                       _SET(set, _EVENT_FIELDS_SET);
+               } else if (!strcmp(left, "loglevel")) {
+                       uint64_t loglevel_value;
+                       bt_event_class_log_level log_level = -1;
+
+                       if (_IS_SET(set, _EVENT_LOG_LEVEL_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "loglevel",
+                                       "event class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
+                               &loglevel_value);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Unexpected unary expression for event class's `loglevel` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       switch (loglevel_value) {
+                       case 0:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY;
+                               break;
+                       case 1:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_ALERT;
+                               break;
+                       case 2:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_CRITICAL;
+                               break;
+                       case 3:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_ERROR;
+                               break;
+                       case 4:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_WARNING;
+                               break;
+                       case 5:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_NOTICE;
+                               break;
+                       case 6:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_INFO;
+                               break;
+                       case 7:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM;
+                               break;
+                       case 8:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM;
+                               break;
+                       case 9:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS;
+                               break;
+                       case 10:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE;
+                               break;
+                       case 11:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT;
+                               break;
+                       case 12:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION;
+                               break;
+                       case 13:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE;
+                               break;
+                       case 14:
+                               log_level = BT_EVENT_CLASS_LOG_LEVEL_DEBUG;
+                               break;
+                       default:
+                               _BT_LOGW_NODE(node, "Not setting event class's log level because its value is unknown: "
+                                       "log-level=%" PRIu64, loglevel_value);
+                       }
+
+                       if (log_level != -1) {
+                               event_class->log_level = log_level;
+                       }
+
+                       _SET(set, _EVENT_LOG_LEVEL_SET);
+               } else if (!strcmp(left, "model.emf.uri")) {
+                       char *right;
+
+                       if (_IS_SET(set, _EVENT_MODEL_EMF_URI_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "model.emf.uri",
+                                       "event class");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       right = concatenate_unary_strings(
+                               &node->u.ctf_expression.right);
+                       if (!right) {
+                               _BT_LOGE_NODE(node,
+                                       "Unexpected unary expression for event class's `model.emf.uri` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (strlen(right) == 0) {
+                               _BT_LOGW_NODE(node,
+                                       "Not setting event class's EMF URI because it's empty.");
+                       } else {
+                               g_string_assign(event_class->emf_uri,
+                                       right);
+                       }
+
+                       g_free(right);
+                       _SET(set, _EVENT_MODEL_EMF_URI_SET);
+               } else {
+                       _BT_LOGW_NODE(node,
+                               "Unknown attribute in event class: "
+                               "attr-name=\"%s\"", left);
+               }
+
+               g_free(left);
+               left = NULL;
+               break;
+       }
+       default:
+               ret = -EPERM;
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (left) {
+               g_free(left);
+       }
+
+end:
+       return ret;
+}
+
+static
+char *get_event_decl_name(struct ctx *ctx, struct ctf_node *node)
+{
+       char *left = NULL;
+       char *name = NULL;
+       struct ctf_node *iter;
+       struct bt_list_head *decl_list = &node->u.event.declaration_list;
+
+       bt_list_for_each_entry(iter, decl_list, siblings) {
+               if (iter->type != NODE_CTF_EXPRESSION) {
+                       continue;
+               }
+
+               left = concatenate_unary_strings(&iter->u.ctf_expression.left);
+               if (!left) {
+                       _BT_LOGE_NODE(iter,
+                               "Cannot concatenate unary strings.");
+                       goto error;
+               }
+
+               if (!strcmp(left, "name")) {
+                       name = concatenate_unary_strings(
+                               &iter->u.ctf_expression.right);
+                       if (!name) {
+                               _BT_LOGE_NODE(iter,
+                                       "Unexpected unary expression for event class's `name` attribute.");
+                               goto error;
+                       }
+               }
+
+               g_free(left);
+               left = NULL;
+
+               if (name) {
+                       break;
+               }
+       }
+
+       return name;
+
+error:
+       g_free(left);
+       return NULL;
+}
+
+static
+int visit_event_decl(struct ctx *ctx, struct ctf_node *node)
+{
+       int ret = 0;
+       int set = 0;
+       struct ctf_node *iter;
+       uint64_t stream_id = 0;
+       char *event_name = NULL;
+       struct ctf_event_class *event_class = NULL;
+       struct ctf_stream_class *stream_class = NULL;
+       struct bt_list_head *decl_list = &node->u.event.declaration_list;
+       bool pop_scope = false;
+
+       if (node->visited) {
+               goto end;
+       }
+
+       node->visited = TRUE;
+       event_name = get_event_decl_name(ctx, node);
+       if (!event_name) {
+               _BT_LOGE_NODE(node,
+                       "Missing `name` attribute in event class.");
+               ret = -EPERM;
+               goto error;
+       }
+
+       event_class = ctf_event_class_create();
+       BT_ASSERT(event_class);
+       g_string_assign(event_class->name, event_name);
+       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
+       pop_scope = true;
+
+       bt_list_for_each_entry(iter, decl_list, siblings) {
+               ret = visit_event_decl_entry(ctx, iter, event_class,
+                       &stream_id, &set);
+               if (ret) {
+                       _BT_LOGE_NODE(iter, "Cannot visit event class's entry: "
+                               "ret=%d", ret);
+                       goto error;
+               }
+       }
+
+       if (!_IS_SET(&set, _EVENT_STREAM_ID_SET)) {
+               /*
+                * Allow missing stream_id if there is only a single
+                * stream class.
+                */
+               switch (ctx->ctf_tc->stream_classes->len) {
+               case 0:
+                       /* Create implicit stream class if there's none */
+                       stream_id = 0;
+                       stream_class = ctf_stream_class_create();
+                       BT_ASSERT(stream_class);
+                       stream_class->id = stream_id;
+                       g_ptr_array_add(ctx->ctf_tc->stream_classes,
+                               stream_class);
+                       break;
+               case 1:
+                       /* Single stream class: get its ID */
+                       stream_class = ctx->ctf_tc->stream_classes->pdata[0];
+                       stream_id = stream_class->id;
+                       break;
+               default:
+                       _BT_LOGE_NODE(node,
+                               "Missing `stream_id` attribute in event class.");
+                       ret = -EPERM;
+                       goto error;
+               }
+       }
+
+       /* We have the stream ID now; get the stream class if found */
+       if (!stream_class) {
+               stream_class = ctf_trace_class_borrow_stream_class_by_id(
+                       ctx->ctf_tc, stream_id);
+               if (!stream_class) {
+                       _BT_LOGE_NODE(node,
+                               "Cannot find stream class at this point: "
+                               "id=%" PRId64, stream_id);
+                       ret = -EINVAL;
+                       goto error;
+               }
+       }
+
+       BT_ASSERT(stream_class);
+
+       if (!_IS_SET(&set, _EVENT_ID_SET)) {
+               /* Allow only one event without ID per stream */
+               if (stream_class->event_classes->len != 0) {
+                       _BT_LOGE_NODE(node,
+                               "Missing `id` attribute in event class.");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               /* Automatic ID */
+               event_class->id = 0;
+       }
+
+       if (ctf_stream_class_borrow_event_class_by_id(stream_class,
+                       event_class->id)) {
+               _BT_LOGE_NODE(node,
+                       "Duplicate event class (same ID) in the same stream class: "
+                       "id=%" PRId64, event_class->id);
+               ret = -EEXIST;
+               goto error;
+       }
+
+       ctf_stream_class_append_event_class(stream_class, event_class);
+       event_class = NULL;
+       goto end;
+
+error:
+       ctf_event_class_destroy(event_class);
+       event_class = NULL;
+
+       if (ret >= 0) {
+               ret = -1;
+       }
+
+end:
+       if (pop_scope) {
+               ctx_pop_scope(ctx);
+       }
+
+       if (event_name) {
+               g_free(event_name);
+       }
+
+       return ret;
+}
+
+static
+int auto_map_field_to_trace_clock_class(struct ctx *ctx,
+               struct ctf_field_class *fc)
+{
+       struct ctf_clock_class *clock_class_to_map_to = NULL;
+       struct ctf_field_class_int *int_fc = (void *) fc;
+       int ret = 0;
+       uint64_t clock_class_count;
+
+       if (!fc) {
+               goto end;
+       }
+
+       if (fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                       fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+               goto end;
+       }
+
+       if (int_fc->mapped_clock_class) {
+               /* Already mapped */
+               goto end;
+       }
+
+       clock_class_count = ctx->ctf_tc->clock_classes->len;
+
+       switch (clock_class_count) {
+       case 0:
+               /*
+                * No clock class exists in the trace at this point. Create an
+                * implicit one at 1 GHz, named `default`, and use this clock
+                * class.
+                */
+               clock_class_to_map_to = ctf_clock_class_create();
+               BT_ASSERT(clock_class_to_map_to);
+               clock_class_to_map_to->frequency = UINT64_C(1000000000);
+               g_string_assign(clock_class_to_map_to->name, "default");
+               BT_ASSERT(ret == 0);
+               g_ptr_array_add(ctx->ctf_tc->clock_classes,
+                       clock_class_to_map_to);
+               break;
+       case 1:
+               /*
+                * Only one clock class exists in the trace at this point: use
+                * this one.
+                */
+               clock_class_to_map_to = ctx->ctf_tc->clock_classes->pdata[0];
+               break;
+       default:
+               /*
+                * Timestamp field not mapped to a clock class and there's more
+                * than one clock class in the trace: this is an error.
+                */
+               BT_LOGE_STR("Timestamp field found with no mapped clock class, "
+                       "but there's more than one clock class in the trace at this point.");
+               ret = -1;
+               goto end;
+       }
+
+       BT_ASSERT(clock_class_to_map_to);
+       int_fc->mapped_clock_class = clock_class_to_map_to;
+
+end:
+       return ret;
+}
+
+static
+int auto_map_fields_to_trace_clock_class(struct ctx *ctx,
+               struct ctf_field_class *root_fc, const char *field_name)
+{
+       int ret = 0;
+       uint64_t i, count;
+       struct ctf_field_class_struct *struct_fc = (void *) root_fc;
+       struct ctf_field_class_variant *var_fc = (void *) root_fc;
+
+       if (!root_fc) {
+               goto end;
+       }
+
+       if (root_fc->type != CTF_FIELD_CLASS_TYPE_STRUCT &&
+                       root_fc->type != CTF_FIELD_CLASS_TYPE_VARIANT) {
+               goto end;
+       }
+
+       if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) {
+               count = struct_fc->members->len;
+       } else {
+               count = var_fc->options->len;
+       }
+
+       for (i = 0; i < count; i++) {
+               struct ctf_named_field_class *named_fc = NULL;
+
+               if (root_fc->type == CTF_FIELD_CLASS_TYPE_STRUCT) {
+                       named_fc = ctf_field_class_struct_borrow_member_by_index(
+                               struct_fc, i);
+               } else if (root_fc->type == CTF_FIELD_CLASS_TYPE_VARIANT) {
+                       named_fc = ctf_field_class_variant_borrow_option_by_index(
+                               var_fc, i);
+               }
+
+               if (strcmp(named_fc->name->str, field_name) == 0) {
+                       ret = auto_map_field_to_trace_clock_class(ctx,
+                               named_fc->fc);
+                       if (ret) {
+                               BT_LOGE("Cannot automatically map field to trace's clock class: "
+                                       "field-name=\"%s\"", field_name);
+                               goto end;
+                       }
+               }
+
+               ret = auto_map_fields_to_trace_clock_class(ctx, named_fc->fc,
+                       field_name);
+               if (ret) {
+                       BT_LOGE("Cannot automatically map structure or variant field class's fields to trace's clock class: "
+                               "field-name=\"%s\", root-field-name=\"%s\"",
+                               field_name, named_fc->name->str);
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int visit_stream_decl_entry(struct ctx *ctx, struct ctf_node *node,
+               struct ctf_stream_class *stream_class, int *set)
+{
+       int ret = 0;
+       char *left = NULL;
+
+       switch (node->type) {
+       case NODE_TYPEDEF:
+               ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
+                       &node->u.field_class_def.field_class_declarators);
+               if (ret) {
+                       _BT_LOGE_NODE(node,
+                               "Cannot add field class found in stream class.");
+                       goto error;
+               }
+               break;
+       case NODE_TYPEALIAS:
+               ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
+                       node->u.field_class_alias.alias);
+               if (ret) {
+                       _BT_LOGE_NODE(node,
+                               "Cannot add field class alias found in stream class.");
+                       goto error;
+               }
+               break;
+       case NODE_CTF_EXPRESSION:
+       {
+               left = concatenate_unary_strings(&node->u.ctf_expression.left);
+               if (!left) {
+                       _BT_LOGE_NODE(node, "Cannot concatenate unary strings.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (!strcmp(left, "id")) {
+                       int64_t id;
+
+                       if (_IS_SET(set, _STREAM_ID_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "id",
+                                       "stream declaration");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
+                               (uint64_t *) &id);
+
+                       /* Only read "id" if get_unary_unsigned() succeeded. */
+                       if (ret || (!ret && id < 0)) {
+                               _BT_LOGE_NODE(node,
+                                       "Unexpected unary expression for stream class's `id` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (ctf_trace_class_borrow_stream_class_by_id(
+                                       ctx->ctf_tc, id)) {
+                               _BT_LOGE_NODE(node,
+                                       "Duplicate stream class (same ID): id=%" PRId64,
+                                       id);
+                               ret = -EEXIST;
+                               goto error;
+                       }
+
+                       stream_class->id = id;
+                       _SET(set, _STREAM_ID_SET);
+               } else if (!strcmp(left, "event.header")) {
+                       if (_IS_SET(set, _STREAM_EVENT_HEADER_SET)) {
+                               _BT_LOGE_NODE(node,
+                                       "Duplicate `event.header` entry in stream class.");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = visit_field_class_specifier_list(ctx,
+                               _BT_LIST_FIRST_ENTRY(
+                                       &node->u.ctf_expression.right,
+                                       struct ctf_node, siblings),
+                               &stream_class->event_header_fc);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot create stream class's event header field class.");
+                               goto error;
+                       }
+
+                       BT_ASSERT(stream_class->event_header_fc);
+                       ret = auto_map_fields_to_trace_clock_class(ctx,
+                               stream_class->event_header_fc, "timestamp");
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot automatically map specific event header field class fields named `timestamp` to trace's clock class.");
+                               goto error;
+                       }
+
+                       _SET(set, _STREAM_EVENT_HEADER_SET);
+               } else if (!strcmp(left, "event.context")) {
+                       if (_IS_SET(set, _STREAM_EVENT_CONTEXT_SET)) {
+                               _BT_LOGE_NODE(node,
+                                       "Duplicate `event.context` entry in stream class.");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = visit_field_class_specifier_list(ctx,
+                               _BT_LIST_FIRST_ENTRY(
+                                       &node->u.ctf_expression.right,
+                                       struct ctf_node, siblings),
+                               &stream_class->event_common_context_fc);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot create stream class's event context field class.");
+                               goto error;
+                       }
+
+                       BT_ASSERT(stream_class->event_common_context_fc);
+                       _SET(set, _STREAM_EVENT_CONTEXT_SET);
+               } else if (!strcmp(left, "packet.context")) {
+                       if (_IS_SET(set, _STREAM_PACKET_CONTEXT_SET)) {
+                               _BT_LOGE_NODE(node,
+                                       "Duplicate `packet.context` entry in stream class.");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = visit_field_class_specifier_list(ctx,
+                               _BT_LIST_FIRST_ENTRY(
+                                       &node->u.ctf_expression.right,
+                                       struct ctf_node, siblings),
+                               &stream_class->packet_context_fc);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot create stream class's packet context field class.");
+                               goto error;
+                       }
+
+                       BT_ASSERT(stream_class->packet_context_fc);
+                       ret = auto_map_fields_to_trace_clock_class(ctx,
+                               stream_class->packet_context_fc,
+                               "timestamp_begin");
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot automatically map specific packet context field class fields named `timestamp_begin` to trace's clock class.");
+                               goto error;
+                       }
+
+                       ret = auto_map_fields_to_trace_clock_class(ctx,
+                               stream_class->packet_context_fc,
+                               "timestamp_end");
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot automatically map specific packet context field class fields named `timestamp_end` to trace's clock class.");
+                               goto error;
+                       }
+
+                       _SET(set, _STREAM_PACKET_CONTEXT_SET);
+               } else {
+                       _BT_LOGW_NODE(node,
+                               "Unknown attribute in stream class: "
+                               "attr-name=\"%s\"", left);
+               }
+
+               g_free(left);
+               left = NULL;
+               break;
+       }
+
+       default:
+               ret = -EPERM;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       g_free(left);
+       return ret;
+}
+
+static
+int visit_stream_decl(struct ctx *ctx, struct ctf_node *node)
+{
+       int set = 0;
+       int ret = 0;
+       struct ctf_node *iter;
+       struct ctf_stream_class *stream_class = NULL;
+       struct bt_list_head *decl_list = &node->u.stream.declaration_list;
+
+       if (node->visited) {
+               goto end;
+       }
+
+       node->visited = TRUE;
+       stream_class = ctf_stream_class_create();
+       BT_ASSERT(stream_class);
+       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
+
+       bt_list_for_each_entry(iter, decl_list, siblings) {
+               ret = visit_stream_decl_entry(ctx, iter, stream_class, &set);
+               if (ret) {
+                       _BT_LOGE_NODE(iter,
+                               "Cannot visit stream class's entry: "
+                               "ret=%d", ret);
+                       ctx_pop_scope(ctx);
+                       goto error;
+               }
+       }
+
+       ctx_pop_scope(ctx);
+
+       if (_IS_SET(&set, _STREAM_ID_SET)) {
+               /* Check that packet header has `stream_id` field */
+               struct ctf_named_field_class *named_fc = NULL;
+
+               if (!ctx->ctf_tc->packet_header_fc) {
+                       _BT_LOGE_NODE(node,
+                               "Stream class has a `id` attribute, "
+                               "but trace has no packet header field class.");
+                       goto error;
+               }
+
+               named_fc = ctf_field_class_struct_borrow_member_by_name(
+                       (void *) ctx->ctf_tc->packet_header_fc, "stream_id");
+               if (!named_fc) {
+                       _BT_LOGE_NODE(node,
+                               "Stream class has a `id` attribute, "
+                               "but trace's packet header field class has no `stream_id` field.");
+                       goto error;
+               }
+
+               if (named_fc->fc->type != CTF_FIELD_CLASS_TYPE_INT &&
+                               named_fc->fc->type != CTF_FIELD_CLASS_TYPE_ENUM) {
+                       _BT_LOGE_NODE(node,
+                               "Stream class has a `id` attribute, "
+                               "but trace's packet header field class's `stream_id` field is not an integer field class.");
+                       goto error;
+               }
+       } else {
+               /* Allow only _one_ ID-less stream */
+               if (ctx->ctf_tc->stream_classes->len != 0) {
+                       _BT_LOGE_NODE(node,
+                               "Missing `id` attribute in stream class as there's more than one stream class in the trace.");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               /* Automatic ID: 0 */
+               stream_class->id = 0;
+       }
+
+       /*
+        * Make sure that this stream class's ID is currently unique in
+        * the trace.
+        */
+       if (ctf_trace_class_borrow_stream_class_by_id(ctx->ctf_tc,
+                       stream_class->id)) {
+               _BT_LOGE_NODE(node,
+                       "Duplicate stream class (same ID): id=%" PRId64,
+                       stream_class->id);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       g_ptr_array_add(ctx->ctf_tc->stream_classes, stream_class);
+       stream_class = NULL;
+       goto end;
+
+error:
+       ctf_stream_class_destroy(stream_class);
+       stream_class = NULL;
+
+end:
+       return ret;
+}
+
+static
+int visit_trace_decl_entry(struct ctx *ctx, struct ctf_node *node, int *set)
+{
+       int ret = 0;
+       char *left = NULL;
+       uint64_t val;
+
+       switch (node->type) {
+       case NODE_TYPEDEF:
+               ret = visit_field_class_def(ctx, node->u.field_class_def.field_class_specifier_list,
+                       &node->u.field_class_def.field_class_declarators);
+               if (ret) {
+                       _BT_LOGE_NODE(node,
+                               "Cannot add field class found in trace (`trace` block).");
+                       goto error;
+               }
+               break;
+       case NODE_TYPEALIAS:
+               ret = visit_field_class_alias(ctx, node->u.field_class_alias.target,
+                       node->u.field_class_alias.alias);
+               if (ret) {
+                       _BT_LOGE_NODE(node,
+                               "Cannot add field class alias found in trace (`trace` block).");
+                       goto error;
+               }
+               break;
+       case NODE_CTF_EXPRESSION:
+       {
+               left = concatenate_unary_strings(&node->u.ctf_expression.left);
+               if (!left) {
+                       _BT_LOGE_NODE(node, "Cannot concatenate unary strings.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (!strcmp(left, "major")) {
+                       if (_IS_SET(set, _TRACE_MAJOR_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "major", "trace");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
+                               &val);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Unexpected unary expression for trace's `major` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (val != 1) {
+                               _BT_LOGE_NODE(node,
+                                       "Invalid trace's `minor` attribute: expecting 1.");
+                               goto error;
+                       }
+
+                       ctx->ctf_tc->major = val;
+                       _SET(set, _TRACE_MAJOR_SET);
+               } else if (!strcmp(left, "minor")) {
+                       if (_IS_SET(set, _TRACE_MINOR_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "minor", "trace");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = get_unary_unsigned(&node->u.ctf_expression.right,
+                               &val);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Unexpected unary expression for trace's `minor` attribute.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (val != 8) {
+                               _BT_LOGE_NODE(node,
+                                       "Invalid trace's `minor` attribute: expecting 8.");
+                               goto error;
+                       }
+
+                       ctx->ctf_tc->minor = val;
+                       _SET(set, _TRACE_MINOR_SET);
+               } else if (!strcmp(left, "uuid")) {
+                       if (_IS_SET(set, _TRACE_UUID_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "uuid", "trace");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = get_unary_uuid(&node->u.ctf_expression.right,
+                               ctx->ctf_tc->uuid);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Invalid trace's `uuid` attribute.");
+                               goto error;
+                       }
+
+                       ctx->ctf_tc->is_uuid_set = true;
+                       _SET(set, _TRACE_UUID_SET);
+               } else if (!strcmp(left, "byte_order")) {
+                       /* Default byte order is already known at this stage */
+                       if (_IS_SET(set, _TRACE_BYTE_ORDER_SET)) {
+                               _BT_LOGE_DUP_ATTR(node, "byte_order",
+                                       "trace");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       BT_ASSERT(ctx->ctf_tc->default_byte_order != -1);
+                       _SET(set, _TRACE_BYTE_ORDER_SET);
+               } else if (!strcmp(left, "packet.header")) {
+                       if (_IS_SET(set, _TRACE_PACKET_HEADER_SET)) {
+                               _BT_LOGE_NODE(node,
+                                       "Duplicate `packet.header` entry in trace.");
+                               ret = -EPERM;
+                               goto error;
+                       }
+
+                       ret = visit_field_class_specifier_list(ctx,
+                               _BT_LIST_FIRST_ENTRY(
+                                       &node->u.ctf_expression.right,
+                                       struct ctf_node, siblings),
+                               &ctx->ctf_tc->packet_header_fc);
+                       if (ret) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot create trace's packet header field class.");
+                               goto error;
+                       }
+
+                       BT_ASSERT(ctx->ctf_tc->packet_header_fc);
+                       _SET(set, _TRACE_PACKET_HEADER_SET);
+               } else {
+                       _BT_LOGW_NODE(node,
+                               "Unknown attribute in stream class: "
+                               "attr-name=\"%s\"", left);
+               }
+
+               g_free(left);
+               left = NULL;
+               break;
+       }
+       default:
+               _BT_LOGE_NODE(node, "Unknown expression in trace.");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       g_free(left);
+       return ret;
+}
+
+static
+int visit_trace_decl(struct ctx *ctx, struct ctf_node *node)
+{
+       int ret = 0;
+       int set = 0;
+       struct ctf_node *iter;
+       struct bt_list_head *decl_list = &node->u.trace.declaration_list;
+
+       if (node->visited) {
+               goto end;
+       }
+
+       node->visited = TRUE;
+
+       if (ctx->is_trace_visited) {
+               _BT_LOGE_NODE(node, "Duplicate trace (`trace` block).");
+               ret = -EEXIST;
+               goto error;
+       }
+
+       _TRY_PUSH_SCOPE_OR_GOTO_ERROR();
+
+       bt_list_for_each_entry(iter, decl_list, siblings) {
+               ret = visit_trace_decl_entry(ctx, iter, &set);
+               if (ret) {
+                       _BT_LOGE_NODE(iter, "Cannot visit trace's entry (`trace` block): "
+                               "ret=%d", ret);
+                       ctx_pop_scope(ctx);
+                       goto error;
+               }
+       }
+
+       ctx_pop_scope(ctx);
+
+       if (!_IS_SET(&set, _TRACE_MAJOR_SET)) {
+               _BT_LOGE_NODE(node,
+                       "Missing `major` attribute in trace (`trace` block).");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (!_IS_SET(&set, _TRACE_MINOR_SET)) {
+               _BT_LOGE_NODE(node,
+                       "Missing `minor` attribute in trace (`trace` block).");
+               ret = -EPERM;
+               goto error;
+       }
+
+       if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
+               _BT_LOGE_NODE(node,
+                       "Missing `byte_order` attribute in trace (`trace` block).");
+               ret = -EPERM;
+               goto error;
+       }
+
+       ctx->is_trace_visited = true;
+
+end:
+       return 0;
+
+error:
+       return ret;
+}
+
+static
+int visit_env(struct ctx *ctx, struct ctf_node *node)
+{
+       int ret = 0;
+       char *left = NULL;
+       struct ctf_node *entry_node;
+       struct bt_list_head *decl_list = &node->u.env.declaration_list;
+
+       if (node->visited) {
+               goto end;
+       }
+
+       node->visited = TRUE;
+
+       bt_list_for_each_entry(entry_node, decl_list, siblings) {
+               struct bt_list_head *right_head =
+                       &entry_node->u.ctf_expression.right;
+
+               if (entry_node->type != NODE_CTF_EXPRESSION) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Wrong expression in environment entry: "
+                               "node-type=%d", entry_node->type);
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               left = concatenate_unary_strings(
+                       &entry_node->u.ctf_expression.left);
+               if (!left) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Cannot get environment entry's name.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (is_unary_string(right_head)) {
+                       char *right = concatenate_unary_strings(right_head);
+
+                       if (!right) {
+                               _BT_LOGE_NODE(entry_node,
+                                       "Unexpected unary expression for environment entry's value: "
+                                       "name=\"%s\"", left);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (strcmp(left, "tracer_name") == 0) {
+                               if (strncmp(right, "lttng", 5) == 0) {
+                                       BT_LOGI("Detected LTTng trace from `%s` environment value: "
+                                               "tracer-name=\"%s\"",
+                                               left, right);
+                                       ctx->is_lttng = true;
+                               }
+                       }
+
+                       ctf_trace_class_append_env_entry(ctx->ctf_tc,
+                               left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_STR,
+                               right, 0);
+                       g_free(right);
+               } else if (is_unary_unsigned(right_head) ||
+                               is_unary_signed(right_head)) {
+                       int64_t v;
+
+                       if (is_unary_unsigned(right_head)) {
+                               ret = get_unary_unsigned(right_head,
+                                       (uint64_t *) &v);
+                       } else {
+                               ret = get_unary_signed(right_head, &v);
+                       }
+                       if (ret) {
+                               _BT_LOGE_NODE(entry_node,
+                                       "Unexpected unary expression for environment entry's value: "
+                                       "name=\"%s\"", left);
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       ctf_trace_class_append_env_entry(ctx->ctf_tc,
+                               left, CTF_TRACE_CLASS_ENV_ENTRY_TYPE_INT,
+                               NULL, v);
+               } else {
+                       _BT_LOGW_NODE(entry_node,
+                               "Environment entry has unknown type: "
+                               "name=\"%s\"", left);
+               }
+
+               g_free(left);
+               left = NULL;
+       }
+
+end:
+       return 0;
+
+error:
+       g_free(left);
+       return ret;
+}
+
+static
+int set_trace_byte_order(struct ctx *ctx, struct ctf_node *trace_node)
+{
+       int ret = 0;
+       int set = 0;
+       char *left = NULL;
+       struct ctf_node *node;
+       struct bt_list_head *decl_list = &trace_node->u.trace.declaration_list;
+
+       bt_list_for_each_entry(node, decl_list, siblings) {
+               if (node->type == NODE_CTF_EXPRESSION) {
+                       struct ctf_node *right_node;
+
+                       left = concatenate_unary_strings(
+                               &node->u.ctf_expression.left);
+                       if (!left) {
+                               _BT_LOGE_NODE(node,
+                                       "Cannot concatenate unary strings.");
+                               ret = -EINVAL;
+                               goto error;
+                       }
+
+                       if (!strcmp(left, "byte_order")) {
+                               enum ctf_byte_order bo;
+
+                               if (_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
+                                       _BT_LOGE_DUP_ATTR(node, "byte_order",
+                                               "trace");
+                                       ret = -EPERM;
+                                       goto error;
+                               }
+
+                               _SET(&set, _TRACE_BYTE_ORDER_SET);
+                               right_node = _BT_LIST_FIRST_ENTRY(
+                                       &node->u.ctf_expression.right,
+                                       struct ctf_node, siblings);
+                               bo = byte_order_from_unary_expr(right_node);
+                               if (bo == -1) {
+                                       _BT_LOGE_NODE(node,
+                                               "Invalid `byte_order` attribute in trace (`trace` block): "
+                                               "expecting `le`, `be`, or `network`.");
+                                       ret = -EINVAL;
+                                       goto error;
+                               } else if (bo == CTF_BYTE_ORDER_DEFAULT) {
+                                       _BT_LOGE_NODE(node,
+                                               "Invalid `byte_order` attribute in trace (`trace` block): "
+                                               "cannot be set to `native` here.");
+                                       ret = -EPERM;
+                                       goto error;
+                               }
+
+                               ctx->ctf_tc->default_byte_order = bo;
+                       }
+
+                       g_free(left);
+                       left = NULL;
+               }
+       }
+
+       if (!_IS_SET(&set, _TRACE_BYTE_ORDER_SET)) {
+               _BT_LOGE_NODE(trace_node,
+                       "Missing `byte_order` attribute in trace (`trace` block).");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       g_free(left);
+       return ret;
+}
+
+static
+int visit_clock_decl_entry(struct ctx *ctx, struct ctf_node *entry_node,
+       struct ctf_clock_class *clock, int *set, int64_t *offset_seconds,
+       uint64_t *offset_cycles)
+{
+       int ret = 0;
+       char *left = NULL;
+
+       if (entry_node->type != NODE_CTF_EXPRESSION) {
+               _BT_LOGE_NODE(entry_node,
+                       "Unexpected node type: node-type=%d",
+                       entry_node->type);
+               ret = -EPERM;
+               goto error;
+       }
+
+       left = concatenate_unary_strings(&entry_node->u.ctf_expression.left);
+       if (!left) {
+               _BT_LOGE_NODE(entry_node, "Cannot concatenate unary strings.");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       if (!strcmp(left, "name")) {
+               char *right;
+
+               if (_IS_SET(set, _CLOCK_NAME_SET)) {
+                       _BT_LOGE_DUP_ATTR(entry_node, "name", "clock class");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               right = concatenate_unary_strings(
+                       &entry_node->u.ctf_expression.right);
+               if (!right) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Unexpected unary expression for clock class's `name` attribute.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               g_string_assign(clock->name, right);
+               g_free(right);
+               _SET(set, _CLOCK_NAME_SET);
+       } else if (!strcmp(left, "uuid")) {
+               uint8_t uuid[BABELTRACE_UUID_LEN];
+
+               if (_IS_SET(set, _CLOCK_UUID_SET)) {
+                       _BT_LOGE_DUP_ATTR(entry_node, "uuid", "clock class");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               ret = get_unary_uuid(&entry_node->u.ctf_expression.right, uuid);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Invalid clock class's `uuid` attribute.");
+                       goto error;
+               }
+
+               clock->has_uuid = true;
+               memcpy(&clock->uuid[0], uuid, 16);
+               _SET(set, _CLOCK_UUID_SET);
+       } else if (!strcmp(left, "description")) {
+               char *right;
+
+               if (_IS_SET(set, _CLOCK_DESCRIPTION_SET)) {
+                       _BT_LOGE_DUP_ATTR(entry_node, "description",
+                               "clock class");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               right = concatenate_unary_strings(
+                       &entry_node->u.ctf_expression.right);
+               if (!right) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Unexpected unary expression for clock class's `description` attribute.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               g_string_assign(clock->description, right);
+               g_free(right);
+               _SET(set, _CLOCK_DESCRIPTION_SET);
+       } else if (!strcmp(left, "freq")) {
+               uint64_t freq = UINT64_C(-1);
+
+               if (_IS_SET(set, _CLOCK_FREQ_SET)) {
+                       _BT_LOGE_DUP_ATTR(entry_node, "freq", "clock class");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               ret = get_unary_unsigned(
+                       &entry_node->u.ctf_expression.right, &freq);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Unexpected unary expression for clock class's `freq` attribute.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               if (freq == UINT64_C(-1) || freq == 0) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Invalid clock class frequency: freq=%" PRIu64,
+                               freq);
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               clock->frequency = freq;
+               _SET(set, _CLOCK_FREQ_SET);
+       } else if (!strcmp(left, "precision")) {
+               uint64_t precision;
+
+               if (_IS_SET(set, _CLOCK_PRECISION_SET)) {
+                       _BT_LOGE_DUP_ATTR(entry_node, "precision",
+                               "clock class");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               ret = get_unary_unsigned(
+                       &entry_node->u.ctf_expression.right, &precision);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Unexpected unary expression for clock class's `precision` attribute.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               clock->precision = precision;
+               _SET(set, _CLOCK_PRECISION_SET);
+       } else if (!strcmp(left, "offset_s")) {
+               if (_IS_SET(set, _CLOCK_OFFSET_S_SET)) {
+                       _BT_LOGE_DUP_ATTR(entry_node, "offset_s",
+                               "clock class");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               ret = get_unary_signed(
+                       &entry_node->u.ctf_expression.right, offset_seconds);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Unexpected unary expression for clock class's `offset_s` attribute.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               _SET(set, _CLOCK_OFFSET_S_SET);
+       } else if (!strcmp(left, "offset")) {
+               if (_IS_SET(set, _CLOCK_OFFSET_SET)) {
+                       _BT_LOGE_DUP_ATTR(entry_node, "offset", "clock class");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               ret = get_unary_unsigned(
+                       &entry_node->u.ctf_expression.right, offset_cycles);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Unexpected unary expression for clock class's `offset` attribute.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               _SET(set, _CLOCK_OFFSET_SET);
+       } else if (!strcmp(left, "absolute")) {
+               struct ctf_node *right;
+
+               if (_IS_SET(set, _CLOCK_ABSOLUTE_SET)) {
+                       _BT_LOGE_DUP_ATTR(entry_node, "absolute",
+                               "clock class");
+                       ret = -EPERM;
+                       goto error;
+               }
+
+               right = _BT_LIST_FIRST_ENTRY(
+                       &entry_node->u.ctf_expression.right,
+                       struct ctf_node, siblings);
+               ret = get_boolean(right);
+               if (ret < 0) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Unexpected unary expression for clock class's `absolute` attribute.");
+                       ret = -EINVAL;
+                       goto error;
+               }
+
+               clock->is_absolute = ret;
+               _SET(set, _CLOCK_ABSOLUTE_SET);
+       } else {
+               _BT_LOGW_NODE(entry_node,
+                       "Unknown attribute in clock class: attr-name=\"%s\"",
+                       left);
+       }
+
+       g_free(left);
+       left = NULL;
+       return 0;
+
+error:
+       g_free(left);
+       return ret;
+}
+
+static inline
+uint64_t cycles_from_ns(uint64_t frequency, uint64_t ns)
+{
+       uint64_t cycles;
+
+       /* 1GHz */
+       if (frequency == UINT64_C(1000000000)) {
+               cycles = ns;
+       } else {
+               cycles = (uint64_t) (((double) ns * (double) frequency) / 1e9);
+       }
+
+       return cycles;
+}
+
+static
+void calibrate_clock_class_offsets(int64_t *offset_seconds,
+               uint64_t *offset_cycles, uint64_t freq)
+{
+       if (*offset_cycles >= freq) {
+               const uint64_t s_in_offset_cycles = *offset_cycles / freq;
+
+               *offset_seconds += (int64_t) s_in_offset_cycles;
+               *offset_cycles -= (s_in_offset_cycles * freq);
+       }
+}
+
+static
+void apply_clock_class_offset(struct ctx *ctx,
+               struct ctf_clock_class *clock)
+{
+       uint64_t freq;
+       int64_t offset_s_to_apply = ctx->decoder_config.clock_class_offset_s;
+       uint64_t offset_ns_to_apply;
+       int64_t cur_offset_s;
+       uint64_t cur_offset_cycles;
+
+       if (ctx->decoder_config.clock_class_offset_s == 0 &&
+                       ctx->decoder_config.clock_class_offset_ns == 0) {
+               goto end;
+       }
+
+       /* Transfer nanoseconds to seconds as much as possible */
+       if (ctx->decoder_config.clock_class_offset_ns < 0) {
+               const int64_t abs_ns = -ctx->decoder_config.clock_class_offset_ns;
+               const int64_t abs_extra_s = abs_ns / INT64_C(1000000000) + 1;
+               const int64_t extra_s = -abs_extra_s;
+               const int64_t offset_ns = ctx->decoder_config.clock_class_offset_ns -
+                       (extra_s * INT64_C(1000000000));
+
+               BT_ASSERT(offset_ns > 0);
+               offset_ns_to_apply = (uint64_t) offset_ns;
+               offset_s_to_apply += extra_s;
+       } else {
+               const int64_t extra_s = ctx->decoder_config.clock_class_offset_ns /
+                       INT64_C(1000000000);
+               const int64_t offset_ns = ctx->decoder_config.clock_class_offset_ns -
+                       (extra_s * INT64_C(1000000000));
+
+               BT_ASSERT(offset_ns >= 0);
+               offset_ns_to_apply = (uint64_t) offset_ns;
+               offset_s_to_apply += extra_s;
+       }
+
+       freq = clock->frequency;
+       cur_offset_s = clock->offset_seconds;
+       cur_offset_cycles = clock->offset_cycles;
+
+       /* Apply offsets */
+       cur_offset_s += offset_s_to_apply;
+       cur_offset_cycles += cycles_from_ns(freq, offset_ns_to_apply);
+
+       /*
+        * Recalibrate offsets because the part in cycles can be greater
+        * than the frequency at this point.
+        */
+       calibrate_clock_class_offsets(&cur_offset_s, &cur_offset_cycles, freq);
+
+       /* Set final offsets */
+       clock->offset_seconds = cur_offset_s;
+       clock->offset_cycles = cur_offset_cycles;
+
+end:
+       return;
+}
+
+static
+int visit_clock_decl(struct ctx *ctx, struct ctf_node *clock_node)
+{
+       int ret = 0;
+       int set = 0;
+       struct ctf_clock_class *clock;
+       struct ctf_node *entry_node;
+       struct bt_list_head *decl_list = &clock_node->u.clock.declaration_list;
+       const char *clock_class_name;
+       int64_t offset_seconds = 0;
+       uint64_t offset_cycles = 0;
+       uint64_t freq;
+
+       if (clock_node->visited) {
+               return 0;
+       }
+
+       clock_node->visited = TRUE;
+
+       /* CTF 1.8's default frequency for a clock class is 1 GHz */
+       clock = ctf_clock_class_create();
+       if (!clock) {
+               _BT_LOGE_NODE(clock_node,
+                       "Cannot create default clock class.");
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       bt_list_for_each_entry(entry_node, decl_list, siblings) {
+               ret = visit_clock_decl_entry(ctx, entry_node, clock, &set,
+                       &offset_seconds, &offset_cycles);
+               if (ret) {
+                       _BT_LOGE_NODE(entry_node,
+                               "Cannot visit clock class's entry: ret=%d",
+                               ret);
+                       goto end;
+               }
+       }
+
+       if (!_IS_SET(&set, _CLOCK_NAME_SET)) {
+               _BT_LOGE_NODE(clock_node,
+                       "Missing `name` attribute in clock class.");
+               ret = -EPERM;
+               goto end;
+       }
+
+       clock_class_name = clock->name->str;
+       BT_ASSERT(clock_class_name);
+       if (ctx->is_lttng && strcmp(clock_class_name, "monotonic") == 0) {
+               /*
+                * Old versions of LTTng forgot to set its clock class
+                * as absolute, even if it is. This is important because
+                * it's a condition to be able to sort messages
+                * from different sources.
+                */
+               clock->is_absolute = true;
+       }
+
+       /*
+        * Adjust offsets so that the part in cycles is less than the
+        * frequency (move to the part in seconds).
+        */
+       freq = clock->frequency;
+       calibrate_clock_class_offsets(&offset_seconds, &offset_cycles, freq);
+       BT_ASSERT(offset_cycles < clock->frequency);
+       clock->offset_seconds = offset_seconds;
+       clock->offset_cycles = offset_cycles;
+       apply_clock_class_offset(ctx, clock);
+       g_ptr_array_add(ctx->ctf_tc->clock_classes, clock);
+       clock = NULL;
+
+end:
+       if (clock) {
+               ctf_clock_class_destroy(clock);
+       }
+
+       return ret;
+}
+
+static
+int visit_root_decl(struct ctx *ctx, struct ctf_node *root_decl_node)
+{
+       int ret = 0;
+
+       if (root_decl_node->visited) {
+               goto end;
+       }
+
+       root_decl_node->visited = TRUE;
+
+       switch (root_decl_node->type) {
+       case NODE_TYPEDEF:
+               ret = visit_field_class_def(ctx,
+                       root_decl_node->u.field_class_def.field_class_specifier_list,
+                       &root_decl_node->u.field_class_def.field_class_declarators);
+               if (ret) {
+                       _BT_LOGE_NODE(root_decl_node,
+                               "Cannot add field class found in root scope.");
+                       goto end;
+               }
+               break;
+       case NODE_TYPEALIAS:
+               ret = visit_field_class_alias(ctx, root_decl_node->u.field_class_alias.target,
+                       root_decl_node->u.field_class_alias.alias);
+               if (ret) {
+                       _BT_LOGE_NODE(root_decl_node,
+                               "Cannot add field class alias found in root scope.");
+                       goto end;
+               }
+               break;
+       case NODE_TYPE_SPECIFIER_LIST:
+       {
+               struct ctf_field_class *decl = NULL;
+
+               /*
+                * Just add the field class specifier to the root
+                * declaration scope. Put local reference.
+                */
+               ret = visit_field_class_specifier_list(ctx, root_decl_node, &decl);
+               if (ret) {
+                       _BT_LOGE_NODE(root_decl_node,
+                               "Cannot visit root scope's field class: "
+                               "ret=%d", ret);
+                       BT_ASSERT(!decl);
+                       goto end;
+               }
+
+               ctf_field_class_destroy(decl);
+               decl = NULL;
+               break;
+       }
+       default:
+               _BT_LOGE_NODE(root_decl_node,
+                       "Unexpected node type: node-type=%d",
+                       root_decl_node->type);
+               ret = -EPERM;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(
+               bt_self_component_source *self_comp,
+               const struct ctf_metadata_decoder_config *decoder_config)
+{
+       struct ctx *ctx = NULL;
+
+       /* Create visitor's context */
+       ctx = ctx_create(self_comp, decoder_config);
+       if (!ctx) {
+               BT_LOGE_STR("Cannot create visitor's context.");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ctx_destroy(ctx);
+       ctx = NULL;
+
+end:
+       return (void *) ctx;
+}
+
+BT_HIDDEN
+void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor)
+{
+       ctx_destroy((void *) visitor);
+}
+
+BT_HIDDEN
+bt_trace_class *ctf_visitor_generate_ir_get_ir_trace_class(
+               struct ctf_visitor_generate_ir *visitor)
+{
+       struct ctx *ctx = (void *) visitor;
+
+       BT_ASSERT(ctx);
+
+       if (ctx->trace_class) {
+               bt_trace_class_get_ref(ctx->trace_class);
+       }
+
+       return ctx->trace_class;
+}
+
+BT_HIDDEN
+struct ctf_trace_class *ctf_visitor_generate_ir_borrow_ctf_trace_class(
+               struct ctf_visitor_generate_ir *visitor)
+{
+       struct ctx *ctx = (void *) visitor;
+
+       BT_ASSERT(ctx);
+       BT_ASSERT(ctx->ctf_tc);
+       return ctx->ctf_tc;
+}
+
+BT_HIDDEN
+int ctf_visitor_generate_ir_visit_node(struct ctf_visitor_generate_ir *visitor,
+               struct ctf_node *node)
+{
+       int ret = 0;
+       struct ctx *ctx = (void *) visitor;
+
+       BT_LOGI_STR("Visiting metadata's AST to generate CTF IR objects.");
+
+       switch (node->type) {
+       case NODE_ROOT:
+       {
+               struct ctf_node *iter;
+               bool got_trace_decl = false;
+
+               /*
+                * The first thing we need is the native byte order of
+                * the trace block, because early class aliases can have
+                * a `byte_order` attribute set to `native`. If we don't
+                * have the native byte order yet, and we don't have any
+                * trace block yet, then fail with EINCOMPLETE.
+                */
+               if (ctx->ctf_tc->default_byte_order == -1) {
+                       bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+                               if (got_trace_decl) {
+                                       _BT_LOGE_NODE(node,
+                                               "Duplicate trace (`trace` block).");
+                                       ret = -1;
+                                       goto end;
+                               }
+
+                               ret = set_trace_byte_order(ctx, iter);
+                               if (ret) {
+                                       _BT_LOGE_NODE(node,
+                                               "Cannot set trace's native byte order: "
+                                               "ret=%d", ret);
+                                       goto end;
+                               }
+
+                               got_trace_decl = true;
+                       }
+
+                       if (!got_trace_decl) {
+                               BT_LOGD_STR("Incomplete AST: need trace (`trace` block).");
+                               ret = -EINCOMPLETE;
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_LITTLE ||
+                       ctx->ctf_tc->default_byte_order == CTF_BYTE_ORDER_BIG);
+               BT_ASSERT(ctx->current_scope &&
+                               ctx->current_scope->parent_scope == NULL);
+
+               /* Environment */
+               bt_list_for_each_entry(iter, &node->u.root.env, siblings) {
+                       ret = visit_env(ctx, iter);
+                       if (ret) {
+                               _BT_LOGE_NODE(iter,
+                                       "Cannot visit trace's environment (`env` block) entry: "
+                                       "ret=%d", ret);
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
+               /*
+                * Visit clock blocks.
+                */
+               bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
+                       ret = visit_clock_decl(ctx, iter);
+                       if (ret) {
+                               _BT_LOGE_NODE(iter,
+                                       "Cannot visit clock class: ret=%d",
+                                       ret);
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
+               /*
+                * Visit root declarations next, as they can be used by any
+                * following entity.
+                */
+               bt_list_for_each_entry(iter, &node->u.root.declaration_list,
+                               siblings) {
+                       ret = visit_root_decl(ctx, iter);
+                       if (ret) {
+                               _BT_LOGE_NODE(iter,
+                                       "Cannot visit root entry: ret=%d",
+                                       ret);
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
+               /* Callsite blocks are not supported */
+               bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
+                       _BT_LOGW_NODE(iter,
+                               "\"callsite\" blocks are not supported as of this version.");
+               }
+
+               BT_ASSERT(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
+               /* Trace */
+               bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+                       ret = visit_trace_decl(ctx, iter);
+                       if (ret) {
+                               _BT_LOGE_NODE(iter,
+                                       "Cannot visit trace (`trace` block): "
+                                       "ret=%d", ret);
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
+               /* Streams */
+               bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
+                       ret = visit_stream_decl(ctx, iter);
+                       if (ret) {
+                               _BT_LOGE_NODE(iter,
+                                       "Cannot visit stream class: ret=%d",
+                                       ret);
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+
+               /* Events */
+               bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
+                       ret = visit_event_decl(ctx, iter);
+                       if (ret) {
+                               _BT_LOGE_NODE(iter,
+                                       "Cannot visit event class: ret=%d",
+                                       ret);
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(ctx->current_scope &&
+                       ctx->current_scope->parent_scope == NULL);
+               break;
+       }
+       default:
+               _BT_LOGE_NODE(node,
+                       "Unexpected node type: node-type=%d",
+                       node->type);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Update default clock classes */
+       ret = ctf_trace_class_update_default_clock_classes(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Update trace class meanings */
+       ret = ctf_trace_class_update_meanings(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Update stream class configuration */
+       ret = ctf_trace_class_update_stream_class_config(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Update text arrays and sequences */
+       ret = ctf_trace_class_update_text_array_sequence(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Resolve sequence lengths and variant tags */
+       ret = ctf_trace_class_resolve_field_classes(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       if (ctx->trace_class) {
+               /*
+                * Update "in IR" for field classes.
+                *
+                * If we have no IR trace class, then we'll have no way
+                * to create IR fields anyway, so we leave all the
+                * `in_ir` members false.
+                */
+               ret = ctf_trace_class_update_in_ir(ctx->ctf_tc);
+               if (ret) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+       }
+
+       /* Update saved value indexes */
+       ret = ctf_trace_class_update_value_storing_indexes(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Validate what we have so far */
+       ret = ctf_trace_class_validate(ctx->ctf_tc);
+       if (ret) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /*
+        * If there are fields which are not related to the CTF format
+        * itself in the packet header and in event header field
+        * classes, warn about it because they are never translated.
+        */
+       ctf_trace_class_warn_meaningless_header_fields(ctx->ctf_tc);
+
+       if (ctx->trace_class) {
+               /* Copy new CTF metadata -> new IR metadata */
+               ret = ctf_trace_class_translate(ctx->self_comp,
+                               ctx->trace_class, ctx->ctf_tc);
+               if (ret) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/visitor-parent-links.c b/src/plugins/ctf/common/metadata/visitor-parent-links.c
new file mode 100644 (file)
index 0000000..64098a9
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * ctf-visitor-parent-links.c
+ *
+ * Common Trace Format Metadata Parent Link Creator.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-PARENT-LINKS-VISITOR"
+#include "logging.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "common/assert.h"
+#include <glib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "common/babeltrace.h"
+#include "common/list.h"
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+
+static
+int ctf_visitor_unary_expression(int depth, struct ctf_node *node)
+{
+       int ret = 0;
+
+       switch (node->u.unary_expression.link) {
+       case UNARY_LINK_UNKNOWN:
+       case UNARY_DOTLINK:
+       case UNARY_ARROWLINK:
+       case UNARY_DOTDOTDOT:
+               break;
+       default:
+               _BT_LOGE_LINENO(node->lineno,
+                       "Unknown expression link type: type=%d\n",
+                       node->u.unary_expression.link);
+               return -EINVAL;
+       }
+
+       switch (node->u.unary_expression.type) {
+       case UNARY_STRING:
+       case UNARY_SIGNED_CONSTANT:
+       case UNARY_UNSIGNED_CONSTANT:
+               break;
+       case UNARY_SBRAC:
+               node->u.unary_expression.u.sbrac_exp->parent = node;
+               ret = ctf_visitor_unary_expression(depth + 1,
+                       node->u.unary_expression.u.sbrac_exp);
+               if (ret)
+                       return ret;
+               break;
+
+       case UNARY_UNKNOWN:
+       default:
+               _BT_LOGE_LINENO(node->lineno,
+                       "Unknown expression link type: type=%d\n",
+                       node->u.unary_expression.link);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static
+int ctf_visitor_type_specifier(int depth, struct ctf_node *node)
+{
+       int ret;
+
+       switch (node->u.field_class_specifier.type) {
+       case TYPESPEC_VOID:
+       case TYPESPEC_CHAR:
+       case TYPESPEC_SHORT:
+       case TYPESPEC_INT:
+       case TYPESPEC_LONG:
+       case TYPESPEC_FLOAT:
+       case TYPESPEC_DOUBLE:
+       case TYPESPEC_SIGNED:
+       case TYPESPEC_UNSIGNED:
+       case TYPESPEC_BOOL:
+       case TYPESPEC_COMPLEX:
+       case TYPESPEC_IMAGINARY:
+       case TYPESPEC_CONST:
+       case TYPESPEC_ID_TYPE:
+               break;
+       case TYPESPEC_FLOATING_POINT:
+       case TYPESPEC_INTEGER:
+       case TYPESPEC_STRING:
+       case TYPESPEC_STRUCT:
+       case TYPESPEC_VARIANT:
+       case TYPESPEC_ENUM:
+               node->u.field_class_specifier.node->parent = node;
+               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_specifier.node);
+               if (ret)
+                       return ret;
+               break;
+
+       case TYPESPEC_UNKNOWN:
+       default:
+               _BT_LOGE_LINENO(node->lineno,
+                       "Unknown type specifier: type=%d\n",
+                       node->u.field_class_specifier.type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static
+int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+
+       depth++;
+
+       bt_list_for_each_entry(iter, &node->u.field_class_declarator.pointers,
+                               siblings) {
+               iter->parent = node;
+               ret = ctf_visitor_parent_links(depth + 1, iter);
+               if (ret)
+                       return ret;
+       }
+
+       switch (node->u.field_class_declarator.type) {
+       case TYPEDEC_ID:
+               break;
+       case TYPEDEC_NESTED:
+               if (node->u.field_class_declarator.u.nested.field_class_declarator) {
+                       node->u.field_class_declarator.u.nested.field_class_declarator->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1,
+                               node->u.field_class_declarator.u.nested.field_class_declarator);
+                       if (ret)
+                               return ret;
+               }
+               if (!node->u.field_class_declarator.u.nested.abstract_array) {
+                       bt_list_for_each_entry(iter, &node->u.field_class_declarator.u.nested.length,
+                                               siblings) {
+                               iter->parent = node;
+                               ret = ctf_visitor_parent_links(depth + 1, iter);
+                               if (ret)
+                                       return ret;
+                       }
+               }
+               if (node->u.field_class_declarator.bitfield_len) {
+                       node->u.field_class_declarator.bitfield_len = node;
+                       ret = ctf_visitor_parent_links(depth + 1,
+                               node->u.field_class_declarator.bitfield_len);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case TYPEDEC_UNKNOWN:
+       default:
+               _BT_LOGE_LINENO(node->lineno,
+                       "Unknown type declarator: type=%d\n",
+                       node->u.field_class_declarator.type);
+               return -EINVAL;
+       }
+       depth--;
+       return 0;
+}
+
+int ctf_visitor_parent_links(int depth, struct ctf_node *node)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+
+       if (node->visited)
+               return 0;
+
+       switch (node->type) {
+       case NODE_ROOT:
+               bt_list_for_each_entry(iter, &node->u.root.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.clock, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.callsite, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case NODE_EVENT:
+               bt_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_STREAM:
+               bt_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_ENV:
+               bt_list_for_each_entry(iter, &node->u.env.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_TRACE:
+               bt_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_CLOCK:
+               bt_list_for_each_entry(iter, &node->u.clock.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_CALLSITE:
+               bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case NODE_CTF_EXPRESSION:
+               depth++;
+               bt_list_for_each_entry(iter, &node->u.ctf_expression.left, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               depth--;
+               break;
+       case NODE_UNARY_EXPRESSION:
+               return ctf_visitor_unary_expression(depth, node);
+
+       case NODE_TYPEDEF:
+               depth++;
+               node->u.field_class_def.field_class_specifier_list->parent = node;
+               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_def.field_class_specifier_list);
+               if (ret)
+                       return ret;
+               bt_list_for_each_entry(iter, &node->u.field_class_def.field_class_declarators, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               depth--;
+               break;
+       case NODE_TYPEALIAS_TARGET:
+               depth++;
+               node->u.field_class_alias_target.field_class_specifier_list->parent = node;
+               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias_target.field_class_specifier_list);
+               if (ret)
+                       return ret;
+               bt_list_for_each_entry(iter, &node->u.field_class_alias_target.field_class_declarators, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               depth--;
+               break;
+       case NODE_TYPEALIAS_ALIAS:
+               depth++;
+               node->u.field_class_alias_name.field_class_specifier_list->parent = node;
+               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias_name.field_class_specifier_list);
+               if (ret)
+                       return ret;
+               bt_list_for_each_entry(iter, &node->u.field_class_alias_name.field_class_declarators, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               depth--;
+               break;
+       case NODE_TYPEALIAS:
+               node->u.field_class_alias.target->parent = node;
+               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias.target);
+               if (ret)
+                       return ret;
+               node->u.field_class_alias.alias->parent = node;
+               ret = ctf_visitor_parent_links(depth + 1, node->u.field_class_alias.alias);
+               if (ret)
+                       return ret;
+               break;
+
+       case NODE_TYPE_SPECIFIER_LIST:
+               bt_list_for_each_entry(iter, &node->u.field_class_specifier_list.head, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case NODE_TYPE_SPECIFIER:
+               ret = ctf_visitor_type_specifier(depth, node);
+               if (ret)
+                       return ret;
+               break;
+       case NODE_POINTER:
+               break;
+       case NODE_TYPE_DECLARATOR:
+               ret = ctf_visitor_field_class_declarator(depth, node);
+               if (ret)
+                       return ret;
+               break;
+
+       case NODE_FLOATING_POINT:
+               bt_list_for_each_entry(iter, &node->u.floating_point.expressions, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_INTEGER:
+               bt_list_for_each_entry(iter, &node->u.integer.expressions, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_STRING:
+               bt_list_for_each_entry(iter, &node->u.string.expressions, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_ENUMERATOR:
+               bt_list_for_each_entry(iter, &node->u.enumerator.values, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_ENUM:
+               depth++;
+               if (node->u._enum.container_field_class) {
+                       ret = ctf_visitor_parent_links(depth + 1, node->u._enum.container_field_class);
+                       if (ret)
+                               return ret;
+               }
+
+               bt_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               depth--;
+               break;
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               node->u.struct_or_variant_declaration.field_class_specifier_list->parent = node;
+               ret = ctf_visitor_parent_links(depth + 1,
+                       node->u.struct_or_variant_declaration.field_class_specifier_list);
+               if (ret)
+                       return ret;
+               bt_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_VARIANT:
+               bt_list_for_each_entry(iter, &node->u.variant.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_STRUCT:
+               bt_list_for_each_entry(iter, &node->u._struct.declaration_list, siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u._struct.min_align,
+                                       siblings) {
+                       iter->parent = node;
+                       ret = ctf_visitor_parent_links(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case NODE_UNKNOWN:
+       default:
+               _BT_LOGE_LINENO(node->lineno,
+                       "Unknown node type: type=%d\n", node->type);
+               return -EINVAL;
+       }
+       return ret;
+}
diff --git a/src/plugins/ctf/common/metadata/visitor-semantic-validator.c b/src/plugins/ctf/common/metadata/visitor-semantic-validator.c
new file mode 100644 (file)
index 0000000..5592d6d
--- /dev/null
@@ -0,0 +1,1012 @@
+/*
+ * ctf-visitor-semantic-validator.c
+ *
+ * Common Trace Format Metadata Semantic Validator.
+ *
+ * Copyright 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-METADATA-SEMANTIC-VALIDATOR-VISITOR"
+#include "logging.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include "common/assert.h"
+#include <glib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include "common/list.h"
+#include "scanner.h"
+#include "parser.h"
+#include "ast.h"
+
+#define _bt_list_first_entry(ptr, type, member)        \
+       bt_list_entry((ptr)->next, type, member)
+
+static
+int _ctf_visitor_semantic_check(int depth, struct ctf_node *node);
+
+static
+int ctf_visitor_unary_expression(int depth, struct ctf_node *node)
+{
+       struct ctf_node *iter;
+       int is_ctf_exp = 0, is_ctf_exp_left = 0;
+
+       switch (node->parent->type) {
+       case NODE_CTF_EXPRESSION:
+               is_ctf_exp = 1;
+               bt_list_for_each_entry(iter, &node->parent->u.ctf_expression.left,
+                                       siblings) {
+                       if (iter == node) {
+                               is_ctf_exp_left = 1;
+                               /*
+                                * We are a left child of a ctf expression.
+                                * We are only allowed to be a string.
+                                */
+                               if (node->u.unary_expression.type != UNARY_STRING) {
+                                       _BT_LOGE_LINENO(node->lineno,
+                                               "Left child of a CTF expression is only allowed to be a string.");
+                                       goto errperm;
+                               }
+                               break;
+                       }
+               }
+               /* Right child of a ctf expression can be any type of unary exp. */
+               break;                  /* OK */
+       case NODE_TYPE_DECLARATOR:
+               /*
+                * We are the length of a type declarator.
+                */
+               switch (node->u.unary_expression.type) {
+               case UNARY_UNSIGNED_CONSTANT:
+               case UNARY_STRING:
+                       break;
+               default:
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Children of field class declarator and `enum` can only be unsigned numeric constants or references to fields (e.g., `a.b.c`).");
+                       goto errperm;
+               }
+               break;                  /* OK */
+
+       case NODE_STRUCT:
+               /*
+                * We are the size of a struct align attribute.
+                */
+               switch (node->u.unary_expression.type) {
+               case UNARY_UNSIGNED_CONSTANT:
+                       break;
+               default:
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Structure alignment attribute can only be an unsigned numeric constant.");
+                       goto errperm;
+               }
+               break;
+
+       case NODE_ENUMERATOR:
+               /* The enumerator's parent has validated its validity already. */
+               break;                  /* OK */
+
+       case NODE_UNARY_EXPRESSION:
+               /*
+                * We disallow nested unary expressions and "sbrac" unary
+                * expressions.
+                */
+               _BT_LOGE_LINENO(node->lineno,
+                       "Nested unary expressions not allowed (`()` and `[]`).");
+               goto errperm;
+
+       case NODE_ROOT:
+       case NODE_EVENT:
+       case NODE_STREAM:
+       case NODE_ENV:
+       case NODE_TRACE:
+       case NODE_CLOCK:
+       case NODE_CALLSITE:
+       case NODE_TYPEDEF:
+       case NODE_TYPEALIAS_TARGET:
+       case NODE_TYPEALIAS_ALIAS:
+       case NODE_TYPEALIAS:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_POINTER:
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_ENUM:
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+       case NODE_VARIANT:
+       default:
+               goto errinval;
+       }
+
+       switch (node->u.unary_expression.link) {
+       case UNARY_LINK_UNKNOWN:
+               /* We don't allow empty link except on the first node of the list */
+               if (is_ctf_exp && _bt_list_first_entry(is_ctf_exp_left ?
+                                         &node->parent->u.ctf_expression.left :
+                                         &node->parent->u.ctf_expression.right,
+                                         struct ctf_node,
+                                         siblings) != node) {
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Empty link is not allowed except on first node of unary expression (need to separate nodes with `.` or `->`).");
+                       goto errperm;
+               }
+               break;                  /* OK */
+       case UNARY_DOTLINK:
+       case UNARY_ARROWLINK:
+               /* We only allow -> and . links between children of ctf_expression. */
+               if (node->parent->type != NODE_CTF_EXPRESSION) {
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Links `.` and `->` are only allowed as children of CTF expression.");
+                       goto errperm;
+               }
+               /*
+                * Only strings can be separated linked by . or ->.
+                * This includes "", '' and non-quoted identifiers.
+                */
+               if (node->u.unary_expression.type != UNARY_STRING) {
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Links `.` and `->` are only allowed to separate strings and identifiers.");
+                       goto errperm;
+               }
+               /* We don't allow link on the first node of the list */
+               if (is_ctf_exp && _bt_list_first_entry(is_ctf_exp_left ?
+                                         &node->parent->u.ctf_expression.left :
+                                         &node->parent->u.ctf_expression.right,
+                                         struct ctf_node,
+                                         siblings) == node) {
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Links `.` and `->` are not allowed before first node of the unary expression list.");
+                       goto errperm;
+               }
+               break;
+       case UNARY_DOTDOTDOT:
+               /* We only allow ... link between children of enumerator. */
+               if (node->parent->type != NODE_ENUMERATOR) {
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Link `...` is only allowed within enumerator.");
+                       goto errperm;
+               }
+               /* We don't allow link on the first node of the list */
+               if (_bt_list_first_entry(&node->parent->u.enumerator.values,
+                                         struct ctf_node,
+                                         siblings) == node) {
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Link `...` is not allowed on the first node of the unary expression list.");
+                       goto errperm;
+               }
+               break;
+       default:
+               _BT_LOGE_LINENO(node->lineno,
+                       "Unknown expression link type: type=%d",
+                       node->u.unary_expression.link);
+               return -EINVAL;
+       }
+       return 0;
+
+errinval:
+       _BT_LOGE_LINENO(node->lineno,
+               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
+               node_type(node), node_type(node->parent));
+       return -EINVAL;         /* Incoherent structure */
+
+errperm:
+       _BT_LOGE_LINENO(node->lineno,
+               "Semantic error: node-type=%s, parent-node-type=%s",
+               node_type(node), node_type(node->parent));
+       return -EPERM;          /* Structure not allowed */
+}
+
+static
+int ctf_visitor_field_class_specifier_list(int depth, struct ctf_node *node)
+{
+       switch (node->parent->type) {
+       case NODE_CTF_EXPRESSION:
+       case NODE_TYPE_DECLARATOR:
+       case NODE_TYPEDEF:
+       case NODE_TYPEALIAS_TARGET:
+       case NODE_TYPEALIAS_ALIAS:
+       case NODE_ENUM:
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+       case NODE_ROOT:
+               break;                  /* OK */
+
+       case NODE_EVENT:
+       case NODE_STREAM:
+       case NODE_ENV:
+       case NODE_TRACE:
+       case NODE_CLOCK:
+       case NODE_CALLSITE:
+       case NODE_UNARY_EXPRESSION:
+       case NODE_TYPEALIAS:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_TYPE_SPECIFIER_LIST:
+       case NODE_POINTER:
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_ENUMERATOR:
+       case NODE_VARIANT:
+       case NODE_STRUCT:
+       default:
+               goto errinval;
+       }
+       return 0;
+errinval:
+       _BT_LOGE_LINENO(node->lineno,
+               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
+               node_type(node), node_type(node->parent));
+       return -EINVAL;         /* Incoherent structure */
+}
+
+static
+int ctf_visitor_field_class_specifier(int depth, struct ctf_node *node)
+{
+       switch (node->parent->type) {
+       case NODE_TYPE_SPECIFIER_LIST:
+               break;                  /* OK */
+
+       case NODE_CTF_EXPRESSION:
+       case NODE_TYPE_DECLARATOR:
+       case NODE_TYPEDEF:
+       case NODE_TYPEALIAS_TARGET:
+       case NODE_TYPEALIAS_ALIAS:
+       case NODE_ENUM:
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+       case NODE_ROOT:
+       case NODE_EVENT:
+       case NODE_STREAM:
+       case NODE_ENV:
+       case NODE_TRACE:
+       case NODE_CLOCK:
+       case NODE_CALLSITE:
+       case NODE_UNARY_EXPRESSION:
+       case NODE_TYPEALIAS:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_POINTER:
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_ENUMERATOR:
+       case NODE_VARIANT:
+       case NODE_STRUCT:
+       default:
+               goto errinval;
+       }
+       return 0;
+errinval:
+       _BT_LOGE_LINENO(node->lineno,
+               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
+               node_type(node), node_type(node->parent));
+       return -EINVAL;         /* Incoherent structure */
+}
+
+static
+int ctf_visitor_field_class_declarator(int depth, struct ctf_node *node)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+
+       depth++;
+
+       switch (node->parent->type) {
+       case NODE_TYPE_DECLARATOR:
+               /*
+                * A nested field class declarator is not allowed to
+                * contain pointers.
+                */
+               if (!bt_list_empty(&node->u.field_class_declarator.pointers))
+                       goto errperm;
+               break;                  /* OK */
+       case NODE_TYPEALIAS_TARGET:
+               break;                  /* OK */
+       case NODE_TYPEALIAS_ALIAS:
+               /*
+                * Only accept alias name containing:
+                * - identifier
+                * - identifier *   (any number of pointers)
+                * NOT accepting alias names containing [] (would otherwise
+                * cause semantic clash for later declarations of
+                * arrays/sequences of elements, where elements could be
+                * arrays/sequences themselves (if allowed in field class alias).
+                * NOT accepting alias with identifier. The declarator should
+                * be either empty or contain pointer(s).
+                */
+               if (node->u.field_class_declarator.type == TYPEDEC_NESTED)
+                       goto errperm;
+               bt_list_for_each_entry(iter, &node->parent->u.field_class_alias_name.field_class_specifier_list->u.field_class_specifier_list.head,
+                                       siblings) {
+                       switch (iter->u.field_class_specifier.type) {
+                       case TYPESPEC_FLOATING_POINT:
+                       case TYPESPEC_INTEGER:
+                       case TYPESPEC_STRING:
+                       case TYPESPEC_STRUCT:
+                       case TYPESPEC_VARIANT:
+                       case TYPESPEC_ENUM:
+                               if (bt_list_empty(&node->u.field_class_declarator.pointers))
+                                       goto errperm;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               if (node->u.field_class_declarator.type == TYPEDEC_ID &&
+                   node->u.field_class_declarator.u.id != NULL)
+                       goto errperm;
+               break;                  /* OK */
+       case NODE_TYPEDEF:
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               break;                  /* OK */
+
+       case NODE_ROOT:
+       case NODE_EVENT:
+       case NODE_STREAM:
+       case NODE_ENV:
+       case NODE_TRACE:
+       case NODE_CLOCK:
+       case NODE_CALLSITE:
+       case NODE_CTF_EXPRESSION:
+       case NODE_UNARY_EXPRESSION:
+       case NODE_TYPEALIAS:
+       case NODE_TYPE_SPECIFIER:
+       case NODE_POINTER:
+       case NODE_FLOATING_POINT:
+       case NODE_INTEGER:
+       case NODE_STRING:
+       case NODE_ENUMERATOR:
+       case NODE_ENUM:
+       case NODE_VARIANT:
+       case NODE_STRUCT:
+       default:
+               goto errinval;
+       }
+
+       bt_list_for_each_entry(iter, &node->u.field_class_declarator.pointers,
+                               siblings) {
+               ret = _ctf_visitor_semantic_check(depth + 1, iter);
+               if (ret)
+                       return ret;
+       }
+
+       switch (node->u.field_class_declarator.type) {
+       case TYPEDEC_ID:
+               break;
+       case TYPEDEC_NESTED:
+       {
+               if (node->u.field_class_declarator.u.nested.field_class_declarator) {
+                       ret = _ctf_visitor_semantic_check(depth + 1,
+                               node->u.field_class_declarator.u.nested.field_class_declarator);
+                       if (ret)
+                               return ret;
+               }
+               if (!node->u.field_class_declarator.u.nested.abstract_array) {
+                       bt_list_for_each_entry(iter, &node->u.field_class_declarator.u.nested.length,
+                                               siblings) {
+                               if (iter->type != NODE_UNARY_EXPRESSION) {
+                                       _BT_LOGE_LINENO(node->lineno,
+                                               "Expecting unary expression as length: node-type=%s",
+                                               node_type(iter));
+                                       return -EINVAL;
+                               }
+                               ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                               if (ret)
+                                       return ret;
+                       }
+               } else {
+                       if (node->parent->type == NODE_TYPEALIAS_TARGET) {
+                               _BT_LOGE_LINENO(node->lineno,
+                                       "Abstract array declarator not permitted as target of field class alias.");
+                               return -EINVAL;
+                       }
+               }
+               if (node->u.field_class_declarator.bitfield_len) {
+                       ret = _ctf_visitor_semantic_check(depth + 1,
+                               node->u.field_class_declarator.bitfield_len);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       }
+       case TYPEDEC_UNKNOWN:
+       default:
+               _BT_LOGE_LINENO(node->lineno,
+                       "Unknown field class declarator: type=%d",
+                       node->u.field_class_declarator.type);
+               return -EINVAL;
+       }
+       depth--;
+       return 0;
+
+errinval:
+       _BT_LOGE_LINENO(node->lineno,
+               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
+               node_type(node), node_type(node->parent));
+       return -EINVAL;         /* Incoherent structure */
+
+errperm:
+       _BT_LOGE_LINENO(node->lineno,
+               "Semantic error: node-type=%s, parent-node-type=%s",
+               node_type(node), node_type(node->parent));
+       return -EPERM;          /* Structure not allowed */
+}
+
+static
+int _ctf_visitor_semantic_check(int depth, struct ctf_node *node)
+{
+       int ret = 0;
+       struct ctf_node *iter;
+
+       if (node->visited)
+               return 0;
+
+       switch (node->type) {
+       case NODE_ROOT:
+               bt_list_for_each_entry(iter, &node->u.root.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.trace, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.stream, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.root.event, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case NODE_EVENT:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+
+               bt_list_for_each_entry(iter, &node->u.event.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_STREAM:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+
+               bt_list_for_each_entry(iter, &node->u.stream.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_ENV:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+
+               bt_list_for_each_entry(iter, &node->u.env.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_TRACE:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+
+               bt_list_for_each_entry(iter, &node->u.trace.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_CLOCK:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+
+               bt_list_for_each_entry(iter, &node->u.clock.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_CALLSITE:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+
+               bt_list_for_each_entry(iter, &node->u.callsite.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case NODE_CTF_EXPRESSION:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+               case NODE_EVENT:
+               case NODE_STREAM:
+               case NODE_ENV:
+               case NODE_TRACE:
+               case NODE_CLOCK:
+               case NODE_CALLSITE:
+               case NODE_FLOATING_POINT:
+               case NODE_INTEGER:
+               case NODE_STRING:
+                       break;                  /* OK */
+
+               case NODE_CTF_EXPRESSION:
+               case NODE_UNARY_EXPRESSION:
+               case NODE_TYPEDEF:
+               case NODE_TYPEALIAS_TARGET:
+               case NODE_TYPEALIAS_ALIAS:
+               case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               case NODE_TYPEALIAS:
+               case NODE_TYPE_SPECIFIER:
+               case NODE_TYPE_SPECIFIER_LIST:
+               case NODE_POINTER:
+               case NODE_TYPE_DECLARATOR:
+               case NODE_ENUMERATOR:
+               case NODE_ENUM:
+               case NODE_VARIANT:
+               case NODE_STRUCT:
+               default:
+                       goto errinval;
+               }
+
+               depth++;
+               bt_list_for_each_entry(iter, &node->u.ctf_expression.left, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               bt_list_for_each_entry(iter, &node->u.ctf_expression.right, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               depth--;
+               break;
+       case NODE_UNARY_EXPRESSION:
+               return ctf_visitor_unary_expression(depth, node);
+
+       case NODE_TYPEDEF:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+               case NODE_EVENT:
+               case NODE_STREAM:
+               case NODE_TRACE:
+               case NODE_VARIANT:
+               case NODE_STRUCT:
+                       break;                  /* OK */
+
+               case NODE_CTF_EXPRESSION:
+               case NODE_UNARY_EXPRESSION:
+               case NODE_TYPEDEF:
+               case NODE_TYPEALIAS_TARGET:
+               case NODE_TYPEALIAS_ALIAS:
+               case NODE_TYPEALIAS:
+               case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               case NODE_TYPE_SPECIFIER:
+               case NODE_TYPE_SPECIFIER_LIST:
+               case NODE_POINTER:
+               case NODE_TYPE_DECLARATOR:
+               case NODE_FLOATING_POINT:
+               case NODE_INTEGER:
+               case NODE_STRING:
+               case NODE_ENUMERATOR:
+               case NODE_ENUM:
+               case NODE_CLOCK:
+               case NODE_CALLSITE:
+               case NODE_ENV:
+               default:
+                       goto errinval;
+               }
+
+               depth++;
+               ret = _ctf_visitor_semantic_check(depth + 1,
+                       node->u.field_class_def.field_class_specifier_list);
+               if (ret)
+                       return ret;
+               bt_list_for_each_entry(iter, &node->u.field_class_def.field_class_declarators, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               depth--;
+               break;
+       case NODE_TYPEALIAS_TARGET:
+       {
+               int nr_declarators;
+
+               switch (node->parent->type) {
+               case NODE_TYPEALIAS:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+
+               depth++;
+               ret = _ctf_visitor_semantic_check(depth + 1,
+                       node->u.field_class_alias_target.field_class_specifier_list);
+               if (ret)
+                       return ret;
+               nr_declarators = 0;
+               bt_list_for_each_entry(iter, &node->u.field_class_alias_target.field_class_declarators, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+                       nr_declarators++;
+               }
+               if (nr_declarators > 1) {
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Too many declarators in field class alias's name (maximum is 1): count=%d",
+                               nr_declarators);
+                       return -EINVAL;
+               }
+               depth--;
+               break;
+       }
+       case NODE_TYPEALIAS_ALIAS:
+       {
+               int nr_declarators;
+
+               switch (node->parent->type) {
+               case NODE_TYPEALIAS:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+
+               depth++;
+               ret = _ctf_visitor_semantic_check(depth + 1,
+                       node->u.field_class_alias_name.field_class_specifier_list);
+               if (ret)
+                       return ret;
+               nr_declarators = 0;
+               bt_list_for_each_entry(iter, &node->u.field_class_alias_name.field_class_declarators, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+                       nr_declarators++;
+               }
+               if (nr_declarators > 1) {
+                       _BT_LOGE_LINENO(node->lineno,
+                               "Too many declarators in field class alias's name (maximum is 1): count=%d",
+                               nr_declarators);
+                       return -EINVAL;
+               }
+               depth--;
+               break;
+       }
+       case NODE_TYPEALIAS:
+               switch (node->parent->type) {
+               case NODE_ROOT:
+               case NODE_EVENT:
+               case NODE_STREAM:
+               case NODE_TRACE:
+               case NODE_VARIANT:
+               case NODE_STRUCT:
+                       break;                  /* OK */
+
+               case NODE_CTF_EXPRESSION:
+               case NODE_UNARY_EXPRESSION:
+               case NODE_TYPEDEF:
+               case NODE_TYPEALIAS_TARGET:
+               case NODE_TYPEALIAS_ALIAS:
+               case NODE_TYPEALIAS:
+               case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               case NODE_TYPE_SPECIFIER:
+               case NODE_TYPE_SPECIFIER_LIST:
+               case NODE_POINTER:
+               case NODE_TYPE_DECLARATOR:
+               case NODE_FLOATING_POINT:
+               case NODE_INTEGER:
+               case NODE_STRING:
+               case NODE_ENUMERATOR:
+               case NODE_ENUM:
+               case NODE_CLOCK:
+               case NODE_CALLSITE:
+               case NODE_ENV:
+               default:
+                       goto errinval;
+               }
+
+               ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.target);
+               if (ret)
+                       return ret;
+               ret = _ctf_visitor_semantic_check(depth + 1, node->u.field_class_alias.alias);
+               if (ret)
+                       return ret;
+               break;
+
+       case NODE_TYPE_SPECIFIER_LIST:
+               ret = ctf_visitor_field_class_specifier_list(depth, node);
+               if (ret)
+                       return ret;
+               break;
+       case NODE_TYPE_SPECIFIER:
+               ret = ctf_visitor_field_class_specifier(depth, node);
+               if (ret)
+                       return ret;
+               break;
+       case NODE_POINTER:
+               switch (node->parent->type) {
+               case NODE_TYPE_DECLARATOR:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+               }
+               break;
+       case NODE_TYPE_DECLARATOR:
+               ret = ctf_visitor_field_class_declarator(depth, node);
+               if (ret)
+                       return ret;
+               break;
+
+       case NODE_FLOATING_POINT:
+               switch (node->parent->type) {
+               case NODE_TYPE_SPECIFIER:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+
+               case NODE_UNARY_EXPRESSION:
+                       goto errperm;
+               }
+               bt_list_for_each_entry(iter, &node->u.floating_point.expressions, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_INTEGER:
+               switch (node->parent->type) {
+               case NODE_TYPE_SPECIFIER:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+
+               }
+
+               bt_list_for_each_entry(iter, &node->u.integer.expressions, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_STRING:
+               switch (node->parent->type) {
+               case NODE_TYPE_SPECIFIER:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+
+               case NODE_UNARY_EXPRESSION:
+                       goto errperm;
+               }
+
+               bt_list_for_each_entry(iter, &node->u.string.expressions, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_ENUMERATOR:
+               switch (node->parent->type) {
+               case NODE_ENUM:
+                       break;
+               default:
+                       goto errinval;
+               }
+               /*
+                * Enumerators are only allows to contain:
+                *    numeric unary expression
+                * or num. unary exp. ... num. unary exp
+                */
+               {
+                       int count = 0;
+
+                       bt_list_for_each_entry(iter, &node->u.enumerator.values,
+                                               siblings) {
+                               switch (count++) {
+                               case 0: if (iter->type != NODE_UNARY_EXPRESSION
+                                           || (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT
+                                               && iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT)
+                                           || iter->u.unary_expression.link != UNARY_LINK_UNKNOWN) {
+                                               _BT_LOGE_LINENO(iter->lineno,
+                                                       "First unary expression of enumerator is unexpected.");
+                                               goto errperm;
+                                       }
+                                       break;
+                               case 1: if (iter->type != NODE_UNARY_EXPRESSION
+                                           || (iter->u.unary_expression.type != UNARY_SIGNED_CONSTANT
+                                               && iter->u.unary_expression.type != UNARY_UNSIGNED_CONSTANT)
+                                           || iter->u.unary_expression.link != UNARY_DOTDOTDOT) {
+                                               _BT_LOGE_LINENO(iter->lineno,
+                                                       "Second unary expression of enumerator is unexpected.");
+                                               goto errperm;
+                                       }
+                                       break;
+                               default:
+                                       goto errperm;
+                               }
+                       }
+               }
+
+               bt_list_for_each_entry(iter, &node->u.enumerator.values, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_ENUM:
+               switch (node->parent->type) {
+               case NODE_TYPE_SPECIFIER:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+
+               case NODE_UNARY_EXPRESSION:
+                       goto errperm;
+               }
+
+               depth++;
+               ret = _ctf_visitor_semantic_check(depth + 1, node->u._enum.container_field_class);
+               if (ret)
+                       return ret;
+
+               bt_list_for_each_entry(iter, &node->u._enum.enumerator_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               depth--;
+               break;
+       case NODE_STRUCT_OR_VARIANT_DECLARATION:
+               switch (node->parent->type) {
+               case NODE_STRUCT:
+               case NODE_VARIANT:
+                       break;
+               default:
+                       goto errinval;
+               }
+               ret = _ctf_visitor_semantic_check(depth + 1,
+                       node->u.struct_or_variant_declaration.field_class_specifier_list);
+               if (ret)
+                       return ret;
+               bt_list_for_each_entry(iter, &node->u.struct_or_variant_declaration.field_class_declarators, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+       case NODE_VARIANT:
+               switch (node->parent->type) {
+               case NODE_TYPE_SPECIFIER:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+
+               case NODE_UNARY_EXPRESSION:
+                       goto errperm;
+               }
+               bt_list_for_each_entry(iter, &node->u.variant.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case NODE_STRUCT:
+               switch (node->parent->type) {
+               case NODE_TYPE_SPECIFIER:
+                       break;                  /* OK */
+               default:
+                       goto errinval;
+
+               case NODE_UNARY_EXPRESSION:
+                       goto errperm;
+               }
+               bt_list_for_each_entry(iter, &node->u._struct.declaration_list, siblings) {
+                       ret = _ctf_visitor_semantic_check(depth + 1, iter);
+                       if (ret)
+                               return ret;
+               }
+               break;
+
+       case NODE_UNKNOWN:
+       default:
+               _BT_LOGE_LINENO(node->lineno,
+                       "Unknown node type: type=%d", node->type);
+               return -EINVAL;
+       }
+       return ret;
+
+errinval:
+       _BT_LOGE_LINENO(node->lineno,
+               "Incoherent parent node's type: node-type=%s, parent-node-type=%s",
+               node_type(node), node_type(node->parent));
+       return -EINVAL;         /* Incoherent structure */
+
+errperm:
+       _BT_LOGE_LINENO(node->lineno,
+               "Semantic error: node-type=%s, parent-node-type=%s",
+               node_type(node), node_type(node->parent));
+       return -EPERM;          /* Structure not allowed */
+}
+
+int ctf_visitor_semantic_check(int depth, struct ctf_node *node)
+{
+       int ret = 0;
+
+       /*
+        * First make sure we create the parent links for all children. Let's
+        * take the safe route and recreate them at each validation, just in
+        * case the structure has changed.
+        */
+       ret = ctf_visitor_parent_links(depth, node);
+       if (ret) {
+               _BT_LOGE_LINENO(node->lineno,
+                       "Cannot create parent links in metadata's AST: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+       ret = _ctf_visitor_semantic_check(depth, node);
+       if (ret) {
+               _BT_LOGE_LINENO(node->lineno,
+                       "Cannot check metadata's AST semantics: "
+                       "ret=%d", ret);
+               goto end;
+       }
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/common/msg-iter/Makefile.am b/src/plugins/ctf/common/msg-iter/Makefile.am
new file mode 100644 (file)
index 0000000..7c3c208
--- /dev/null
@@ -0,0 +1,7 @@
+noinst_LTLIBRARIES = libctf-msg-iter.la
+
+libctf_msg_iter_la_SOURCES = \
+       msg-iter.c \
+       msg-iter.h \
+       logging.c \
+       logging.h
diff --git a/src/plugins/ctf/common/msg-iter/logging.c b/src/plugins/ctf/common/msg-iter/logging.c
new file mode 100644 (file)
index 0000000..662c443
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL ctf_msg_iter_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(ctf_msg_iter_log_level,
+       "BABELTRACE_PLUGIN_CTF_MSG_ITER_LOG_LEVEL");
diff --git a/src/plugins/ctf/common/msg-iter/logging.h b/src/plugins/ctf/common/msg-iter/logging.h
new file mode 100644 (file)
index 0000000..9788916
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef CTF_MSG_ITER_LOGGING_H
+#define CTF_MSG_ITER_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL ctf_msg_iter_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(ctf_msg_iter_log_level);
+
+#endif /* CTF_MSG_ITER_LOGGING_H */
diff --git a/src/plugins/ctf/common/msg-iter/msg-iter.c b/src/plugins/ctf/common/msg-iter/msg-iter.c
new file mode 100644 (file)
index 0000000..2a1c471
--- /dev/null
@@ -0,0 +1,3046 @@
+/*
+ * Babeltrace - CTF message iterator
+ *
+ * Copyright (c) 2015-2018 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-MSG-ITER"
+#include "logging.h"
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "common/assert.h"
+#include <string.h>
+#include <babeltrace2/babeltrace.h>
+#include "common/common.h"
+#include <glib.h>
+#include <stdlib.h>
+
+#include "msg-iter.h"
+#include "../bfcr/bfcr.h"
+
+struct bt_msg_iter;
+
+/* A visit stack entry */
+struct stack_entry {
+       /*
+        * Current base field, one of:
+        *
+        *   * string
+        *   * structure
+        *   * array
+        *   * sequence
+        *   * variant
+        *
+        * Field is borrowed.
+        */
+       bt_field *base;
+
+       /* Index of next field to set */
+       size_t index;
+};
+
+/* Visit stack */
+struct stack {
+       /* Entries (struct stack_entry) */
+       GArray *entries;
+
+       /* Number of active entries */
+       size_t size;
+};
+
+/* State */
+enum state {
+       STATE_INIT,
+       STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN,
+       STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE,
+       STATE_AFTER_TRACE_PACKET_HEADER,
+       STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN,
+       STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
+       STATE_AFTER_STREAM_PACKET_CONTEXT,
+       STATE_CHECK_EMIT_MSG_STREAM_BEGINNING,
+       STATE_EMIT_MSG_STREAM_BEGINNING,
+       STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING,
+       STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS,
+       STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS,
+       STATE_EMIT_MSG_DISCARDED_EVENTS,
+       STATE_EMIT_MSG_DISCARDED_PACKETS,
+       STATE_EMIT_MSG_PACKET_BEGINNING,
+       STATE_DSCOPE_EVENT_HEADER_BEGIN,
+       STATE_DSCOPE_EVENT_HEADER_CONTINUE,
+       STATE_AFTER_EVENT_HEADER,
+       STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN,
+       STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE,
+       STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
+       STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE,
+       STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
+       STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
+       STATE_EMIT_MSG_EVENT,
+       STATE_SKIP_PACKET_PADDING,
+       STATE_EMIT_MSG_PACKET_END_MULTI,
+       STATE_EMIT_MSG_PACKET_END_SINGLE,
+       STATE_CHECK_EMIT_MSG_STREAM_ACTIVITY_END,
+       STATE_EMIT_MSG_STREAM_ACTIVITY_END,
+       STATE_EMIT_MSG_STREAM_END,
+       STATE_DONE,
+};
+
+struct end_of_packet_snapshots {
+       uint64_t discarded_events;
+       uint64_t packets;
+       uint64_t beginning_clock;
+       uint64_t end_clock;
+};
+
+/* CTF message iterator */
+struct bt_msg_iter {
+       /* Visit stack */
+       struct stack *stack;
+
+       /* Current message iterator to create messages (weak) */
+       bt_self_message_iterator *msg_iter;
+
+       /*
+        * True to emit stream beginning and stream activity beginning
+        * messages.
+        */
+       bool emit_stream_begin_msg;
+
+       /* True to emit stream end and stream activity end messages */
+       bool emit_stream_end_msg;
+
+       /* True to set the stream */
+       bool set_stream;
+
+       /*
+        * Current dynamic scope field pointer.
+        *
+        * This is set by read_dscope_begin_state() and contains the
+        * value of one of the pointers in `dscopes` below.
+        */
+       bt_field *cur_dscope_field;
+
+       /*
+        * True if we're done filling a string field from a text
+        * array/sequence payload.
+        */
+       bool done_filling_string;
+
+       /* Trace and classes */
+       /* True to set IR fields */
+       bool set_ir_fields;
+
+       struct {
+               struct ctf_trace_class *tc;
+               struct ctf_stream_class *sc;
+               struct ctf_event_class *ec;
+       } meta;
+
+       /* Current packet context field wrapper (NULL if not created yet) */
+       bt_packet_context_field *packet_context_field;
+
+       /* Current packet (NULL if not created yet) */
+       bt_packet *packet;
+
+       /* Current stream (NULL if not set yet) */
+       bt_stream *stream;
+
+       /* Current event (NULL if not created yet) */
+       bt_event *event;
+
+       /* Current event message (NULL if not created yet) */
+       bt_message *event_msg;
+
+       /* Database of current dynamic scopes */
+       struct {
+               bt_field *stream_packet_context;
+               bt_field *event_common_context;
+               bt_field *event_spec_context;
+               bt_field *event_payload;
+       } dscopes;
+
+       /* Current state */
+       enum state state;
+
+       /* Current medium buffer data */
+       struct {
+               /* Last address provided by medium */
+               const uint8_t *addr;
+
+               /* Buffer size provided by medium (bytes) */
+               size_t sz;
+
+               /* Offset within whole packet of addr (bits) */
+               size_t packet_offset;
+
+               /* Current position from addr (bits) */
+               size_t at;
+
+               /* Position of the last event header from addr (bits) */
+               size_t last_eh_at;
+       } buf;
+
+       /* Binary type reader */
+       struct bt_bfcr *bfcr;
+
+       /* Current medium data */
+       struct {
+               struct bt_msg_iter_medium_ops medops;
+               size_t max_request_sz;
+               void *data;
+       } medium;
+
+       /* Current packet size (bits) (-1 if unknown) */
+       int64_t cur_exp_packet_total_size;
+
+       /* Current content size (bits) (-1 if unknown) */
+       int64_t cur_exp_packet_content_size;
+
+       /* Current stream class ID */
+       int64_t cur_stream_class_id;
+
+       /* Current event class ID */
+       int64_t cur_event_class_id;
+
+       /* Current data stream ID */
+       int64_t cur_data_stream_id;
+
+       /*
+        * Offset, in the underlying media, of the current packet's
+        * start (-1 if unknown).
+        */
+       off_t cur_packet_offset;
+
+       /* Default clock's current value */
+       uint64_t default_clock_snapshot;
+
+       /* End of current packet snapshots */
+       struct end_of_packet_snapshots snapshots;
+
+       /* End of previous packet snapshots */
+       struct end_of_packet_snapshots prev_packet_snapshots;
+
+       /* Stored values (for sequence lengths, variant tags) */
+       GArray *stored_values;
+};
+
+static inline
+const char *state_string(enum state state)
+{
+       switch (state) {
+       case STATE_INIT:
+               return "STATE_INIT";
+       case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
+               return "STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN";
+       case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
+               return "STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE";
+       case STATE_AFTER_TRACE_PACKET_HEADER:
+               return "STATE_AFTER_TRACE_PACKET_HEADER";
+       case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
+               return "STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN";
+       case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
+               return "STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE";
+       case STATE_AFTER_STREAM_PACKET_CONTEXT:
+               return "STATE_AFTER_STREAM_PACKET_CONTEXT";
+       case STATE_EMIT_MSG_STREAM_BEGINNING:
+               return "STATE_EMIT_MSG_STREAM_BEGINNING";
+       case STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING:
+               return "STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING";
+       case STATE_EMIT_MSG_PACKET_BEGINNING:
+               return "STATE_EMIT_MSG_PACKET_BEGINNING";
+       case STATE_EMIT_MSG_DISCARDED_EVENTS:
+               return "STATE_EMIT_MSG_DISCARDED_EVENTS";
+       case STATE_EMIT_MSG_DISCARDED_PACKETS:
+               return "STATE_EMIT_MSG_DISCARDED_PACKETS";
+       case STATE_DSCOPE_EVENT_HEADER_BEGIN:
+               return "STATE_DSCOPE_EVENT_HEADER_BEGIN";
+       case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
+               return "STATE_DSCOPE_EVENT_HEADER_CONTINUE";
+       case STATE_AFTER_EVENT_HEADER:
+               return "STATE_AFTER_EVENT_HEADER";
+       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
+               return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN";
+       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
+               return "STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE";
+       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
+               return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN";
+       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
+               return "STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE";
+       case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
+               return "STATE_DSCOPE_EVENT_PAYLOAD_BEGIN";
+       case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
+               return "STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE";
+       case STATE_EMIT_MSG_EVENT:
+               return "STATE_EMIT_MSG_EVENT";
+       case STATE_SKIP_PACKET_PADDING:
+               return "STATE_SKIP_PACKET_PADDING";
+       case STATE_EMIT_MSG_PACKET_END_MULTI:
+               return "STATE_EMIT_MSG_PACKET_END_MULTI";
+       case STATE_EMIT_MSG_PACKET_END_SINGLE:
+               return "STATE_EMIT_MSG_PACKET_END_SINGLE";
+       case STATE_EMIT_MSG_STREAM_ACTIVITY_END:
+               return "STATE_EMIT_MSG_STREAM_ACTIVITY_END";
+       case STATE_EMIT_MSG_STREAM_END:
+               return "STATE_EMIT_MSG_STREAM_END";
+       case STATE_DONE:
+               return "STATE_DONE";
+       default:
+               return "(unknown)";
+       }
+}
+
+static
+int bt_msg_iter_switch_packet(struct bt_msg_iter *notit);
+
+static
+struct stack *stack_new(struct bt_msg_iter *notit)
+{
+       struct stack *stack = NULL;
+
+       stack = g_new0(struct stack, 1);
+       if (!stack) {
+               BT_LOGE_STR("Failed to allocate one stack.");
+               goto error;
+       }
+
+       stack->entries = g_array_new(FALSE, TRUE, sizeof(struct stack_entry));
+       if (!stack->entries) {
+               BT_LOGE_STR("Failed to allocate a GArray.");
+               goto error;
+       }
+
+       BT_LOGD("Created stack: notit-addr=%p, stack-addr=%p", notit, stack);
+       goto end;
+
+error:
+       g_free(stack);
+       stack = NULL;
+
+end:
+       return stack;
+}
+
+static
+void stack_destroy(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       BT_LOGD("Destroying stack: addr=%p", stack);
+
+       if (stack->entries) {
+               g_array_free(stack->entries, TRUE);
+       }
+
+       g_free(stack);
+}
+
+static
+void stack_push(struct stack *stack, bt_field *base)
+{
+       struct stack_entry *entry;
+
+       BT_ASSERT(stack);
+       BT_ASSERT(base);
+       BT_LOGV("Pushing base field on stack: stack-addr=%p, "
+               "stack-size-before=%zu, stack-size-after=%zu",
+               stack, stack->size, stack->size + 1);
+
+       if (stack->entries->len == stack->size) {
+               g_array_set_size(stack->entries, stack->size + 1);
+       }
+
+       entry = &g_array_index(stack->entries, struct stack_entry, stack->size);
+       entry->base = base;
+       entry->index = 0;
+       stack->size++;
+}
+
+static inline
+unsigned int stack_size(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       return stack->size;
+}
+
+static
+void stack_pop(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       BT_ASSERT(stack_size(stack));
+       BT_LOGV("Popping from stack: "
+               "stack-addr=%p, stack-size-before=%zu, stack-size-after=%zu",
+               stack, stack->size, stack->size - 1);
+       stack->size--;
+}
+
+static inline
+struct stack_entry *stack_top(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       BT_ASSERT(stack_size(stack));
+       return &g_array_index(stack->entries, struct stack_entry,
+               stack->size - 1);
+}
+
+static inline
+bool stack_empty(struct stack *stack)
+{
+       return stack_size(stack) == 0;
+}
+
+static
+void stack_clear(struct stack *stack)
+{
+       BT_ASSERT(stack);
+       stack->size = 0;
+}
+
+static inline
+enum bt_msg_iter_status msg_iter_status_from_m_status(
+               enum bt_msg_iter_medium_status m_status)
+{
+       /* They are the same */
+       return (int) m_status;
+}
+
+static inline
+size_t buf_size_bits(struct bt_msg_iter *notit)
+{
+       return notit->buf.sz * 8;
+}
+
+static inline
+size_t buf_available_bits(struct bt_msg_iter *notit)
+{
+       return buf_size_bits(notit) - notit->buf.at;
+}
+
+static inline
+size_t packet_at(struct bt_msg_iter *notit)
+{
+       return notit->buf.packet_offset + notit->buf.at;
+}
+
+static inline
+void buf_consume_bits(struct bt_msg_iter *notit, size_t incr)
+{
+       BT_LOGV("Advancing cursor: notit-addr=%p, cur-before=%zu, cur-after=%zu",
+               notit, notit->buf.at, notit->buf.at + incr);
+       notit->buf.at += incr;
+}
+
+static
+enum bt_msg_iter_status request_medium_bytes(
+               struct bt_msg_iter *notit)
+{
+       uint8_t *buffer_addr = NULL;
+       size_t buffer_sz = 0;
+       enum bt_msg_iter_medium_status m_status;
+
+       BT_LOGV("Calling user function (request bytes): notit-addr=%p, "
+               "request-size=%zu", notit, notit->medium.max_request_sz);
+       m_status = notit->medium.medops.request_bytes(
+               notit->medium.max_request_sz, &buffer_addr,
+               &buffer_sz, notit->medium.data);
+       BT_LOGV("User function returned: status=%s, buf-addr=%p, buf-size=%zu",
+               bt_msg_iter_medium_status_string(m_status),
+               buffer_addr, buffer_sz);
+       if (m_status == BT_MSG_ITER_MEDIUM_STATUS_OK) {
+               BT_ASSERT(buffer_sz != 0);
+
+               /* New packet offset is old one + old size (in bits) */
+               notit->buf.packet_offset += buf_size_bits(notit);
+
+               /* Restart at the beginning of the new medium buffer */
+               notit->buf.at = 0;
+               notit->buf.last_eh_at = SIZE_MAX;
+
+               /* New medium buffer size */
+               notit->buf.sz = buffer_sz;
+
+               /* New medium buffer address */
+               notit->buf.addr = buffer_addr;
+
+               BT_LOGV("User function returned new bytes: "
+                       "packet-offset=%zu, cur=%zu, size=%zu, addr=%p",
+                       notit->buf.packet_offset, notit->buf.at,
+                       notit->buf.sz, notit->buf.addr);
+               BT_LOGV_MEM(buffer_addr, buffer_sz, "Returned bytes at %p:",
+                       buffer_addr);
+       } else if (m_status == BT_MSG_ITER_MEDIUM_STATUS_EOF) {
+               /*
+                * User returned end of stream: validate that we're not
+                * in the middle of a packet header, packet context, or
+                * event.
+                */
+               if (notit->cur_exp_packet_total_size >= 0) {
+                       if (packet_at(notit) ==
+                                       notit->cur_exp_packet_total_size) {
+                               goto end;
+                       }
+               } else {
+                       if (packet_at(notit) == 0) {
+                               goto end;
+                       }
+
+                       if (notit->buf.last_eh_at != SIZE_MAX &&
+                                       notit->buf.at == notit->buf.last_eh_at) {
+                               goto end;
+                       }
+               }
+
+               /* All other states are invalid */
+               BT_LOGW("User function returned %s, but message iterator is in an unexpected state: "
+                       "state=%s, cur-packet-size=%" PRId64 ", cur=%zu, "
+                       "packet-cur=%zu, last-eh-at=%zu",
+                       bt_msg_iter_medium_status_string(m_status),
+                       state_string(notit->state),
+                       notit->cur_exp_packet_total_size,
+                       notit->buf.at, packet_at(notit),
+                       notit->buf.last_eh_at);
+               m_status = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
+       } else if (m_status < 0) {
+               BT_LOGW("User function failed: status=%s",
+                       bt_msg_iter_medium_status_string(m_status));
+       }
+
+end:
+       return msg_iter_status_from_m_status(m_status);
+}
+
+static inline
+enum bt_msg_iter_status buf_ensure_available_bits(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+
+       if (unlikely(buf_available_bits(notit) == 0)) {
+               /*
+                * This _cannot_ return BT_MSG_ITER_STATUS_OK
+                * _and_ no bits.
+                */
+               status = request_medium_bytes(notit);
+       }
+
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_dscope_begin_state(
+               struct bt_msg_iter *notit,
+               struct ctf_field_class *dscope_fc,
+               enum state done_state, enum state continue_state,
+               bt_field *dscope_field)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       enum bt_bfcr_status bfcr_status;
+       size_t consumed_bits;
+
+       notit->cur_dscope_field = dscope_field;
+       BT_LOGV("Starting BFCR: notit-addr=%p, bfcr-addr=%p, fc-addr=%p",
+               notit, notit->bfcr, dscope_fc);
+       consumed_bits = bt_bfcr_start(notit->bfcr, dscope_fc,
+               notit->buf.addr, notit->buf.at, packet_at(notit),
+               notit->buf.sz, &bfcr_status);
+       BT_LOGV("BFCR consumed bits: size=%zu", consumed_bits);
+
+       switch (bfcr_status) {
+       case BT_BFCR_STATUS_OK:
+               /* Field class was read completely */
+               BT_LOGV_STR("Field was completely decoded.");
+               notit->state = done_state;
+               break;
+       case BT_BFCR_STATUS_EOF:
+               BT_LOGV_STR("BFCR needs more data to decode field completely.");
+               notit->state = continue_state;
+               break;
+       default:
+               BT_LOGW("BFCR failed to start: notit-addr=%p, bfcr-addr=%p, "
+                       "status=%s", notit, notit->bfcr,
+                       bt_bfcr_status_string(bfcr_status));
+               status = BT_MSG_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       /* Consume bits now since we know we're not in an error state */
+       buf_consume_bits(notit, consumed_bits);
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_dscope_continue_state(
+               struct bt_msg_iter *notit, enum state done_state)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       enum bt_bfcr_status bfcr_status;
+       size_t consumed_bits;
+
+       BT_LOGV("Continuing BFCR: notit-addr=%p, bfcr-addr=%p",
+               notit, notit->bfcr);
+
+       status = buf_ensure_available_bits(notit);
+       if (status != BT_MSG_ITER_STATUS_OK) {
+               if (status < 0) {
+                       BT_LOGW("Cannot ensure that buffer has at least one byte: "
+                               "msg-addr=%p, status=%s",
+                               notit, bt_msg_iter_status_string(status));
+               } else {
+                       BT_LOGV("Cannot ensure that buffer has at least one byte: "
+                               "msg-addr=%p, status=%s",
+                               notit, bt_msg_iter_status_string(status));
+               }
+
+               goto end;
+       }
+
+       consumed_bits = bt_bfcr_continue(notit->bfcr, notit->buf.addr,
+               notit->buf.sz, &bfcr_status);
+       BT_LOGV("BFCR consumed bits: size=%zu", consumed_bits);
+
+       switch (bfcr_status) {
+       case BT_BFCR_STATUS_OK:
+               /* Type was read completely. */
+               BT_LOGV_STR("Field was completely decoded.");
+               notit->state = done_state;
+               break;
+       case BT_BFCR_STATUS_EOF:
+               /* Stay in this continue state. */
+               BT_LOGV_STR("BFCR needs more data to decode field completely.");
+               break;
+       default:
+               BT_LOGW("BFCR failed to continue: notit-addr=%p, bfcr-addr=%p, "
+                       "status=%s", notit, notit->bfcr,
+                       bt_bfcr_status_string(bfcr_status));
+               status = BT_MSG_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       /* Consume bits now since we know we're not in an error state. */
+       buf_consume_bits(notit, consumed_bits);
+end:
+       return status;
+}
+
+static
+void release_event_dscopes(struct bt_msg_iter *notit)
+{
+       notit->dscopes.event_common_context = NULL;
+       notit->dscopes.event_spec_context = NULL;
+       notit->dscopes.event_payload = NULL;
+}
+
+static
+void release_all_dscopes(struct bt_msg_iter *notit)
+{
+       notit->dscopes.stream_packet_context = NULL;
+
+       if (notit->packet_context_field) {
+               bt_packet_context_field_release(notit->packet_context_field);
+               notit->packet_context_field = NULL;
+       }
+
+       release_event_dscopes(notit);
+}
+
+static
+enum bt_msg_iter_status read_packet_header_begin_state(
+               struct bt_msg_iter *notit)
+{
+       struct ctf_field_class *packet_header_fc = NULL;
+       enum bt_msg_iter_status ret = BT_MSG_ITER_STATUS_OK;
+
+       if (bt_msg_iter_switch_packet(notit)) {
+               BT_LOGW("Cannot switch packet: notit-addr=%p", notit);
+               ret = BT_MSG_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       /*
+        * Make sure at least one bit is available for this packet. An
+        * empty packet is impossible. If we reach the end of the medium
+        * at this point, then it's considered the end of the stream.
+        */
+       ret = buf_ensure_available_bits(notit);
+       switch (ret) {
+       case BT_MSG_ITER_STATUS_OK:
+               break;
+       case BT_MSG_ITER_STATUS_EOF:
+               ret = BT_MSG_ITER_STATUS_OK;
+               notit->state = STATE_CHECK_EMIT_MSG_STREAM_ACTIVITY_END;
+               goto end;
+       default:
+               goto end;
+       }
+
+       /* Packet header class is common to the whole trace class. */
+       packet_header_fc = notit->meta.tc->packet_header_fc;
+       if (!packet_header_fc) {
+               notit->state = STATE_AFTER_TRACE_PACKET_HEADER;
+               goto end;
+       }
+
+       notit->cur_stream_class_id = -1;
+       notit->cur_event_class_id = -1;
+       notit->cur_data_stream_id = -1;
+       BT_LOGV("Decoding packet header field:"
+               "notit-addr=%p, trace-class-addr=%p, fc-addr=%p",
+               notit, notit->meta.tc, packet_header_fc);
+       ret = read_dscope_begin_state(notit, packet_header_fc,
+               STATE_AFTER_TRACE_PACKET_HEADER,
+               STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE, NULL);
+       if (ret < 0) {
+               BT_LOGW("Cannot decode packet header field: "
+                       "notit-addr=%p, trace-class-addr=%p, "
+                       "fc-addr=%p",
+                       notit, notit->meta.tc, packet_header_fc);
+       }
+
+end:
+       return ret;
+}
+
+static
+enum bt_msg_iter_status read_packet_header_continue_state(
+               struct bt_msg_iter *notit)
+{
+       return read_dscope_continue_state(notit,
+               STATE_AFTER_TRACE_PACKET_HEADER);
+}
+
+static inline
+enum bt_msg_iter_status set_current_stream_class(struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       struct ctf_stream_class *new_stream_class = NULL;
+
+       if (notit->cur_stream_class_id == -1) {
+               /*
+                * No current stream class ID field, therefore only one
+                * stream class.
+                */
+               if (notit->meta.tc->stream_classes->len != 1) {
+                       BT_LOGW("Need exactly one stream class since there's "
+                               "no stream class ID field: "
+                               "notit-addr=%p", notit);
+                       status = BT_MSG_ITER_STATUS_ERROR;
+                       goto end;
+               }
+
+               new_stream_class = notit->meta.tc->stream_classes->pdata[0];
+               notit->cur_stream_class_id = new_stream_class->id;
+       }
+
+       new_stream_class = ctf_trace_class_borrow_stream_class_by_id(
+               notit->meta.tc, notit->cur_stream_class_id);
+       if (!new_stream_class) {
+               BT_LOGW("No stream class with ID of stream class ID to use in trace class: "
+                       "notit-addr=%p, stream-class-id=%" PRIu64 ", "
+                       "trace-class-addr=%p",
+                       notit, notit->cur_stream_class_id, notit->meta.tc);
+               status = BT_MSG_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       if (notit->meta.sc) {
+               if (new_stream_class != notit->meta.sc) {
+                       BT_LOGW("Two packets refer to two different stream classes within the same packet sequence: "
+                               "notit-addr=%p, prev-stream-class-addr=%p, "
+                               "prev-stream-class-id=%" PRId64 ", "
+                               "next-stream-class-addr=%p, "
+                               "next-stream-class-id=%" PRId64 ", "
+                               "trace-addr=%p",
+                               notit, notit->meta.sc,
+                               notit->meta.sc->id,
+                               new_stream_class,
+                               new_stream_class->id,
+                               notit->meta.tc);
+                       status = BT_MSG_ITER_STATUS_ERROR;
+                       goto end;
+               }
+       } else {
+               notit->meta.sc = new_stream_class;
+       }
+
+       BT_LOGV("Set current stream class: "
+               "notit-addr=%p, stream-class-addr=%p, "
+               "stream-class-id=%" PRId64,
+               notit, notit->meta.sc, notit->meta.sc->id);
+
+end:
+       return status;
+}
+
+static inline
+enum bt_msg_iter_status set_current_stream(struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       bt_stream *stream = NULL;
+
+       BT_LOGV("Calling user function (get stream): notit-addr=%p, "
+               "stream-class-addr=%p, stream-class-id=%" PRId64,
+               notit, notit->meta.sc,
+               notit->meta.sc->id);
+       stream = notit->medium.medops.borrow_stream(
+               notit->meta.sc->ir_sc, notit->cur_data_stream_id,
+               notit->medium.data);
+       bt_stream_get_ref(stream);
+       BT_LOGV("User function returned: stream-addr=%p", stream);
+       if (!stream) {
+               BT_LOGW_STR("User function failed to return a stream object "
+                       "for the given stream class.");
+               status = BT_MSG_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       if (notit->stream && stream != notit->stream) {
+               BT_LOGW("User function returned a different stream than the "
+                       "previous one for the same sequence of packets.");
+               status = BT_MSG_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_STREAM_MOVE_REF(notit->stream, stream);
+
+end:
+       bt_stream_put_ref(stream);
+       return status;
+}
+
+static inline
+enum bt_msg_iter_status set_current_packet(struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       bt_packet *packet = NULL;
+
+       BT_LOGV("Creating packet for packet message: "
+               "notit-addr=%p", notit);
+       BT_LOGV("Creating packet from stream: "
+               "notit-addr=%p, stream-addr=%p, "
+               "stream-class-addr=%p, "
+               "stream-class-id=%" PRId64,
+               notit, notit->stream, notit->meta.sc,
+               notit->meta.sc->id);
+
+       /* Create packet */
+       BT_ASSERT(notit->stream);
+       packet = bt_packet_create(notit->stream);
+       if (!packet) {
+               BT_LOGE("Cannot create packet from stream: "
+                       "notit-addr=%p, stream-addr=%p, "
+                       "stream-class-addr=%p, "
+                       "stream-class-id=%" PRId64,
+                       notit, notit->stream, notit->meta.sc,
+                       notit->meta.sc->id);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_PACKET_PUT_REF_AND_RESET(packet);
+       status = BT_MSG_ITER_STATUS_ERROR;
+
+end:
+       BT_PACKET_MOVE_REF(notit->packet, packet);
+       return status;
+}
+
+static
+enum bt_msg_iter_status after_packet_header_state(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status;
+
+       status = set_current_stream_class(notit);
+       if (status != BT_MSG_ITER_STATUS_OK) {
+               goto end;
+       }
+
+       notit->state = STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN;
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_packet_context_begin_state(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       struct ctf_field_class *packet_context_fc;
+
+       BT_ASSERT(notit->meta.sc);
+       packet_context_fc = notit->meta.sc->packet_context_fc;
+       if (!packet_context_fc) {
+               BT_LOGV("No packet packet context field class in stream class: continuing: "
+                       "notit-addr=%p, stream-class-addr=%p, "
+                       "stream-class-id=%" PRId64,
+                       notit, notit->meta.sc,
+                       notit->meta.sc->id);
+               notit->state = STATE_AFTER_STREAM_PACKET_CONTEXT;
+               goto end;
+       }
+
+       BT_ASSERT(!notit->packet_context_field);
+
+       if (packet_context_fc->in_ir) {
+               /*
+                * Create free packet context field from stream class.
+                * This field is going to be moved to the packet once we
+                * create it. We cannot create the packet now because a
+                * packet is created from a stream, and this API must be
+                * able to return the packet context properties without
+                * creating a stream
+                * (bt_msg_iter_get_packet_properties()).
+                */
+               notit->packet_context_field =
+                       bt_packet_context_field_create(
+                               notit->meta.sc->ir_sc);
+               if (!notit->packet_context_field) {
+                       BT_LOGE_STR("Cannot create packet context field wrapper from stream class.");
+                       status = BT_MSG_ITER_STATUS_ERROR;
+                       goto end;
+               }
+
+               notit->dscopes.stream_packet_context =
+                       bt_packet_context_field_borrow_field(
+                               notit->packet_context_field);
+               BT_ASSERT(notit->dscopes.stream_packet_context);
+       }
+
+       BT_LOGV("Decoding packet context field: "
+               "notit-addr=%p, stream-class-addr=%p, "
+               "stream-class-id=%" PRId64 ", fc-addr=%p",
+               notit, notit->meta.sc,
+               notit->meta.sc->id, packet_context_fc);
+       status = read_dscope_begin_state(notit, packet_context_fc,
+               STATE_AFTER_STREAM_PACKET_CONTEXT,
+               STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE,
+               notit->dscopes.stream_packet_context);
+       if (status < 0) {
+               BT_LOGW("Cannot decode packet context field: "
+                       "notit-addr=%p, stream-class-addr=%p, "
+                       "stream-class-id=%" PRId64 ", fc-addr=%p",
+                       notit, notit->meta.sc,
+                       notit->meta.sc->id,
+                       packet_context_fc);
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_packet_context_continue_state(
+               struct bt_msg_iter *notit)
+{
+       return read_dscope_continue_state(notit,
+                       STATE_AFTER_STREAM_PACKET_CONTEXT);
+}
+
+static
+enum bt_msg_iter_status set_current_packet_content_sizes(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+
+       if (notit->cur_exp_packet_total_size == -1) {
+               if (notit->cur_exp_packet_content_size != -1) {
+                       notit->cur_exp_packet_total_size =
+                               notit->cur_exp_packet_content_size;
+               }
+       } else {
+               if (notit->cur_exp_packet_content_size == -1) {
+                       notit->cur_exp_packet_content_size =
+                               notit->cur_exp_packet_total_size;
+               }
+       }
+
+       BT_ASSERT((notit->cur_exp_packet_total_size >= 0 &&
+               notit->cur_exp_packet_content_size >= 0) ||
+               (notit->cur_exp_packet_total_size < 0 &&
+               notit->cur_exp_packet_content_size < 0));
+
+       if (notit->cur_exp_packet_content_size >
+                       notit->cur_exp_packet_total_size) {
+               BT_LOGW("Invalid packet or content size: "
+                       "content size is greater than packet size: "
+                       "notit-addr=%p, packet-context-field-addr=%p, "
+                       "packet-size=%" PRId64 ", content-size=%" PRId64,
+                       notit, notit->dscopes.stream_packet_context,
+                       notit->cur_exp_packet_total_size,
+                       notit->cur_exp_packet_content_size);
+               status = BT_MSG_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_LOGV("Set current packet and content sizes: "
+               "notit-addr=%p, packet-size=%" PRIu64 ", content-size=%" PRIu64,
+               notit, notit->cur_exp_packet_total_size,
+               notit->cur_exp_packet_content_size);
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status after_packet_context_state(struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status;
+
+       status = set_current_packet_content_sizes(notit);
+       if (status != BT_MSG_ITER_STATUS_OK) {
+               goto end;
+       }
+
+       if (notit->stream) {
+               /*
+                * Stream exists, which means we already emitted at
+                * least one packet beginning message, so the initial
+                * stream beginning message was also emitted.
+                */
+               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
+       } else {
+               notit->state = STATE_CHECK_EMIT_MSG_STREAM_BEGINNING;
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_event_header_begin_state(struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       struct ctf_field_class *event_header_fc = NULL;
+
+       /* Reset the position of the last event header */
+       notit->buf.last_eh_at = notit->buf.at;
+       notit->cur_event_class_id = -1;
+
+       /* Check if we have some content left */
+       if (notit->cur_exp_packet_content_size >= 0) {
+               if (unlikely(packet_at(notit) ==
+                               notit->cur_exp_packet_content_size)) {
+                       /* No more events! */
+                       BT_LOGV("Reached end of packet: notit-addr=%p, "
+                               "cur=%zu", notit, packet_at(notit));
+                       notit->state = STATE_EMIT_MSG_PACKET_END_MULTI;
+                       goto end;
+               } else if (unlikely(packet_at(notit) >
+                               notit->cur_exp_packet_content_size)) {
+                       /* That's not supposed to happen */
+                       BT_LOGV("Before decoding event header field: cursor is passed the packet's content: "
+                               "notit-addr=%p, content-size=%" PRId64 ", "
+                               "cur=%zu", notit,
+                               notit->cur_exp_packet_content_size,
+                               packet_at(notit));
+                       status = BT_MSG_ITER_STATUS_ERROR;
+                       goto end;
+               }
+       } else {
+               /*
+                * "Infinite" content: we're done when the medium has
+                * nothing else for us.
+                */
+               status = buf_ensure_available_bits(notit);
+               switch (status) {
+               case BT_MSG_ITER_STATUS_OK:
+                       break;
+               case BT_MSG_ITER_STATUS_EOF:
+                       status = BT_MSG_ITER_STATUS_OK;
+                       notit->state = STATE_EMIT_MSG_PACKET_END_SINGLE;
+                       goto end;
+               default:
+                       goto end;
+               }
+       }
+
+       release_event_dscopes(notit);
+       BT_ASSERT(notit->meta.sc);
+       event_header_fc = notit->meta.sc->event_header_fc;
+       if (!event_header_fc) {
+               notit->state = STATE_AFTER_EVENT_HEADER;
+               goto end;
+       }
+
+       BT_LOGV("Decoding event header field: "
+               "notit-addr=%p, stream-class-addr=%p, "
+               "stream-class-id=%" PRId64 ", "
+               "fc-addr=%p",
+               notit, notit->meta.sc,
+               notit->meta.sc->id,
+               event_header_fc);
+       status = read_dscope_begin_state(notit, event_header_fc,
+               STATE_AFTER_EVENT_HEADER,
+               STATE_DSCOPE_EVENT_HEADER_CONTINUE, NULL);
+       if (status < 0) {
+               BT_LOGW("Cannot decode event header field: "
+                       "notit-addr=%p, stream-class-addr=%p, "
+                       "stream-class-id=%" PRId64 ", fc-addr=%p",
+                       notit, notit->meta.sc,
+                       notit->meta.sc->id,
+                       event_header_fc);
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_event_header_continue_state(
+               struct bt_msg_iter *notit)
+{
+       return read_dscope_continue_state(notit,
+               STATE_AFTER_EVENT_HEADER);
+}
+
+static inline
+enum bt_msg_iter_status set_current_event_class(struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+
+       struct ctf_event_class *new_event_class = NULL;
+
+       if (notit->cur_event_class_id == -1) {
+               /*
+                * No current event class ID field, therefore only one
+                * event class.
+                */
+               if (notit->meta.sc->event_classes->len != 1) {
+                       BT_LOGW("Need exactly one event class since there's "
+                               "no event class ID field: "
+                               "notit-addr=%p", notit);
+                       status = BT_MSG_ITER_STATUS_ERROR;
+                       goto end;
+               }
+
+               new_event_class = notit->meta.sc->event_classes->pdata[0];
+               notit->cur_event_class_id = new_event_class->id;
+       }
+
+       new_event_class = ctf_stream_class_borrow_event_class_by_id(
+               notit->meta.sc, notit->cur_event_class_id);
+       if (!new_event_class) {
+               BT_LOGW("No event class with ID of event class ID to use in stream class: "
+                       "notit-addr=%p, stream-class-id=%" PRIu64 ", "
+                       "event-class-id=%" PRIu64 ", "
+                       "trace-class-addr=%p",
+                       notit, notit->meta.sc->id, notit->cur_event_class_id,
+                       notit->meta.tc);
+               status = BT_MSG_ITER_STATUS_ERROR;
+               goto end;
+       }
+
+       notit->meta.ec = new_event_class;
+       BT_LOGV("Set current event class: "
+               "notit-addr=%p, event-class-addr=%p, "
+               "event-class-id=%" PRId64 ", "
+               "event-class-name=\"%s\"",
+               notit, notit->meta.ec, notit->meta.ec->id,
+               notit->meta.ec->name->str);
+
+end:
+       return status;
+}
+
+static inline
+enum bt_msg_iter_status set_current_event_message(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       bt_message *msg = NULL;
+
+       BT_ASSERT(notit->meta.ec);
+       BT_ASSERT(notit->packet);
+       BT_LOGV("Creating event message from event class and packet: "
+               "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", packet-addr=%p",
+               notit, notit->meta.ec,
+               notit->meta.ec->name->str,
+               notit->packet);
+       BT_ASSERT(notit->msg_iter);
+       BT_ASSERT(notit->meta.sc);
+
+       if (bt_stream_class_borrow_default_clock_class(notit->meta.sc->ir_sc)) {
+               msg = bt_message_event_create_with_default_clock_snapshot(
+                       notit->msg_iter, notit->meta.ec->ir_ec,
+                       notit->packet, notit->default_clock_snapshot);
+       } else {
+               msg = bt_message_event_create(notit->msg_iter,
+                       notit->meta.ec->ir_ec, notit->packet);
+       }
+
+       if (!msg) {
+               BT_LOGE("Cannot create event message: "
+                       "notit-addr=%p, ec-addr=%p, ec-name=\"%s\", "
+                       "packet-addr=%p",
+                       notit, notit->meta.ec,
+                       notit->meta.ec->name->str,
+                       notit->packet);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_MESSAGE_PUT_REF_AND_RESET(msg);
+       status = BT_MSG_ITER_STATUS_ERROR;
+
+end:
+       BT_MESSAGE_MOVE_REF(notit->event_msg, msg);
+       return status;
+}
+
+static
+enum bt_msg_iter_status after_event_header_state(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status;
+
+       status = set_current_event_class(notit);
+       if (status != BT_MSG_ITER_STATUS_OK) {
+               goto end;
+       }
+
+       status = set_current_event_message(notit);
+       if (status != BT_MSG_ITER_STATUS_OK) {
+               goto end;
+       }
+
+       notit->event = bt_message_event_borrow_event(
+               notit->event_msg);
+       BT_ASSERT(notit->event);
+       notit->state = STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN;
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_event_common_context_begin_state(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       struct ctf_field_class *event_common_context_fc;
+
+       event_common_context_fc = notit->meta.sc->event_common_context_fc;
+       if (!event_common_context_fc) {
+               notit->state = STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN;
+               goto end;
+       }
+
+       if (event_common_context_fc->in_ir) {
+               BT_ASSERT(!notit->dscopes.event_common_context);
+               notit->dscopes.event_common_context =
+                       bt_event_borrow_common_context_field(
+                               notit->event);
+               BT_ASSERT(notit->dscopes.event_common_context);
+       }
+
+       BT_LOGV("Decoding event common context field: "
+               "notit-addr=%p, stream-class-addr=%p, "
+               "stream-class-id=%" PRId64 ", "
+               "fc-addr=%p",
+               notit, notit->meta.sc,
+               notit->meta.sc->id,
+               event_common_context_fc);
+       status = read_dscope_begin_state(notit, event_common_context_fc,
+               STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN,
+               STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE,
+               notit->dscopes.event_common_context);
+       if (status < 0) {
+               BT_LOGW("Cannot decode event common context field: "
+                       "notit-addr=%p, stream-class-addr=%p, "
+                       "stream-class-id=%" PRId64 ", fc-addr=%p",
+                       notit, notit->meta.sc,
+                       notit->meta.sc->id,
+                       event_common_context_fc);
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_event_common_context_continue_state(
+               struct bt_msg_iter *notit)
+{
+       return read_dscope_continue_state(notit,
+               STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN);
+}
+
+static
+enum bt_msg_iter_status read_event_spec_context_begin_state(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       struct ctf_field_class *event_spec_context_fc;
+
+       event_spec_context_fc = notit->meta.ec->spec_context_fc;
+       if (!event_spec_context_fc) {
+               notit->state = STATE_DSCOPE_EVENT_PAYLOAD_BEGIN;
+               goto end;
+       }
+
+       if (event_spec_context_fc->in_ir) {
+               BT_ASSERT(!notit->dscopes.event_spec_context);
+               notit->dscopes.event_spec_context =
+                       bt_event_borrow_specific_context_field(
+                               notit->event);
+               BT_ASSERT(notit->dscopes.event_spec_context);
+       }
+
+       BT_LOGV("Decoding event specific context field: "
+               "notit-addr=%p, event-class-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "fc-addr=%p",
+               notit, notit->meta.ec,
+               notit->meta.ec->name->str,
+               notit->meta.ec->id,
+               event_spec_context_fc);
+       status = read_dscope_begin_state(notit, event_spec_context_fc,
+               STATE_DSCOPE_EVENT_PAYLOAD_BEGIN,
+               STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE,
+               notit->dscopes.event_spec_context);
+       if (status < 0) {
+               BT_LOGW("Cannot decode event specific context field: "
+                       "notit-addr=%p, event-class-addr=%p, "
+                       "event-class-name=\"%s\", "
+                       "event-class-id=%" PRId64 ", fc-addr=%p",
+                       notit, notit->meta.ec,
+                       notit->meta.ec->name->str,
+                       notit->meta.ec->id,
+                       event_spec_context_fc);
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_event_spec_context_continue_state(
+               struct bt_msg_iter *notit)
+{
+       return read_dscope_continue_state(notit,
+               STATE_DSCOPE_EVENT_PAYLOAD_BEGIN);
+}
+
+static
+enum bt_msg_iter_status read_event_payload_begin_state(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       struct ctf_field_class *event_payload_fc;
+
+       event_payload_fc = notit->meta.ec->payload_fc;
+       if (!event_payload_fc) {
+               notit->state = STATE_EMIT_MSG_EVENT;
+               goto end;
+       }
+
+       if (event_payload_fc->in_ir) {
+               BT_ASSERT(!notit->dscopes.event_payload);
+               notit->dscopes.event_payload =
+                       bt_event_borrow_payload_field(
+                               notit->event);
+               BT_ASSERT(notit->dscopes.event_payload);
+       }
+
+       BT_LOGV("Decoding event payload field: "
+               "notit-addr=%p, event-class-addr=%p, "
+               "event-class-name=\"%s\", event-class-id=%" PRId64 ", "
+               "fc-addr=%p",
+               notit, notit->meta.ec,
+               notit->meta.ec->name->str,
+               notit->meta.ec->id,
+               event_payload_fc);
+       status = read_dscope_begin_state(notit, event_payload_fc,
+               STATE_EMIT_MSG_EVENT,
+               STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE,
+               notit->dscopes.event_payload);
+       if (status < 0) {
+               BT_LOGW("Cannot decode event payload field: "
+                       "notit-addr=%p, event-class-addr=%p, "
+                       "event-class-name=\"%s\", "
+                       "event-class-id=%" PRId64 ", fc-addr=%p",
+                       notit, notit->meta.ec,
+                       notit->meta.ec->name->str,
+                       notit->meta.ec->id,
+                       event_payload_fc);
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_event_payload_continue_state(
+               struct bt_msg_iter *notit)
+{
+       return read_dscope_continue_state(notit, STATE_EMIT_MSG_EVENT);
+}
+
+static
+enum bt_msg_iter_status skip_packet_padding_state(struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       size_t bits_to_skip;
+
+       BT_ASSERT(notit->cur_exp_packet_total_size > 0);
+       bits_to_skip = notit->cur_exp_packet_total_size - packet_at(notit);
+       if (bits_to_skip == 0) {
+               notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
+               goto end;
+       } else {
+               size_t bits_to_consume;
+
+               BT_LOGV("Trying to skip %zu bits of padding: notit-addr=%p, size=%zu",
+                       bits_to_skip, notit, bits_to_skip);
+               status = buf_ensure_available_bits(notit);
+               if (status != BT_MSG_ITER_STATUS_OK) {
+                       goto end;
+               }
+
+               bits_to_consume = MIN(buf_available_bits(notit), bits_to_skip);
+               BT_LOGV("Skipping %zu bits of padding: notit-addr=%p, size=%zu",
+                       bits_to_consume, notit, bits_to_consume);
+               buf_consume_bits(notit, bits_to_consume);
+               bits_to_skip = notit->cur_exp_packet_total_size -
+                       packet_at(notit);
+               if (bits_to_skip == 0) {
+                       notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
+                       goto end;
+               }
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status check_emit_msg_stream_beginning_state(
+               struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+
+       if (notit->set_stream) {
+               status = set_current_stream(notit);
+               if (status != BT_MSG_ITER_STATUS_OK) {
+                       goto end;
+               }
+       }
+
+       if (notit->emit_stream_begin_msg) {
+               notit->state = STATE_EMIT_MSG_STREAM_BEGINNING;
+       } else {
+               /* Stream's first packet */
+               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status check_emit_msg_discarded_events(
+               struct bt_msg_iter *notit)
+{
+       notit->state = STATE_EMIT_MSG_DISCARDED_EVENTS;
+
+       if (!notit->meta.sc->has_discarded_events) {
+               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
+               goto end;
+       }
+
+       if (notit->prev_packet_snapshots.discarded_events == UINT64_C(-1)) {
+               if (notit->snapshots.discarded_events == 0 ||
+                               notit->snapshots.discarded_events == UINT64_C(-1)) {
+                       /*
+                        * Stream's first packet with no discarded
+                        * events or no information about discarded
+                        * events: do not emit.
+                        */
+                       notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
+               }
+       } else {
+               /*
+                * If the previous packet has a value for this counter,
+                * then this counter is defined for the whole stream.
+                */
+               BT_ASSERT(notit->snapshots.discarded_events != UINT64_C(-1));
+
+               if (notit->snapshots.discarded_events -
+                               notit->prev_packet_snapshots.discarded_events == 0) {
+                       /*
+                        * No discarded events since previous packet: do
+                        * not emit.
+                        */
+                       notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
+               }
+       }
+
+end:
+       return BT_MSG_ITER_STATUS_OK;
+}
+
+static
+enum bt_msg_iter_status check_emit_msg_discarded_packets(
+               struct bt_msg_iter *notit)
+{
+       notit->state = STATE_EMIT_MSG_DISCARDED_PACKETS;
+
+       if (!notit->meta.sc->has_discarded_packets) {
+               notit->state = STATE_EMIT_MSG_PACKET_BEGINNING;
+               goto end;
+       }
+
+       if (notit->prev_packet_snapshots.packets == UINT64_C(-1)) {
+               /*
+                * Stream's first packet or no information about
+                * discarded packets: do not emit. In other words, if
+                * this is the first packet and its sequence number is
+                * not 0, do not consider that packets were previously
+                * lost: we might be reading a partial stream (LTTng
+                * snapshot for example).
+                */
+               notit->state = STATE_EMIT_MSG_PACKET_BEGINNING;
+       } else {
+               /*
+                * If the previous packet has a value for this counter,
+                * then this counter is defined for the whole stream.
+                */
+               BT_ASSERT(notit->snapshots.packets != UINT64_C(-1));
+
+               if (notit->snapshots.packets -
+                               notit->prev_packet_snapshots.packets <= 1) {
+                       /*
+                        * No discarded packets since previous packet:
+                        * do not emit.
+                        */
+                       notit->state = STATE_EMIT_MSG_PACKET_BEGINNING;
+               }
+       }
+
+end:
+       return BT_MSG_ITER_STATUS_OK;
+}
+
+static
+enum bt_msg_iter_status check_emit_msg_stream_activity_end(
+               struct bt_msg_iter *notit)
+{
+       if (notit->emit_stream_end_msg) {
+               notit->state = STATE_EMIT_MSG_STREAM_ACTIVITY_END;
+       } else {
+               notit->state = STATE_DONE;
+       }
+
+       return BT_MSG_ITER_STATUS_OK;
+}
+
+static inline
+enum bt_msg_iter_status handle_state(struct bt_msg_iter *notit)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+       const enum state state = notit->state;
+
+       BT_LOGV("Handling state: notit-addr=%p, state=%s",
+               notit, state_string(state));
+
+       // TODO: optimalize!
+       switch (state) {
+       case STATE_INIT:
+               notit->state = STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN;
+               break;
+       case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
+               status = read_packet_header_begin_state(notit);
+               break;
+       case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
+               status = read_packet_header_continue_state(notit);
+               break;
+       case STATE_AFTER_TRACE_PACKET_HEADER:
+               status = after_packet_header_state(notit);
+               break;
+       case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
+               status = read_packet_context_begin_state(notit);
+               break;
+       case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
+               status = read_packet_context_continue_state(notit);
+               break;
+       case STATE_AFTER_STREAM_PACKET_CONTEXT:
+               status = after_packet_context_state(notit);
+               break;
+       case STATE_CHECK_EMIT_MSG_STREAM_BEGINNING:
+               status = check_emit_msg_stream_beginning_state(notit);
+               break;
+       case STATE_EMIT_MSG_STREAM_BEGINNING:
+               notit->state = STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING;
+               break;
+       case STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING:
+               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS;
+               break;
+       case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
+               status = check_emit_msg_discarded_events(notit);
+               break;
+       case STATE_EMIT_MSG_DISCARDED_EVENTS:
+               notit->state = STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS;
+               break;
+       case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
+               status = check_emit_msg_discarded_packets(notit);
+               break;
+       case STATE_EMIT_MSG_DISCARDED_PACKETS:
+               notit->state = STATE_EMIT_MSG_PACKET_BEGINNING;
+               break;
+       case STATE_EMIT_MSG_PACKET_BEGINNING:
+               notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
+               break;
+       case STATE_DSCOPE_EVENT_HEADER_BEGIN:
+               status = read_event_header_begin_state(notit);
+               break;
+       case STATE_DSCOPE_EVENT_HEADER_CONTINUE:
+               status = read_event_header_continue_state(notit);
+               break;
+       case STATE_AFTER_EVENT_HEADER:
+               status = after_event_header_state(notit);
+               break;
+       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_BEGIN:
+               status = read_event_common_context_begin_state(notit);
+               break;
+       case STATE_DSCOPE_EVENT_COMMON_CONTEXT_CONTINUE:
+               status = read_event_common_context_continue_state(notit);
+               break;
+       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_BEGIN:
+               status = read_event_spec_context_begin_state(notit);
+               break;
+       case STATE_DSCOPE_EVENT_SPEC_CONTEXT_CONTINUE:
+               status = read_event_spec_context_continue_state(notit);
+               break;
+       case STATE_DSCOPE_EVENT_PAYLOAD_BEGIN:
+               status = read_event_payload_begin_state(notit);
+               break;
+       case STATE_DSCOPE_EVENT_PAYLOAD_CONTINUE:
+               status = read_event_payload_continue_state(notit);
+               break;
+       case STATE_EMIT_MSG_EVENT:
+               notit->state = STATE_DSCOPE_EVENT_HEADER_BEGIN;
+               break;
+       case STATE_SKIP_PACKET_PADDING:
+               status = skip_packet_padding_state(notit);
+               break;
+       case STATE_EMIT_MSG_PACKET_END_MULTI:
+               notit->state = STATE_SKIP_PACKET_PADDING;
+               break;
+       case STATE_EMIT_MSG_PACKET_END_SINGLE:
+               notit->state = STATE_CHECK_EMIT_MSG_STREAM_ACTIVITY_END;
+               break;
+       case STATE_CHECK_EMIT_MSG_STREAM_ACTIVITY_END:
+               status = check_emit_msg_stream_activity_end(notit);
+               break;
+       case STATE_EMIT_MSG_STREAM_ACTIVITY_END:
+               notit->state = STATE_EMIT_MSG_STREAM_END;
+               break;
+       case STATE_EMIT_MSG_STREAM_END:
+               notit->state = STATE_DONE;
+               break;
+       case STATE_DONE:
+               break;
+       default:
+               BT_LOGD("Unknown CTF plugin message iterator state: "
+                       "notit-addr=%p, state=%d", notit, notit->state);
+               abort();
+       }
+
+       BT_LOGV("Handled state: notit-addr=%p, status=%s, "
+               "prev-state=%s, cur-state=%s",
+               notit, bt_msg_iter_status_string(status),
+               state_string(state), state_string(notit->state));
+       return status;
+}
+
+BT_HIDDEN
+void bt_msg_iter_reset_for_next_stream_file(struct bt_msg_iter *notit)
+{
+       BT_ASSERT(notit);
+       BT_LOGD("Resetting message iterator: addr=%p", notit);
+       stack_clear(notit->stack);
+       notit->meta.sc = NULL;
+       notit->meta.ec = NULL;
+       BT_PACKET_PUT_REF_AND_RESET(notit->packet);
+       BT_STREAM_PUT_REF_AND_RESET(notit->stream);
+       BT_MESSAGE_PUT_REF_AND_RESET(notit->event_msg);
+       release_all_dscopes(notit);
+       notit->cur_dscope_field = NULL;
+
+       if (notit->packet_context_field) {
+               bt_packet_context_field_release(notit->packet_context_field);
+               notit->packet_context_field = NULL;
+       }
+
+       notit->buf.addr = NULL;
+       notit->buf.sz = 0;
+       notit->buf.at = 0;
+       notit->buf.last_eh_at = SIZE_MAX;
+       notit->buf.packet_offset = 0;
+       notit->state = STATE_INIT;
+       notit->cur_exp_packet_content_size = -1;
+       notit->cur_exp_packet_total_size = -1;
+       notit->cur_packet_offset = -1;
+       notit->cur_event_class_id = -1;
+       notit->snapshots.beginning_clock = UINT64_C(-1);
+       notit->snapshots.end_clock = UINT64_C(-1);
+}
+
+/**
+ * Resets the internal state of a CTF message iterator.
+ */
+BT_HIDDEN
+void bt_msg_iter_reset(struct bt_msg_iter *notit)
+{
+       bt_msg_iter_reset_for_next_stream_file(notit);
+       notit->cur_stream_class_id = -1;
+       notit->cur_data_stream_id = -1;
+       notit->emit_stream_begin_msg = true;
+       notit->emit_stream_end_msg = true;
+       notit->snapshots.discarded_events = UINT64_C(-1);
+       notit->snapshots.packets = UINT64_C(-1);
+       notit->prev_packet_snapshots.discarded_events = UINT64_C(-1);
+       notit->prev_packet_snapshots.packets = UINT64_C(-1);
+       notit->prev_packet_snapshots.beginning_clock = UINT64_C(-1);
+       notit->prev_packet_snapshots.end_clock = UINT64_C(-1);
+}
+
+static
+int bt_msg_iter_switch_packet(struct bt_msg_iter *notit)
+{
+       int ret = 0;
+
+       /*
+        * We don't put the stream class here because we need to make
+        * sure that all the packets processed by the same message
+        * iterator refer to the same stream class (the first one).
+        */
+       BT_ASSERT(notit);
+
+       if (notit->cur_exp_packet_total_size != -1) {
+               notit->cur_packet_offset += notit->cur_exp_packet_total_size;
+       }
+
+       BT_LOGV("Switching packet: notit-addr=%p, cur=%zu, "
+               "packet-offset=%" PRId64, notit, notit->buf.at,
+               notit->cur_packet_offset);
+       stack_clear(notit->stack);
+       notit->meta.ec = NULL;
+       BT_PACKET_PUT_REF_AND_RESET(notit->packet);
+       BT_MESSAGE_PUT_REF_AND_RESET(notit->event_msg);
+       release_all_dscopes(notit);
+       notit->cur_dscope_field = NULL;
+
+       /*
+        * Adjust current buffer so that addr points to the beginning of the new
+        * packet.
+        */
+       if (notit->buf.addr) {
+               size_t consumed_bytes = (size_t) (notit->buf.at / CHAR_BIT);
+
+               /* Packets are assumed to start on a byte frontier. */
+               if (notit->buf.at % CHAR_BIT) {
+                       BT_LOGW("Cannot switch packet: current position is not a multiple of 8: "
+                               "notit-addr=%p, cur=%zu", notit, notit->buf.at);
+                       ret = -1;
+                       goto end;
+               }
+
+               notit->buf.addr += consumed_bytes;
+               notit->buf.sz -= consumed_bytes;
+               notit->buf.at = 0;
+               notit->buf.packet_offset = 0;
+               BT_LOGV("Adjusted buffer: addr=%p, size=%zu",
+                       notit->buf.addr, notit->buf.sz);
+       }
+
+       notit->cur_exp_packet_content_size = -1;
+       notit->cur_exp_packet_total_size = -1;
+       notit->cur_stream_class_id = -1;
+       notit->cur_event_class_id = -1;
+       notit->cur_data_stream_id = -1;
+       notit->prev_packet_snapshots = notit->snapshots;
+       notit->snapshots.discarded_events = UINT64_C(-1);
+       notit->snapshots.packets = UINT64_C(-1);
+       notit->snapshots.beginning_clock = UINT64_C(-1);
+       notit->snapshots.end_clock = UINT64_C(-1);
+
+end:
+       return ret;
+}
+
+static
+bt_field *borrow_next_field(struct bt_msg_iter *notit)
+{
+       bt_field *next_field = NULL;
+       bt_field *base_field;
+       const bt_field_class *base_fc;
+       size_t index;
+
+       BT_ASSERT(!stack_empty(notit->stack));
+       index = stack_top(notit->stack)->index;
+       base_field = stack_top(notit->stack)->base;
+       BT_ASSERT(base_field);
+       base_fc = bt_field_borrow_class_const(base_field);
+       BT_ASSERT(base_fc);
+
+       switch (bt_field_class_get_type(base_fc)) {
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       {
+               BT_ASSERT(index <
+                       bt_field_class_structure_get_member_count(
+                               bt_field_borrow_class_const(
+                                               base_field)));
+               next_field =
+                       bt_field_structure_borrow_member_field_by_index(
+                               base_field, index);
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+               BT_ASSERT(index < bt_field_array_get_length(base_field));
+               next_field = bt_field_array_borrow_element_field_by_index(
+                       base_field, index);
+               break;
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+               BT_ASSERT(index == 0);
+               next_field = bt_field_variant_borrow_selected_option_field(
+                       base_field);
+               break;
+       default:
+               abort();
+       }
+
+       BT_ASSERT(next_field);
+       return next_field;
+}
+
+static
+void update_default_clock(struct bt_msg_iter *notit, uint64_t new_val,
+               uint64_t new_val_size)
+{
+       uint64_t new_val_mask;
+       uint64_t cur_value_masked;
+
+       BT_ASSERT(new_val_size > 0);
+
+       /*
+        * Special case for a 64-bit new value, which is the limit
+        * of a clock value as of this version: overwrite the
+        * current value directly.
+        */
+       if (new_val_size == 64) {
+               notit->default_clock_snapshot = new_val;
+               goto end;
+       }
+
+       new_val_mask = (1ULL << new_val_size) - 1;
+       cur_value_masked = notit->default_clock_snapshot & new_val_mask;
+
+       if (new_val < cur_value_masked) {
+               /*
+                * It looks like a wrap happened on the number of bits
+                * of the requested new value. Assume that the clock
+                * value wrapped only one time.
+                */
+               notit->default_clock_snapshot += new_val_mask + 1;
+       }
+
+       /* Clear the low bits of the current clock value. */
+       notit->default_clock_snapshot &= ~new_val_mask;
+
+       /* Set the low bits of the current clock value. */
+       notit->default_clock_snapshot |= new_val;
+
+end:
+       BT_LOGV("Updated default clock's value from integer field's value: "
+               "value=%" PRIu64, notit->default_clock_snapshot);
+}
+
+static
+enum bt_bfcr_status bfcr_unsigned_int_cb(uint64_t value,
+               struct ctf_field_class *fc, void *data)
+{
+       struct bt_msg_iter *notit = data;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       bt_field *field = NULL;
+       struct ctf_field_class_int *int_fc = (void *) fc;
+
+       BT_LOGV("Unsigned integer function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d, value=%" PRIu64,
+               notit, notit->bfcr, fc, fc->type, fc->in_ir, value);
+
+       if (likely(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE)) {
+               goto update_def_clock;
+       }
+
+       switch (int_fc->meaning) {
+       case CTF_FIELD_CLASS_MEANING_EVENT_CLASS_ID:
+               notit->cur_event_class_id = value;
+               break;
+       case CTF_FIELD_CLASS_MEANING_DATA_STREAM_ID:
+               notit->cur_data_stream_id = value;
+               break;
+       case CTF_FIELD_CLASS_MEANING_PACKET_BEGINNING_TIME:
+               notit->snapshots.beginning_clock = value;
+               break;
+       case CTF_FIELD_CLASS_MEANING_PACKET_END_TIME:
+               notit->snapshots.end_clock = value;
+               break;
+       case CTF_FIELD_CLASS_MEANING_STREAM_CLASS_ID:
+               notit->cur_stream_class_id = value;
+               break;
+       case CTF_FIELD_CLASS_MEANING_MAGIC:
+               if (value != 0xc1fc1fc1) {
+                       BT_LOGW("Invalid CTF magic number: notit-addr=%p, "
+                               "magic=%" PRIx64, notit, value);
+                       status = BT_BFCR_STATUS_ERROR;
+                       goto end;
+               }
+
+               break;
+       case CTF_FIELD_CLASS_MEANING_PACKET_COUNTER_SNAPSHOT:
+               notit->snapshots.packets = value;
+               break;
+       case CTF_FIELD_CLASS_MEANING_DISC_EV_REC_COUNTER_SNAPSHOT:
+               notit->snapshots.discarded_events = value;
+               break;
+       case CTF_FIELD_CLASS_MEANING_EXP_PACKET_TOTAL_SIZE:
+               notit->cur_exp_packet_total_size = value;
+               break;
+       case CTF_FIELD_CLASS_MEANING_EXP_PACKET_CONTENT_SIZE:
+               notit->cur_exp_packet_content_size = value;
+               break;
+       default:
+               abort();
+       }
+
+update_def_clock:
+       if (unlikely(int_fc->mapped_clock_class)) {
+               update_default_clock(notit, value, int_fc->base.size);
+       }
+
+       if (unlikely(int_fc->storing_index >= 0)) {
+               g_array_index(notit->stored_values, uint64_t,
+                       (uint64_t) int_fc->storing_index) = value;
+       }
+
+       if (unlikely(!fc->in_ir)) {
+               goto end;
+       }
+
+       field = borrow_next_field(notit);
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
+       BT_ASSERT(bt_field_get_class_type(field) ==
+                 BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
+                 bt_field_get_class_type(field) ==
+                 BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION);
+       bt_field_unsigned_integer_set_value(field, value);
+       stack_top(notit->stack)->index++;
+
+end:
+       return status;
+}
+
+static
+enum bt_bfcr_status bfcr_unsigned_int_char_cb(uint64_t value,
+               struct ctf_field_class *fc, void *data)
+{
+       int ret;
+       struct bt_msg_iter *notit = data;
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       bt_field *string_field = NULL;
+       struct ctf_field_class_int *int_fc = (void *) fc;
+       char str[2] = {'\0', '\0'};
+
+       BT_LOGV("Unsigned integer character function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d, value=%" PRIu64,
+               notit, notit->bfcr, fc, fc->type, fc->in_ir, value);
+       BT_ASSERT(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
+       BT_ASSERT(!int_fc->mapped_clock_class);
+       BT_ASSERT(int_fc->storing_index < 0);
+
+       if (unlikely(!fc->in_ir)) {
+               goto end;
+       }
+
+       if (notit->done_filling_string) {
+               goto end;
+       }
+
+       if (value == 0) {
+               notit->done_filling_string = true;
+               goto end;
+       }
+
+       string_field = stack_top(notit->stack)->base;
+       BT_ASSERT(bt_field_get_class_type(string_field) ==
+                 BT_FIELD_CLASS_TYPE_STRING);
+
+       /* Append character */
+       str[0] = (char) value;
+       ret = bt_field_string_append_with_length(string_field, str, 1);
+       if (ret) {
+               BT_LOGE("Cannot append character to string field's value: "
+                       "notit-addr=%p, field-addr=%p, ret=%d",
+                       notit, string_field, ret);
+               status = BT_BFCR_STATUS_ERROR;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_bfcr_status bfcr_signed_int_cb(int64_t value,
+               struct ctf_field_class *fc, void *data)
+{
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       bt_field *field = NULL;
+       struct bt_msg_iter *notit = data;
+       struct ctf_field_class_int *int_fc = (void *) fc;
+
+       BT_LOGV("Signed integer function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d, value=%" PRId64,
+               notit, notit->bfcr, fc, fc->type, fc->in_ir, value);
+       BT_ASSERT(int_fc->meaning == CTF_FIELD_CLASS_MEANING_NONE);
+
+       if (unlikely(int_fc->storing_index >= 0)) {
+               g_array_index(notit->stored_values, uint64_t,
+                       (uint64_t) int_fc->storing_index) = (uint64_t) value;
+       }
+
+       if (unlikely(!fc->in_ir)) {
+               goto end;
+       }
+
+       field = borrow_next_field(notit);
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
+       BT_ASSERT(bt_field_get_class_type(field) ==
+                 BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
+                 bt_field_get_class_type(field) ==
+                 BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION);
+       bt_field_signed_integer_set_value(field, value);
+       stack_top(notit->stack)->index++;
+
+end:
+       return status;
+}
+
+static
+enum bt_bfcr_status bfcr_floating_point_cb(double value,
+               struct ctf_field_class *fc, void *data)
+{
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       bt_field *field = NULL;
+       struct bt_msg_iter *notit = data;
+
+       BT_LOGV("Floating point number function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d, value=%f",
+               notit, notit->bfcr, fc, fc->type, fc->in_ir, value);
+
+       if (unlikely(!fc->in_ir)) {
+               goto end;
+       }
+
+       field = borrow_next_field(notit);
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
+       BT_ASSERT(bt_field_get_class_type(field) ==
+                 BT_FIELD_CLASS_TYPE_REAL);
+       bt_field_real_set_value(field, value);
+       stack_top(notit->stack)->index++;
+
+end:
+       return status;
+}
+
+static
+enum bt_bfcr_status bfcr_string_begin_cb(
+               struct ctf_field_class *fc, void *data)
+{
+       bt_field *field = NULL;
+       struct bt_msg_iter *notit = data;
+       int ret;
+
+       BT_LOGV("String (beginning) function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d",
+               notit, notit->bfcr, fc, fc->type, fc->in_ir);
+
+       if (unlikely(!fc->in_ir)) {
+               goto end;
+       }
+
+       field = borrow_next_field(notit);
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
+       BT_ASSERT(bt_field_get_class_type(field) ==
+                 BT_FIELD_CLASS_TYPE_STRING);
+       ret = bt_field_string_clear(field);
+       BT_ASSERT(ret == 0);
+
+       /*
+        * Push on stack. Not a compound class per se, but we know that
+        * only bfcr_string_cb() may be called between this call and a
+        * subsequent call to bfcr_string_end_cb().
+        */
+       stack_push(notit->stack, field);
+
+end:
+       return BT_BFCR_STATUS_OK;
+}
+
+static
+enum bt_bfcr_status bfcr_string_cb(const char *value,
+               size_t len, struct ctf_field_class *fc, void *data)
+{
+       enum bt_bfcr_status status = BT_BFCR_STATUS_OK;
+       bt_field *field = NULL;
+       struct bt_msg_iter *notit = data;
+       int ret;
+
+       BT_LOGV("String (substring) function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d, string-length=%zu",
+               notit, notit->bfcr, fc, fc->type, fc->in_ir,
+               len);
+
+       if (unlikely(!fc->in_ir)) {
+               goto end;
+       }
+
+       field = stack_top(notit->stack)->base;
+       BT_ASSERT(field);
+
+       /* Append current substring */
+       ret = bt_field_string_append_with_length(field, value, len);
+       if (ret) {
+               BT_LOGE("Cannot append substring to string field's value: "
+                       "notit-addr=%p, field-addr=%p, string-length=%zu, "
+                       "ret=%d", notit, field, len, ret);
+               status = BT_BFCR_STATUS_ERROR;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_bfcr_status bfcr_string_end_cb(
+               struct ctf_field_class *fc, void *data)
+{
+       struct bt_msg_iter *notit = data;
+
+       BT_LOGV("String (end) function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d",
+               notit, notit->bfcr, fc, fc->type, fc->in_ir);
+
+       if (unlikely(!fc->in_ir)) {
+               goto end;
+       }
+
+       /* Pop string field */
+       stack_pop(notit->stack);
+
+       /* Go to next field */
+       stack_top(notit->stack)->index++;
+
+end:
+       return BT_BFCR_STATUS_OK;
+}
+
+enum bt_bfcr_status bfcr_compound_begin_cb(
+               struct ctf_field_class *fc, void *data)
+{
+       struct bt_msg_iter *notit = data;
+       bt_field *field;
+
+       BT_LOGV("Compound (beginning) function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d",
+               notit, notit->bfcr, fc, fc->type, fc->in_ir);
+
+       if (!fc->in_ir) {
+               goto end;
+       }
+
+       /* Borrow field */
+       if (stack_empty(notit->stack)) {
+               /* Root: already set by read_dscope_begin_state() */
+               field = notit->cur_dscope_field;
+       } else {
+               field = borrow_next_field(notit);
+               BT_ASSERT(field);
+       }
+
+       /* Push field */
+       BT_ASSERT(field);
+       BT_ASSERT(bt_field_borrow_class_const(field) == fc->ir_fc);
+       stack_push(notit->stack, field);
+
+       /*
+        * Change BFCR "unsigned int" callback if it's a text
+        * array/sequence.
+        */
+       if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY ||
+                       fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               if (array_fc->is_text) {
+                       int ret;
+
+                       BT_ASSERT(bt_field_get_class_type(field) ==
+                                 BT_FIELD_CLASS_TYPE_STRING);
+                       notit->done_filling_string = false;
+                       ret = bt_field_string_clear(field);
+                       BT_ASSERT(ret == 0);
+                       bt_bfcr_set_unsigned_int_cb(notit->bfcr,
+                               bfcr_unsigned_int_char_cb);
+               }
+       }
+
+end:
+       return BT_BFCR_STATUS_OK;
+}
+
+enum bt_bfcr_status bfcr_compound_end_cb(
+               struct ctf_field_class *fc, void *data)
+{
+       struct bt_msg_iter *notit = data;
+
+       BT_LOGV("Compound (end) function called from BFCR: "
+               "notit-addr=%p, bfcr-addr=%p, fc-addr=%p, "
+               "fc-type=%d, fc-in-ir=%d",
+               notit, notit->bfcr, fc, fc->type, fc->in_ir);
+
+       if (!fc->in_ir) {
+               goto end;
+       }
+
+       BT_ASSERT(!stack_empty(notit->stack));
+       BT_ASSERT(bt_field_borrow_class_const(stack_top(notit->stack)->base) ==
+               fc->ir_fc);
+
+       /*
+        * Reset BFCR "unsigned int" callback if it's a text
+        * array/sequence.
+        */
+       if (fc->type == CTF_FIELD_CLASS_TYPE_ARRAY ||
+                       fc->type == CTF_FIELD_CLASS_TYPE_SEQUENCE) {
+               struct ctf_field_class_array_base *array_fc = (void *) fc;
+
+               if (array_fc->is_text) {
+                       BT_ASSERT(bt_field_get_class_type(
+                               stack_top(notit->stack)->base) ==
+                               BT_FIELD_CLASS_TYPE_STRING);
+                       bt_bfcr_set_unsigned_int_cb(notit->bfcr,
+                               bfcr_unsigned_int_cb);
+               }
+       }
+
+       /* Pop stack */
+       stack_pop(notit->stack);
+
+       /* If the stack is not empty, increment the base's index */
+       if (!stack_empty(notit->stack)) {
+               stack_top(notit->stack)->index++;
+       }
+
+end:
+       return BT_BFCR_STATUS_OK;
+}
+
+static
+int64_t bfcr_get_sequence_length_cb(struct ctf_field_class *fc, void *data)
+{
+       bt_field *seq_field;
+       struct bt_msg_iter *notit = data;
+       struct ctf_field_class_sequence *seq_fc = (void *) fc;
+       int64_t length = -1;
+       int ret;
+
+       length = (uint64_t) g_array_index(notit->stored_values, uint64_t,
+               seq_fc->stored_length_index);
+       seq_field = stack_top(notit->stack)->base;
+       BT_ASSERT(seq_field);
+
+       /*
+        * bfcr_get_sequence_length_cb() also gets called back for a
+        * text sequence, but the destination field is a string field.
+        * Only set the field's sequence length if the destination field
+        * is a sequence field.
+        */
+       if (!seq_fc->base.is_text) {
+               BT_ASSERT(bt_field_get_class_type(seq_field) ==
+                       BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY);
+               ret = bt_field_dynamic_array_set_length(seq_field,
+                       (uint64_t) length);
+               if (ret) {
+                       BT_LOGE("Cannot set dynamic array field's length field: "
+                               "notit-addr=%p, field-addr=%p, "
+                               "length=%" PRIu64, notit, seq_field, length);
+               }
+       }
+
+       return length;
+}
+
+static
+struct ctf_field_class *bfcr_borrow_variant_selected_field_class_cb(
+               struct ctf_field_class *fc, void *data)
+{
+       int ret;
+       uint64_t i;
+       int64_t option_index = -1;
+       struct bt_msg_iter *notit = data;
+       struct ctf_field_class_variant *var_fc = (void *) fc;
+       struct ctf_named_field_class *selected_option = NULL;
+       struct ctf_field_class *ret_fc = NULL;
+       union {
+               uint64_t u;
+               int64_t i;
+       } tag;
+
+       /* Get variant's tag */
+       tag.u = g_array_index(notit->stored_values, uint64_t,
+               var_fc->stored_tag_index);
+
+       /*
+        * Check each range to find the selected option's index.
+        */
+       if (var_fc->tag_fc->base.is_signed) {
+               for (i = 0; i < var_fc->ranges->len; i++) {
+                       struct ctf_field_class_variant_range *range =
+                               ctf_field_class_variant_borrow_range_by_index(
+                                       var_fc, i);
+
+                       if (tag.i >= range->range.lower.i &&
+                                       tag.i <= range->range.upper.i) {
+                               option_index = (int64_t) range->option_index;
+                               break;
+                       }
+               }
+       } else {
+               for (i = 0; i < var_fc->ranges->len; i++) {
+                       struct ctf_field_class_variant_range *range =
+                               ctf_field_class_variant_borrow_range_by_index(
+                                       var_fc, i);
+
+                       if (tag.u >= range->range.lower.u &&
+                                       tag.u <= range->range.upper.u) {
+                               option_index = (int64_t) range->option_index;
+                               break;
+                       }
+               }
+       }
+
+       if (option_index < 0) {
+               BT_LOGW("Cannot find variant field class's option: "
+                       "notit-addr=%p, var-fc-addr=%p, u-tag=%" PRIu64 ", "
+                       "i-tag=%" PRId64, notit, var_fc, tag.u, tag.i);
+               goto end;
+       }
+
+       selected_option = ctf_field_class_variant_borrow_option_by_index(
+               var_fc, (uint64_t) option_index);
+
+       if (selected_option->fc->in_ir) {
+               bt_field *var_field = stack_top(notit->stack)->base;
+
+               ret = bt_field_variant_select_option_field(
+                       var_field, option_index);
+               if (ret) {
+                       BT_LOGW("Cannot select variant field's option field: "
+                               "notit-addr=%p, var-field-addr=%p, "
+                               "opt-index=%" PRId64, notit, var_field,
+                               option_index);
+                       goto end;
+               }
+       }
+
+       ret_fc = selected_option->fc;
+
+end:
+       return ret_fc;
+}
+
+static
+void create_msg_stream_beginning(struct bt_msg_iter *notit,
+               bt_message **message)
+{
+       bt_message *ret = NULL;
+
+       BT_ASSERT(notit->stream);
+       BT_ASSERT(notit->msg_iter);
+       ret = bt_message_stream_beginning_create(notit->msg_iter,
+               notit->stream);
+       if (!ret) {
+               BT_LOGE("Cannot create stream beginning message: "
+                       "notit-addr=%p, stream-addr=%p",
+                       notit, notit->stream);
+               return;
+       }
+
+       *message = ret;
+}
+
+static
+void create_msg_stream_activity_beginning(struct bt_msg_iter *notit,
+               bt_message **message)
+{
+       bt_message *ret = NULL;
+
+       BT_ASSERT(notit->stream);
+       BT_ASSERT(notit->msg_iter);
+       ret = bt_message_stream_activity_beginning_create(notit->msg_iter,
+               notit->stream);
+       if (!ret) {
+               BT_LOGE("Cannot create stream activity beginning message: "
+                       "notit-addr=%p, stream-addr=%p",
+                       notit, notit->stream);
+               return;
+       }
+
+       *message = ret;
+}
+
+static
+void create_msg_stream_activity_end(struct bt_msg_iter *notit,
+               bt_message **message)
+{
+       bt_message *ret = NULL;
+
+       if (!notit->stream) {
+               BT_LOGE("Cannot create stream for stream message: "
+                       "notit-addr=%p", notit);
+               return;
+       }
+
+       BT_ASSERT(notit->stream);
+       BT_ASSERT(notit->msg_iter);
+       ret = bt_message_stream_activity_end_create(notit->msg_iter,
+               notit->stream);
+       if (!ret) {
+               BT_LOGE("Cannot create stream activity end message: "
+                       "notit-addr=%p, stream-addr=%p",
+                       notit, notit->stream);
+               return;
+       }
+
+       *message = ret;
+}
+
+static
+void create_msg_stream_end(struct bt_msg_iter *notit, bt_message **message)
+{
+       bt_message *ret;
+
+       if (!notit->stream) {
+               BT_LOGE("Cannot create stream for stream message: "
+                       "notit-addr=%p", notit);
+               return;
+       }
+
+       BT_ASSERT(notit->msg_iter);
+       ret = bt_message_stream_end_create(notit->msg_iter,
+               notit->stream);
+       if (!ret) {
+               BT_LOGE("Cannot create stream end message: "
+                       "notit-addr=%p, stream-addr=%p",
+                       notit, notit->stream);
+               return;
+       }
+
+       *message = ret;
+}
+
+static
+void create_msg_packet_beginning(struct bt_msg_iter *notit,
+               bt_message **message)
+{
+       int ret;
+       enum bt_msg_iter_status status;
+       bt_message *msg = NULL;
+       const bt_stream_class *sc;
+
+       status = set_current_packet(notit);
+       if (status != BT_MSG_ITER_STATUS_OK) {
+               goto end;
+       }
+
+       BT_ASSERT(notit->packet);
+       sc = notit->meta.sc->ir_sc;
+       BT_ASSERT(sc);
+
+       if (notit->packet_context_field) {
+               ret = bt_packet_move_context_field(
+                       notit->packet, notit->packet_context_field);
+               if (ret) {
+                       goto end;
+               }
+
+               notit->packet_context_field = NULL;
+
+               /*
+                * At this point notit->dscopes.stream_packet_context
+                * has the same value as the packet context field within
+                * notit->packet.
+                */
+               BT_ASSERT(bt_packet_borrow_context_field(
+                       notit->packet) ==
+                       notit->dscopes.stream_packet_context);
+       }
+
+       BT_ASSERT(notit->msg_iter);
+
+       if (notit->meta.sc->packets_have_ts_begin) {
+               BT_ASSERT(notit->snapshots.beginning_clock != UINT64_C(-1));
+               msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
+                       notit->msg_iter, notit->packet,
+                       notit->snapshots.beginning_clock);
+       } else {
+               msg = bt_message_packet_beginning_create(notit->msg_iter,
+                       notit->packet);
+       }
+
+       if (!msg) {
+               BT_LOGE("Cannot create packet beginning message: "
+                       "notit-addr=%p, packet-addr=%p",
+                       notit, notit->packet);
+               goto end;
+       }
+
+       *message = msg;
+
+end:
+       return;
+}
+
+static
+void create_msg_packet_end(struct bt_msg_iter *notit, bt_message **message)
+{
+       bt_message *msg;
+
+       if (!notit->packet) {
+               return;
+       }
+
+       /* Update default clock from packet's end time */
+       if (notit->snapshots.end_clock != UINT64_C(-1)) {
+               notit->default_clock_snapshot = notit->snapshots.end_clock;
+       }
+
+       BT_ASSERT(notit->msg_iter);
+
+       if (notit->meta.sc->packets_have_ts_end) {
+               BT_ASSERT(notit->snapshots.end_clock != UINT64_C(-1));
+               msg = bt_message_packet_end_create_with_default_clock_snapshot(
+                       notit->msg_iter, notit->packet,
+                       notit->snapshots.end_clock);
+       } else {
+               msg = bt_message_packet_end_create(notit->msg_iter,
+                       notit->packet);
+       }
+
+       if (!msg) {
+               BT_LOGE("Cannot create packet end message: "
+                       "notit-addr=%p, packet-addr=%p",
+                       notit, notit->packet);
+               return;
+
+       }
+
+       BT_PACKET_PUT_REF_AND_RESET(notit->packet);
+       *message = msg;
+}
+
+static
+void create_msg_discarded_events(struct bt_msg_iter *notit,
+               bt_message **message)
+{
+       bt_message *msg;
+       uint64_t beginning_raw_value = UINT64_C(-1);
+       uint64_t end_raw_value = UINT64_C(-1);
+
+       BT_ASSERT(notit->msg_iter);
+       BT_ASSERT(notit->stream);
+       BT_ASSERT(notit->meta.sc->has_discarded_events);
+
+       if (notit->meta.sc->discarded_events_have_default_cs) {
+               if (notit->prev_packet_snapshots.discarded_events == UINT64_C(-1)) {
+                       /*
+                        * We discarded events, but before (and possibly
+                        * including) the current packet: use this packet's time
+                        * range, and do not have a specific count.
+                        */
+                       beginning_raw_value = notit->snapshots.beginning_clock;
+                       end_raw_value = notit->snapshots.end_clock;
+               } else {
+                       beginning_raw_value = notit->prev_packet_snapshots.end_clock;
+                       end_raw_value = notit->snapshots.end_clock;
+               }
+
+               BT_ASSERT(beginning_raw_value != UINT64_C(-1));
+               BT_ASSERT(end_raw_value != UINT64_C(-1));
+               msg = bt_message_discarded_events_create_with_default_clock_snapshots(
+                       notit->msg_iter, notit->stream, beginning_raw_value,
+                       end_raw_value);
+       } else {
+               msg = bt_message_discarded_events_create(notit->msg_iter,
+                       notit->stream);
+       }
+
+       if (!msg) {
+               BT_LOGE("Cannot create discarded events message: "
+                       "notit-addr=%p, stream-addr=%p",
+                       notit, notit->stream);
+               return;
+       }
+
+       if (notit->prev_packet_snapshots.discarded_events != UINT64_C(-1)) {
+               bt_message_discarded_events_set_count(msg,
+                       notit->snapshots.discarded_events -
+                       notit->prev_packet_snapshots.discarded_events);
+       }
+
+       *message = msg;
+}
+
+static
+void create_msg_discarded_packets(struct bt_msg_iter *notit,
+               bt_message **message)
+{
+       bt_message *msg;
+
+       BT_ASSERT(notit->msg_iter);
+       BT_ASSERT(notit->stream);
+       BT_ASSERT(notit->meta.sc->has_discarded_packets);
+       BT_ASSERT(notit->prev_packet_snapshots.packets !=
+               UINT64_C(-1));
+
+       if (notit->meta.sc->discarded_packets_have_default_cs) {
+               BT_ASSERT(notit->prev_packet_snapshots.end_clock != UINT64_C(-1));
+               BT_ASSERT(notit->snapshots.beginning_clock != UINT64_C(-1));
+               msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
+                       notit->msg_iter, notit->stream,
+                       notit->prev_packet_snapshots.end_clock,
+                       notit->snapshots.beginning_clock);
+       } else {
+               msg = bt_message_discarded_packets_create(notit->msg_iter,
+                       notit->stream);
+       }
+
+       if (!msg) {
+               BT_LOGE("Cannot create discarded packets message: "
+                       "notit-addr=%p, stream-addr=%p",
+                       notit, notit->stream);
+               return;
+       }
+
+       bt_message_discarded_packets_set_count(msg,
+               notit->snapshots.packets -
+                       notit->prev_packet_snapshots.packets - 1);
+       *message = msg;
+}
+
+BT_HIDDEN
+struct bt_msg_iter *bt_msg_iter_create(struct ctf_trace_class *tc,
+               size_t max_request_sz,
+               struct bt_msg_iter_medium_ops medops, void *data)
+{
+       struct bt_msg_iter *notit = NULL;
+       struct bt_bfcr_cbs cbs = {
+               .classes = {
+                       .signed_int = bfcr_signed_int_cb,
+                       .unsigned_int = bfcr_unsigned_int_cb,
+                       .floating_point = bfcr_floating_point_cb,
+                       .string_begin = bfcr_string_begin_cb,
+                       .string = bfcr_string_cb,
+                       .string_end = bfcr_string_end_cb,
+                       .compound_begin = bfcr_compound_begin_cb,
+                       .compound_end = bfcr_compound_end_cb,
+               },
+               .query = {
+                       .get_sequence_length = bfcr_get_sequence_length_cb,
+                       .borrow_variant_selected_field_class = bfcr_borrow_variant_selected_field_class_cb,
+               },
+       };
+
+       BT_ASSERT(tc);
+       BT_ASSERT(medops.request_bytes);
+       BT_ASSERT(medops.borrow_stream);
+       BT_LOGD("Creating CTF plugin message iterator: "
+               "trace-addr=%p, max-request-size=%zu, "
+               "data=%p", tc, max_request_sz, data);
+       notit = g_new0(struct bt_msg_iter, 1);
+       if (!notit) {
+               BT_LOGE_STR("Failed to allocate one CTF plugin message iterator.");
+               goto end;
+       }
+       notit->meta.tc = tc;
+       notit->medium.medops = medops;
+       notit->medium.max_request_sz = max_request_sz;
+       notit->medium.data = data;
+       notit->stack = stack_new(notit);
+       notit->stored_values = g_array_new(FALSE, TRUE, sizeof(uint64_t));
+       g_array_set_size(notit->stored_values, tc->stored_value_count);
+
+       if (!notit->stack) {
+               BT_LOGE_STR("Failed to create field stack.");
+               goto error;
+       }
+
+       notit->bfcr = bt_bfcr_create(cbs, notit);
+       if (!notit->bfcr) {
+               BT_LOGE_STR("Failed to create binary class reader (BFCR).");
+               goto error;
+       }
+
+       bt_msg_iter_reset(notit);
+       BT_LOGD("Created CTF plugin message iterator: "
+               "trace-addr=%p, max-request-size=%zu, "
+               "data=%p, notit-addr=%p",
+               tc, max_request_sz, data, notit);
+       notit->cur_packet_offset = 0;
+
+end:
+       return notit;
+
+error:
+       bt_msg_iter_destroy(notit);
+       notit = NULL;
+       goto end;
+}
+
+void bt_msg_iter_destroy(struct bt_msg_iter *notit)
+{
+       BT_PACKET_PUT_REF_AND_RESET(notit->packet);
+       BT_STREAM_PUT_REF_AND_RESET(notit->stream);
+       release_all_dscopes(notit);
+
+       BT_LOGD("Destroying CTF plugin message iterator: addr=%p", notit);
+
+       if (notit->stack) {
+               BT_LOGD_STR("Destroying field stack.");
+               stack_destroy(notit->stack);
+       }
+
+       if (notit->bfcr) {
+               BT_LOGD("Destroying BFCR: bfcr-addr=%p", notit->bfcr);
+               bt_bfcr_destroy(notit->bfcr);
+       }
+
+       if (notit->stored_values) {
+               g_array_free(notit->stored_values, TRUE);
+       }
+
+       g_free(notit);
+}
+
+enum bt_msg_iter_status bt_msg_iter_get_next_message(
+               struct bt_msg_iter *notit,
+               bt_self_message_iterator *msg_iter, bt_message **message)
+{
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+
+       BT_ASSERT(notit);
+       BT_ASSERT(message);
+       notit->msg_iter = msg_iter;
+       notit->set_stream = true;
+       BT_LOGV("Getting next message: notit-addr=%p", notit);
+
+       while (true) {
+               status = handle_state(notit);
+               if (unlikely(status == BT_MSG_ITER_STATUS_AGAIN)) {
+                       BT_LOGV_STR("Medium returned BT_MSG_ITER_STATUS_AGAIN.");
+                       goto end;
+               } else if (unlikely(status != BT_MSG_ITER_STATUS_OK)) {
+                       BT_LOGW("Cannot handle state: notit-addr=%p, state=%s",
+                               notit, state_string(notit->state));
+                       goto end;
+               }
+
+               switch (notit->state) {
+               case STATE_EMIT_MSG_EVENT:
+                       BT_ASSERT(notit->event_msg);
+                       *message = notit->event_msg;
+                       notit->event_msg = NULL;
+                       goto end;
+               case STATE_EMIT_MSG_DISCARDED_EVENTS:
+                       /* create_msg_discared_events() logs errors */
+                       create_msg_discarded_events(notit, message);
+
+                       if (!*message) {
+                               status = BT_MSG_ITER_STATUS_ERROR;
+                       }
+
+                       goto end;
+               case STATE_EMIT_MSG_DISCARDED_PACKETS:
+                       /* create_msg_discared_packets() logs errors */
+                       create_msg_discarded_packets(notit, message);
+
+                       if (!*message) {
+                               status = BT_MSG_ITER_STATUS_ERROR;
+                       }
+
+                       goto end;
+               case STATE_EMIT_MSG_PACKET_BEGINNING:
+                       /* create_msg_packet_beginning() logs errors */
+                       create_msg_packet_beginning(notit, message);
+
+                       if (!*message) {
+                               status = BT_MSG_ITER_STATUS_ERROR;
+                       }
+
+                       goto end;
+               case STATE_EMIT_MSG_PACKET_END_SINGLE:
+               case STATE_EMIT_MSG_PACKET_END_MULTI:
+                       /* create_msg_packet_end() logs errors */
+                       create_msg_packet_end(notit, message);
+
+                       if (!*message) {
+                               status = BT_MSG_ITER_STATUS_ERROR;
+                       }
+
+                       goto end;
+               case STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING:
+                       /* create_msg_stream_activity_beginning() logs errors */
+                       create_msg_stream_activity_beginning(notit, message);
+
+                       if (!*message) {
+                               status = BT_MSG_ITER_STATUS_ERROR;
+                       }
+
+                       goto end;
+               case STATE_EMIT_MSG_STREAM_ACTIVITY_END:
+                       /* create_msg_stream_activity_end() logs errors */
+                       create_msg_stream_activity_end(notit, message);
+
+                       if (!*message) {
+                               status = BT_MSG_ITER_STATUS_ERROR;
+                       }
+
+                       goto end;
+               case STATE_EMIT_MSG_STREAM_BEGINNING:
+                       /* create_msg_stream_beginning() logs errors */
+                       create_msg_stream_beginning(notit, message);
+
+                       if (!*message) {
+                               status = BT_MSG_ITER_STATUS_ERROR;
+                       }
+
+                       goto end;
+               case STATE_EMIT_MSG_STREAM_END:
+                       /* create_msg_stream_end() logs errors */
+                       create_msg_stream_end(notit, message);
+
+                       if (!*message) {
+                               status = BT_MSG_ITER_STATUS_ERROR;
+                       }
+
+                       goto end;
+               case STATE_DONE:
+                       status = BT_MSG_ITER_STATUS_EOF;
+                       goto end;
+               default:
+                       /* Non-emitting state: continue */
+                       break;
+               }
+       }
+
+end:
+       return status;
+}
+
+static
+enum bt_msg_iter_status read_packet_header_context_fields(
+               struct bt_msg_iter *notit)
+{
+       int ret;
+       enum bt_msg_iter_status status = BT_MSG_ITER_STATUS_OK;
+
+       BT_ASSERT(notit);
+       notit->set_stream = false;
+
+       if (notit->state == STATE_EMIT_MSG_PACKET_BEGINNING) {
+               /* We're already there */
+               goto end;
+       }
+
+       while (true) {
+               status = handle_state(notit);
+               if (unlikely(status == BT_MSG_ITER_STATUS_AGAIN)) {
+                       BT_LOGV_STR("Medium returned BT_MSG_ITER_STATUS_AGAIN.");
+                       goto end;
+               } else if (unlikely(status != BT_MSG_ITER_STATUS_OK)) {
+                       BT_LOGW("Cannot handle state: notit-addr=%p, state=%s",
+                               notit, state_string(notit->state));
+                       goto end;
+               }
+
+               switch (notit->state) {
+               case STATE_EMIT_MSG_PACKET_BEGINNING:
+                       /*
+                        * Packet header and context fields are
+                        * potentially decoded (or they don't exist).
+                        */
+                       goto end;
+               case STATE_INIT:
+               case STATE_DSCOPE_TRACE_PACKET_HEADER_BEGIN:
+               case STATE_DSCOPE_TRACE_PACKET_HEADER_CONTINUE:
+               case STATE_AFTER_TRACE_PACKET_HEADER:
+               case STATE_DSCOPE_STREAM_PACKET_CONTEXT_BEGIN:
+               case STATE_DSCOPE_STREAM_PACKET_CONTEXT_CONTINUE:
+               case STATE_AFTER_STREAM_PACKET_CONTEXT:
+               case STATE_CHECK_EMIT_MSG_STREAM_BEGINNING:
+               case STATE_EMIT_MSG_STREAM_BEGINNING:
+               case STATE_EMIT_MSG_STREAM_ACTIVITY_BEGINNING:
+               case STATE_CHECK_EMIT_MSG_DISCARDED_EVENTS:
+               case STATE_EMIT_MSG_DISCARDED_EVENTS:
+               case STATE_CHECK_EMIT_MSG_DISCARDED_PACKETS:
+               case STATE_EMIT_MSG_DISCARDED_PACKETS:
+                       /* Non-emitting state: continue */
+                       break;
+               default:
+                       /*
+                        * We should never get past the
+                        * STATE_EMIT_MSG_PACKET_BEGINNING state.
+                        */
+                       BT_LOGF("Unexpected state: notit-addr=%p, state=%s",
+                               notit, state_string(notit->state));
+                       abort();
+               }
+       }
+
+end:
+       ret = set_current_packet_content_sizes(notit);
+       if (ret) {
+               status = BT_MSG_ITER_STATUS_ERROR;
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+void bt_msg_iter_set_medops_data(struct bt_msg_iter *notit,
+               void *medops_data)
+{
+       BT_ASSERT(notit);
+       notit->medium.data = medops_data;
+}
+
+BT_HIDDEN
+enum bt_msg_iter_status bt_msg_iter_seek(struct bt_msg_iter *notit,
+               off_t offset)
+{
+       enum bt_msg_iter_status ret = BT_MSG_ITER_STATUS_OK;
+       enum bt_msg_iter_medium_status medium_status;
+
+       BT_ASSERT(notit);
+       if (offset < 0) {
+               BT_LOGE("Cannot seek to negative offset: offset=%jd", offset);
+               ret = BT_MSG_ITER_STATUS_INVAL;
+               goto end;
+       }
+
+       if (!notit->medium.medops.seek) {
+               ret = BT_MSG_ITER_STATUS_UNSUPPORTED;
+               BT_LOGD("Aborting seek as the iterator's underlying media does not implement seek support.");
+               goto end;
+       }
+
+       medium_status = notit->medium.medops.seek(
+               BT_MSG_ITER_SEEK_WHENCE_SET, offset, notit->medium.data);
+       if (medium_status != BT_MSG_ITER_MEDIUM_STATUS_OK) {
+               if (medium_status == BT_MSG_ITER_MEDIUM_STATUS_EOF) {
+                       ret = BT_MSG_ITER_STATUS_EOF;
+               } else {
+                       ret = BT_MSG_ITER_STATUS_ERROR;
+                       goto end;
+               }
+       }
+
+       bt_msg_iter_reset(notit);
+       notit->cur_packet_offset = offset;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+enum bt_msg_iter_status bt_msg_iter_get_packet_properties(
+               struct bt_msg_iter *notit,
+               struct bt_msg_iter_packet_properties *props)
+{
+       enum bt_msg_iter_status status;
+
+       BT_ASSERT(notit);
+       BT_ASSERT(props);
+       status = read_packet_header_context_fields(notit);
+       if (status != BT_MSG_ITER_STATUS_OK) {
+               goto end;
+       }
+
+       props->exp_packet_total_size = notit->cur_exp_packet_total_size;
+       props->exp_packet_content_size = notit->cur_exp_packet_content_size;
+       props->stream_class_id = (uint64_t) notit->cur_stream_class_id;
+       props->data_stream_id = notit->cur_data_stream_id;
+       props->snapshots.discarded_events = notit->snapshots.discarded_events;
+       props->snapshots.packets = notit->snapshots.packets;
+       props->snapshots.beginning_clock = notit->snapshots.beginning_clock;
+       props->snapshots.end_clock = notit->snapshots.end_clock;
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+void bt_msg_iter_set_emit_stream_beginning_message(struct bt_msg_iter *notit,
+               bool val)
+{
+       notit->emit_stream_begin_msg = val;
+}
+
+BT_HIDDEN
+void bt_msg_iter_set_emit_stream_end_message(struct bt_msg_iter *notit,
+               bool val)
+{
+       notit->emit_stream_end_msg = val;
+}
diff --git a/src/plugins/ctf/common/msg-iter/msg-iter.h b/src/plugins/ctf/common/msg-iter/msg-iter.h
new file mode 100644 (file)
index 0000000..65dd0ee
--- /dev/null
@@ -0,0 +1,382 @@
+#ifndef CTF_MSG_ITER_H
+#define CTF_MSG_ITER_H
+
+/*
+ * Babeltrace - CTF message iterator
+ *
+ * Copyright (c) 2015-2016 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015-2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+
+#include "../metadata/ctf-meta.h"
+
+/**
+ * @file ctf-msg-iter.h
+ *
+ * CTF message iterator
+ *
+ * This is a common internal API used by CTF source plugins. It allows
+ * one to get messages from a user-provided medium.
+ */
+
+/**
+ * Medium operations status codes.
+ */
+enum bt_msg_iter_medium_status {
+       /**
+        * End of file.
+        *
+        * The medium function called by the message iterator
+        * function reached the end of the file.
+        */
+       BT_MSG_ITER_MEDIUM_STATUS_EOF = 1,
+
+       /**
+        * There is no data available right now, try again later.
+        */
+       BT_MSG_ITER_MEDIUM_STATUS_AGAIN = 11,
+
+       /** Unsupported operation. */
+       BT_MSG_ITER_MEDIUM_STATUS_UNSUPPORTED = -3,
+
+       /** Invalid argument. */
+       BT_MSG_ITER_MEDIUM_STATUS_INVAL = -2,
+
+       /** General error. */
+       BT_MSG_ITER_MEDIUM_STATUS_ERROR = -1,
+
+       /** Everything okay. */
+       BT_MSG_ITER_MEDIUM_STATUS_OK = 0,
+};
+
+/**
+ * CTF message iterator API status code.
+ */
+enum bt_msg_iter_status {
+       /**
+        * End of file.
+        *
+        * The medium function called by the message iterator
+        * function reached the end of the file.
+        */
+       BT_MSG_ITER_STATUS_EOF = BT_MSG_ITER_MEDIUM_STATUS_EOF,
+
+       /**
+        * There is no data available right now, try again later.
+        *
+        * Some condition resulted in the
+        * bt_msg_iter_medium_ops::request_bytes() user function not
+        * having access to any data now. You should retry calling the
+        * last called message iterator function once the situation
+        * is resolved.
+        */
+       BT_MSG_ITER_STATUS_AGAIN = BT_MSG_ITER_MEDIUM_STATUS_AGAIN,
+
+       /** Invalid argument. */
+       BT_MSG_ITER_STATUS_INVAL = BT_MSG_ITER_MEDIUM_STATUS_INVAL,
+
+       /** Unsupported operation. */
+       BT_MSG_ITER_STATUS_UNSUPPORTED = BT_MSG_ITER_MEDIUM_STATUS_UNSUPPORTED,
+
+       /** General error. */
+       BT_MSG_ITER_STATUS_ERROR = BT_MSG_ITER_MEDIUM_STATUS_ERROR,
+
+       /** Everything okay. */
+       BT_MSG_ITER_STATUS_OK = 0,
+};
+
+/**
+ * CTF message iterator seek operation directives.
+ */
+enum bt_msg_iter_seek_whence {
+       /**
+        * Set the iterator's position to an absolute offset in the underlying
+        * medium.
+        */
+       BT_MSG_ITER_SEEK_WHENCE_SET,
+};
+
+/**
+ * Medium operations.
+ *
+ * Those user functions are called by the message iterator
+ * functions to request medium actions.
+ */
+struct bt_msg_iter_medium_ops {
+       /**
+        * Returns the next byte buffer to be used by the binary file
+        * reader to deserialize binary data.
+        *
+        * This function \em must be defined.
+        *
+        * The purpose of this function is to return a buffer of bytes
+        * to the message iterator, of a maximum of \p request_sz
+        * bytes. If this function cannot return a buffer of at least
+        * \p request_sz bytes, it may return a smaller buffer. In
+        * either cases, \p buffer_sz must be set to the returned buffer
+        * size (in bytes).
+        *
+        * The returned buffer's ownership remains the medium, in that
+        * it won't be freed by the message iterator functions. The
+        * returned buffer won't be modified by the message
+        * iterator functions either.
+        *
+        * When this function is called for the first time for a given
+        * file, the offset within the file is considered to be 0. The
+        * next times this function is called, the returned buffer's
+        * byte offset within the complete file must be the previous
+        * offset plus the last returned value of \p buffer_sz by this
+        * medium.
+        *
+        * This function must return one of the following statuses:
+        *
+        *   - <b>#BT_MSG_ITER_MEDIUM_STATUS_OK</b>: Everything
+        *     is okay, i.e. \p buffer_sz is set to a positive value
+        *     reflecting the number of available bytes in the buffer
+        *     starting at the address written in \p buffer_addr.
+        *   - <b>#BT_MSG_ITER_MEDIUM_STATUS_AGAIN</b>: No data is
+        *     available right now. In this case, the message
+        *     iterator function called by the user returns
+        *     #BT_MSG_ITER_STATUS_AGAIN, and it is the user's
+        *     responsibility to make sure enough data becomes available
+        *     before calling the \em same message iterator
+        *     function again to continue the decoding process.
+        *   - <b>#BT_MSG_ITER_MEDIUM_STATUS_EOF</b>: The end of
+        *     the file was reached, and no more data will ever be
+        *     available for this file. In this case, the message
+        *     iterator function called by the user returns
+        *     #BT_MSG_ITER_STATUS_EOF. This must \em not be
+        *     returned when returning at least one byte of data to the
+        *     caller, i.e. this must be returned when there's
+        *     absolutely nothing left; should the request size be
+        *     larger than what's left in the file, this function must
+        *     return what's left, setting \p buffer_sz to the number of
+        *     remaining bytes, and return
+        *     #BT_MSG_ITER_MEDIUM_STATUS_EOF on the \em following
+        *     call.
+        *   - <b>#BT_MSG_ITER_MEDIUM_STATUS_ERROR</b>: A fatal
+        *     error occured during this operation. In this case, the
+        *     message iterator function called by the user returns
+        *     #BT_MSG_ITER_STATUS_ERROR.
+        *
+        * If #BT_MSG_ITER_MEDIUM_STATUS_OK is not returned, the
+        * values of \p buffer_sz and \p buffer_addr are \em ignored by
+        * the caller.
+        *
+        * @param request_sz    Requested buffer size (bytes)
+        * @param buffer_addr   Returned buffer address
+        * @param buffer_sz     Returned buffer's size (bytes)
+        * @param data          User data
+        * @returns             Status code (see description above)
+        */
+       enum bt_msg_iter_medium_status (* request_bytes)(size_t request_sz,
+                       uint8_t **buffer_addr, size_t *buffer_sz, void *data);
+
+       /**
+        * Repositions the underlying stream's position.
+        *
+        * This *optional* method repositions the underlying stream
+        * to a given absolute or relative position, as indicated by
+        * the whence directive.
+        *
+        * @param whence        One of #bt_msg_iter_seek_whence values
+        * @param offset        Offset to use for the given directive
+        * @param data          User data
+        * @returns             One of #bt_msg_iter_medium_status values
+        */
+       enum bt_msg_iter_medium_status (* seek)(
+                       enum bt_msg_iter_seek_whence whence,
+                       off_t offset, void *data);
+
+       /**
+        * Returns a stream instance (weak reference) for the given
+        * stream class.
+        *
+        * This is called after a packet header is read, and the
+        * corresponding stream class is found by the message
+        * iterator.
+        *
+        * @param stream_class  Stream class of the stream to get
+        * @param stream_id     Stream (instance) ID of the stream
+        *                      to get (-1ULL if not available)
+        * @param data          User data
+        * @returns             Stream instance (weak reference) or
+        *                      \c NULL on error
+        */
+       bt_stream * (* borrow_stream)(bt_stream_class *stream_class,
+                       int64_t stream_id, void *data);
+};
+
+/** CTF message iterator. */
+struct bt_msg_iter;
+
+/**
+ * Creates a CTF message iterator.
+ *
+ * Upon successful completion, the reference count of \p trace is
+ * incremented.
+ *
+ * @param trace                        Trace to read
+ * @param max_request_sz       Maximum buffer size, in bytes, to
+ *                             request to
+ *                             bt_msg_iter_medium_ops::request_bytes()
+ *                             at a time
+ * @param medops               Medium operations
+ * @param medops_data          User data (passed to medium operations)
+ * @returns                    New CTF message iterator on
+ *                             success, or \c NULL on error
+ */
+BT_HIDDEN
+struct bt_msg_iter *bt_msg_iter_create(struct ctf_trace_class *tc,
+       size_t max_request_sz, struct bt_msg_iter_medium_ops medops,
+       void *medops_data);
+
+/**
+ * Destroys a CTF message iterator, freeing all internal resources.
+ *
+ * The registered trace's reference count is decremented.
+ *
+ * @param msg_iter             CTF message iterator
+ */
+BT_HIDDEN
+void bt_msg_iter_destroy(struct bt_msg_iter *msg_iter);
+
+/**
+ * Returns the next message from a CTF message iterator.
+ *
+ * Upon successful completion, #BT_MSG_ITER_STATUS_OK is
+ * returned, and the next message is written to \p msg.
+ * In this case, the caller is responsible for calling
+ * bt_message_put() on the returned message.
+ *
+ * If this function returns #BT_MSG_ITER_STATUS_AGAIN, the caller
+ * should make sure that data becomes available to its medium, and
+ * call this function again, until another status is returned.
+ *
+ * @param msg_iter             CTF message iterator
+ * @param message              Returned message if the function's
+ *                             return value is #BT_MSG_ITER_STATUS_OK
+ * @returns                    One of #bt_msg_iter_status values
+ */
+BT_HIDDEN
+enum bt_msg_iter_status bt_msg_iter_get_next_message(
+               struct bt_msg_iter *notit,
+               bt_self_message_iterator *msg_iter,
+               bt_message **message);
+
+struct bt_msg_iter_packet_properties {
+       int64_t exp_packet_total_size;
+       int64_t exp_packet_content_size;
+       uint64_t stream_class_id;
+       int64_t data_stream_id;
+
+       struct {
+               uint64_t discarded_events;
+               uint64_t packets;
+               uint64_t beginning_clock;
+               uint64_t end_clock;
+       } snapshots;
+};
+
+BT_HIDDEN
+enum bt_msg_iter_status bt_msg_iter_get_packet_properties(
+               struct bt_msg_iter *notit,
+               struct bt_msg_iter_packet_properties *props);
+
+BT_HIDDEN
+void bt_msg_iter_set_medops_data(struct bt_msg_iter *notit,
+               void *medops_data);
+
+BT_HIDDEN
+enum bt_msg_iter_status bt_msg_iter_seek(
+               struct bt_msg_iter *notit, off_t offset);
+
+/*
+ * Resets the iterator so that the next requested medium bytes are
+ * assumed to be the first bytes of a new stream. Depending on
+ * bt_msg_iter_set_emit_stream_beginning_message(), the first message
+ * which this iterator emits after calling bt_msg_iter_reset() is of
+ * type `BT_MESSAGE_TYPE_STREAM_BEGINNING`.
+ */
+BT_HIDDEN
+void bt_msg_iter_reset(struct bt_msg_iter *notit);
+
+/*
+ * Like bt_msg_iter_reset(), but preserves stream-dependent state.
+ */
+BT_HIDDEN
+void bt_msg_iter_reset_for_next_stream_file(struct bt_msg_iter *notit);
+
+BT_HIDDEN
+void bt_msg_iter_set_emit_stream_beginning_message(struct bt_msg_iter *notit,
+               bool val);
+
+BT_HIDDEN
+void bt_msg_iter_set_emit_stream_end_message(struct bt_msg_iter *notit,
+               bool val);
+
+static inline
+const char *bt_msg_iter_medium_status_string(
+               enum bt_msg_iter_medium_status status)
+{
+       switch (status) {
+       case BT_MSG_ITER_MEDIUM_STATUS_EOF:
+               return "BT_MSG_ITER_MEDIUM_STATUS_EOF";
+       case BT_MSG_ITER_MEDIUM_STATUS_AGAIN:
+               return "BT_MSG_ITER_MEDIUM_STATUS_AGAIN";
+       case BT_MSG_ITER_MEDIUM_STATUS_INVAL:
+               return "BT_MSG_ITER_MEDIUM_STATUS_INVAL";
+       case BT_MSG_ITER_MEDIUM_STATUS_ERROR:
+               return "BT_MSG_ITER_MEDIUM_STATUS_ERROR";
+       case BT_MSG_ITER_MEDIUM_STATUS_OK:
+               return "BT_MSG_ITER_MEDIUM_STATUS_OK";
+       default:
+               return "(unknown)";
+       }
+}
+
+static inline
+const char *bt_msg_iter_status_string(
+               enum bt_msg_iter_status status)
+{
+       switch (status) {
+       case BT_MSG_ITER_STATUS_EOF:
+               return "BT_MSG_ITER_STATUS_EOF";
+       case BT_MSG_ITER_STATUS_AGAIN:
+               return "BT_MSG_ITER_STATUS_AGAIN";
+       case BT_MSG_ITER_STATUS_INVAL:
+               return "BT_MSG_ITER_STATUS_INVAL";
+       case BT_MSG_ITER_STATUS_ERROR:
+               return "BT_MSG_ITER_STATUS_ERROR";
+       case BT_MSG_ITER_STATUS_OK:
+               return "BT_MSG_ITER_STATUS_OK";
+       default:
+               return "(unknown)";
+       }
+}
+
+#endif /* CTF_MSG_ITER_H */
diff --git a/src/plugins/ctf/common/print.h b/src/plugins/ctf/common/print.h
new file mode 100644 (file)
index 0000000..8825a9a
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef CTF_BTR_PRINT_H
+#define CTF_BTR_PRINT_H
+
+/*
+ * Define PRINT_PREFIX and PRINT_ERR_STREAM, then include this file.
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "common/babeltrace.h"
+
+#define PERR(fmt, ...)                                                 \
+       do {                                                            \
+               if (PRINT_ERR_STREAM) {                                 \
+                       fprintf(PRINT_ERR_STREAM,                       \
+                               "Error: " PRINT_PREFIX ": " fmt,        \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#define PWARN(fmt, ...)                                                        \
+       do {                                                            \
+               if (PRINT_ERR_STREAM) {                                 \
+                       fprintf(PRINT_ERR_STREAM,                       \
+                               "Warning: " PRINT_PREFIX ": " fmt,      \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#define PDBG(fmt, ...)                                                 \
+       do {                                                            \
+               if (babeltrace_debug) {                                 \
+                       fprintf(stderr,                                 \
+                               "Debug: " PRINT_PREFIX ": " fmt,        \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#endif /* CTF_BTR_PRINT_H */
diff --git a/src/plugins/ctf/common/utils/Makefile.am b/src/plugins/ctf/common/utils/Makefile.am
new file mode 100644 (file)
index 0000000..c4b62ff
--- /dev/null
@@ -0,0 +1,6 @@
+noinst_LTLIBRARIES = libctf-utils.la
+libctf_utils_la_SOURCES = \
+       logging.c \
+       logging.h \
+       utils.c \
+       utils.h
diff --git a/src/plugins/ctf/common/utils/logging.c b/src/plugins/ctf/common/utils/logging.c
new file mode 100644 (file)
index 0000000..bd773ea
--- /dev/null
@@ -0,0 +1,26 @@
+ /*
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL utils_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(utils_log_level, "BABELTRACE_PLUGIN_CTF_UTILS_LOG_LEVEL");
diff --git a/src/plugins/ctf/common/utils/logging.h b/src/plugins/ctf/common/utils/logging.h
new file mode 100644 (file)
index 0000000..2eeace4
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef CTF_UTILS_LOGGING_H
+#define CTF_UTILS_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL utils_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(utils_log_level);
+
+#endif /* CTF_UTILS_LOGGING_H */
diff --git a/src/plugins/ctf/common/utils/utils.c b/src/plugins/ctf/common/utils/utils.c
new file mode 100644 (file)
index 0000000..dd65f94
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Babeltrace - CTF Utils
+ *
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-UTILS"
+#include "logging.h"
+
+#include "utils.h"
diff --git a/src/plugins/ctf/common/utils/utils.h b/src/plugins/ctf/common/utils/utils.h
new file mode 100644 (file)
index 0000000..28f056c
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef CTF_UTILS_H
+#define CTF_UTILS_H
+
+/*
+ * Babeltrace - CTF Utilities
+ *
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+
+#endif /* CTF_UTILS_H */
diff --git a/src/plugins/ctf/fs-sink/Makefile.am b/src/plugins/ctf/fs-sink/Makefile.am
new file mode 100644 (file)
index 0000000..6035b1a
--- /dev/null
@@ -0,0 +1,17 @@
+noinst_LTLIBRARIES = libbabeltrace2-plugin-ctf-fs-sink.la
+
+libbabeltrace2_plugin_ctf_fs_sink_la_LIBADD =
+libbabeltrace2_plugin_ctf_fs_sink_la_SOURCES = \
+       fs-sink.c \
+       fs-sink.h \
+       logging.c \
+       logging.h \
+       fs-sink-ctf-meta.h \
+       translate-trace-ir-to-ctf-ir.c \
+       translate-trace-ir-to-ctf-ir.h \
+       translate-ctf-ir-to-tsdl.c \
+       translate-ctf-ir-to-tsdl.h \
+       fs-sink-stream.c \
+       fs-sink-stream.h \
+       fs-sink-trace.c \
+       fs-sink-trace.h
diff --git a/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h b/src/plugins/ctf/fs-sink/fs-sink-ctf-meta.h
new file mode 100644 (file)
index 0000000..6ae88df
--- /dev/null
@@ -0,0 +1,926 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_CTF_META_H
+#define BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_CTF_META_H
+
+/*
+ * Copyright 2018-2019 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "common/common.h"
+#include "common/assert.h"
+#include "compat/uuid.h"
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <ctype.h>
+
+enum fs_sink_ctf_field_class_type {
+       FS_SINK_CTF_FIELD_CLASS_TYPE_INT,
+       FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT,
+       FS_SINK_CTF_FIELD_CLASS_TYPE_STRING,
+       FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT,
+       FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY,
+       FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE,
+       FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT,
+};
+
+struct fs_sink_ctf_field_class {
+       enum fs_sink_ctf_field_class_type type;
+
+       /* Weak */
+       const bt_field_class *ir_fc;
+
+       unsigned int alignment;
+
+       /* Index of the field class within its own parent */
+       uint64_t index_in_parent;
+};
+
+struct fs_sink_ctf_field_class_bit_array {
+       struct fs_sink_ctf_field_class base;
+       unsigned int size;
+};
+
+struct fs_sink_ctf_field_class_int {
+       struct fs_sink_ctf_field_class_bit_array base;
+       bool is_signed;
+};
+
+struct fs_sink_ctf_field_class_float {
+       struct fs_sink_ctf_field_class_bit_array base;
+};
+
+struct fs_sink_ctf_field_class_string {
+       struct fs_sink_ctf_field_class base;
+};
+
+struct fs_sink_ctf_named_field_class {
+       GString *name;
+
+       /* Owned by this */
+       struct fs_sink_ctf_field_class *fc;
+};
+
+struct fs_sink_ctf_field_class_struct {
+       struct fs_sink_ctf_field_class base;
+
+       /* Array of `struct fs_sink_ctf_named_field_class` */
+       GArray *members;
+};
+
+struct fs_sink_ctf_field_class_variant {
+       struct fs_sink_ctf_field_class base;
+       GString *tag_ref;
+       bool tag_is_before;
+
+       /* Array of `struct fs_sink_ctf_named_field_class` */
+       GArray *options;
+};
+
+struct fs_sink_ctf_field_class_array_base {
+       struct fs_sink_ctf_field_class base;
+       struct fs_sink_ctf_field_class *elem_fc;
+};
+
+struct fs_sink_ctf_field_class_array {
+       struct fs_sink_ctf_field_class_array_base base;
+       uint64_t length;
+};
+
+struct fs_sink_ctf_field_class_sequence {
+       struct fs_sink_ctf_field_class_array_base base;
+       GString *length_ref;
+       bool length_is_before;
+};
+
+struct fs_sink_ctf_stream_class;
+
+struct fs_sink_ctf_event_class {
+       /* Weak */
+       const bt_event_class *ir_ec;
+
+       /* Weak */
+       struct fs_sink_ctf_stream_class *sc;
+
+       /* Owned by this */
+       struct fs_sink_ctf_field_class *spec_context_fc;
+
+       /* Owned by this */
+       struct fs_sink_ctf_field_class *payload_fc;
+};
+
+struct fs_sink_ctf_trace_class;
+
+struct fs_sink_ctf_stream_class {
+       /* Weak */
+       struct fs_sink_ctf_trace_class *tc;
+
+       /* Weak */
+       const bt_stream_class *ir_sc;
+
+       /* Weak */
+       const bt_clock_class *default_clock_class;
+
+       GString *default_clock_class_name;
+       bool packets_have_ts_begin;
+       bool packets_have_ts_end;
+       bool has_discarded_events;
+       bool discarded_events_has_ts;
+       bool discarded_packets_has_ts;
+
+       /* Owned by this */
+       struct fs_sink_ctf_field_class *packet_context_fc;
+
+       /* Owned by this */
+       struct fs_sink_ctf_field_class *event_common_context_fc;
+
+       /* Array of `struct fs_sink_ctf_event_class *` (owned by this) */
+       GPtrArray *event_classes;
+
+       /*
+        * `const bt_event_class *` (weak) ->
+        * `struct fs_sink_ctf_event_class *` (weak)
+        */
+       GHashTable *event_classes_from_ir;
+};
+
+struct fs_sink_ctf_trace_class {
+       /* Weak */
+       const bt_trace_class *ir_tc;
+
+       unsigned char uuid[BABELTRACE_UUID_LEN];
+
+       /* Array of `struct fs_sink_ctf_stream_class *` (owned by this) */
+       GPtrArray *stream_classes;
+};
+
+static inline
+void fs_sink_ctf_field_class_destroy(struct fs_sink_ctf_field_class *fc);
+
+static inline
+void _fs_sink_ctf_field_class_init(struct fs_sink_ctf_field_class *fc,
+               enum fs_sink_ctf_field_class_type type,
+               const bt_field_class *ir_fc, unsigned int alignment,
+               uint64_t index_in_parent)
+{
+       BT_ASSERT(fc);
+       fc->type = type;
+       fc->ir_fc = ir_fc;
+       fc->alignment = alignment;
+       fc->index_in_parent = index_in_parent;
+}
+
+static inline
+void _fs_sink_ctf_field_class_bit_array_init(
+               struct fs_sink_ctf_field_class_bit_array *fc,
+               enum fs_sink_ctf_field_class_type type,
+               const bt_field_class *ir_fc, unsigned int size,
+               uint64_t index_in_parent)
+{
+       _fs_sink_ctf_field_class_init((void *) fc, type, ir_fc,
+               size % 8 == 0 ? 8 : 1, index_in_parent);
+       fc->size = size;
+}
+
+static inline
+void _fs_sink_ctf_field_class_int_init(struct fs_sink_ctf_field_class_int *fc,
+               enum fs_sink_ctf_field_class_type type,
+               const bt_field_class *ir_fc, uint64_t index_in_parent)
+{
+       bt_field_class_type ir_fc_type = bt_field_class_get_type(ir_fc);
+
+       _fs_sink_ctf_field_class_bit_array_init((void *) fc, type, ir_fc,
+               (unsigned int) bt_field_class_integer_get_field_value_range(
+                       ir_fc),
+               index_in_parent);
+       fc->is_signed = (ir_fc_type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
+               ir_fc_type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION);
+}
+
+static inline
+void _fs_sink_ctf_named_field_class_init(
+               struct fs_sink_ctf_named_field_class *named_fc)
+{
+       BT_ASSERT(named_fc);
+       named_fc->name = g_string_new(NULL);
+       BT_ASSERT(named_fc->name);
+}
+
+static inline
+void _fs_sink_ctf_named_field_class_fini(
+               struct fs_sink_ctf_named_field_class *named_fc)
+{
+       BT_ASSERT(named_fc);
+
+       if (named_fc->name) {
+               g_string_free(named_fc->name, TRUE);
+               named_fc->name = NULL;
+       }
+
+       fs_sink_ctf_field_class_destroy(named_fc->fc);
+       named_fc->fc = NULL;
+}
+
+static inline
+struct fs_sink_ctf_field_class_int *fs_sink_ctf_field_class_int_create(
+               const bt_field_class *ir_fc, uint64_t index_in_parent)
+{
+       struct fs_sink_ctf_field_class_int *fc =
+               g_new0(struct fs_sink_ctf_field_class_int, 1);
+
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_int_init(fc, FS_SINK_CTF_FIELD_CLASS_TYPE_INT,
+               ir_fc, index_in_parent);
+       return fc;
+}
+
+static inline
+struct fs_sink_ctf_field_class_float *fs_sink_ctf_field_class_float_create(
+               const bt_field_class *ir_fc, uint64_t index_in_parent)
+{
+       struct fs_sink_ctf_field_class_float *fc =
+               g_new0(struct fs_sink_ctf_field_class_float, 1);
+
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_bit_array_init((void *) fc,
+               FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT,
+               ir_fc, bt_field_class_real_is_single_precision(ir_fc) ? 32 : 64,
+               index_in_parent);
+       return fc;
+}
+
+static inline
+struct fs_sink_ctf_field_class_string *fs_sink_ctf_field_class_string_create(
+               const bt_field_class *ir_fc, uint64_t index_in_parent)
+{
+       struct fs_sink_ctf_field_class_string *fc =
+               g_new0(struct fs_sink_ctf_field_class_string, 1);
+
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_init((void *) fc,
+               FS_SINK_CTF_FIELD_CLASS_TYPE_STRING, ir_fc,
+               8, index_in_parent);
+       return fc;
+}
+
+static inline
+struct fs_sink_ctf_field_class_struct *fs_sink_ctf_field_class_struct_create_empty(
+               const bt_field_class *ir_fc, uint64_t index_in_parent)
+{
+       struct fs_sink_ctf_field_class_struct *fc =
+               g_new0(struct fs_sink_ctf_field_class_struct, 1);
+
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_init((void *) fc,
+               FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT, ir_fc, 1, index_in_parent);
+       fc->members = g_array_new(FALSE, TRUE,
+               sizeof(struct fs_sink_ctf_named_field_class));
+       BT_ASSERT(fc->members);
+       return fc;
+}
+
+static inline
+struct fs_sink_ctf_field_class_variant *fs_sink_ctf_field_class_variant_create_empty(
+               const bt_field_class *ir_fc, uint64_t index_in_parent)
+{
+       struct fs_sink_ctf_field_class_variant *fc =
+               g_new0(struct fs_sink_ctf_field_class_variant, 1);
+
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_init((void *) fc,
+               FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT, ir_fc,
+               1, index_in_parent);
+       fc->options = g_array_new(FALSE, TRUE,
+               sizeof(struct fs_sink_ctf_named_field_class));
+       BT_ASSERT(fc->options);
+       fc->tag_ref = g_string_new(NULL);
+       BT_ASSERT(fc->tag_ref);
+       fc->tag_is_before =
+               bt_field_class_variant_borrow_selector_field_path_const(ir_fc) ==
+               NULL;
+       return fc;
+}
+
+static inline
+struct fs_sink_ctf_field_class_array *fs_sink_ctf_field_class_array_create_empty(
+               const bt_field_class *ir_fc, uint64_t index_in_parent)
+{
+       struct fs_sink_ctf_field_class_array *fc =
+               g_new0(struct fs_sink_ctf_field_class_array, 1);
+
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_init((void *) fc,
+               FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY, ir_fc,
+               1, index_in_parent);
+       fc->length = bt_field_class_static_array_get_length(ir_fc);
+       return fc;
+}
+
+static inline
+struct fs_sink_ctf_field_class_sequence *fs_sink_ctf_field_class_sequence_create_empty(
+               const bt_field_class *ir_fc, uint64_t index_in_parent)
+{
+       struct fs_sink_ctf_field_class_sequence *fc =
+               g_new0(struct fs_sink_ctf_field_class_sequence, 1);
+
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_init((void *) fc,
+               FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE,
+               ir_fc, 1, index_in_parent);
+       fc->length_ref = g_string_new(NULL);
+       BT_ASSERT(fc->length_ref);
+       fc->length_is_before =
+               bt_field_class_dynamic_array_borrow_length_field_path_const(ir_fc) ==
+               NULL;
+       return fc;
+}
+
+static inline
+struct fs_sink_ctf_named_field_class *
+fs_sink_ctf_field_class_struct_borrow_member_by_index(
+               struct fs_sink_ctf_field_class_struct *fc, uint64_t index);
+
+static inline
+struct fs_sink_ctf_named_field_class *
+fs_sink_ctf_field_class_variant_borrow_option_by_index(
+               struct fs_sink_ctf_field_class_variant *fc, uint64_t index);
+
+static inline
+void _fs_sink_ctf_field_class_fini(struct fs_sink_ctf_field_class *fc)
+{
+       BT_ASSERT(fc);
+}
+
+static inline
+void _fs_sink_ctf_field_class_int_destroy(
+               struct fs_sink_ctf_field_class_int *fc)
+{
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_fini((void *) fc);
+       g_free(fc);
+}
+
+static inline
+void _fs_sink_ctf_field_class_float_destroy(
+               struct fs_sink_ctf_field_class_float *fc)
+{
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_fini((void *) fc);
+       g_free(fc);
+}
+
+static inline
+void _fs_sink_ctf_field_class_string_destroy(
+               struct fs_sink_ctf_field_class_string *fc)
+{
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_fini((void *) fc);
+       g_free(fc);
+}
+
+static inline
+void _fs_sink_ctf_field_class_struct_destroy(
+               struct fs_sink_ctf_field_class_struct *fc)
+{
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_fini((void *) fc);
+
+       if (fc->members) {
+               uint64_t i;
+
+               for (i = 0; i < fc->members->len; i++) {
+                       struct fs_sink_ctf_named_field_class *named_fc =
+                               fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                                       fc, i);
+
+                       _fs_sink_ctf_named_field_class_fini(named_fc);
+               }
+
+               g_array_free(fc->members, TRUE);
+               fc->members = NULL;
+       }
+
+       g_free(fc);
+}
+
+static inline
+void _fs_sink_ctf_field_class_array_base_fini(
+               struct fs_sink_ctf_field_class_array_base *fc)
+{
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_fini((void *) fc);
+       fs_sink_ctf_field_class_destroy(fc->elem_fc);
+       fc->elem_fc = NULL;
+}
+
+static inline
+void _fs_sink_ctf_field_class_array_destroy(
+               struct fs_sink_ctf_field_class_array *fc)
+{
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_array_base_fini((void *) fc);
+       g_free(fc);
+}
+
+static inline
+void _fs_sink_ctf_field_class_sequence_destroy(
+               struct fs_sink_ctf_field_class_sequence *fc)
+{
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_array_base_fini((void *) fc);
+
+       if (fc->length_ref) {
+               g_string_free(fc->length_ref, TRUE);
+               fc->length_ref = NULL;
+       }
+
+       g_free(fc);
+}
+
+static inline
+void _fs_sink_ctf_field_class_variant_destroy(
+               struct fs_sink_ctf_field_class_variant *fc)
+{
+       BT_ASSERT(fc);
+       _fs_sink_ctf_field_class_fini((void *) fc);
+
+       if (fc->options) {
+               uint64_t i;
+
+               for (i = 0; i < fc->options->len; i++) {
+                       struct fs_sink_ctf_named_field_class *named_fc =
+                               fs_sink_ctf_field_class_variant_borrow_option_by_index(
+                                       fc, i);
+
+                       _fs_sink_ctf_named_field_class_fini(named_fc);
+               }
+
+               g_array_free(fc->options, TRUE);
+               fc->options = NULL;
+       }
+
+       if (fc->tag_ref) {
+               g_string_free(fc->tag_ref, TRUE);
+               fc->tag_ref = NULL;
+       }
+
+       g_free(fc);
+}
+
+static inline
+void fs_sink_ctf_field_class_destroy(struct fs_sink_ctf_field_class *fc)
+{
+       if (!fc) {
+               return;
+       }
+
+       switch (fc->type) {
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_INT:
+               _fs_sink_ctf_field_class_int_destroy((void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT:
+               _fs_sink_ctf_field_class_float_destroy((void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRING:
+               _fs_sink_ctf_field_class_string_destroy((void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+               _fs_sink_ctf_field_class_struct_destroy((void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
+               _fs_sink_ctf_field_class_array_destroy((void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
+               _fs_sink_ctf_field_class_sequence_destroy((void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+               _fs_sink_ctf_field_class_variant_destroy((void *) fc);
+               break;
+       default:
+               abort();
+       }
+}
+
+static inline
+struct fs_sink_ctf_named_field_class *
+fs_sink_ctf_field_class_struct_borrow_member_by_index(
+               struct fs_sink_ctf_field_class_struct *fc, uint64_t index)
+{
+       BT_ASSERT(fc);
+       BT_ASSERT(index < fc->members->len);
+       return &g_array_index(fc->members, struct fs_sink_ctf_named_field_class,
+               index);
+}
+
+static inline
+struct fs_sink_ctf_named_field_class *
+fs_sink_ctf_field_class_struct_borrow_member_by_name(
+               struct fs_sink_ctf_field_class_struct *fc, const char *name)
+{
+       uint64_t i;
+       struct fs_sink_ctf_named_field_class *ret_named_fc = NULL;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(name);
+
+       for (i = 0; i < fc->members->len; i++) {
+               struct fs_sink_ctf_named_field_class *named_fc =
+                       fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                               fc, i);
+
+               if (strcmp(name, named_fc->name->str) == 0) {
+                       ret_named_fc = named_fc;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_named_fc;
+}
+
+static inline
+struct fs_sink_ctf_field_class *
+fs_sink_ctf_field_class_struct_borrow_member_field_class_by_name(
+               struct fs_sink_ctf_field_class_struct *struct_fc, const char *name)
+{
+       struct fs_sink_ctf_named_field_class *named_fc = NULL;
+       struct fs_sink_ctf_field_class *fc = NULL;
+
+       if (!struct_fc) {
+               goto end;
+       }
+
+       named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_name(
+               struct_fc, name);
+       if (!named_fc) {
+               goto end;
+       }
+
+       fc = named_fc->fc;
+
+end:
+       return fc;
+}
+
+static inline
+struct fs_sink_ctf_field_class_int *
+fs_sink_ctf_field_class_struct_borrow_member_int_field_class_by_name(
+               struct fs_sink_ctf_field_class_struct *struct_fc,
+               const char *name)
+{
+       struct fs_sink_ctf_field_class_int *int_fc = NULL;
+
+       int_fc = (void *)
+               fs_sink_ctf_field_class_struct_borrow_member_field_class_by_name(
+                       struct_fc, name);
+       if (!int_fc) {
+               goto end;
+       }
+
+       if (int_fc->base.base.type != FS_SINK_CTF_FIELD_CLASS_TYPE_INT) {
+               int_fc = NULL;
+               goto end;
+       }
+
+end:
+       return int_fc;
+}
+
+static inline
+void fs_sink_ctf_field_class_struct_align_at_least(
+               struct fs_sink_ctf_field_class_struct *fc,
+               unsigned int alignment)
+{
+       if (alignment > fc->base.alignment) {
+               fc->base.alignment = alignment;
+       }
+}
+
+static inline
+void fs_sink_ctf_field_class_struct_append_member(
+               struct fs_sink_ctf_field_class_struct *fc,
+               const char *name, struct fs_sink_ctf_field_class *member_fc)
+{
+       struct fs_sink_ctf_named_field_class *named_fc;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(name);
+       g_array_set_size(fc->members, fc->members->len + 1);
+
+       named_fc = &g_array_index(fc->members,
+               struct fs_sink_ctf_named_field_class, fc->members->len - 1);
+       _fs_sink_ctf_named_field_class_init(named_fc);
+       g_string_assign(named_fc->name, name);
+       named_fc->fc = member_fc;
+       fs_sink_ctf_field_class_struct_align_at_least(fc, member_fc->alignment);
+}
+
+static inline
+struct fs_sink_ctf_named_field_class *
+fs_sink_ctf_field_class_variant_borrow_option_by_index(
+               struct fs_sink_ctf_field_class_variant *fc, uint64_t index)
+{
+       BT_ASSERT(fc);
+       BT_ASSERT(index < fc->options->len);
+       return &g_array_index(fc->options, struct fs_sink_ctf_named_field_class,
+               index);
+}
+
+static inline
+struct fs_sink_ctf_named_field_class *
+fs_sink_ctf_field_class_variant_borrow_option_by_name(
+               struct fs_sink_ctf_field_class_variant *fc, const char *name)
+{
+       uint64_t i;
+       struct fs_sink_ctf_named_field_class *ret_named_fc = NULL;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(name);
+
+       for (i = 0; i < fc->options->len; i++) {
+               struct fs_sink_ctf_named_field_class *named_fc =
+                       fs_sink_ctf_field_class_variant_borrow_option_by_index(
+                               fc, i);
+
+               if (strcmp(name, named_fc->name->str) == 0) {
+                       ret_named_fc = named_fc;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_named_fc;
+}
+
+static inline
+void fs_sink_ctf_field_class_variant_append_option(
+               struct fs_sink_ctf_field_class_variant *fc,
+               const char *name, struct fs_sink_ctf_field_class *option_fc)
+{
+       struct fs_sink_ctf_named_field_class *named_fc;
+
+       BT_ASSERT(fc);
+       BT_ASSERT(name);
+       g_array_set_size(fc->options, fc->options->len + 1);
+
+       named_fc = &g_array_index(fc->options,
+               struct fs_sink_ctf_named_field_class, fc->options->len - 1);
+       _fs_sink_ctf_named_field_class_init(named_fc);
+       g_string_assign(named_fc->name, name);
+       named_fc->fc = option_fc;
+}
+
+static inline
+struct fs_sink_ctf_event_class *fs_sink_ctf_event_class_create(
+               struct fs_sink_ctf_stream_class *sc,
+               const bt_event_class *ir_ec)
+{
+       struct fs_sink_ctf_event_class *ec =
+               g_new0(struct fs_sink_ctf_event_class, 1);
+
+       BT_ASSERT(sc);
+       BT_ASSERT(ir_ec);
+       BT_ASSERT(ec);
+       ec->ir_ec = ir_ec;
+       ec->sc = sc;
+       g_ptr_array_add(sc->event_classes, ec);
+       g_hash_table_insert(sc->event_classes_from_ir, (gpointer) ir_ec, ec);
+       return ec;
+}
+
+static inline
+void fs_sink_ctf_event_class_destroy(struct fs_sink_ctf_event_class *ec)
+{
+       if (!ec) {
+               return;
+       }
+
+       fs_sink_ctf_field_class_destroy(ec->spec_context_fc);
+       ec->spec_context_fc = NULL;
+       fs_sink_ctf_field_class_destroy(ec->payload_fc);
+       ec->payload_fc = NULL;
+       g_free(ec);
+}
+
+static inline
+struct fs_sink_ctf_stream_class *fs_sink_ctf_stream_class_create(
+               struct fs_sink_ctf_trace_class *tc,
+               const bt_stream_class *ir_sc)
+{
+       struct fs_sink_ctf_stream_class *sc =
+               g_new0(struct fs_sink_ctf_stream_class, 1);
+
+       BT_ASSERT(tc);
+       BT_ASSERT(ir_sc);
+       BT_ASSERT(sc);
+       sc->tc = tc;
+       sc->ir_sc = ir_sc;
+       sc->default_clock_class =
+               bt_stream_class_borrow_default_clock_class_const(ir_sc);
+       sc->default_clock_class_name = g_string_new(NULL);
+       BT_ASSERT(sc->default_clock_class_name);
+       sc->event_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) fs_sink_ctf_event_class_destroy);
+       BT_ASSERT(sc->event_classes);
+       sc->event_classes_from_ir = g_hash_table_new(g_direct_hash,
+               g_direct_equal);
+       BT_ASSERT(sc->event_classes_from_ir);
+       sc->packets_have_ts_begin =
+               bt_stream_class_packets_have_beginning_default_clock_snapshot(
+                       ir_sc);
+       sc->packets_have_ts_end =
+               bt_stream_class_packets_have_end_default_clock_snapshot(ir_sc);
+       sc->has_discarded_events =
+               bt_stream_class_supports_discarded_events(ir_sc);
+
+       if (sc->has_discarded_events) {
+               sc->discarded_events_has_ts =
+                       bt_stream_class_discarded_events_have_default_clock_snapshots(
+                               ir_sc);
+       }
+
+       if (bt_stream_class_supports_discarded_packets(ir_sc)) {
+               sc->discarded_packets_has_ts =
+                       bt_stream_class_discarded_packets_have_default_clock_snapshots(
+                               ir_sc);
+       }
+
+       g_ptr_array_add(tc->stream_classes, sc);
+       return sc;
+}
+
+static inline
+void fs_sink_ctf_stream_class_destroy(struct fs_sink_ctf_stream_class *sc)
+{
+       if (!sc) {
+               return;
+       }
+
+       if (sc->default_clock_class_name) {
+               g_string_free(sc->default_clock_class_name, TRUE);
+               sc->default_clock_class_name = NULL;
+       }
+
+       if (sc->event_classes) {
+               g_ptr_array_free(sc->event_classes, TRUE);
+               sc->event_classes = NULL;
+       }
+
+       if (sc->event_classes_from_ir) {
+               g_hash_table_destroy(sc->event_classes_from_ir);
+               sc->event_classes_from_ir = NULL;
+       }
+
+       fs_sink_ctf_field_class_destroy(sc->packet_context_fc);
+       sc->packet_context_fc = NULL;
+       fs_sink_ctf_field_class_destroy(sc->event_common_context_fc);
+       sc->event_common_context_fc = NULL;
+       g_free(sc);
+}
+
+static inline
+void fs_sink_ctf_stream_class_append_event_class(
+               struct fs_sink_ctf_stream_class *sc,
+               struct fs_sink_ctf_event_class *ec)
+{
+       g_ptr_array_add(sc->event_classes, ec);
+}
+
+static inline
+void fs_sink_ctf_trace_class_destroy(struct fs_sink_ctf_trace_class *tc)
+{
+       if (!tc) {
+               return;
+       }
+
+       if (tc->stream_classes) {
+               g_ptr_array_free(tc->stream_classes, TRUE);
+               tc->stream_classes = NULL;
+       }
+
+       g_free(tc);
+}
+
+static inline
+struct fs_sink_ctf_trace_class *fs_sink_ctf_trace_class_create(
+               const bt_trace_class *ir_tc)
+{
+       struct fs_sink_ctf_trace_class *tc =
+               g_new0(struct fs_sink_ctf_trace_class, 1);
+
+       BT_ASSERT(tc);
+
+       if (bt_uuid_generate(tc->uuid)) {
+               fs_sink_ctf_trace_class_destroy(tc);
+               tc = NULL;
+               goto end;
+       }
+
+       tc->ir_tc = ir_tc;
+       tc->stream_classes = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) fs_sink_ctf_stream_class_destroy);
+       BT_ASSERT(tc->stream_classes);
+
+end:
+       return tc;
+}
+
+static inline
+bool fs_sink_ctf_ist_valid_identifier(const char *name)
+{
+       const char *at;
+       uint64_t i;
+       bool ist_valid = true;
+       static const char *reserved_keywords[] = {
+               "align",
+               "callsite",
+               "const",
+               "char",
+               "clock",
+               "double",
+               "enum",
+               "env",
+               "event",
+               "floating_point",
+               "float",
+               "integer",
+               "int",
+               "long",
+               "short",
+               "signed",
+               "stream",
+               "string",
+               "struct",
+               "trace",
+               "typealias",
+               "typedef",
+               "unsigned",
+               "variant",
+               "void",
+               "_Bool",
+               "_Complex",
+               "_Imaginary",
+       };
+
+       /* Make sure the name is not a reserved keyword */
+       for (i = 0; i < sizeof(reserved_keywords) / sizeof(*reserved_keywords);
+                       i++) {
+               if (strcmp(name, reserved_keywords[i]) == 0) {
+                       ist_valid = false;
+                       goto end;
+               }
+       }
+
+       /* Make sure the name is not an empty string */
+       if (strlen(name) == 0) {
+               ist_valid = false;
+               goto end;
+       }
+
+       /* Make sure the name starts with a letter or `_` */
+       if (!isalpha(name[0]) && name[0] != '_') {
+               ist_valid = false;
+               goto end;
+       }
+
+       /* Make sure the name only contains letters, digits, and `_` */
+       for (at = name; *at != '\0'; at++) {
+               if (!isalnum(*at) && *at != '_') {
+                       ist_valid = false;
+                       goto end;
+               }
+       }
+
+end:
+       return ist_valid;
+}
+
+static inline
+int fs_sink_ctf_protect_name(GString *name)
+{
+       int ret = 0;
+
+       if (!fs_sink_ctf_ist_valid_identifier(name->str)) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Prepend `_` to protect it */
+       g_string_prepend_c(name, '_');
+
+end:
+       return ret;
+}
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_CTF_META_H */
diff --git a/src/plugins/ctf/fs-sink/fs-sink-stream.c b/src/plugins/ctf/fs-sink/fs-sink-stream.c
new file mode 100644 (file)
index 0000000..026251a
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-STREAM"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include "common/assert.h"
+#include "ctfser/ctfser.h"
+#include "compat/endian.h"
+
+#include "fs-sink-trace.h"
+#include "fs-sink-stream.h"
+#include "translate-trace-ir-to-ctf-ir.h"
+
+BT_HIDDEN
+void fs_sink_stream_destroy(struct fs_sink_stream *stream)
+{
+       if (!stream) {
+               goto end;
+       }
+
+       bt_ctfser_fini(&stream->ctfser);
+
+       if (stream->file_name) {
+               g_string_free(stream->file_name, TRUE);
+               stream->file_name = NULL;
+       }
+
+       bt_packet_put_ref(stream->packet_state.packet);
+       g_free(stream);
+
+end:
+       return;
+}
+
+static
+bool stream_file_name_exists(struct fs_sink_trace *trace, const char *name)
+{
+       bool exists = false;
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_hash_table_iter_init(&iter, trace->streams);
+
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               struct fs_sink_stream *stream = value;
+
+               if (strcmp(name, stream->file_name->str) == 0) {
+                       exists = true;
+                       goto end;
+               }
+       }
+
+end:
+       return exists;
+}
+
+static
+GString *sanitize_stream_file_name(const char *file_name)
+{
+       GString *san_file_name = g_string_new(NULL);
+       const char *ch;
+       gchar *basename;
+
+       BT_ASSERT(san_file_name);
+       BT_ASSERT(file_name);
+       basename = g_path_get_basename(file_name);
+
+       for (ch = basename; *ch != '\0'; ch++) {
+               if (*ch == '/') {
+                       g_string_append_c(san_file_name, '_');
+               } else {
+                       g_string_append_c(san_file_name, *ch);
+               }
+       }
+
+       /* Do not allow `.` and `..` either */
+       if (strcmp(san_file_name->str, ".") == 0 ||
+                       strcmp(san_file_name->str, "..") == 0) {
+               g_string_assign(san_file_name, "stream");
+       }
+
+       g_free(basename);
+       return san_file_name;
+}
+
+static
+GString *make_unique_stream_file_name(struct fs_sink_trace *trace,
+               const char *base)
+{
+       GString *san_base = sanitize_stream_file_name(base);
+       GString *name = g_string_new(san_base->str);
+       unsigned int suffix = 0;
+
+       BT_ASSERT(name);
+
+       while (stream_file_name_exists(trace, name->str) &&
+                       strcmp(name->str, "metadata") == 0) {
+               g_string_printf(name, "%s-%u", san_base->str, suffix);
+               suffix++;
+       }
+
+       g_string_free(san_base, TRUE);
+       return name;
+}
+
+static
+void set_stream_file_name(struct fs_sink_stream *stream)
+{
+       const char *base_name = bt_stream_get_name(stream->ir_stream);
+
+       if (!base_name) {
+               base_name = "stream";
+       }
+
+       BT_ASSERT(!stream->file_name);
+       stream->file_name = make_unique_stream_file_name(stream->trace,
+               base_name);
+}
+
+BT_HIDDEN
+struct fs_sink_stream *fs_sink_stream_create(struct fs_sink_trace *trace,
+               const bt_stream *ir_stream)
+{
+       struct fs_sink_stream *stream = g_new0(struct fs_sink_stream, 1);
+       int ret;
+       GString *path = g_string_new(trace->path->str);
+
+       if (!stream) {
+               goto end;
+       }
+
+       stream->trace = trace;
+       stream->ir_stream = ir_stream;
+       stream->packet_state.beginning_cs = UINT64_C(-1);
+       stream->packet_state.end_cs = UINT64_C(-1);
+       stream->prev_packet_state.end_cs = UINT64_C(-1);
+       stream->prev_packet_state.discarded_events_counter = UINT64_C(-1);
+       stream->prev_packet_state.seq_num = UINT64_C(-1);
+       ret = try_translate_stream_class_trace_ir_to_ctf_ir(trace->tc,
+               bt_stream_borrow_class_const(ir_stream), &stream->sc);
+       if (ret) {
+               goto error;
+       }
+
+       set_stream_file_name(stream);
+       g_string_append_printf(path, "/%s", stream->file_name->str);
+       ret = bt_ctfser_init(&stream->ctfser, path->str);
+       if (ret) {
+               goto error;
+       }
+
+       g_hash_table_insert(trace->streams, (gpointer) ir_stream, stream);
+       goto end;
+
+error:
+       fs_sink_stream_destroy(stream);
+       stream = NULL;
+
+end:
+       if (path) {
+               g_string_free(path, TRUE);
+       }
+
+       return stream;
+}
+
+static
+int write_field(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class *fc, const bt_field *field);
+
+static inline
+int write_int_field(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class_int *fc, const bt_field *field)
+{
+       int ret;
+
+       if (fc->is_signed) {
+               ret = bt_ctfser_write_signed_int(&stream->ctfser,
+                       bt_field_signed_integer_get_value(field),
+                       fc->base.base.alignment, fc->base.size, BYTE_ORDER);
+       } else {
+               ret = bt_ctfser_write_unsigned_int(&stream->ctfser,
+                       bt_field_unsigned_integer_get_value(field),
+                       fc->base.base.alignment, fc->base.size, BYTE_ORDER);
+       }
+
+       return ret;
+}
+
+static inline
+int write_float_field(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class_float *fc, const bt_field *field)
+{
+       int ret;
+       double val = bt_field_real_get_value(field);
+
+       if (fc->base.size == 32) {
+               ret = bt_ctfser_write_float32(&stream->ctfser, val,
+                       fc->base.base.alignment, BYTE_ORDER);
+       } else {
+               ret = bt_ctfser_write_float64(&stream->ctfser, val,
+                       fc->base.base.alignment, BYTE_ORDER);
+       }
+
+       return ret;
+}
+
+static inline
+int write_string_field(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class_string *fc, const bt_field *field)
+{
+       return bt_ctfser_write_string(&stream->ctfser,
+               bt_field_string_get_value(field));
+}
+
+static inline
+int write_array_field_elements(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class_array_base *fc,
+               const bt_field *field)
+{
+       uint64_t i;
+       uint64_t len = bt_field_array_get_length(field);
+       int ret = 0;
+
+       for (i = 0; i < len; i++) {
+               const bt_field *elem_field =
+                       bt_field_array_borrow_element_field_by_index_const(
+                               field, i);
+               ret = write_field(stream, fc->elem_fc, elem_field);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static inline
+int write_sequence_field(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class_sequence *fc,
+               const bt_field *field)
+{
+       int ret;
+
+       if (fc->length_is_before) {
+               ret = bt_ctfser_write_unsigned_int(&stream->ctfser,
+                       bt_field_array_get_length(field), 8, 32, BYTE_ORDER);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       ret = write_array_field_elements(stream, (void *) fc, field);
+
+end:
+       return ret;
+}
+
+static inline
+int write_struct_field(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class_struct *fc,
+               const bt_field *field, bool align_struct)
+{
+       int ret = 0;
+       uint64_t i;
+
+       if (likely(align_struct)) {
+               ret = bt_ctfser_align_offset_in_current_packet(&stream->ctfser,
+                       fc->base.alignment);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < fc->members->len; i++) {
+               const bt_field *memb_field =
+                       bt_field_structure_borrow_member_field_by_index_const(
+                               field, i);
+               struct fs_sink_ctf_field_class *member_fc =
+                       fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                               fc, i)->fc;
+
+               ret = write_field(stream, member_fc, memb_field);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static inline
+int write_variant_field(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class_variant *fc,
+               const bt_field *field)
+{
+       uint64_t opt_index =
+               bt_field_variant_get_selected_option_field_index(field);
+       int ret;
+
+       if (fc->tag_is_before) {
+               ret = bt_ctfser_write_unsigned_int(&stream->ctfser,
+                       opt_index, 8, 16, BYTE_ORDER);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       ret = write_field(stream,
+               fs_sink_ctf_field_class_variant_borrow_option_by_index(fc,
+                       opt_index)->fc,
+               bt_field_variant_borrow_selected_option_field_const(field));
+
+end:
+       return ret;
+}
+
+static
+int write_field(struct fs_sink_stream *stream,
+               struct fs_sink_ctf_field_class *fc, const bt_field *field)
+{
+       int ret;
+
+       switch (fc->type) {
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_INT:
+               ret = write_int_field(stream, (void *) fc, field);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT:
+               ret = write_float_field(stream, (void *) fc, field);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRING:
+               ret = write_string_field(stream, (void *) fc, field);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+               ret = write_struct_field(stream, (void *) fc, field, true);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
+               ret = write_array_field_elements(stream, (void *) fc, field);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
+               ret = write_sequence_field(stream, (void *) fc, field);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+               ret = write_variant_field(stream, (void *) fc, field);
+               break;
+       default:
+               abort();
+       }
+
+       return ret;
+}
+
+static inline
+int write_event_header(struct fs_sink_stream *stream,
+               const bt_clock_snapshot *cs, struct fs_sink_ctf_event_class *ec)
+{
+       int ret;
+
+       /* Event class ID */
+       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+               bt_event_class_get_id(ec->ir_ec), 8, 64, BYTE_ORDER);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+       /* Time */
+       if (stream->sc->default_clock_class) {
+               BT_ASSERT(cs);
+               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+                       bt_clock_snapshot_get_value(cs), 8, 64, BYTE_ORDER);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int fs_sink_stream_write_event(struct fs_sink_stream *stream,
+               const bt_clock_snapshot *cs, const bt_event *event,
+               struct fs_sink_ctf_event_class *ec)
+{
+       int ret;
+       const bt_field *field;
+
+       /* Header */
+       ret = write_event_header(stream, cs, ec);
+       if (unlikely(ret)) {
+               goto end;
+       }
+
+       /* Common context */
+       if (stream->sc->event_common_context_fc) {
+               field = bt_event_borrow_common_context_field_const(event);
+               BT_ASSERT(field);
+               ret = write_struct_field(stream,
+                       (void *) stream->sc->event_common_context_fc,
+                       field, true);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       /* Specific context */
+       if (ec->spec_context_fc) {
+               field = bt_event_borrow_specific_context_field_const(event);
+               BT_ASSERT(field);
+               ret = write_struct_field(stream, (void *) ec->spec_context_fc,
+                       field, true);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+       /* Specific context */
+       if (ec->payload_fc) {
+               field = bt_event_borrow_payload_field_const(event);
+               BT_ASSERT(field);
+               ret = write_struct_field(stream, (void *) ec->payload_fc,
+                       field, true);
+               if (unlikely(ret)) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static
+int write_packet_context(struct fs_sink_stream *stream)
+{
+       int ret;
+
+       /* Packet total size */
+       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+               stream->packet_state.total_size, 8, 64, BYTE_ORDER);
+       if (ret) {
+               goto end;
+       }
+
+       /* Packet content size */
+       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+               stream->packet_state.content_size, 8, 64, BYTE_ORDER);
+       if (ret) {
+               goto end;
+       }
+
+       if (stream->sc->packets_have_ts_begin) {
+               /* Beginning time */
+               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+                       stream->packet_state.beginning_cs, 8, 64, BYTE_ORDER);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       if (stream->sc->packets_have_ts_end) {
+               /* End time */
+               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+                       stream->packet_state.end_cs, 8, 64, BYTE_ORDER);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       if (stream->sc->has_discarded_events) {
+               /* Discarded event counter */
+               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+                       stream->packet_state.discarded_events_counter, 8, 64,
+                       BYTE_ORDER);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Sequence number */
+       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+               stream->packet_state.seq_num, 8, 64, BYTE_ORDER);
+       if (ret) {
+               goto end;
+       }
+
+       /* Other members */
+       if (stream->sc->packet_context_fc) {
+               const bt_field *packet_context_field =
+                       bt_packet_borrow_context_field_const(
+                               stream->packet_state.packet);
+
+               BT_ASSERT(packet_context_field);
+               ret = write_struct_field(stream,
+                       (void *) stream->sc->packet_context_fc,
+                       packet_context_field, false);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int fs_sink_stream_open_packet(struct fs_sink_stream *stream,
+               const bt_clock_snapshot *cs, const bt_packet *packet)
+{
+       int ret;
+       uint64_t i;
+
+       BT_ASSERT(!stream->packet_state.is_open);
+       bt_packet_put_ref(stream->packet_state.packet);
+       stream->packet_state.packet = packet;
+       bt_packet_get_ref(stream->packet_state.packet);
+       if (cs) {
+               stream->packet_state.beginning_cs =
+                       bt_clock_snapshot_get_value(cs);
+       }
+
+       /* Open packet */
+       ret = bt_ctfser_open_packet(&stream->ctfser);
+       if (ret) {
+               /* bt_ctfser_open_packet() logs errors */
+               goto end;
+       }
+
+       /* Packet header: magic */
+       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+               UINT64_C(0xc1fc1fc1), 8, 32, BYTE_ORDER);
+       if (ret) {
+               BT_LOGE("Error writing packet header magic: stream-file-name=%s",
+                       stream->file_name->str);
+               goto end;
+       }
+
+       /* Packet header: UUID */
+       for (i = 0; i < BABELTRACE_UUID_LEN; i++) {
+               ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+                       (uint64_t) stream->sc->tc->uuid[i], 8, 8, BYTE_ORDER);
+               if (ret) {
+                       BT_LOGE("Error writing packet header UUID: stream-file-name=%s",
+                               stream->file_name->str);
+                       goto end;
+               }
+       }
+
+       /* Packet header: stream class ID */
+       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+               bt_stream_class_get_id(stream->sc->ir_sc), 8, 64, BYTE_ORDER);
+       if (ret) {
+               BT_LOGE("Error writing packet header stream class id: "
+                       "stream-file-name=%s, stream-class-id=%"PRIu64,
+                       stream->file_name->str,
+                       bt_stream_class_get_id(stream->sc->ir_sc));
+               goto end;
+       }
+
+       /* Packet header: stream ID */
+       ret = bt_ctfser_write_byte_aligned_unsigned_int(&stream->ctfser,
+               bt_stream_get_id(stream->ir_stream), 8, 64, BYTE_ORDER);
+       if (ret) {
+               BT_LOGE("Error writing packet header stream id: "
+                       "stream-file-name=%s, stream-id=%"PRIu64,
+                       stream->file_name->str,
+                       bt_stream_get_id(stream->ir_stream));
+               goto end;
+       }
+
+       /* Save packet context's offset to rewrite it later */
+       stream->packet_state.context_offset_bits =
+               bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser);
+
+       /* Write packet context just to advance to content (first event) */
+       ret = write_packet_context(stream);
+       if (ret) {
+               goto end;
+       }
+
+       stream->packet_state.is_open = true;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int fs_sink_stream_close_packet(struct fs_sink_stream *stream,
+               const bt_clock_snapshot *cs)
+{
+       int ret;
+
+       BT_ASSERT(stream->packet_state.is_open);
+
+       if (cs) {
+               stream->packet_state.end_cs = bt_clock_snapshot_get_value(cs);
+       }
+
+       stream->packet_state.content_size =
+               bt_ctfser_get_offset_in_current_packet_bits(&stream->ctfser);
+       stream->packet_state.total_size =
+               (stream->packet_state.content_size + 7) & ~UINT64_C(7);
+
+       /* Rewrite packet context */
+       bt_ctfser_set_offset_in_current_packet_bits(&stream->ctfser,
+               stream->packet_state.context_offset_bits);
+       ret = write_packet_context(stream);
+       if (ret) {
+               goto end;
+       }
+
+       /* Close packet */
+       bt_ctfser_close_current_packet(&stream->ctfser,
+               stream->packet_state.total_size / 8);
+
+       /* Partially copy current packet state to previous packet state */
+       stream->prev_packet_state.end_cs = stream->packet_state.end_cs;
+       stream->prev_packet_state.discarded_events_counter =
+               stream->packet_state.discarded_events_counter;
+       stream->prev_packet_state.seq_num =
+               stream->packet_state.seq_num;
+
+       /* Reset current packet state */
+       stream->packet_state.beginning_cs = UINT64_C(-1);
+       stream->packet_state.end_cs = UINT64_C(-1);
+       stream->packet_state.content_size = 0;
+       stream->packet_state.total_size = 0;
+       stream->packet_state.seq_num += 1;
+       stream->packet_state.context_offset_bits = 0;
+       stream->packet_state.is_open = false;
+       BT_PACKET_PUT_REF_AND_RESET(stream->packet_state.packet);
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/fs-sink/fs-sink-stream.h b/src/plugins/ctf/fs-sink/fs-sink-stream.h
new file mode 100644 (file)
index 0000000..c3efc9a
--- /dev/null
@@ -0,0 +1,191 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_STREAM_H
+#define BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_STREAM_H
+
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+#include "ctfser/ctfser.h"
+#include <glib.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "fs-sink-ctf-meta.h"
+
+struct fs_sink_trace;
+
+struct fs_sink_stream {
+       struct fs_sink_trace *trace;
+       struct bt_ctfser ctfser;
+
+       /* Stream's file name */
+       GString *file_name;
+
+       /* Weak */
+       const bt_stream *ir_stream;
+
+       struct fs_sink_ctf_stream_class *sc;
+
+       /* Current packet's state */
+       struct {
+               /*
+                * True if we're, for this stream, within an opened
+                * packet (got a packet beginning message, but no
+                * packet end message yet).
+                */
+               bool is_open;
+
+               /*
+                * Current beginning default clock snapshot for the
+                * current packet (`UINT64_C(-1)` if not set).
+                */
+               uint64_t beginning_cs;
+
+               /*
+                * Current end default clock snapshot for the current
+                * packet (`UINT64_C(-1)` if not set).
+                */
+               uint64_t end_cs;
+
+               /*
+                * Current packet's content size (bits) for the current
+                * packet.
+                */
+               uint64_t content_size;
+
+               /*
+                * Current packet's total size (bits) for the current
+                * packet.
+                */
+               uint64_t total_size;
+
+               /*
+                * Discarded events (free running) counter for the
+                * current packet.
+                */
+               uint64_t discarded_events_counter;
+
+               /* Sequence number (free running) of the current packet */
+               uint64_t seq_num;
+
+               /*
+                * Offset of the packet context structure within the
+                * current packet (bits).
+                */
+               uint64_t context_offset_bits;
+
+               /* Owned by this */
+               const bt_packet *packet;
+       } packet_state;
+
+       /* Previous packet's state */
+       struct {
+               /* End default clock snapshot (`UINT64_C(-1)` if not set) */
+               uint64_t end_cs;
+
+               /* Discarded events (free running) counter */
+               uint64_t discarded_events_counter;
+
+               /* Sequence number (free running) */
+               uint64_t seq_num;
+       } prev_packet_state;
+
+       /* State to handle discarded events */
+       struct {
+               /*
+                * True if we're in the time range given by a previously
+                * received discarded events message. In this case,
+                * `beginning_cs` and `end_cs` below contain the
+                * beginning and end clock snapshots for this range.
+                *
+                * This is used to validate that, when receiving a
+                * packet end message, the current discarded events time
+                * range matches what's expected for CTF 1.8, that is:
+                *
+                * * Its beginning time is the previous packet's end
+                *   time (or the current packet's beginning time if
+                *   this is the first packet).
+                *
+                * * Its end time is the current packet's end time.
+                */
+               bool in_range;
+
+               /*
+                * Beginning and end times of the time range given by a
+                * previously received discarded events message.
+                */
+               uint64_t beginning_cs;
+               uint64_t end_cs;
+       } discarded_events_state;
+
+       /* State to handle discarded packets */
+       struct {
+               /*
+                * True if we're in the time range given by a previously
+                * received discarded packets message. In this case,
+                * `beginning_cs` and `end_cs` below contain the
+                * beginning and end clock snapshots for this range.
+                *
+                * This is used to validate that, when receiving a
+                * packet beginning message, the current discarded
+                * packets time range matches what's expected for CTF
+                * 1.8, that is:
+                *
+                * * Its beginning time is the previous packet's end
+                *   time.
+                *
+                * * Its end time is the current packet's beginning
+                *   time.
+                */
+               bool in_range;
+
+               /*
+                * Beginning and end times of the time range given by a
+                * previously received discarded packets message.
+                */
+               uint64_t beginning_cs;
+               uint64_t end_cs;
+       } discarded_packets_state;
+};
+
+BT_HIDDEN
+struct fs_sink_stream *fs_sink_stream_create(struct fs_sink_trace *trace,
+               const bt_stream *ir_stream);
+
+BT_HIDDEN
+void fs_sink_stream_destroy(struct fs_sink_stream *stream);
+
+BT_HIDDEN
+int fs_sink_stream_write_event(struct fs_sink_stream *stream,
+               const bt_clock_snapshot *cs, const bt_event *event,
+               struct fs_sink_ctf_event_class *ec);
+
+BT_HIDDEN
+int fs_sink_stream_open_packet(struct fs_sink_stream *stream,
+               const bt_clock_snapshot *cs, const bt_packet *packet);
+
+BT_HIDDEN
+int fs_sink_stream_close_packet(struct fs_sink_stream *stream,
+               const bt_clock_snapshot *cs);
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_STREAM_H */
diff --git a/src/plugins/ctf/fs-sink/fs-sink-trace.c b/src/plugins/ctf/fs-sink/fs-sink-trace.c
new file mode 100644 (file)
index 0000000..7f5c83a
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRACE"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include "common/assert.h"
+#include "ctfser/ctfser.h"
+
+#include "translate-trace-ir-to-ctf-ir.h"
+#include "translate-ctf-ir-to-tsdl.h"
+#include "fs-sink.h"
+#include "fs-sink-trace.h"
+#include "fs-sink-stream.h"
+
+/*
+ * Sanitizes `path` so as to:
+ *
+ * * Replace `.` subdirectories with `_`.
+ * * Replace `..` subdirectories with `__`.
+ * * Remove trailing slashes.
+ */
+static
+GString *sanitize_trace_path(const char *path)
+{
+       GString *san_path = g_string_new(NULL);
+       const char *ch = path;
+       bool dir_start = true;
+
+       BT_ASSERT(san_path);
+       BT_ASSERT(path);
+
+       while (*ch != '\0') {
+               switch (*ch) {
+               case '/':
+                       /* Start of directory */
+                       dir_start = true;
+                       g_string_append_c(san_path, *ch);
+                       ch++;
+                       continue;
+               case '.':
+                       if (dir_start) {
+                               switch (ch[1]) {
+                               case '\0':
+                               case '/':
+                                       /* `.` -> `_` */
+                                       g_string_append_c(san_path, '_');
+                                       ch++;
+                                       continue;
+                               case '.':
+                                       switch (ch[2]) {
+                                       case '\0':
+                                       case '/':
+                                               /* `..` -> `__` */
+                                               g_string_append(san_path, "__");
+                                               ch += 2;
+                                               continue;
+                                       default:
+                                               break;
+                                       }
+                               default:
+                                       break;
+                               }
+                       }
+               default:
+                       break;
+               }
+
+               /* Not a special character */
+               g_string_append_c(san_path, *ch);
+               ch++;
+               dir_start = false;
+       }
+
+       /* Remove trailing slashes */
+       while (san_path->len > 0 &&
+                       san_path->str[san_path->len - 1] == '/') {
+               /* Remove trailing slash */
+               g_string_set_size(san_path, san_path->len - 1);
+       }
+
+       if (san_path->len == 0) {
+               /* Looks like there's nothing left: just use `trace` */
+               g_string_assign(san_path, "trace");
+       }
+
+       return san_path;
+}
+
+/*
+ * Find a path based on `path` that doesn't exist yet.  First, try `path`
+ * itself, then try with incrementing suffixes.
+ */
+
+static
+GString *make_unique_trace_path(const char *path)
+{
+       GString *unique_path;
+       unsigned int suffix = 0;
+
+       unique_path = g_string_new(path);
+
+       while (g_file_test(unique_path->str, G_FILE_TEST_EXISTS)) {
+               g_string_printf(unique_path, "%s-%u", path, suffix);
+               suffix++;
+       }
+
+       return unique_path;
+}
+
+/*
+ * Validate that the input string `datetime` is an ISO8601-compliant string (the
+ * format used by LTTng in the metadata).
+ */
+
+static
+int lttng_validate_datetime(const char *datetime)
+{
+       GTimeVal tv;
+       int ret = -1;
+
+       /*
+        * We are using g_time_val_from_iso8601, as the safer/more modern
+        * alternative, g_date_time_new_from_iso8601, is only available in
+        * glib >= 2.56, and this is sufficient for our use case of validating
+        * the format.
+        */
+       if (!g_time_val_from_iso8601(datetime, &tv)) {
+               BT_LOGD("Couldn't parse datetime as iso8601: date=\"%s\"", datetime);
+               goto end;
+       }
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static
+int append_lttng_trace_path_ust_uid(GString *path, const bt_trace_class *tc)
+{
+       const bt_value *v;
+       int ret;
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_buffering_id");
+       if (!v || !bt_value_is_signed_integer(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_buffering_id\"");
+               goto error;
+       }
+
+       g_string_append_printf(path, G_DIR_SEPARATOR_S "%" PRId64,
+               bt_value_signed_integer_get(v));
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "isa_length");
+       if (!v || !bt_value_is_signed_integer(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"isa_length\"");
+               goto error;
+       }
+
+       g_string_append_printf(path, G_DIR_SEPARATOR_S "%" PRIu64 "-bit",
+               bt_value_signed_integer_get(v));
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int append_lttng_trace_path_ust_pid(GString *path, const bt_trace_class *tc)
+{
+       const bt_value *v;
+       const char *datetime;
+       int ret;
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "procname");
+       if (!v || !bt_value_is_string(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"procname\"");
+               goto error;
+       }
+
+       g_string_append_printf(path, G_DIR_SEPARATOR_S "%s", bt_value_string_get(v));
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "vpid");
+       if (!v || !bt_value_is_signed_integer(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"vpid\"");
+               goto error;
+       }
+
+       g_string_append_printf(path, "-%" PRId64, bt_value_signed_integer_get(v));
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "vpid_datetime");
+       if (!v || !bt_value_is_string(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"vpid_datetime\"");
+               goto error;
+       }
+
+       datetime = bt_value_string_get(v);
+
+       if (lttng_validate_datetime(datetime)) {
+               goto error;
+       }
+
+       g_string_append_printf(path, "-%s", datetime);
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+/*
+ * Try to build a trace path based on environment values put in the trace
+ * environment by the LTTng tracer, starting with version 2.11.
+ */
+static
+GString *make_lttng_trace_path_rel(const struct fs_sink_trace *trace)
+{
+       const bt_trace_class *tc;
+       const bt_value *v;
+       const char *tracer_name, *domain, *datetime;
+       int64_t tracer_major, tracer_minor;
+       GString *path;
+
+       path = g_string_new(NULL);
+       if (!path) {
+               goto error;
+       }
+
+       tc = bt_trace_borrow_class_const(trace->ir_trace);
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_name");
+       if (!v || !bt_value_is_string(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_name\"");
+               goto error;
+       }
+
+       tracer_name = bt_value_string_get(v);
+
+       if (!g_str_equal(tracer_name, "lttng-ust")
+                       && !g_str_equal(tracer_name, "lttng-modules")) {
+               BT_LOGD("Unrecognized tracer name: name=\"%s\"", tracer_name);
+               goto error;
+       }
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_major");
+       if (!v || !bt_value_is_signed_integer(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_major\"");
+               goto error;
+       }
+
+       tracer_major = bt_value_signed_integer_get(v);
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_minor");
+       if (!v || !bt_value_is_signed_integer(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_minor\"");
+               goto error;
+       }
+
+       tracer_minor = bt_value_signed_integer_get(v);
+
+       if (!(tracer_major >= 3 || (tracer_major == 2 && tracer_minor >= 11))) {
+               BT_LOGD("Unsupported LTTng version for automatic trace path: major=%" PRId64 ", minor=%" PRId64,
+                       tracer_major, tracer_minor);
+               goto error;
+       }
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "hostname");
+       if (!v || !bt_value_is_string(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"tracer_hostname\"");
+               goto error;
+       }
+
+       g_string_assign(path, bt_value_string_get(v));
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "trace_name");
+       if (!v || !bt_value_is_string(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"trace_name\"");
+               goto error;
+       }
+
+       g_string_append_printf(path, G_DIR_SEPARATOR_S "%s", bt_value_string_get(v));
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "trace_creation_datetime");
+       if (!v || !bt_value_is_string(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"trace_creation_datetime\"");
+               goto error;
+       }
+
+       datetime = bt_value_string_get(v);
+
+       if (lttng_validate_datetime(datetime)) {
+               goto error;
+       }
+
+       g_string_append_printf(path, "-%s", datetime);
+
+       v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "domain");
+       if (!v || !bt_value_is_string(v)) {
+               BT_LOGD_STR("Couldn't get environment value: name=\"domain\"");
+               goto error;
+       }
+
+       domain = bt_value_string_get(v);
+       g_string_append_printf(path, G_DIR_SEPARATOR_S "%s", domain);
+
+       if (g_str_equal(domain, "ust")) {
+               const char *tracer_buffering_scheme;
+
+               v = bt_trace_class_borrow_environment_entry_value_by_name_const(tc, "tracer_buffering_scheme");
+               if (!v || !bt_value_is_string(v)) {
+                       BT_LOGD_STR("Couldn't get environment value: name=\"tracer_buffering_scheme\"");
+                       goto error;
+               }
+
+               tracer_buffering_scheme = bt_value_string_get(v);
+               g_string_append_printf(path, G_DIR_SEPARATOR_S "%s", tracer_buffering_scheme);
+
+               if (g_str_equal(tracer_buffering_scheme, "uid")) {
+                       if (append_lttng_trace_path_ust_uid(path, tc)) {
+                               goto error;
+                       }
+               } else if (g_str_equal(tracer_buffering_scheme, "pid")){
+                       if (append_lttng_trace_path_ust_pid(path, tc)) {
+                               goto error;
+                       }
+               } else {
+                       /* Unknown buffering scheme. */
+                       BT_LOGD("Unknown buffering scheme: tracer_buffering_scheme=\"%s\"", tracer_buffering_scheme);
+                       goto error;
+               }
+       } else if (!g_str_equal(domain, "kernel")) {
+               /* Unknown domain. */
+               BT_LOGD("Unknown domain: domain=\"%s\"", domain);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (path) {
+               g_string_free(path, TRUE);
+               path = NULL;
+       }
+
+end:
+       return path;
+}
+
+/* Build the relative output path for `trace`. */
+
+static
+GString *make_trace_path_rel(const struct fs_sink_trace *trace)
+{
+       GString *path = NULL;
+
+       if (trace->fs_sink->assume_single_trace) {
+               /* Use output directory directly */
+               path = g_string_new("");
+               goto end;
+       }
+
+       /* First, try to build a path using environment fields written by LTTng. */
+       path = make_lttng_trace_path_rel(trace);
+       if (path) {
+               goto end;
+       }
+
+       /* Otherwise, use the trace name, if available. */
+       const char *trace_name = bt_trace_get_name(trace->ir_trace);
+       if (trace_name) {
+               path = g_string_new(trace_name);
+               goto end;
+       }
+
+       /* Otherwise, use "trace". */
+       path = g_string_new("trace");
+
+end:
+       return path;
+}
+
+/*
+ * Compute the trace output path for `trace`, rooted at `output_base_directory`.
+ */
+
+static
+GString *make_trace_path(const struct fs_sink_trace *trace, const char *output_base_directory)
+{
+       GString *rel_path = NULL;
+       GString *rel_path_san = NULL;
+       GString *full_path = NULL;
+       GString *unique_full_path = NULL;
+
+       rel_path = make_trace_path_rel(trace);
+       if (!rel_path) {
+               goto end;
+       }
+
+       rel_path_san = sanitize_trace_path(rel_path->str);
+       if (!rel_path_san) {
+               goto end;
+       }
+
+       full_path = g_string_new(NULL);
+       if (!full_path) {
+               goto end;
+       }
+
+       g_string_printf(full_path, "%s" G_DIR_SEPARATOR_S "%s",
+               output_base_directory, rel_path_san->str);
+
+       unique_full_path = make_unique_trace_path(full_path->str);
+
+end:
+       if (rel_path) {
+               g_string_free(rel_path, TRUE);
+       }
+
+       if (rel_path_san) {
+               g_string_free(rel_path_san, TRUE);
+       }
+
+       if (full_path) {
+               g_string_free(full_path, TRUE);
+       }
+
+       return unique_full_path;
+}
+
+BT_HIDDEN
+void fs_sink_trace_destroy(struct fs_sink_trace *trace)
+{
+       GString *tsdl = NULL;
+       FILE *fh = NULL;
+       size_t len;
+
+       if (!trace) {
+               goto end;
+       }
+
+       if (trace->ir_trace_destruction_listener_id != UINT64_C(-1)) {
+               /*
+                * Remove the destruction listener, otherwise it could
+                * be called in the future, and its private data is this
+                * CTF FS sink trace object which won't exist anymore.
+                */
+               (void) bt_trace_remove_destruction_listener(trace->ir_trace,
+                       trace->ir_trace_destruction_listener_id);
+               trace->ir_trace_destruction_listener_id = UINT64_C(-1);
+       }
+
+       if (trace->streams) {
+               g_hash_table_destroy(trace->streams);
+               trace->streams = NULL;
+       }
+
+       tsdl = g_string_new(NULL);
+       BT_ASSERT(tsdl);
+       translate_trace_class_ctf_ir_to_tsdl(trace->tc, tsdl);
+
+       BT_ASSERT(trace->metadata_path);
+       fh = fopen(trace->metadata_path->str, "wb");
+       if (!fh) {
+               BT_LOGF_ERRNO("In trace destruction listener: "
+                       "cannot open metadata file for writing: ",
+                       ": path=\"%s\"", trace->metadata_path->str);
+               abort();
+       }
+
+       len = fwrite(tsdl->str, sizeof(*tsdl->str), tsdl->len, fh);
+       if (len != tsdl->len) {
+               BT_LOGF_ERRNO("In trace destruction listener: "
+                       "cannot write metadata file: ",
+                       ": path=\"%s\"", trace->metadata_path->str);
+               abort();
+       }
+
+       if (!trace->fs_sink->quiet) {
+               printf("Created CTF trace `%s`.\n", trace->path->str);
+       }
+
+       if (trace->path) {
+               g_string_free(trace->path, TRUE);
+               trace->path = NULL;
+       }
+
+       g_string_free(trace->metadata_path, TRUE);
+       trace->metadata_path = NULL;
+
+       fs_sink_ctf_trace_class_destroy(trace->tc);
+       trace->tc = NULL;
+       g_free(trace);
+
+end:
+       if (fh) {
+               int ret = fclose(fh);
+
+               if (ret != 0) {
+                       BT_LOGW_ERRNO("In trace destruction listener: "
+                               "cannot close metadata file: ",
+                               ": path=\"%s\"", trace->metadata_path->str);
+               }
+       }
+
+       if (tsdl) {
+               g_string_free(tsdl, TRUE);
+       }
+
+       return;
+}
+
+static
+void ir_trace_destruction_listener(const bt_trace *ir_trace, void *data)
+{
+       struct fs_sink_trace *trace = data;
+
+       /*
+        * Prevent bt_trace_remove_destruction_listener() from being
+        * called in fs_sink_trace_destroy(), which is called by
+        * g_hash_table_remove() below.
+        */
+       trace->ir_trace_destruction_listener_id = UINT64_C(-1);
+       g_hash_table_remove(trace->fs_sink->traces, ir_trace);
+}
+
+BT_HIDDEN
+struct fs_sink_trace *fs_sink_trace_create(struct fs_sink_comp *fs_sink,
+               const bt_trace *ir_trace)
+{
+       int ret;
+       struct fs_sink_trace *trace = g_new0(struct fs_sink_trace, 1);
+       bt_trace_status trace_status;
+
+       if (!trace) {
+               goto end;
+       }
+
+       trace->fs_sink = fs_sink;
+       trace->ir_trace = ir_trace;
+       trace->ir_trace_destruction_listener_id = UINT64_C(-1);
+       trace->tc = translate_trace_class_trace_ir_to_ctf_ir(
+               bt_trace_borrow_class_const(ir_trace));
+       if (!trace->tc) {
+               goto error;
+       }
+
+       trace->path = make_trace_path(trace, fs_sink->output_dir_path->str);
+       BT_ASSERT(trace->path);
+       ret = g_mkdir_with_parents(trace->path->str, 0755);
+       if (ret) {
+               BT_LOGE_ERRNO("Cannot create directories for trace directory",
+                       ": path=\"%s\"", trace->path->str);
+               goto error;
+       }
+
+       trace->metadata_path = g_string_new(trace->path->str);
+       BT_ASSERT(trace->metadata_path);
+       g_string_append(trace->metadata_path, "/metadata");
+       trace->streams = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+               NULL, (GDestroyNotify) fs_sink_stream_destroy);
+       BT_ASSERT(trace->streams);
+       trace_status = bt_trace_add_destruction_listener(ir_trace,
+               ir_trace_destruction_listener, trace,
+               &trace->ir_trace_destruction_listener_id);
+       if (trace_status) {
+               goto error;
+       }
+
+       g_hash_table_insert(fs_sink->traces, (gpointer) ir_trace, trace);
+       goto end;
+
+error:
+       fs_sink_trace_destroy(trace);
+       trace = NULL;
+
+end:
+       return trace;
+}
diff --git a/src/plugins/ctf/fs-sink/fs-sink-trace.h b/src/plugins/ctf/fs-sink/fs-sink-trace.h
new file mode 100644 (file)
index 0000000..9a8ac52
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_TRACE_H
+#define BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_TRACE_H
+
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+#include "ctfser/ctfser.h"
+#include <glib.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "fs-sink-ctf-meta.h"
+
+struct fs_sink_comp;
+
+struct fs_sink_trace {
+       struct fs_sink_comp *fs_sink;
+
+       /* Owned by this */
+       struct fs_sink_ctf_trace_class *tc;
+
+       /*
+        * Weak reference: this object does not own it, and `tc` above
+        * does not own its trace IR trace class either. Instead, we add
+        * a "trace destruction" listener (in create_trace()) so that
+        * this object gets destroyed when the trace object is
+        * destroyed.
+        *
+        * Otherwise (with a strong reference), we would keep this trace
+        * object alive until the upstream message iterator ends. This
+        * could "leak" resources (memory, file descriptors) associated
+        * to traces and streams which otherwise would not exist.
+        */
+       const bt_trace *ir_trace;
+
+       uint64_t ir_trace_destruction_listener_id;
+
+       /* Trace's directory */
+       GString *path;
+
+       /* `metadata` file path */
+       GString *metadata_path;
+
+       /*
+        * Hash table of `const bt_stream *` (weak) to
+        * `struct fs_sink_stream *` (owned by hash table).
+        */
+       GHashTable *streams;
+};
+
+BT_HIDDEN
+struct fs_sink_trace *fs_sink_trace_create(struct fs_sink_comp *fs_sink,
+               const bt_trace *ir_trace);
+
+BT_HIDDEN
+void fs_sink_trace_destroy(struct fs_sink_trace *trace);
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_TRACE_H */
diff --git a/src/plugins/ctf/fs-sink/fs-sink.c b/src/plugins/ctf/fs-sink/fs-sink.c
new file mode 100644 (file)
index 0000000..42d822e
--- /dev/null
@@ -0,0 +1,1031 @@
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include "common/assert.h"
+#include "ctfser/ctfser.h"
+
+#include "fs-sink.h"
+#include "fs-sink-trace.h"
+#include "fs-sink-stream.h"
+#include "fs-sink-ctf-meta.h"
+#include "translate-trace-ir-to-ctf-ir.h"
+#include "translate-ctf-ir-to-tsdl.h"
+
+static
+const char * const in_port_name = "in";
+
+static
+bt_self_component_status ensure_output_dir_exists(
+               struct fs_sink_comp *fs_sink)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       int ret;
+
+       ret = g_mkdir_with_parents(fs_sink->output_dir_path->str, 0755);
+       if (ret) {
+               BT_LOGE_ERRNO("Cannot create directories for output directory",
+                       ": output-dir-path=\"%s\"",
+                       fs_sink->output_dir_path->str);
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+static
+bt_self_component_status configure_component(struct fs_sink_comp *fs_sink,
+               const bt_value *params)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       const bt_value *value;
+
+       value = bt_value_map_borrow_entry_value_const(params, "path");
+       if (!value) {
+               BT_LOGE_STR("Missing mandatory `path` parameter.");
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       if (!bt_value_is_string(value)) {
+               BT_LOGE_STR("`path` parameter: expecting a string.");
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       g_string_assign(fs_sink->output_dir_path,
+               bt_value_string_get(value));
+       value = bt_value_map_borrow_entry_value_const(params,
+               "assume-single-trace");
+       if (value) {
+               if (!bt_value_is_bool(value)) {
+                       BT_LOGE_STR("`assume-single-trace` parameter: expecting a boolean.");
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+
+               fs_sink->assume_single_trace = (bool) bt_value_bool_get(value);
+       }
+
+       value = bt_value_map_borrow_entry_value_const(params,
+               "ignore-discarded-events");
+       if (value) {
+               if (!bt_value_is_bool(value)) {
+                       BT_LOGE_STR("`ignore-discarded-events` parameter: expecting a boolean.");
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+
+               fs_sink->ignore_discarded_events =
+                       (bool) bt_value_bool_get(value);
+       }
+
+       value = bt_value_map_borrow_entry_value_const(params,
+               "ignore-discarded-packets");
+       if (value) {
+               if (!bt_value_is_bool(value)) {
+                       BT_LOGE_STR("`ignore-discarded-packets` parameter: expecting a boolean.");
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+
+               fs_sink->ignore_discarded_packets =
+                       (bool) bt_value_bool_get(value);
+       }
+
+       value = bt_value_map_borrow_entry_value_const(params,
+               "quiet");
+       if (value) {
+               if (!bt_value_is_bool(value)) {
+                       BT_LOGE_STR("`quiet` parameter: expecting a boolean.");
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+
+               fs_sink->quiet = (bool) bt_value_bool_get(value);
+       }
+
+end:
+       return status;
+}
+
+static
+void destroy_fs_sink_comp(struct fs_sink_comp *fs_sink)
+{
+       if (!fs_sink) {
+               goto end;
+       }
+
+       if (fs_sink->output_dir_path) {
+               g_string_free(fs_sink->output_dir_path, TRUE);
+               fs_sink->output_dir_path = NULL;
+       }
+
+       if (fs_sink->traces) {
+               g_hash_table_destroy(fs_sink->traces);
+               fs_sink->traces = NULL;
+       }
+
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
+               fs_sink->upstream_iter);
+       g_free(fs_sink);
+
+end:
+       return;
+}
+
+BT_HIDDEN
+bt_self_component_status ctf_fs_sink_init(
+               bt_self_component_sink *self_comp, const bt_value *params,
+               void *init_method_data)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct fs_sink_comp *fs_sink = NULL;
+
+       fs_sink = g_new0(struct fs_sink_comp, 1);
+       if (!fs_sink) {
+               BT_LOGE_STR("Failed to allocate one CTF FS sink structure.");
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       fs_sink->output_dir_path = g_string_new(NULL);
+       fs_sink->self_comp = self_comp;
+       status = configure_component(fs_sink, params);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               /* configure_component() logs errors */
+               goto end;
+       }
+
+       if (fs_sink->assume_single_trace &&
+                       g_file_test(fs_sink->output_dir_path->str,
+                               G_FILE_TEST_EXISTS)) {
+               BT_LOGE("Single trace mode, but output path exists: "
+                       "output-path=\"%s\"", fs_sink->output_dir_path->str);
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       status = ensure_output_dir_exists(fs_sink);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               /* ensure_output_dir_exists() logs errors */
+               goto end;
+       }
+
+       fs_sink->traces = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+               NULL, (GDestroyNotify) fs_sink_trace_destroy);
+       if (!fs_sink->traces) {
+               BT_LOGE_STR("Failed to allocate one GHashTable.");
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       status = bt_self_component_sink_add_input_port(self_comp, in_port_name,
+               NULL, NULL);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto end;
+       }
+
+       bt_self_component_set_data(
+               bt_self_component_sink_as_self_component(self_comp), fs_sink);
+
+end:
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               destroy_fs_sink_comp(fs_sink);
+       }
+
+       return status;
+}
+
+static inline
+struct fs_sink_stream *borrow_stream(struct fs_sink_comp *fs_sink,
+               const bt_stream *ir_stream)
+{
+       const bt_trace *ir_trace = bt_stream_borrow_trace_const(ir_stream);
+       struct fs_sink_trace *trace;
+       struct fs_sink_stream *stream = NULL;
+
+       trace = g_hash_table_lookup(fs_sink->traces, ir_trace);
+       if (unlikely(!trace)) {
+               if (fs_sink->assume_single_trace &&
+                               g_hash_table_size(fs_sink->traces) > 0) {
+                       BT_LOGE("Single trace mode, but getting more than one trace: "
+                               "stream-name=\"%s\"",
+                               bt_stream_get_name(ir_stream));
+                       goto end;
+               }
+
+               trace = fs_sink_trace_create(fs_sink, ir_trace);
+               if (!trace) {
+                       goto end;
+               }
+       }
+
+       stream = g_hash_table_lookup(trace->streams, ir_stream);
+       if (unlikely(!stream)) {
+               stream = fs_sink_stream_create(trace, ir_stream);
+               if (!stream) {
+                       goto end;
+               }
+       }
+
+end:
+       return stream;
+}
+
+static inline
+bt_self_component_status handle_event_msg(struct fs_sink_comp *fs_sink,
+               const bt_message *msg)
+{
+       int ret;
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       const bt_event *ir_event = bt_message_event_borrow_event_const(msg);
+       const bt_stream *ir_stream = bt_event_borrow_stream_const(ir_event);
+       struct fs_sink_stream *stream;
+       struct fs_sink_ctf_event_class *ec = NULL;
+       const bt_clock_snapshot *cs = NULL;
+
+       stream = borrow_stream(fs_sink, ir_stream);
+       if (unlikely(!stream)) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       ret = try_translate_event_class_trace_ir_to_ctf_ir(stream->sc,
+               bt_event_borrow_class_const(ir_event), &ec);
+       if (ret) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_ASSERT(ec);
+
+       if (stream->sc->default_clock_class) {
+               cs = bt_message_event_borrow_default_clock_snapshot_const(
+                       msg);
+       }
+
+       ret = fs_sink_stream_write_event(stream, cs, ir_event, ec);
+       if (unlikely(ret)) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+static inline
+bt_self_component_status handle_packet_beginning_msg(
+               struct fs_sink_comp *fs_sink, const bt_message *msg)
+{
+       int ret;
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       const bt_packet *ir_packet =
+               bt_message_packet_beginning_borrow_packet_const(msg);
+       const bt_stream *ir_stream = bt_packet_borrow_stream_const(ir_packet);
+       struct fs_sink_stream *stream;
+       const bt_clock_snapshot *cs = NULL;
+
+       stream = borrow_stream(fs_sink, ir_stream);
+       if (unlikely(!stream)) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       if (stream->sc->packets_have_ts_begin) {
+               cs = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
+                       msg);
+               BT_ASSERT(cs);
+       }
+
+       /*
+        * If we previously received a discarded events message with
+        * a time range, make sure that its beginning time matches what's
+        * expected for CTF 1.8, that is:
+        *
+        * * Its beginning time is the previous packet's end
+        *   time (or the current packet's beginning time if
+        *   this is the first packet).
+        *
+        * We check this here instead of in handle_packet_end_msg()
+        * because we want to catch any incompatible message as early as
+        * possible to report the error.
+        *
+        * Validation of the discarded events message's end time is
+        * performed in handle_packet_end_msg().
+        */
+       if (stream->discarded_events_state.in_range) {
+               uint64_t expected_cs;
+
+               /*
+                * `stream->discarded_events_state.in_range` is only set
+                * when the stream class's discarded events have a time
+                * range.
+                *
+                * It is required that the packet beginning and end
+                * messages for this stream class have times when
+                * discarded events have a time range.
+                */
+               BT_ASSERT(stream->sc->discarded_events_has_ts);
+               BT_ASSERT(stream->sc->packets_have_ts_begin);
+               BT_ASSERT(stream->sc->packets_have_ts_end);
+
+               if (stream->prev_packet_state.end_cs == UINT64_C(-1)) {
+                       /* We're opening the first packet */
+                       expected_cs = bt_clock_snapshot_get_value(cs);
+               } else {
+                       expected_cs = stream->prev_packet_state.end_cs;
+               }
+
+               if (stream->discarded_events_state.beginning_cs !=
+                               expected_cs) {
+                       BT_LOGE("Incompatible discarded events message: "
+                               "unexpected beginning time: "
+                               "beginning-cs-val=%" PRIu64 ", "
+                               "expected-beginning-cs-val=%" PRIu64 ", "
+                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                               "trace-name=\"%s\", path=\"%s/%s\"",
+                               stream->discarded_events_state.beginning_cs,
+                               expected_cs,
+                               bt_stream_get_id(ir_stream),
+                               bt_stream_get_name(ir_stream),
+                               bt_trace_get_name(
+                                       bt_stream_borrow_trace_const(ir_stream)),
+                               stream->trace->path->str, stream->file_name->str);
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+       }
+
+       /*
+        * If we previously received a discarded packets message with a
+        * time range, make sure that its beginning and end times match
+        * what's expected for CTF 1.8, that is:
+        *
+        * * Its beginning time is the previous packet's end time.
+        *
+        * * Its end time is the current packet's beginning time.
+        */
+       if (stream->discarded_packets_state.in_range) {
+               uint64_t expected_end_cs;
+
+               /*
+                * `stream->discarded_packets_state.in_range` is only
+                * set when the stream class's discarded packets have a
+                * time range.
+                *
+                * It is required that the packet beginning and end
+                * messages for this stream class have times when
+                * discarded packets have a time range.
+                */
+               BT_ASSERT(stream->sc->discarded_packets_has_ts);
+               BT_ASSERT(stream->sc->packets_have_ts_begin);
+               BT_ASSERT(stream->sc->packets_have_ts_end);
+
+               /*
+                * It is not supported to have a discarded packets
+                * message _before_ the first packet: we cannot validate
+                * that its beginning time is compatible with CTF 1.8 in
+                * this case.
+                */
+               if (stream->prev_packet_state.end_cs == UINT64_C(-1)) {
+                       BT_LOGE("Incompatible discarded packets message "
+                               "occuring before the stream's first packet: "
+                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                               "trace-name=\"%s\", path=\"%s/%s\"",
+                               bt_stream_get_id(ir_stream),
+                               bt_stream_get_name(ir_stream),
+                               bt_trace_get_name(
+                                       bt_stream_borrow_trace_const(ir_stream)),
+                               stream->trace->path->str, stream->file_name->str);
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+
+               if (stream->discarded_packets_state.beginning_cs !=
+                               stream->prev_packet_state.end_cs) {
+                       BT_LOGE("Incompatible discarded packets message: "
+                               "unexpected beginning time: "
+                               "beginning-cs-val=%" PRIu64 ", "
+                               "expected-beginning-cs-val=%" PRIu64 ", "
+                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                               "trace-name=\"%s\", path=\"%s/%s\"",
+                               stream->discarded_packets_state.beginning_cs,
+                               stream->prev_packet_state.end_cs,
+                               bt_stream_get_id(ir_stream),
+                               bt_stream_get_name(ir_stream),
+                               bt_trace_get_name(
+                                       bt_stream_borrow_trace_const(ir_stream)),
+                               stream->trace->path->str, stream->file_name->str);
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+
+               expected_end_cs = bt_clock_snapshot_get_value(cs);
+
+               if (stream->discarded_packets_state.end_cs !=
+                               expected_end_cs) {
+                       BT_LOGE("Incompatible discarded packets message: "
+                               "unexpected end time: "
+                               "end-cs-val=%" PRIu64 ", "
+                               "expected-end-cs-val=%" PRIu64 ", "
+                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                               "trace-name=\"%s\", path=\"%s/%s\"",
+                               stream->discarded_packets_state.end_cs,
+                               expected_end_cs,
+                               bt_stream_get_id(ir_stream),
+                               bt_stream_get_name(ir_stream),
+                               bt_trace_get_name(
+                                       bt_stream_borrow_trace_const(ir_stream)),
+                               stream->trace->path->str, stream->file_name->str);
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+       }
+
+       /*
+        * We're not in a discarded packets time range anymore since we
+        * require that the discarded packets time ranges go from one
+        * packet's end time to the next packet's beginning time, and
+        * we're handling a packet beginning message here.
+        */
+       stream->discarded_packets_state.in_range = false;
+
+       ret = fs_sink_stream_open_packet(stream, cs, ir_packet);
+       if (ret) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+static inline
+bt_self_component_status handle_packet_end_msg(
+               struct fs_sink_comp *fs_sink, const bt_message *msg)
+{
+       int ret;
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       const bt_packet *ir_packet =
+               bt_message_packet_end_borrow_packet_const(msg);
+       const bt_stream *ir_stream = bt_packet_borrow_stream_const(ir_packet);
+       struct fs_sink_stream *stream;
+       const bt_clock_snapshot *cs = NULL;
+
+       stream = borrow_stream(fs_sink, ir_stream);
+       if (unlikely(!stream)) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       if (stream->sc->packets_have_ts_end) {
+               cs = bt_message_packet_end_borrow_default_clock_snapshot_const(
+                       msg);
+               BT_ASSERT(cs);
+       }
+
+       /*
+        * If we previously received a discarded events message with
+        * a time range, make sure that its end time matches what's
+        * expected for CTF 1.8, that is:
+        *
+        * * Its end time is the current packet's end time.
+        *
+        * Validation of the discarded events message's beginning time
+        * is performed in handle_packet_beginning_msg().
+        */
+       if (stream->discarded_events_state.in_range) {
+               uint64_t expected_cs;
+
+               /*
+                * `stream->discarded_events_state.in_range` is only set
+                * when the stream class's discarded events have a time
+                * range.
+                *
+                * It is required that the packet beginning and end
+                * messages for this stream class have times when
+                * discarded events have a time range.
+                */
+               BT_ASSERT(stream->sc->discarded_events_has_ts);
+               BT_ASSERT(stream->sc->packets_have_ts_begin);
+               BT_ASSERT(stream->sc->packets_have_ts_end);
+
+               expected_cs = bt_clock_snapshot_get_value(cs);
+
+               if (stream->discarded_events_state.end_cs != expected_cs) {
+                       BT_LOGE("Incompatible discarded events message: "
+                               "unexpected end time: "
+                               "end-cs-val=%" PRIu64 ", "
+                               "expected-end-cs-val=%" PRIu64 ", "
+                               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                               "trace-name=\"%s\", path=\"%s/%s\"",
+                               stream->discarded_events_state.end_cs,
+                               expected_cs,
+                               bt_stream_get_id(ir_stream),
+                               bt_stream_get_name(ir_stream),
+                               bt_trace_get_name(
+                                       bt_stream_borrow_trace_const(ir_stream)),
+                               stream->trace->path->str, stream->file_name->str);
+                       status = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+       }
+
+       ret = fs_sink_stream_close_packet(stream, cs);
+       if (ret) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       /*
+        * We're not in a discarded events time range anymore since we
+        * require that the discarded events time ranges go from one
+        * packet's end time to the next packet's end time, and we're
+        * handling a packet end message here.
+        */
+       stream->discarded_events_state.in_range = false;
+
+end:
+       return status;
+}
+
+static inline
+bt_self_component_status handle_stream_beginning_msg(
+               struct fs_sink_comp *fs_sink, const bt_message *msg)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       const bt_stream *ir_stream =
+               bt_message_stream_beginning_borrow_stream_const(msg);
+       const bt_stream_class *ir_sc =
+               bt_stream_borrow_class_const(ir_stream);
+       struct fs_sink_stream *stream;
+       bool packets_have_beginning_end_cs =
+               bt_stream_class_packets_have_beginning_default_clock_snapshot(ir_sc) &&
+               bt_stream_class_packets_have_end_default_clock_snapshot(ir_sc);
+
+       /*
+        * Not supported: discarded events with default clock snapshots,
+        * but packet beginning/end without default clock snapshot.
+        */
+       if (!fs_sink->ignore_discarded_events &&
+                       bt_stream_class_discarded_events_have_default_clock_snapshots(ir_sc) &&
+                       !packets_have_beginning_end_cs) {
+               BT_LOGE("Unsupported stream: discarded events have "
+                       "default clock snapshots, but packets have no "
+                       "beginning and/or end default clock snapshots: "
+                       "stream-addr=%p, "
+                       "stream-id=%" PRIu64 ", "
+                       "stream-name=\"%s\"",
+                       ir_stream, bt_stream_get_id(ir_stream),
+                       bt_stream_get_name(ir_stream));
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       /*
+        * Not supported: discarded packets with default clock
+        * snapshots, but packet beginning/end without default clock
+        * snapshot.
+        */
+       if (!fs_sink->ignore_discarded_packets &&
+                       bt_stream_class_discarded_packets_have_default_clock_snapshots(ir_sc) &&
+                       !packets_have_beginning_end_cs) {
+               BT_LOGE("Unsupported stream: discarded packets have "
+                       "default clock snapshots, but packets have no "
+                       "beginning and/or end default clock snapshots: "
+                       "stream-addr=%p, "
+                       "stream-id=%" PRIu64 ", "
+                       "stream-name=\"%s\"",
+                       ir_stream, bt_stream_get_id(ir_stream),
+                       bt_stream_get_name(ir_stream));
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       stream = borrow_stream(fs_sink, ir_stream);
+       if (!stream) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_LOGI("Created new, empty stream file: "
+               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+               "trace-name=\"%s\", path=\"%s/%s\"",
+               bt_stream_get_id(ir_stream), bt_stream_get_name(ir_stream),
+               bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream)),
+               stream->trace->path->str, stream->file_name->str);
+
+end:
+       return status;
+}
+
+static inline
+bt_self_component_status handle_stream_end_msg(struct fs_sink_comp *fs_sink,
+               const bt_message *msg)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       const bt_stream *ir_stream =
+               bt_message_stream_end_borrow_stream_const(msg);
+       struct fs_sink_stream *stream;
+
+       stream = borrow_stream(fs_sink, ir_stream);
+       if (!stream) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_LOGI("Closing stream file: "
+               "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+               "trace-name=\"%s\", path=\"%s/%s\"",
+               bt_stream_get_id(ir_stream), bt_stream_get_name(ir_stream),
+               bt_trace_get_name(bt_stream_borrow_trace_const(ir_stream)),
+               stream->trace->path->str, stream->file_name->str);
+
+       /*
+        * This destroys the stream object and frees all its resources,
+        * closing the stream file.
+        */
+       g_hash_table_remove(stream->trace->streams, ir_stream);
+
+end:
+       return status;
+}
+
+static inline
+bt_self_component_status handle_discarded_events_msg(
+               struct fs_sink_comp *fs_sink, const bt_message *msg)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       const bt_stream *ir_stream =
+               bt_message_discarded_events_borrow_stream_const(msg);
+       struct fs_sink_stream *stream;
+       const bt_clock_snapshot *cs = NULL;
+       bt_property_availability avail;
+       uint64_t count;
+
+       stream = borrow_stream(fs_sink, ir_stream);
+       if (!stream) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       if (fs_sink->ignore_discarded_events) {
+               BT_LOGI("Ignoring discarded events message: "
+                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                       "trace-name=\"%s\", path=\"%s/%s\"",
+                       bt_stream_get_id(ir_stream),
+                       bt_stream_get_name(ir_stream),
+                       bt_trace_get_name(
+                               bt_stream_borrow_trace_const(ir_stream)),
+                       stream->trace->path->str, stream->file_name->str);
+               goto end;
+       }
+
+       if (stream->discarded_events_state.in_range) {
+               BT_LOGE("Unsupported contiguous discarded events message: "
+                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                       "trace-name=\"%s\", path=\"%s/%s\"",
+                       bt_stream_get_id(ir_stream),
+                       bt_stream_get_name(ir_stream),
+                       bt_trace_get_name(
+                               bt_stream_borrow_trace_const(ir_stream)),
+                       stream->trace->path->str, stream->file_name->str);
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       /*
+        * If we're currently in an opened packet (got a packet
+        * beginning message, but no packet end message yet), we do not
+        * support having a discarded events message with a time range
+        * because we require that the discarded events message's time
+        * range go from a packet's end time to the next packet's end
+        * time.
+        */
+       if (stream->packet_state.is_open &&
+                       stream->sc->discarded_events_has_ts) {
+               BT_LOGE("Unsupported discarded events message with "
+                       "default clock snapshots occuring within a packet: "
+                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                       "trace-name=\"%s\", path=\"%s/%s\"",
+                       bt_stream_get_id(ir_stream),
+                       bt_stream_get_name(ir_stream),
+                       bt_trace_get_name(
+                               bt_stream_borrow_trace_const(ir_stream)),
+                       stream->trace->path->str, stream->file_name->str);
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       if (stream->sc->discarded_events_has_ts) {
+               /*
+                * Make the stream's state be in the time range of a
+                * discarded events message since we have the message's
+                * time range (`stream->sc->discarded_events_has_ts`).
+                */
+               stream->discarded_events_state.in_range = true;
+
+               /*
+                * The clock snapshot values will be validated when
+                * handling the next packet beginning and end messages
+                * (next calls to handle_packet_beginning_msg() and
+                * handle_packet_end_msg()).
+                */
+               cs = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+                       msg);
+               BT_ASSERT(cs);
+               stream->discarded_events_state.beginning_cs =
+                       bt_clock_snapshot_get_value(cs);
+               cs = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
+                       msg);
+               BT_ASSERT(cs);
+               stream->discarded_events_state.end_cs = bt_clock_snapshot_get_value(cs);
+       }
+
+       avail = bt_message_discarded_events_get_count(msg, &count);
+       if (avail != BT_PROPERTY_AVAILABILITY_AVAILABLE) {
+               /*
+                * There's no specific count of discarded events: set it
+                * to 1 so that we know that we at least discarded
+                * something.
+                */
+               count = 1;
+       }
+
+       stream->packet_state.discarded_events_counter += count;
+
+end:
+       return status;
+}
+
+static inline
+bt_self_component_status handle_discarded_packets_msg(
+               struct fs_sink_comp *fs_sink, const bt_message *msg)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       const bt_stream *ir_stream =
+               bt_message_discarded_packets_borrow_stream_const(msg);
+       struct fs_sink_stream *stream;
+       const bt_clock_snapshot *cs = NULL;
+       bt_property_availability avail;
+       uint64_t count;
+
+       stream = borrow_stream(fs_sink, ir_stream);
+       if (!stream) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       if (fs_sink->ignore_discarded_packets) {
+               BT_LOGI("Ignoring discarded packets message: "
+                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                       "trace-name=\"%s\", path=\"%s/%s\"",
+                       bt_stream_get_id(ir_stream),
+                       bt_stream_get_name(ir_stream),
+                       bt_trace_get_name(
+                               bt_stream_borrow_trace_const(ir_stream)),
+                       stream->trace->path->str, stream->file_name->str);
+               goto end;
+       }
+
+       if (stream->discarded_packets_state.in_range) {
+               BT_LOGE("Unsupported contiguous discarded packets message: "
+                       "stream-id=%" PRIu64 ", stream-name=\"%s\", "
+                       "trace-name=\"%s\", path=\"%s/%s\"",
+                       bt_stream_get_id(ir_stream),
+                       bt_stream_get_name(ir_stream),
+                       bt_trace_get_name(
+                               bt_stream_borrow_trace_const(ir_stream)),
+                       stream->trace->path->str, stream->file_name->str);
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       /*
+        * Discarded packets messages are guaranteed to occur between
+        * packets.
+        */
+       BT_ASSERT(!stream->packet_state.is_open);
+
+       if (stream->sc->discarded_packets_has_ts) {
+               /*
+                * Make the stream's state be in the time range of a
+                * discarded packets message since we have the message's
+                * time range (`stream->sc->discarded_packets_has_ts`).
+                */
+               stream->discarded_packets_state.in_range = true;
+
+               /*
+                * The clock snapshot values will be validated when
+                * handling the next packet beginning message (next call
+                * to handle_packet_beginning_msg()).
+                */
+               cs = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+                       msg);
+               BT_ASSERT(cs);
+               stream->discarded_packets_state.beginning_cs =
+                       bt_clock_snapshot_get_value(cs);
+               cs = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
+                       msg);
+               BT_ASSERT(cs);
+               stream->discarded_packets_state.end_cs =
+                       bt_clock_snapshot_get_value(cs);
+       }
+
+       avail = bt_message_discarded_packets_get_count(msg, &count);
+       if (avail != BT_PROPERTY_AVAILABILITY_AVAILABLE) {
+               /*
+                * There's no specific count of discarded packets: set
+                * it to 1 so that we know that we at least discarded
+                * something.
+                */
+               count = 1;
+       }
+
+       stream->packet_state.seq_num += count;
+
+end:
+       return status;
+}
+
+static inline
+void put_messages(bt_message_array_const msgs, uint64_t count)
+{
+       uint64_t i;
+
+       for (i = 0; i < count; i++) {
+               BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
+       }
+}
+
+BT_HIDDEN
+bt_self_component_status ctf_fs_sink_consume(bt_self_component_sink *self_comp)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct fs_sink_comp *fs_sink;
+       bt_message_iterator_status it_status;
+       uint64_t msg_count = 0;
+       bt_message_array_const msgs;
+
+       fs_sink = bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(self_comp));
+       BT_ASSERT(fs_sink);
+       BT_ASSERT(fs_sink->upstream_iter);
+
+       /* Consume messages */
+       it_status = bt_self_component_port_input_message_iterator_next(
+               fs_sink->upstream_iter, &msgs, &msg_count);
+       if (it_status < 0) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       switch (it_status) {
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+       {
+               uint64_t i;
+
+               for (i = 0; i < msg_count; i++) {
+                       const bt_message *msg = msgs[i];
+
+                       BT_ASSERT(msg);
+
+                       switch (bt_message_get_type(msg)) {
+                       case BT_MESSAGE_TYPE_EVENT:
+                               status = handle_event_msg(fs_sink, msg);
+                               break;
+                       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+                               status = handle_packet_beginning_msg(
+                                       fs_sink, msg);
+                               break;
+                       case BT_MESSAGE_TYPE_PACKET_END:
+                               status = handle_packet_end_msg(
+                                       fs_sink, msg);
+                               break;
+                       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+                               /* Ignore */
+                               BT_LOGD_STR("Ignoring message iterator inactivity message.");
+                               break;
+                       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
+                               status = handle_stream_beginning_msg(
+                                       fs_sink, msg);
+                               break;
+                       case BT_MESSAGE_TYPE_STREAM_END:
+                               status = handle_stream_end_msg(
+                                       fs_sink, msg);
+                               break;
+                       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+                       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+                               /* Not supported by CTF 1.8 */
+                               BT_LOGD_STR("Ignoring stream activity message.");
+                               break;
+                       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+                               status = handle_discarded_events_msg(
+                                       fs_sink, msg);
+                               break;
+                       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+                               status = handle_discarded_packets_msg(
+                                       fs_sink, msg);
+                               break;
+                       default:
+                               abort();
+                       }
+
+                       BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
+
+                       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+                               BT_LOGE("Failed to handle message: "
+                                       "generated CTF traces could be incomplete: "
+                                       "output-dir-path=\"%s\"",
+                                       fs_sink->output_dir_path->str);
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               status = BT_SELF_COMPONENT_STATUS_AGAIN;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_END:
+               /* TODO: Finalize all traces (should already be done?) */
+               status = BT_SELF_COMPONENT_STATUS_END;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_ERROR:
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               break;
+       default:
+               break;
+       }
+
+       goto end;
+
+error:
+       BT_ASSERT(status != BT_SELF_COMPONENT_STATUS_OK);
+       put_messages(msgs, msg_count);
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+bt_self_component_status ctf_fs_sink_graph_is_configured(
+               bt_self_component_sink *self_comp)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct fs_sink_comp *fs_sink = bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(self_comp));
+
+       fs_sink->upstream_iter =
+               bt_self_component_port_input_message_iterator_create(
+                       bt_self_component_sink_borrow_input_port_by_name(
+                               self_comp, in_port_name));
+       if (!fs_sink->upstream_iter) {
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+void ctf_fs_sink_finalize(bt_self_component_sink *self_comp)
+{
+       struct fs_sink_comp *fs_sink = bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(self_comp));
+
+       destroy_fs_sink_comp(fs_sink);
+}
diff --git a/src/plugins/ctf/fs-sink/fs-sink.h b/src/plugins/ctf/fs-sink/fs-sink.h
new file mode 100644 (file)
index 0000000..7a740bc
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_H
+#define BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_H
+
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+#include <stdbool.h>
+#include <glib.h>
+
+struct fs_sink_comp {
+       bt_self_component_sink *self_comp;
+
+       /* Owned by this */
+       bt_self_component_port_input_message_iterator *upstream_iter;
+
+       /* Base output directory path */
+       GString *output_dir_path;
+
+       /*
+        * True if the component assumes that it will only write a
+        * single CTF trace (which can contain one or more data
+        * streams). This makes the component write the stream files
+        * directly in the output directory (`output_dir_path` above).
+        */
+       bool assume_single_trace;
+
+       /* True to completely ignore discarded events messages */
+       bool ignore_discarded_events;
+
+       /* True to completely ignore discarded packets messages */
+       bool ignore_discarded_packets;
+
+       /*
+        * True to make the component quiet (nothing printed to the
+        * standard output).
+        */
+       bool quiet;
+
+       /*
+        * Hash table of `const bt_trace *` (weak) to
+        * `struct fs_sink_trace *` (owned by hash table).
+        */
+       GHashTable *traces;
+};
+
+BT_HIDDEN
+bt_self_component_status ctf_fs_sink_init(
+               bt_self_component_sink *component,
+               const bt_value *params,
+               void *init_method_data);
+
+BT_HIDDEN
+bt_self_component_status ctf_fs_sink_consume(
+               bt_self_component_sink *component);
+
+BT_HIDDEN
+bt_self_component_status ctf_fs_sink_graph_is_configured(
+               bt_self_component_sink *component);
+
+BT_HIDDEN
+void ctf_fs_sink_finalize(bt_self_component_sink *component);
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_FS_SINK_H */
diff --git a/src/plugins/ctf/fs-sink/logging.c b/src/plugins/ctf/fs-sink/logging.c
new file mode 100644 (file)
index 0000000..0469b7a
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_fs_sink_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_plugin_fs_sink_log_level,
+       "BABELTRACE_SINK_CTF_FS_LOG_LEVEL");
diff --git a/src/plugins/ctf/fs-sink/logging.h b/src/plugins/ctf/fs-sink/logging.h
new file mode 100644 (file)
index 0000000..a6c9dd4
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef PLUGINS_FS_SINK_LOGGING_H
+#define PLUGINS_FS_SINK_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_fs_sink_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_fs_sink_log_level);
+
+#endif /* PLUGINS_FS_SINK_LOGGING_H */
diff --git a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.c
new file mode 100644 (file)
index 0000000..3b6d2bc
--- /dev/null
@@ -0,0 +1,907 @@
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRANSLATE-CTF-IR-TO-TSDL"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <glib.h>
+#include "common/assert.h"
+#include "compat/endian.h"
+
+#include "fs-sink-ctf-meta.h"
+
+struct ctx {
+       unsigned int indent_level;
+       GString *tsdl;
+};
+
+static inline
+void append_indent(struct ctx *ctx)
+{
+       unsigned int i;
+
+       for (i = 0; i < ctx->indent_level; i++) {
+               g_string_append_c(ctx->tsdl, '\t');
+       }
+}
+
+static
+void append_uuid(struct ctx *ctx, bt_uuid uuid)
+{
+       g_string_append_printf(ctx->tsdl,
+               "\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+               (unsigned int) uuid[0],
+               (unsigned int) uuid[1],
+               (unsigned int) uuid[2],
+               (unsigned int) uuid[3],
+               (unsigned int) uuid[4],
+               (unsigned int) uuid[5],
+               (unsigned int) uuid[6],
+               (unsigned int) uuid[7],
+               (unsigned int) uuid[8],
+               (unsigned int) uuid[9],
+               (unsigned int) uuid[10],
+               (unsigned int) uuid[11],
+               (unsigned int) uuid[12],
+               (unsigned int) uuid[13],
+               (unsigned int) uuid[14],
+               (unsigned int) uuid[15]);
+}
+
+static
+void append_quoted_string_content(struct ctx *ctx, const char *str)
+{
+       const char *ch;
+
+       for (ch = str; *ch != '\0'; ch++) {
+               unsigned char uch = (unsigned char) *ch;
+
+               if (uch < 32 || uch >= 127) {
+                       switch (*ch) {
+                       case '\a':
+                               g_string_append(ctx->tsdl, "\\a");
+                               break;
+                       case '\b':
+                               g_string_append(ctx->tsdl, "\\b");
+                               break;
+                       case '\f':
+                               g_string_append(ctx->tsdl, "\\f");
+                               break;
+                       case '\n':
+                               g_string_append(ctx->tsdl, "\\n");
+                               break;
+                       case '\r':
+                               g_string_append(ctx->tsdl, "\\r");
+                               break;
+                       case '\t':
+                               g_string_append(ctx->tsdl, "\\t");
+                               break;
+                       case '\v':
+                               g_string_append(ctx->tsdl, "\\v");
+                               break;
+                       default:
+                               g_string_append_printf(ctx->tsdl, "\\x%02x",
+                                       (unsigned int) uch);
+                               break;
+                       }
+               } else if (*ch == '"' || *ch == '\\') {
+                       g_string_append_c(ctx->tsdl, '\\');
+                       g_string_append_c(ctx->tsdl, *ch);
+               } else {
+                       g_string_append_c(ctx->tsdl, *ch);
+               }
+       }
+}
+
+static
+void append_quoted_string(struct ctx *ctx, const char *str)
+{
+       g_string_append_c(ctx->tsdl, '"');
+       append_quoted_string_content(ctx, str);
+       g_string_append_c(ctx->tsdl, '"');
+}
+
+static
+void append_integer_field_class_from_props(struct ctx *ctx, unsigned int size,
+               unsigned int alignment, bool is_signed,
+               bt_field_class_integer_preferred_display_base disp_base,
+               const char *mapped_clock_class_name, const char *field_name,
+               bool end)
+{
+       g_string_append_printf(ctx->tsdl,
+               "integer { size = %u; align = %u;",
+               size, alignment);
+
+       if (is_signed) {
+               g_string_append(ctx->tsdl, " signed = true;");
+       }
+
+       if (disp_base != BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL) {
+               g_string_append(ctx->tsdl, " base = ");
+
+               switch (disp_base) {
+               case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
+                       g_string_append(ctx->tsdl, "b");
+                       break;
+               case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
+                       g_string_append(ctx->tsdl, "o");
+                       break;
+               case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
+                       g_string_append(ctx->tsdl, "x");
+                       break;
+               default:
+                       abort();
+               }
+
+               g_string_append_c(ctx->tsdl, ';');
+       }
+
+       if (mapped_clock_class_name) {
+               g_string_append_printf(ctx->tsdl, " map = clock.%s.value;",
+                       mapped_clock_class_name);
+       }
+
+       g_string_append(ctx->tsdl, " }");
+
+       if (field_name) {
+               g_string_append_printf(ctx->tsdl, " %s", field_name);
+       }
+
+       if (end) {
+               g_string_append(ctx->tsdl, ";\n");
+       }
+}
+
+static
+void append_end_block(struct ctx *ctx)
+{
+       ctx->indent_level--;
+       append_indent(ctx);
+       g_string_append(ctx->tsdl, "}");
+}
+
+static
+void append_end_block_semi_nl(struct ctx *ctx)
+{
+       ctx->indent_level--;
+       append_indent(ctx);
+       g_string_append(ctx->tsdl, "};\n");
+}
+
+static
+void append_end_block_semi_nl_nl(struct ctx *ctx)
+{
+       append_end_block_semi_nl(ctx);
+       g_string_append_c(ctx->tsdl, '\n');
+}
+
+static
+void append_integer_field_class(struct ctx *ctx,
+               struct fs_sink_ctf_field_class_int *fc)
+{
+       const bt_field_class *ir_fc = fc->base.base.ir_fc;
+       bt_field_class_type type = bt_field_class_get_type(ir_fc);
+       bool is_signed = type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION ||
+               type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER;
+
+       if (type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION ||
+                       type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
+               g_string_append(ctx->tsdl, "enum : ");
+       }
+
+       append_integer_field_class_from_props(ctx, fc->base.size,
+               fc->base.base.alignment, is_signed,
+               bt_field_class_integer_get_preferred_display_base(ir_fc),
+               NULL, NULL, false);
+
+       if (type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION ||
+                       type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
+               uint64_t i;
+
+               g_string_append(ctx->tsdl, " {\n");
+               ctx->indent_level++;
+
+               for (i = 0; i < bt_field_class_enumeration_get_mapping_count(ir_fc); i++) {
+                       const char *label;
+                       const bt_field_class_enumeration_mapping *mapping;
+                       const bt_field_class_unsigned_enumeration_mapping *u_mapping;
+                       const bt_field_class_signed_enumeration_mapping *i_mapping;
+                       uint64_t range_count;
+                       uint64_t range_i;
+
+                       if (is_signed) {
+                               i_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
+                                       ir_fc, i);
+                               mapping = bt_field_class_signed_enumeration_mapping_as_mapping_const(
+                                       i_mapping);
+                       } else {
+                               u_mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
+                                       ir_fc, i);
+                               mapping = bt_field_class_unsigned_enumeration_mapping_as_mapping_const(
+                                       u_mapping);
+                       }
+
+                       label = bt_field_class_enumeration_mapping_get_label(
+                               mapping);
+                       range_count =
+                               bt_field_class_enumeration_mapping_get_range_count(
+                                       mapping);
+
+                       for (range_i = 0; range_i < range_count; range_i++) {
+                               append_indent(ctx);
+
+                               /*
+                                * Systematically prepend `_` to the
+                                * mapping's label as this could be used
+                                * as the tag of a subsequent variant
+                                * field class and variant FC option
+                                * names are systematically protected
+                                * with a leading `_`.
+                                *
+                                * FIXME: This is temporary as the
+                                * library's API should change to
+                                * decouple variant FC option names from
+                                * selector FC labels. The current
+                                * drawback is that an original label
+                                * `HELLO` becomes `_HELLO` in the
+                                * generated metadata, therefore tools
+                                * expecting `HELLO` could fail.
+                                */
+                               g_string_append(ctx->tsdl, "\"_");
+                               append_quoted_string_content(ctx, label);
+                               g_string_append(ctx->tsdl, "\" = ");
+
+                               if (is_signed) {
+                                       int64_t lower, upper;
+
+                                       bt_field_class_signed_enumeration_mapping_get_range_by_index(
+                                               i_mapping, range_i,
+                                               &lower, &upper);
+
+                                       if (lower == upper) {
+                                               g_string_append_printf(
+                                                       ctx->tsdl, "%" PRId64,
+                                                       lower);
+                                       } else {
+                                               g_string_append_printf(
+                                                       ctx->tsdl, "%" PRId64 " ... %" PRId64,
+                                                       lower, upper);
+                                       }
+                               } else {
+                                       uint64_t lower, upper;
+
+                                       bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
+                                               u_mapping, range_i,
+                                               &lower, &upper);
+
+                                       if (lower == upper) {
+                                               g_string_append_printf(
+                                                       ctx->tsdl, "%" PRIu64,
+                                                       lower);
+                                       } else {
+                                               g_string_append_printf(
+                                                       ctx->tsdl, "%" PRIu64 " ... %" PRIu64,
+                                                       lower, upper);
+                                       }
+                               }
+
+                               g_string_append(ctx->tsdl, ",\n");
+                       }
+               }
+
+               append_end_block(ctx);
+       }
+}
+
+static
+void append_float_field_class(struct ctx *ctx,
+               struct fs_sink_ctf_field_class_float *fc)
+{
+       unsigned int mant_dig, exp_dig;
+
+       if (bt_field_class_real_is_single_precision(fc->base.base.ir_fc)) {
+               mant_dig = 24;
+               exp_dig = 8;
+       } else {
+               mant_dig = 53;
+               exp_dig = 11;
+       }
+
+       g_string_append_printf(ctx->tsdl,
+               "floating_point { mant_dig = %u; exp_dig = %u; align = %u; }",
+               mant_dig, exp_dig, fc->base.base.alignment);
+}
+
+static
+void append_string_field_class(struct ctx *ctx,
+               struct fs_sink_ctf_field_class_float *fc)
+{
+       g_string_append(ctx->tsdl, "string { encoding = UTF8; }");
+}
+
+static
+void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc);
+
+static
+void append_member(struct ctx *ctx, const char *name,
+               struct fs_sink_ctf_field_class *fc)
+{
+       GString *lengths = NULL;
+       const char *lengths_str = "";
+
+       while (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY ||
+                       fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
+               if (!lengths) {
+                       lengths = g_string_new(NULL);
+                       BT_ASSERT(lengths);
+               }
+
+               if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY) {
+                       struct fs_sink_ctf_field_class_array *array_fc =
+                               (void *) fc;
+
+                       g_string_append_printf(lengths, "[%" PRIu64 "]",
+                               array_fc->length);
+                       fc = array_fc->base.elem_fc;
+               } else {
+                       struct fs_sink_ctf_field_class_sequence *seq_fc =
+                               (void *) fc;
+
+                       g_string_append_printf(lengths, "[%s]",
+                               seq_fc->length_ref->str);
+                       fc = seq_fc->base.elem_fc;
+               }
+       }
+
+       append_field_class(ctx, fc);
+
+       if (lengths) {
+               lengths_str = lengths->str;
+       }
+
+       g_string_append_printf(ctx->tsdl, " %s%s;\n", name, lengths_str);
+
+       if (lengths) {
+               g_string_free(lengths, TRUE);
+       }
+}
+
+static
+void append_struct_field_class_members(struct ctx *ctx,
+               struct fs_sink_ctf_field_class_struct *struct_fc)
+{
+       uint64_t i;
+
+       for (i = 0; i < struct_fc->members->len; i++) {
+               struct fs_sink_ctf_named_field_class *named_fc =
+                       fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                               struct_fc, i);
+               struct fs_sink_ctf_field_class *fc = named_fc->fc;
+
+               if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
+                       struct fs_sink_ctf_field_class_sequence *seq_fc =
+                               (void *) fc;
+
+                       if (seq_fc->length_is_before) {
+                               append_indent(ctx);
+                               append_integer_field_class_from_props(ctx,
+                                       32, 8, false,
+                                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+                                       NULL, seq_fc->length_ref->str, true);
+                       }
+               } else if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT) {
+                       struct fs_sink_ctf_field_class_variant *var_fc =
+                               (void *) fc;
+
+                       if (var_fc->tag_is_before) {
+                               append_indent(ctx);
+                               g_string_append(ctx->tsdl, "enum : ");
+                               append_integer_field_class_from_props(ctx,
+                                       16, 8, false,
+                                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+                                       NULL, NULL, false);
+                               g_string_append(ctx->tsdl, " {\n");
+                               ctx->indent_level++;
+
+                               for (i = 0; i < var_fc->options->len; i++) {
+                                       struct fs_sink_ctf_named_field_class *named_fc =
+                                               fs_sink_ctf_field_class_variant_borrow_option_by_index(
+                                                       var_fc, i);
+
+                                       append_indent(ctx);
+                                       g_string_append_printf(ctx->tsdl,
+                                               "\"%s\" = %" PRIu64 ",\n",
+                                               named_fc->name->str, i);
+                               }
+
+                               append_end_block(ctx);
+                               g_string_append_printf(ctx->tsdl, " %s;\n",
+                                       var_fc->tag_ref->str);
+                       }
+               }
+
+               append_indent(ctx);
+               append_member(ctx, named_fc->name->str, fc);
+       }
+}
+
+static
+void append_struct_field_class(struct ctx *ctx,
+               struct fs_sink_ctf_field_class_struct *fc)
+{
+       g_string_append(ctx->tsdl, "struct {\n");
+       ctx->indent_level++;
+       append_struct_field_class_members(ctx, fc);
+       append_end_block(ctx);
+       g_string_append_printf(ctx->tsdl, " align(%u)",
+               fc->base.alignment);
+}
+
+static
+void append_variant_field_class(struct ctx *ctx,
+               struct fs_sink_ctf_field_class_variant *var_fc)
+{
+       uint64_t i;
+
+       g_string_append_printf(ctx->tsdl, "variant <%s> {\n",
+               var_fc->tag_ref->str);
+       ctx->indent_level++;
+
+       for (i = 0; i < var_fc->options->len; i++) {
+               struct fs_sink_ctf_named_field_class *named_fc =
+                       fs_sink_ctf_field_class_variant_borrow_option_by_index(
+                               var_fc, i);
+
+               append_indent(ctx);
+               append_member(ctx, named_fc->name->str, named_fc->fc);
+       }
+
+       append_end_block(ctx);
+}
+
+static
+void append_field_class(struct ctx *ctx, struct fs_sink_ctf_field_class *fc)
+{
+       switch (fc->type) {
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_INT:
+               append_integer_field_class(ctx, (void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_FLOAT:
+               append_float_field_class(ctx, (void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRING:
+               append_string_field_class(ctx, (void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+               append_struct_field_class(ctx, (void *) fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+               append_variant_field_class(ctx, (void *) fc);
+               break;
+       default:
+               abort();
+       }
+}
+
+static
+void append_event_class(struct ctx *ctx, struct fs_sink_ctf_event_class *ec)
+{
+       const char *str;
+       bt_event_class_log_level log_level;
+
+       /* Event class */
+       append_indent(ctx);
+       g_string_append(ctx->tsdl, "event {\n");
+       ctx->indent_level++;
+
+       /* Event class properties */
+       append_indent(ctx);
+       g_string_append(ctx->tsdl, "name = ");
+       str = bt_event_class_get_name(ec->ir_ec);
+       if (!str) {
+               str = "unknown";
+       }
+
+       append_quoted_string(ctx, str);
+       g_string_append(ctx->tsdl, ";\n");
+       append_indent(ctx);
+       g_string_append_printf(ctx->tsdl, "stream_id = %" PRIu64 ";\n",
+               bt_stream_class_get_id(ec->sc->ir_sc));
+       append_indent(ctx);
+       g_string_append_printf(ctx->tsdl, "id = %" PRIu64 ";\n",
+               bt_event_class_get_id(ec->ir_ec));
+
+       str = bt_event_class_get_emf_uri(ec->ir_ec);
+       if (str) {
+               append_indent(ctx);
+               g_string_append(ctx->tsdl, "model.emf.uri = ");
+               append_quoted_string(ctx, str);
+               g_string_append(ctx->tsdl, ";\n");
+       }
+
+       if (bt_event_class_get_log_level(ec->ir_ec, &log_level) ==
+                       BT_PROPERTY_AVAILABILITY_AVAILABLE) {
+               unsigned int level;
+
+               append_indent(ctx);
+               g_string_append(ctx->tsdl, "loglevel = ");
+
+               switch (log_level) {
+               case BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY:
+                       level = 0;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_ALERT:
+                       level = 1;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_CRITICAL:
+                       level = 2;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_ERROR:
+                       level = 3;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_WARNING:
+                       level = 4;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_NOTICE:
+                       level = 5;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_INFO:
+                       level = 6;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM:
+                       level = 7;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM:
+                       level = 8;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS:
+                       level = 9;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE:
+                       level = 10;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT:
+                       level = 11;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION:
+                       level = 12;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE:
+                       level = 13;
+                       break;
+               case BT_EVENT_CLASS_LOG_LEVEL_DEBUG:
+                       level = 14;
+                       break;
+               default:
+                       abort();
+               }
+
+               g_string_append_printf(ctx->tsdl, "%u;\n", level);
+       }
+
+       /* Event specific context field class */
+       if (ec->spec_context_fc) {
+               append_indent(ctx);
+               g_string_append(ctx->tsdl, "context := ");
+               append_field_class(ctx, ec->spec_context_fc);
+               g_string_append(ctx->tsdl, ";\n");
+       }
+
+       /* Event payload field class */
+       if (ec->payload_fc) {
+               append_indent(ctx);
+               g_string_append(ctx->tsdl, "fields := ");
+               append_field_class(ctx, ec->payload_fc);
+               g_string_append(ctx->tsdl, ";\n");
+       }
+
+       append_end_block_semi_nl_nl(ctx);
+}
+
+static
+void append_stream_class(struct ctx *ctx,
+               struct fs_sink_ctf_stream_class *sc)
+{
+       uint64_t i;
+
+       /* Default clock class */
+       if (sc->default_clock_class) {
+               const char *descr;
+               int64_t offset_seconds;
+               uint64_t offset_cycles;
+               bt_uuid uuid;
+
+               append_indent(ctx);
+               g_string_append(ctx->tsdl, "clock {\n");
+               ctx->indent_level++;
+               BT_ASSERT(sc->default_clock_class_name->len > 0);
+               append_indent(ctx);
+               g_string_append_printf(ctx->tsdl, "name = %s;\n",
+                       sc->default_clock_class_name->str);
+               descr = bt_clock_class_get_description(sc->default_clock_class);
+               if (descr) {
+                       append_indent(ctx);
+                       g_string_append(ctx->tsdl, "description = ");
+                       append_quoted_string(ctx, descr);
+                       g_string_append(ctx->tsdl, ";\n");
+               }
+
+               append_indent(ctx);
+               g_string_append_printf(ctx->tsdl, "freq = %" PRIu64 ";\n",
+                       bt_clock_class_get_frequency(sc->default_clock_class));
+               append_indent(ctx);
+               g_string_append_printf(ctx->tsdl, "precision = %" PRIu64 ";\n",
+                       bt_clock_class_get_precision(sc->default_clock_class));
+               bt_clock_class_get_offset(sc->default_clock_class,
+                       &offset_seconds, &offset_cycles);
+               append_indent(ctx);
+               g_string_append_printf(ctx->tsdl, "offset_s = %" PRId64 ";\n",
+                       offset_seconds);
+               append_indent(ctx);
+               g_string_append_printf(ctx->tsdl, "offset = %" PRIu64 ";\n",
+                       offset_cycles);
+               append_indent(ctx);
+               g_string_append(ctx->tsdl, "absolute = ");
+
+               if (bt_clock_class_origin_is_unix_epoch(
+                               sc->default_clock_class)) {
+                       g_string_append(ctx->tsdl, "true");
+               } else {
+                       g_string_append(ctx->tsdl, "false");
+               }
+
+               g_string_append(ctx->tsdl, ";\n");
+               uuid = bt_clock_class_get_uuid(sc->default_clock_class);
+               if (uuid) {
+                       append_indent(ctx);
+                       g_string_append(ctx->tsdl, "uuid = ");
+                       append_uuid(ctx, uuid);
+                       g_string_append(ctx->tsdl, ";\n");
+               }
+
+               /* End clock class */
+               append_end_block_semi_nl_nl(ctx);
+       }
+
+       /* Stream class */
+       append_indent(ctx);
+       g_string_append(ctx->tsdl, "stream {\n");
+       ctx->indent_level++;
+
+       /* Stream class properties */
+       append_indent(ctx);
+       g_string_append_printf(ctx->tsdl, "id = %" PRIu64 ";\n",
+               bt_stream_class_get_id(sc->ir_sc));
+
+       /* Packet context field class */
+       append_indent(ctx);
+       g_string_append(ctx->tsdl, "packet.context := struct {\n");
+       ctx->indent_level++;
+       append_indent(ctx);
+       append_integer_field_class_from_props(ctx, 64, 8, false,
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+               NULL, "packet_size", true);
+       append_indent(ctx);
+       append_integer_field_class_from_props(ctx, 64, 8, false,
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+               NULL, "content_size", true);
+
+       if (sc->packets_have_ts_begin) {
+               append_indent(ctx);
+               append_integer_field_class_from_props(ctx, 64, 8, false,
+                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+                       sc->default_clock_class_name->str,
+                       "timestamp_begin", true);
+       }
+
+       if (sc->packets_have_ts_end) {
+               append_indent(ctx);
+               append_integer_field_class_from_props(ctx, 64, 8, false,
+                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+                       sc->default_clock_class_name->str,
+                       "timestamp_end", true);
+       }
+
+       if (sc->has_discarded_events) {
+               append_indent(ctx);
+               append_integer_field_class_from_props(ctx, 64, 8, false,
+                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+                       NULL, "events_discarded", true);
+       }
+
+       /*
+        * Unconditionnally write the packet sequence number as, even if
+        * there's no possible discarded packets message, it's still
+        * useful information to have.
+        */
+       append_indent(ctx);
+       append_integer_field_class_from_props(ctx, 64, 8, false,
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+               NULL, "packet_seq_num", true);
+
+       if (sc->packet_context_fc) {
+               append_struct_field_class_members(ctx,
+                       (void *) sc->packet_context_fc);
+               fs_sink_ctf_field_class_struct_align_at_least(
+                       (void *) sc->packet_context_fc, 8);
+       }
+
+       /* End packet context field class */
+       append_end_block(ctx);
+       g_string_append_printf(ctx->tsdl, " align(%u);\n\n",
+               sc->packet_context_fc ? sc->packet_context_fc->alignment : 8);
+
+       /* Event header field class */
+       append_indent(ctx);
+       g_string_append(ctx->tsdl, "event.header := struct {\n");
+       ctx->indent_level++;
+       append_indent(ctx);
+       append_integer_field_class_from_props(ctx, 64, 8, false,
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+               NULL, "id", true);
+
+       if (sc->default_clock_class) {
+               append_indent(ctx);
+               append_integer_field_class_from_props(ctx, 64, 8, false,
+                       BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+                       sc->default_clock_class_name->str,
+                       "timestamp", true);
+       }
+
+       /* End event header field class */
+       append_end_block(ctx);
+       g_string_append(ctx->tsdl, " align(8);\n");
+
+       /* Event common context field class */
+       if (sc->event_common_context_fc) {
+               append_indent(ctx);
+               g_string_append(ctx->tsdl, "event.context := ");
+               append_field_class(ctx,
+                       (void *) sc->event_common_context_fc);
+               g_string_append(ctx->tsdl, ";\n");
+       }
+
+       /* End stream class */
+       append_end_block_semi_nl_nl(ctx);
+
+       /* Event classes */
+       for (i = 0; i < sc->event_classes->len; i++) {
+               append_event_class(ctx, sc->event_classes->pdata[i]);
+       }
+}
+
+BT_HIDDEN
+void translate_trace_class_ctf_ir_to_tsdl(struct fs_sink_ctf_trace_class *tc,
+               GString *tsdl)
+{
+       struct ctx ctx = {
+               .indent_level = 0,
+               .tsdl = tsdl,
+       };
+       uint64_t i;
+       uint64_t count;
+
+       g_string_assign(tsdl, "/* CTF 1.8 */\n\n");
+       g_string_append(tsdl, "/* This was generated by a Babeltrace `sink.ctf.fs` component. */\n\n");
+
+       /* Trace class */
+       append_indent(&ctx);
+       g_string_append(tsdl, "trace {\n");
+       ctx.indent_level++;
+
+       /* Trace class properties */
+       append_indent(&ctx);
+       g_string_append(tsdl, "major = 1;\n");
+       append_indent(&ctx);
+       g_string_append(tsdl, "minor = 8;\n");
+       append_indent(&ctx);
+       g_string_append(tsdl, "uuid = ");
+       append_uuid(&ctx, tc->uuid);
+       g_string_append(tsdl, ";\n");
+       append_indent(&ctx);
+       g_string_append(tsdl, "byte_order = ");
+
+       if (BYTE_ORDER == LITTLE_ENDIAN) {
+               g_string_append(tsdl, "le");
+       } else {
+               g_string_append(tsdl, "be");
+       }
+
+       g_string_append(tsdl, ";\n");
+
+       /* Packet header field class */
+       append_indent(&ctx);
+       g_string_append(tsdl, "packet.header := struct {\n");
+       ctx.indent_level++;
+       append_indent(&ctx);
+       append_integer_field_class_from_props(&ctx, 32, 8, false,
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL,
+               NULL, "magic", true);
+       append_indent(&ctx);
+       append_integer_field_class_from_props(&ctx, 8, 8, false,
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+               NULL, "uuid[16]", true);
+       append_indent(&ctx);
+       append_integer_field_class_from_props(&ctx, 64, 8, false,
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+               NULL, "stream_id", true);
+       append_indent(&ctx);
+       append_integer_field_class_from_props(&ctx, 64, 8, false,
+               BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL,
+               NULL, "stream_instance_id", true);
+
+       /* End packet header field class */
+       append_end_block(&ctx);
+       g_string_append(ctx.tsdl, " align(8);\n");
+
+       /* End trace class */
+       append_end_block_semi_nl_nl(&ctx);
+
+       /* Trace class environment */
+       count = bt_trace_class_get_environment_entry_count(tc->ir_tc);
+       if (count > 0) {
+               append_indent(&ctx);
+               g_string_append(tsdl, "env {\n");
+               ctx.indent_level++;
+
+               for (i = 0; i < count; i++) {
+                       const char *name;
+                       const bt_value *val;
+
+                       bt_trace_class_borrow_environment_entry_by_index_const(
+                               tc->ir_tc, i, &name, &val);
+                       append_indent(&ctx);
+                       g_string_append_printf(tsdl, "%s = ", name);
+
+                       switch (bt_value_get_type(val)) {
+                       case BT_VALUE_TYPE_SIGNED_INTEGER:
+                               g_string_append_printf(tsdl, "%" PRId64,
+                                       bt_value_signed_integer_get(val));
+                               break;
+                       case BT_VALUE_TYPE_STRING:
+                               append_quoted_string(&ctx, bt_value_string_get(val));
+                               break;
+                       default:
+                               /*
+                                * This is checked in
+                                * translate_trace_class_trace_ir_to_ctf_ir().
+                                */
+                               abort();
+                       }
+
+                       g_string_append(tsdl, ";\n");
+               }
+
+               /* End trace class environment */
+               append_end_block_semi_nl_nl(&ctx);
+       }
+
+       /* Stream classes and their event classes */
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               append_stream_class(&ctx, tc->stream_classes->pdata[i]);
+       }
+}
diff --git a/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.h b/src/plugins/ctf/fs-sink/translate-ctf-ir-to-tsdl.h
new file mode 100644 (file)
index 0000000..4ed0262
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_CTF_IR_TO_TSDL_H
+#define BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_CTF_IR_TO_TSDL_H
+
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+
+#include "fs-sink-ctf-meta.h"
+
+BT_HIDDEN
+void translate_trace_class_ctf_ir_to_tsdl(struct fs_sink_ctf_trace_class *tc,
+               GString *tsdl);
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_CTF_IR_TO_TSDL_H */
diff --git a/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c b/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.c
new file mode 100644 (file)
index 0000000..64f4d5e
--- /dev/null
@@ -0,0 +1,1290 @@
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-SINK-TRANSLATE-TRACE-IR-TO-CTF-IR"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/common.h"
+#include "common/assert.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <glib.h>
+
+#include "fs-sink-ctf-meta.h"
+
+struct field_path_elem {
+       uint64_t index_in_parent;
+       GString *name;
+
+       /* Weak */
+       const bt_field_class *ir_fc;
+
+       /* Weak */
+       struct fs_sink_ctf_field_class *parent_fc;
+};
+
+struct ctx {
+       /* Weak */
+       struct fs_sink_ctf_stream_class *cur_sc;
+
+       /* Weak */
+       struct fs_sink_ctf_event_class *cur_ec;
+
+       bt_scope cur_scope;
+
+       /*
+        * Array of `struct field_path_elem` */
+       GArray *cur_path;
+};
+
+static inline
+struct field_path_elem *cur_path_stack_at(struct ctx *ctx, uint64_t i)
+{
+       BT_ASSERT(i < ctx->cur_path->len);
+       return &g_array_index(ctx->cur_path, struct field_path_elem, i);
+}
+
+static inline
+struct field_path_elem *cur_path_stack_top(struct ctx *ctx)
+{
+       BT_ASSERT(ctx->cur_path->len > 0);
+       return cur_path_stack_at(ctx, ctx->cur_path->len - 1);
+}
+
+static inline
+bool is_reserved_member_name(const char *name, const char *reserved_name)
+{
+       bool is_reserved = false;
+
+       if (strcmp(name, reserved_name) == 0) {
+               is_reserved = true;
+               goto end;
+       }
+
+       if (name[0] == '_' && strcmp(&name[1], reserved_name) == 0) {
+               is_reserved = true;
+               goto end;
+       }
+
+end:
+       return is_reserved;
+}
+
+static inline
+int cur_path_stack_push(struct ctx *ctx,
+               uint64_t index_in_parent, const char *ir_name,
+               const bt_field_class *ir_fc,
+               struct fs_sink_ctf_field_class *parent_fc)
+{
+       int ret = 0;
+       struct field_path_elem *field_path_elem;
+
+       g_array_set_size(ctx->cur_path, ctx->cur_path->len + 1);
+       field_path_elem = cur_path_stack_top(ctx);
+       field_path_elem->index_in_parent = index_in_parent;
+       field_path_elem->name = g_string_new(ir_name);
+
+       if (ir_name) {
+               if (ctx->cur_scope == BT_SCOPE_PACKET_CONTEXT) {
+                       if (is_reserved_member_name(ir_name, "packet_size") ||
+                                       is_reserved_member_name(ir_name, "content_size") ||
+                                       is_reserved_member_name(ir_name, "timestamp_begin") ||
+                                       is_reserved_member_name(ir_name, "timestamp_end") ||
+                                       is_reserved_member_name(ir_name, "events_discarded") ||
+                                       is_reserved_member_name(ir_name, "packet_seq_num")) {
+                               BT_LOGE("Unsupported reserved TSDL structure field class member "
+                                       "or variant field class option name: name=\"%s\"",
+                                       ir_name);
+                               ret = -1;
+                               goto end;
+                       }
+               }
+
+               ret = fs_sink_ctf_protect_name(field_path_elem->name);
+               if (ret) {
+                       BT_LOGE("Unsupported non-TSDL structure field class member "
+                               "or variant field class option name: name=\"%s\"",
+                               ir_name);
+                       goto end;
+               }
+       }
+
+       field_path_elem->ir_fc = ir_fc;
+       field_path_elem->parent_fc = parent_fc;
+
+end:
+       return ret;
+}
+
+static inline
+void cur_path_stack_pop(struct ctx *ctx)
+{
+       struct field_path_elem *field_path_elem;
+
+       BT_ASSERT(ctx->cur_path->len > 0);
+       field_path_elem = cur_path_stack_top(ctx);
+
+       if (field_path_elem->name) {
+               g_string_free(field_path_elem->name, TRUE);
+               field_path_elem->name = NULL;
+       }
+
+       g_array_set_size(ctx->cur_path, ctx->cur_path->len - 1);
+}
+
+/*
+ * Creates a relative field ref (a single name) from IR field path
+ * `tgt_ir_field_path`.
+ *
+ * This function tries to locate the target field class recursively from
+ * the top to the bottom of the context's current path using only the
+ * target field class's own name. This is because many CTF reading tools
+ * do not support a relative field ref with more than one element, for
+ * example `prev_struct.len`.
+ *
+ * Returns a negative value if this resolving operation failed.
+ */
+static
+int create_relative_field_ref(struct ctx *ctx,
+               const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
+{
+       int ret = 0;
+       struct fs_sink_ctf_field_class *tgt_fc = NULL;
+       uint64_t i;
+       int64_t si;
+       const char *tgt_fc_name = NULL;
+       struct field_path_elem *field_path_elem;
+
+       /* Get target field class's name */
+       switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
+       case BT_SCOPE_PACKET_CONTEXT:
+               BT_ASSERT(ctx->cur_sc);
+               tgt_fc = ctx->cur_sc->packet_context_fc;
+               break;
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               BT_ASSERT(ctx->cur_sc);
+               tgt_fc = ctx->cur_sc->event_common_context_fc;
+               break;
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               BT_ASSERT(ctx->cur_ec);
+               tgt_fc = ctx->cur_ec->spec_context_fc;
+               break;
+       case BT_SCOPE_EVENT_PAYLOAD:
+               BT_ASSERT(ctx->cur_ec);
+               tgt_fc = ctx->cur_ec->payload_fc;
+               break;
+       default:
+               abort();
+       }
+
+       i = 0;
+
+       while (i < bt_field_path_get_item_count(tgt_ir_field_path)) {
+               const bt_field_path_item *fp_item =
+                       bt_field_path_borrow_item_by_index_const(
+                               tgt_ir_field_path, i);
+               struct fs_sink_ctf_named_field_class *named_fc = NULL;
+
+               BT_ASSERT(tgt_fc);
+               BT_ASSERT(fp_item);
+
+               switch (tgt_fc->type) {
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
+                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
+                       named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                               (void *) tgt_fc,
+                               bt_field_path_item_index_get_index(fp_item));
+                       break;
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
+                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
+                       named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
+                               (void *) tgt_fc,
+                               bt_field_path_item_index_get_index(fp_item));
+                       break;
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
+               {
+                       struct fs_sink_ctf_field_class_array_base *array_base_fc =
+                               (void *) tgt_fc;
+
+                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
+                               BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
+                       tgt_fc = array_base_fc->elem_fc;
+                       break;
+               }
+               default:
+                       abort();
+               }
+
+               if (named_fc) {
+                       tgt_fc = named_fc->fc;
+                       tgt_fc_name = named_fc->name->str;
+                       i++;
+               }
+       }
+
+       BT_ASSERT(tgt_fc);
+       BT_ASSERT(tgt_fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_INT);
+       BT_ASSERT(tgt_fc_name);
+
+       /* Find target field class having this name in current context */
+       for (si = ctx->cur_path->len - 1; si >= 0; si--) {
+               struct fs_sink_ctf_field_class *fc;
+               struct fs_sink_ctf_field_class_struct *struct_fc;
+               struct fs_sink_ctf_field_class_variant *var_fc;
+               struct fs_sink_ctf_named_field_class *named_fc;
+               uint64_t len;
+
+               field_path_elem = cur_path_stack_at(ctx, (uint64_t) si);
+               fc = field_path_elem->parent_fc;
+               if (!fc) {
+                       /* Reached stack's bottom */
+                       ret = -1;
+                       goto end;
+               }
+
+               switch (fc->type) {
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+                       break;
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
+                       continue;
+               default:
+                       /* Not supported by TSDL 1.8 */
+                       ret = -1;
+                       goto end;
+               }
+
+               if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
+                       struct_fc = (void *) fc;
+                       len = struct_fc->members->len;
+               } else {
+                       var_fc = (void *) fc;
+                       len = var_fc->options->len;
+               }
+
+               for (i = 0; i < len; i++) {
+                       if (fc->type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
+                               named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+                       } else {
+                               named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+                       }
+
+                       if (strcmp(named_fc->name->str, tgt_fc_name) == 0) {
+                               if (named_fc->fc == tgt_fc) {
+                                       g_string_assign(tgt_field_ref,
+                                               tgt_fc_name);
+                               } else {
+                                       /*
+                                        * Using only the target field
+                                        * class's name, we're not
+                                        * reaching the target field
+                                        * class. This is not supported
+                                        * by TSDL 1.8.
+                                        */
+                                       ret = -1;
+                               }
+
+                               goto end;
+                       }
+               }
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Creates an absolute field ref from IR field path `tgt_ir_field_path`.
+ *
+ * Returns a negative value if this resolving operation failed.
+ */
+static
+int create_absolute_field_ref(struct ctx *ctx,
+               const bt_field_path *tgt_ir_field_path, GString *tgt_field_ref)
+{
+       int ret = 0;
+       struct fs_sink_ctf_field_class *fc = NULL;
+       uint64_t i;
+
+       switch (bt_field_path_get_root_scope(tgt_ir_field_path)) {
+       case BT_SCOPE_PACKET_CONTEXT:
+               BT_ASSERT(ctx->cur_sc);
+               fc = ctx->cur_sc->packet_context_fc;
+               g_string_assign(tgt_field_ref, "stream.packet.context");
+               break;
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               BT_ASSERT(ctx->cur_sc);
+               fc = ctx->cur_sc->event_common_context_fc;
+               g_string_assign(tgt_field_ref, "stream.event.context");
+               break;
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               BT_ASSERT(ctx->cur_ec);
+               fc = ctx->cur_ec->spec_context_fc;
+               g_string_assign(tgt_field_ref, "event.context");
+               break;
+       case BT_SCOPE_EVENT_PAYLOAD:
+               BT_ASSERT(ctx->cur_ec);
+               fc = ctx->cur_ec->payload_fc;
+               g_string_assign(tgt_field_ref, "event.fields");
+               break;
+       default:
+               abort();
+       }
+
+       BT_ASSERT(fc);
+
+       for (i = 0; i < bt_field_path_get_item_count(tgt_ir_field_path); i++) {
+               const bt_field_path_item *fp_item =
+                       bt_field_path_borrow_item_by_index_const(
+                               tgt_ir_field_path, i);
+               struct fs_sink_ctf_named_field_class *named_fc = NULL;
+
+               if (bt_field_path_item_get_type(fp_item) !=
+                               BT_FIELD_PATH_ITEM_TYPE_INDEX) {
+                       /* Not supported by TSDL 1.8 */
+                       ret = -1;
+                       goto end;
+               }
+
+               switch (fc->type) {
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
+                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
+                       named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                               (void *) fc,
+                               bt_field_path_item_index_get_index(fp_item));
+                       break;
+               case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
+                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
+                       named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
+                               (void *) fc,
+                               bt_field_path_item_index_get_index(fp_item));
+                       break;
+               default:
+                       abort();
+               }
+
+               BT_ASSERT(named_fc);
+               g_string_append_c(tgt_field_ref, '.');
+               g_string_append(tgt_field_ref, named_fc->name->str);
+               fc = named_fc->fc;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Resolves a target field class located at `tgt_ir_field_path`, writing
+ * the resolved field ref to `tgt_field_ref` and setting
+ * `*create_before` according to whether or not the target field must be
+ * created immediately before (in which case `tgt_field_ref` is
+ * irrelevant).
+ */
+static
+void resolve_field_class(struct ctx *ctx,
+               const bt_field_path *tgt_ir_field_path,
+               GString *tgt_field_ref, bool *create_before)
+{
+       int ret;
+       bt_scope tgt_scope;
+
+       *create_before = false;
+
+       if (!tgt_ir_field_path) {
+               *create_before = true;
+               goto end;
+       }
+
+       tgt_scope = bt_field_path_get_root_scope(tgt_ir_field_path);
+
+       if (tgt_scope == ctx->cur_scope) {
+               /*
+                * Try, in this order:
+                *
+                * 1. Use a relative path, using only the target field
+                *    class's name. This is what is the most commonly
+                *    supported by popular CTF reading tools.
+                *
+                * 2. Use an absolute path. This could fail if there's
+                *    an array field class from the current root's field
+                *    class to the target field class.
+                *
+                * 3. Create the target field class before the
+                *    requesting field class (fallback).
+                */
+               ret = create_relative_field_ref(ctx, tgt_ir_field_path,
+                       tgt_field_ref);
+               if (ret) {
+                       ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
+                               tgt_field_ref);
+                       if (ret) {
+                               *create_before = true;
+                               ret = 0;
+                               goto end;
+                       }
+               }
+       } else {
+               ret = create_absolute_field_ref(ctx, tgt_ir_field_path,
+                       tgt_field_ref);
+
+               /* It must always work in previous scopes */
+               BT_ASSERT(ret == 0);
+       }
+
+end:
+       return;
+}
+
+static
+int translate_field_class(struct ctx *ctx);
+
+static inline
+void append_to_parent_field_class(struct ctx *ctx,
+               struct fs_sink_ctf_field_class *fc)
+{
+       struct fs_sink_ctf_field_class *parent_fc =
+               cur_path_stack_top(ctx)->parent_fc;
+
+       switch (parent_fc->type) {
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+               fs_sink_ctf_field_class_struct_append_member((void *) parent_fc,
+                       cur_path_stack_top(ctx)->name->str, fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+               fs_sink_ctf_field_class_variant_append_option((void *) parent_fc,
+                       cur_path_stack_top(ctx)->name->str, fc);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct fs_sink_ctf_field_class_array_base *array_base_fc =
+                       (void *) parent_fc;
+
+               BT_ASSERT(!array_base_fc->elem_fc);
+               array_base_fc->elem_fc = fc;
+               array_base_fc->base.alignment = fc->alignment;
+               break;
+       }
+       default:
+               abort();
+       }
+}
+
+static inline
+void update_parent_field_class_alignment(struct ctx *ctx,
+               unsigned int alignment)
+{
+       struct fs_sink_ctf_field_class *parent_fc =
+               cur_path_stack_top(ctx)->parent_fc;
+
+       switch (parent_fc->type) {
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+               fs_sink_ctf_field_class_struct_align_at_least(
+                       (void *) parent_fc, alignment);
+               break;
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct fs_sink_ctf_field_class_array_base *array_base_fc =
+                       (void *) parent_fc;
+
+               array_base_fc->base.alignment = alignment;
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static inline
+int translate_structure_field_class_members(struct ctx *ctx,
+               struct fs_sink_ctf_field_class_struct *struct_fc,
+               const bt_field_class *ir_fc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       for (i = 0; i < bt_field_class_structure_get_member_count(ir_fc); i++) {
+               const bt_field_class_structure_member *member;
+               const char *name;
+               const bt_field_class *memb_ir_fc;
+
+               member =
+                       bt_field_class_structure_borrow_member_by_index_const(
+                               ir_fc, i);
+               name = bt_field_class_structure_member_get_name(member);
+               memb_ir_fc = bt_field_class_structure_member_borrow_field_class_const(
+                       member);
+               ret = cur_path_stack_push(ctx, i, name, memb_ir_fc,
+                       (void *) struct_fc);
+               if (ret) {
+                       BT_LOGE("Cannot translate structure field class member: "
+                               "name=\"%s\"", name);
+                       goto end;
+               }
+
+               ret = translate_field_class(ctx);
+               if (ret) {
+                       BT_LOGE("Cannot translate structure field class member: "
+                               "name=\"%s\"", name);
+                       goto end;
+               }
+
+               cur_path_stack_pop(ctx);
+       }
+
+end:
+       return ret;
+}
+
+static inline
+int translate_structure_field_class(struct ctx *ctx)
+{
+       int ret;
+       struct fs_sink_ctf_field_class_struct *fc =
+               fs_sink_ctf_field_class_struct_create_empty(
+                       cur_path_stack_top(ctx)->ir_fc,
+                       cur_path_stack_top(ctx)->index_in_parent);
+
+       BT_ASSERT(fc);
+       append_to_parent_field_class(ctx, (void *) fc);
+       ret = translate_structure_field_class_members(ctx, fc, fc->base.ir_fc);
+       if (ret) {
+               goto end;
+       }
+
+       update_parent_field_class_alignment(ctx, fc->base.alignment);
+
+end:
+       return ret;
+}
+
+static inline
+int translate_variant_field_class(struct ctx *ctx)
+{
+       int ret = 0;
+       uint64_t i;
+       struct fs_sink_ctf_field_class_variant *fc =
+               fs_sink_ctf_field_class_variant_create_empty(
+                       cur_path_stack_top(ctx)->ir_fc,
+                       cur_path_stack_top(ctx)->index_in_parent);
+
+       BT_ASSERT(fc);
+
+       /* Resolve tag field class before appending to parent */
+       resolve_field_class(ctx,
+               bt_field_class_variant_borrow_selector_field_path_const(
+                       fc->base.ir_fc), fc->tag_ref, &fc->tag_is_before);
+
+       append_to_parent_field_class(ctx, (void *) fc);
+
+       for (i = 0; i < bt_field_class_variant_get_option_count(fc->base.ir_fc);
+                       i++) {
+               const bt_field_class_variant_option *opt;
+               const char *name;
+               const bt_field_class *opt_ir_fc;
+
+               opt = bt_field_class_variant_borrow_option_by_index_const(
+                       fc->base.ir_fc, i);
+               name = bt_field_class_variant_option_get_name(opt);
+               opt_ir_fc = bt_field_class_variant_option_borrow_field_class_const(
+                       opt);
+               ret = cur_path_stack_push(ctx, i, name, opt_ir_fc, (void *) fc);
+               if (ret) {
+                       BT_LOGE("Cannot translate variant field class option: "
+                               "name=\"%s\"", name);
+                       goto end;
+               }
+
+               ret = translate_field_class(ctx);
+               if (ret) {
+                       BT_LOGE("Cannot translate variant field class option: "
+                               "name=\"%s\"", name);
+                       goto end;
+               }
+
+               cur_path_stack_pop(ctx);
+       }
+
+end:
+       return ret;
+}
+
+static inline
+int translate_static_array_field_class(struct ctx *ctx)
+{
+       struct fs_sink_ctf_field_class_array *fc =
+               fs_sink_ctf_field_class_array_create_empty(
+                       cur_path_stack_top(ctx)->ir_fc,
+                       cur_path_stack_top(ctx)->index_in_parent);
+       const bt_field_class *elem_ir_fc =
+               bt_field_class_array_borrow_element_field_class_const(
+                       fc->base.base.ir_fc);
+       int ret;
+
+       BT_ASSERT(fc);
+       append_to_parent_field_class(ctx, (void *) fc);
+       ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
+               (void *) fc);
+       if (ret) {
+               BT_LOGE_STR("Cannot translate static array field class element.");
+               goto end;
+       }
+
+       ret = translate_field_class(ctx);
+       if (ret) {
+               BT_LOGE_STR("Cannot translate static array field class element.");
+               goto end;
+       }
+
+       cur_path_stack_pop(ctx);
+       update_parent_field_class_alignment(ctx, fc->base.base.alignment);
+
+end:
+       return ret;
+}
+
+static inline
+int translate_dynamic_array_field_class(struct ctx *ctx)
+{
+       struct fs_sink_ctf_field_class_sequence *fc =
+               fs_sink_ctf_field_class_sequence_create_empty(
+                       cur_path_stack_top(ctx)->ir_fc,
+                       cur_path_stack_top(ctx)->index_in_parent);
+       const bt_field_class *elem_ir_fc =
+               bt_field_class_array_borrow_element_field_class_const(
+                       fc->base.base.ir_fc);
+       int ret;
+
+       BT_ASSERT(fc);
+
+       /* Resolve length field class before appending to parent */
+       resolve_field_class(ctx,
+               bt_field_class_dynamic_array_borrow_length_field_path_const(
+                       fc->base.base.ir_fc),
+               fc->length_ref, &fc->length_is_before);
+
+       append_to_parent_field_class(ctx, (void *) fc);
+       ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, elem_ir_fc,
+               (void *) fc);
+       if (ret) {
+               BT_LOGE_STR("Cannot translate dynamic array field class element.");
+               goto end;
+       }
+
+       ret = translate_field_class(ctx);
+       if (ret) {
+               BT_LOGE_STR("Cannot translate dynamic array field class element.");
+               goto end;
+       }
+
+       cur_path_stack_pop(ctx);
+       update_parent_field_class_alignment(ctx, fc->base.base.alignment);
+
+end:
+       return ret;
+}
+
+static inline
+int translate_integer_field_class(struct ctx *ctx)
+{
+       struct fs_sink_ctf_field_class_int *fc =
+               fs_sink_ctf_field_class_int_create(
+                       cur_path_stack_top(ctx)->ir_fc,
+                       cur_path_stack_top(ctx)->index_in_parent);
+
+       BT_ASSERT(fc);
+       append_to_parent_field_class(ctx, (void *) fc);
+       return 0;
+}
+
+static inline
+int translate_real_field_class(struct ctx *ctx)
+{
+       struct fs_sink_ctf_field_class_float *fc =
+               fs_sink_ctf_field_class_float_create(
+                       cur_path_stack_top(ctx)->ir_fc,
+                       cur_path_stack_top(ctx)->index_in_parent);
+
+       BT_ASSERT(fc);
+       append_to_parent_field_class(ctx, (void *) fc);
+       return 0;
+}
+
+static inline
+int translate_string_field_class(struct ctx *ctx)
+{
+       struct fs_sink_ctf_field_class_string *fc =
+               fs_sink_ctf_field_class_string_create(
+                       cur_path_stack_top(ctx)->ir_fc,
+                       cur_path_stack_top(ctx)->index_in_parent);
+
+       BT_ASSERT(fc);
+       append_to_parent_field_class(ctx, (void *) fc);
+       return 0;
+}
+
+/*
+ * Translates a field class, recursively.
+ *
+ * The field class's IR field class, parent field class, and index
+ * within its parent are in the context's current path's top element
+ * (cur_path_stack_top()).
+ */
+static
+int translate_field_class(struct ctx *ctx)
+{
+       int ret;
+
+       switch (bt_field_class_get_type(cur_path_stack_top(ctx)->ir_fc)) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
+       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+               ret = translate_integer_field_class(ctx);
+               break;
+       case BT_FIELD_CLASS_TYPE_REAL:
+               ret = translate_real_field_class(ctx);
+               break;
+       case BT_FIELD_CLASS_TYPE_STRING:
+               ret = translate_string_field_class(ctx);
+               break;
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+               ret = translate_structure_field_class(ctx);
+               break;
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+               ret = translate_static_array_field_class(ctx);
+               break;
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+               ret = translate_dynamic_array_field_class(ctx);
+               break;
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+               ret = translate_variant_field_class(ctx);
+               break;
+       default:
+               abort();
+       }
+
+       return ret;
+}
+
+static
+int set_field_ref(struct fs_sink_ctf_field_class *fc, const char *fc_name,
+               struct fs_sink_ctf_field_class *parent_fc)
+{
+       int ret = 0;
+       GString *field_ref = NULL;
+       bool is_before;
+       const char *tgt_type;
+       struct fs_sink_ctf_field_class_struct *parent_struct_fc =
+               (void *) parent_fc;
+       uint64_t i;
+       unsigned int suffix = 0;
+
+       if (!fc_name || !parent_fc ||
+                       parent_fc->type != FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
+               /* Not supported */
+               ret = -1;
+               goto end;
+       }
+
+       switch (fc->type) {
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct fs_sink_ctf_field_class_sequence *seq_fc = (void *) fc;
+
+               field_ref = seq_fc->length_ref;
+               is_before = seq_fc->length_is_before;
+               tgt_type = "len";
+               break;
+       }
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               struct fs_sink_ctf_field_class_variant *var_fc = (void *) fc;
+
+               field_ref = var_fc->tag_ref;
+               is_before = var_fc->tag_is_before;
+               tgt_type = "tag";
+               break;
+       }
+       default:
+               abort();
+       }
+
+       BT_ASSERT(field_ref);
+
+       if (!is_before) {
+               goto end;
+       }
+
+       /* Initial field ref */
+       g_string_printf(field_ref, "__%s_%s", fc_name, tgt_type);
+
+       /*
+        * Make sure field ref does not clash with an existing field
+        * class name within the same parent structure field class.
+        */
+       while (true) {
+               bool name_ok = true;
+
+               for (i = 0; i < parent_struct_fc->members->len; i++) {
+                       struct fs_sink_ctf_named_field_class *named_fc =
+                               fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                                       parent_struct_fc, i);
+
+                       if (strcmp(field_ref->str, named_fc->name->str) == 0) {
+                               /* Name clash */
+                               name_ok = false;
+                               break;
+                       }
+               }
+
+               if (name_ok) {
+                       /* No clash: we're done */
+                       break;
+               }
+
+               /* Append suffix and try again */
+               g_string_printf(field_ref, "__%s_%s_%u", fc_name, tgt_type,
+                       suffix);
+               suffix++;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * This function recursively sets field refs of sequence and variant
+ * field classes when they are immediately before, avoiding name clashes
+ * with existing field class names.
+ *
+ * It can fail at this point if, for example, a sequence field class of
+ * which to set the length's field ref has something else than a
+ * structure field class as its parent: in this case, there's no
+ * location to place the length field class immediately before the
+ * sequence field class.
+ */
+static
+int set_field_refs(struct fs_sink_ctf_field_class * const fc,
+               const char *fc_name, struct fs_sink_ctf_field_class *parent_fc)
+{
+       int ret = 0;
+       enum fs_sink_ctf_field_class_type fc_type;
+       BT_ASSERT(fc);
+
+       fc_type = fc->type;
+
+       switch (fc_type) {
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT:
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_VARIANT:
+       {
+               uint64_t i;
+               uint64_t len;
+               struct fs_sink_ctf_field_class_struct *struct_fc;
+               struct fs_sink_ctf_field_class_variant *var_fc = NULL;
+               struct fs_sink_ctf_named_field_class *named_fc;
+
+               if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
+                       struct_fc = (void *) fc;
+                       len = struct_fc->members->len;
+               } else {
+                       var_fc = (void *) fc;
+                       len = var_fc->options->len;
+                       ret = set_field_ref(fc, fc_name, parent_fc);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               for (i = 0; i < len; i++) {
+                       if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_STRUCT) {
+                               named_fc = fs_sink_ctf_field_class_struct_borrow_member_by_index(
+                                       struct_fc, i);
+                       } else {
+                               named_fc = fs_sink_ctf_field_class_variant_borrow_option_by_index(
+                                       var_fc, i);
+                       }
+
+                       ret = set_field_refs(named_fc->fc, named_fc->name->str,
+                               fc);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               break;
+       }
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_ARRAY:
+       case FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE:
+       {
+               struct fs_sink_ctf_field_class_array_base *array_base_fc =
+                       (void *) fc;
+
+               if (fc_type == FS_SINK_CTF_FIELD_CLASS_TYPE_SEQUENCE) {
+                       ret = set_field_ref(fc, fc_name, parent_fc);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               ret = set_field_refs(array_base_fc->elem_fc, NULL, fc);
+               if (ret) {
+                       goto end;
+               }
+
+               break;
+       }
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * This function translates a root scope trace IR field class to
+ * a CTF IR field class.
+ *
+ * The resulting CTF IR field class is written to `*fc` so that it
+ * exists as the parent object's (stream class or event class) true root
+ * field class during the recursive translation for resolving purposes.
+ * This is also why this function creates the empty structure field
+ * class and then calls translate_structure_field_class_members() to
+ * fill it.
+ */
+static
+int translate_scope_field_class(struct ctx *ctx, bt_scope scope,
+               struct fs_sink_ctf_field_class **fc,
+               const bt_field_class *ir_fc)
+{
+       int ret = 0;
+
+       if (!ir_fc) {
+               goto end;
+       }
+
+       BT_ASSERT(bt_field_class_get_type(ir_fc) ==
+                       BT_FIELD_CLASS_TYPE_STRUCTURE);
+       BT_ASSERT(fc);
+       *fc = (void *) fs_sink_ctf_field_class_struct_create_empty(
+               ir_fc, UINT64_C(-1));
+       BT_ASSERT(*fc);
+       ctx->cur_scope = scope;
+       BT_ASSERT(ctx->cur_path->len == 0);
+       ret = cur_path_stack_push(ctx, UINT64_C(-1), NULL, ir_fc, NULL);
+       if (ret) {
+               BT_LOGE("Cannot translate scope structure field class: "
+                       "scope=%d", scope);
+               goto end;
+       }
+
+       ret = translate_structure_field_class_members(ctx, (void *) *fc, ir_fc);
+       if (ret) {
+               BT_LOGE("Cannot translate scope structure field class: "
+                       "scope=%d", scope);
+               goto end;
+       }
+
+       cur_path_stack_pop(ctx);
+
+       /* Set field refs for preceding targets */
+       ret = set_field_refs(*fc, NULL, NULL);
+
+end:
+       return ret;
+}
+
+static inline
+void ctx_init(struct ctx *ctx)
+{
+       memset(ctx, 0, sizeof(struct ctx));
+       ctx->cur_path = g_array_new(FALSE, TRUE,
+               sizeof(struct field_path_elem));
+       BT_ASSERT(ctx->cur_path);
+}
+
+static inline
+void ctx_fini(struct ctx *ctx)
+{
+       if (ctx->cur_path) {
+               g_array_free(ctx->cur_path, TRUE);
+               ctx->cur_path = NULL;
+       }
+}
+
+static
+int translate_event_class(struct fs_sink_ctf_stream_class *sc,
+               const bt_event_class *ir_ec,
+               struct fs_sink_ctf_event_class **out_ec)
+{
+       int ret = 0;
+       struct ctx ctx;
+       struct fs_sink_ctf_event_class *ec;
+
+       BT_ASSERT(sc);
+       BT_ASSERT(ir_ec);
+
+       ctx_init(&ctx);
+       ec = fs_sink_ctf_event_class_create(sc, ir_ec);
+       BT_ASSERT(ec);
+       ctx.cur_sc = sc;
+       ctx.cur_ec = ec;
+       ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_SPECIFIC_CONTEXT,
+               &ec->spec_context_fc,
+               bt_event_class_borrow_specific_context_field_class_const(
+                       ir_ec));
+       if (ret) {
+               goto end;
+       }
+
+       ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_PAYLOAD,
+               &ec->payload_fc,
+               bt_event_class_borrow_payload_field_class_const(ir_ec));
+       if (ret) {
+               goto end;
+       }
+
+end:
+       ctx_fini(&ctx);
+       *out_ec = ec;
+       return ret;
+}
+
+BT_HIDDEN
+int try_translate_event_class_trace_ir_to_ctf_ir(
+               struct fs_sink_ctf_stream_class *sc,
+               const bt_event_class *ir_ec,
+               struct fs_sink_ctf_event_class **out_ec)
+{
+       int ret = 0;
+
+       BT_ASSERT(sc);
+       BT_ASSERT(ir_ec);
+
+       /* Check in hash table first */
+       *out_ec = g_hash_table_lookup(sc->event_classes_from_ir, ir_ec);
+       if (likely(*out_ec)) {
+               goto end;
+       }
+
+       ret = translate_event_class(sc, ir_ec, out_ec);
+
+end:
+       return ret;
+}
+
+bool default_clock_class_name_exists(struct fs_sink_ctf_trace_class *tc,
+               const char *name)
+{
+       bool exists = false;
+       uint64_t i;
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               struct fs_sink_ctf_stream_class *sc =
+                       tc->stream_classes->pdata[i];
+
+               if (sc->default_clock_class_name->len == 0) {
+                       /* No default clock class */
+                       continue;
+               }
+
+               if (strcmp(sc->default_clock_class_name->str, name) == 0) {
+                       exists = true;
+                       goto end;
+               }
+       }
+
+end:
+       return exists;
+}
+
+static
+void make_unique_default_clock_class_name(struct fs_sink_ctf_stream_class *sc)
+{
+       unsigned int suffix = 0;
+       char buf[16];
+
+       g_string_assign(sc->default_clock_class_name, "");
+       sprintf(buf, "default");
+
+       while (default_clock_class_name_exists(sc->tc, buf)) {
+               sprintf(buf, "default%u", suffix);
+               suffix++;
+       }
+
+       g_string_assign(sc->default_clock_class_name, buf);
+}
+
+static
+int translate_stream_class(struct fs_sink_ctf_trace_class *tc,
+               const bt_stream_class *ir_sc,
+               struct fs_sink_ctf_stream_class **out_sc)
+{
+       int ret = 0;
+       struct ctx ctx;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(ir_sc);
+       ctx_init(&ctx);
+       *out_sc = fs_sink_ctf_stream_class_create(tc, ir_sc);
+       BT_ASSERT(*out_sc);
+
+       /* Set default clock class's protected name, if any */
+       if ((*out_sc)->default_clock_class) {
+               const char *name = bt_clock_class_get_name(
+                       (*out_sc)->default_clock_class);
+
+               if (name) {
+                       /* Try original name, protected */
+                       g_string_assign((*out_sc)->default_clock_class_name,
+                               name);
+                       ret = fs_sink_ctf_protect_name(
+                               (*out_sc)->default_clock_class_name);
+                       if (ret) {
+                               /* Invalid: create a new name */
+                               make_unique_default_clock_class_name(*out_sc);
+                               ret = 0;
+                       }
+               } else {
+                       /* No name: create a name */
+                       make_unique_default_clock_class_name(*out_sc);
+               }
+       }
+
+       ctx.cur_sc = *out_sc;
+       ret = translate_scope_field_class(&ctx, BT_SCOPE_PACKET_CONTEXT,
+               &(*out_sc)->packet_context_fc,
+               bt_stream_class_borrow_packet_context_field_class_const(ir_sc));
+       if (ret) {
+               goto error;
+       }
+
+       if ((*out_sc)->packet_context_fc) {
+               /*
+                * Make sure the structure field class's alignment is
+                * enough: 8 is what we use for our own special members
+                * in the packet context.
+                */
+               fs_sink_ctf_field_class_struct_align_at_least(
+                       (void *) (*out_sc)->packet_context_fc, 8);
+       }
+
+       ret = translate_scope_field_class(&ctx, BT_SCOPE_EVENT_COMMON_CONTEXT,
+               &(*out_sc)->event_common_context_fc,
+               bt_stream_class_borrow_event_common_context_field_class_const(
+                       ir_sc));
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       fs_sink_ctf_stream_class_destroy(*out_sc);
+       *out_sc = NULL;
+
+end:
+       ctx_fini(&ctx);
+       return ret;
+}
+
+BT_HIDDEN
+int try_translate_stream_class_trace_ir_to_ctf_ir(
+               struct fs_sink_ctf_trace_class *tc,
+               const bt_stream_class *ir_sc,
+               struct fs_sink_ctf_stream_class **out_sc)
+{
+       int ret = 0;
+       uint64_t i;
+
+       BT_ASSERT(tc);
+       BT_ASSERT(ir_sc);
+
+       for (i = 0; i < tc->stream_classes->len; i++) {
+               *out_sc = tc->stream_classes->pdata[i];
+
+               if ((*out_sc)->ir_sc == ir_sc) {
+                       goto end;
+               }
+       }
+
+       ret = translate_stream_class(tc, ir_sc, out_sc);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct fs_sink_ctf_trace_class *translate_trace_class_trace_ir_to_ctf_ir(
+               const bt_trace_class *ir_tc)
+{
+       uint64_t count;
+       uint64_t i;
+       struct fs_sink_ctf_trace_class *tc = NULL;
+
+       /* Check that trace class's environment is TSDL-compatible */
+       count = bt_trace_class_get_environment_entry_count(ir_tc);
+       for (i = 0; i < count; i++) {
+               const char *name;
+               const bt_value *val;
+
+               bt_trace_class_borrow_environment_entry_by_index_const(
+                       ir_tc, i, &name, &val);
+
+               if (!fs_sink_ctf_ist_valid_identifier(name)) {
+                       BT_LOGE("Unsupported trace class's environment entry name: "
+                               "name=\"%s\"", name);
+                       goto end;
+               }
+
+               switch (bt_value_get_type(val)) {
+               case BT_VALUE_TYPE_SIGNED_INTEGER:
+               case BT_VALUE_TYPE_STRING:
+                       break;
+               default:
+                       BT_LOGE("Unsupported trace class's environment entry value type: "
+                               "type=%s",
+                               bt_common_value_type_string(
+                                       bt_value_get_type(val)));
+                       goto end;
+               }
+       }
+
+       tc = fs_sink_ctf_trace_class_create(ir_tc);
+       BT_ASSERT(tc);
+
+end:
+       return tc;
+}
diff --git a/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.h b/src/plugins/ctf/fs-sink/translate-trace-ir-to-ctf-ir.h
new file mode 100644 (file)
index 0000000..3a1a31e
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_TRACE_IR_TO_CTF_IR_H
+#define BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_TRACE_IR_TO_CTF_IR_H
+
+/*
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "fs-sink-ctf-meta.h"
+
+BT_HIDDEN
+int try_translate_event_class_trace_ir_to_ctf_ir(
+               struct fs_sink_ctf_stream_class *sc,
+               const bt_event_class *ir_ec,
+               struct fs_sink_ctf_event_class **out_ec);
+
+BT_HIDDEN
+int try_translate_stream_class_trace_ir_to_ctf_ir(
+               struct fs_sink_ctf_trace_class *tc,
+               const bt_stream_class *ir_sc,
+               struct fs_sink_ctf_stream_class **out_sc);
+
+BT_HIDDEN
+struct fs_sink_ctf_trace_class *translate_trace_class_trace_ir_to_ctf_ir(
+               const bt_trace_class *ir_tc);
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_SINK_TRANSLATE_TRACE_IR_TO_CTF_IR_H */
diff --git a/src/plugins/ctf/fs-src/Makefile.am b/src/plugins/ctf/fs-src/Makefile.am
new file mode 100644 (file)
index 0000000..37ad7ed
--- /dev/null
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libbabeltrace2-plugin-ctf-fs-src.la
+
+libbabeltrace2_plugin_ctf_fs_src_la_SOURCES = \
+       data-stream-file.c \
+       data-stream-file.h \
+       file.c \
+       file.h \
+       fs.c \
+       fs.h \
+       lttng-index.h \
+       metadata.c \
+       metadata.h \
+       query.h \
+       query.c \
+       logging.h \
+       logging.c
diff --git a/src/plugins/ctf/fs-src/data-stream-file.c b/src/plugins/ctf/fs-src/data-stream-file.c
new file mode 100644 (file)
index 0000000..5b0086a
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+ * Copyright 2016-2017 - Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <inttypes.h>
+#include "compat/mman.h"
+#include "compat/endian.h"
+#include <babeltrace2/babeltrace.h>
+#include "common/common.h"
+#include "file.h"
+#include "metadata.h"
+#include "../common/msg-iter/msg-iter.h"
+#include "common/assert.h"
+#include "data-stream-file.h"
+#include <string.h>
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-SRC-DS"
+#include "logging.h"
+
+static inline
+size_t remaining_mmap_bytes(struct ctf_fs_ds_file *ds_file)
+{
+       return ds_file->mmap_len - ds_file->request_offset;
+}
+
+static
+int ds_file_munmap(struct ctf_fs_ds_file *ds_file)
+{
+       int ret = 0;
+
+       if (!ds_file || !ds_file->mmap_addr) {
+               goto end;
+       }
+
+       if (bt_munmap(ds_file->mmap_addr, ds_file->mmap_len)) {
+               BT_LOGE_ERRNO("Cannot memory-unmap file",
+                       ": address=%p, size=%zu, file_path=\"%s\", file=%p",
+                       ds_file->mmap_addr, ds_file->mmap_len,
+                       ds_file->file ? ds_file->file->path->str : "NULL",
+                       ds_file->file ? ds_file->file->fp : NULL);
+               ret = -1;
+               goto end;
+       }
+
+       ds_file->mmap_addr = NULL;
+
+end:
+       return ret;
+}
+
+static
+enum bt_msg_iter_medium_status ds_file_mmap_next(
+               struct ctf_fs_ds_file *ds_file)
+{
+       enum bt_msg_iter_medium_status ret =
+                       BT_MSG_ITER_MEDIUM_STATUS_OK;
+
+       /* Unmap old region */
+       if (ds_file->mmap_addr) {
+               if (ds_file_munmap(ds_file)) {
+                       goto error;
+               }
+
+               /*
+                * mmap_len is guaranteed to be page-aligned except on the
+                * last mapping where it may not be possible (since the file's
+                * size itself may not be a page multiple).
+                */
+               ds_file->mmap_offset += ds_file->mmap_len;
+               ds_file->request_offset = 0;
+       }
+
+       ds_file->mmap_len = MIN(ds_file->file->size - ds_file->mmap_offset,
+                       ds_file->mmap_max_len);
+       if (ds_file->mmap_len == 0) {
+               ret = BT_MSG_ITER_MEDIUM_STATUS_EOF;
+               goto end;
+       }
+       /* Map new region */
+       BT_ASSERT(ds_file->mmap_len);
+       ds_file->mmap_addr = bt_mmap((void *) 0, ds_file->mmap_len,
+                       PROT_READ, MAP_PRIVATE, fileno(ds_file->file->fp),
+                       ds_file->mmap_offset);
+       if (ds_file->mmap_addr == MAP_FAILED) {
+               BT_LOGE("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %jd: %s",
+                               ds_file->mmap_len, ds_file->file->path->str,
+                               ds_file->file->fp, (intmax_t) ds_file->mmap_offset,
+                               strerror(errno));
+               goto error;
+       }
+
+       goto end;
+error:
+       ds_file_munmap(ds_file);
+       ret = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
+end:
+       return ret;
+}
+
+static
+enum bt_msg_iter_medium_status medop_request_bytes(
+               size_t request_sz, uint8_t **buffer_addr,
+               size_t *buffer_sz, void *data)
+{
+       enum bt_msg_iter_medium_status status =
+               BT_MSG_ITER_MEDIUM_STATUS_OK;
+       struct ctf_fs_ds_file *ds_file = data;
+
+       if (request_sz == 0) {
+               goto end;
+       }
+
+       /* Check if we have at least one memory-mapped byte left */
+       if (remaining_mmap_bytes(ds_file) == 0) {
+               /* Are we at the end of the file? */
+               if (ds_file->mmap_offset >= ds_file->file->size) {
+                       BT_LOGD("Reached end of file \"%s\" (%p)",
+                               ds_file->file->path->str, ds_file->file->fp);
+                       status = BT_MSG_ITER_MEDIUM_STATUS_EOF;
+                       goto end;
+               }
+
+               status = ds_file_mmap_next(ds_file);
+               switch (status) {
+               case BT_MSG_ITER_MEDIUM_STATUS_OK:
+                       break;
+               case BT_MSG_ITER_MEDIUM_STATUS_EOF:
+                       goto end;
+               default:
+                       BT_LOGE("Cannot memory-map next region of file \"%s\" (%p)",
+                                       ds_file->file->path->str,
+                                       ds_file->file->fp);
+                       goto error;
+               }
+       }
+
+       *buffer_sz = MIN(remaining_mmap_bytes(ds_file), request_sz);
+       *buffer_addr = ((uint8_t *) ds_file->mmap_addr) + ds_file->request_offset;
+       ds_file->request_offset += *buffer_sz;
+       goto end;
+
+error:
+       status = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
+
+end:
+       return status;
+}
+
+static
+bt_stream *medop_borrow_stream(bt_stream_class *stream_class, int64_t stream_id,
+               void *data)
+{
+       struct ctf_fs_ds_file *ds_file = data;
+       bt_stream_class *ds_file_stream_class;
+       bt_stream *stream = NULL;
+
+       ds_file_stream_class = bt_stream_borrow_class(
+               ds_file->stream);
+
+       if (stream_class != ds_file_stream_class) {
+               /*
+                * Not supported: two packets described by two different
+                * stream classes within the same data stream file.
+                */
+               goto end;
+       }
+
+       stream = ds_file->stream;
+
+end:
+       return stream;
+}
+
+static
+enum bt_msg_iter_medium_status medop_seek(enum bt_msg_iter_seek_whence whence,
+               off_t offset, void *data)
+{
+       enum bt_msg_iter_medium_status ret =
+                       BT_MSG_ITER_MEDIUM_STATUS_OK;
+       struct ctf_fs_ds_file *ds_file = data;
+       off_t file_size = ds_file->file->size;
+
+       if (whence != BT_MSG_ITER_SEEK_WHENCE_SET ||
+               offset < 0 || offset > file_size) {
+               BT_LOGE("Invalid medium seek request: whence=%d, offset=%jd, "
+                               "file-size=%jd", (int) whence, offset,
+                               file_size);
+               ret = BT_MSG_ITER_MEDIUM_STATUS_INVAL;
+               goto end;
+       }
+
+       /*
+        * Determine whether or not the destination is contained within the
+        * current mapping.
+        */
+       if (ds_file->mmap_addr && (offset < ds_file->mmap_offset ||
+                       offset >= ds_file->mmap_offset + ds_file->mmap_len)) {
+               int unmap_ret;
+               off_t offset_in_mapping = offset % bt_common_get_page_size();
+
+               BT_LOGD("Medium seek request cannot be accomodated by the current "
+                               "file mapping: offset=%jd, mmap-offset=%jd, "
+                               "mmap-len=%zu", offset, ds_file->mmap_offset,
+                               ds_file->mmap_len);
+               unmap_ret = ds_file_munmap(ds_file);
+               if (unmap_ret) {
+                       ret = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
+                       goto end;
+               }
+
+               ds_file->mmap_offset = offset - offset_in_mapping;
+               ds_file->request_offset = offset_in_mapping;
+               ret = ds_file_mmap_next(ds_file);
+               if (ret != BT_MSG_ITER_MEDIUM_STATUS_OK) {
+                       goto end;
+               }
+       } else {
+               ds_file->request_offset = offset - ds_file->mmap_offset;
+       }
+
+       ds_file->end_reached = (offset == file_size);
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_msg_iter_medium_ops ctf_fs_ds_file_medops = {
+       .request_bytes = medop_request_bytes,
+       .borrow_stream = medop_borrow_stream,
+       .seek = medop_seek,
+};
+
+static
+int convert_cycles_to_ns(struct ctf_clock_class *clock_class,
+               uint64_t cycles, int64_t *ns)
+{
+       return bt_util_clock_cycles_to_ns_from_origin(cycles,
+                       clock_class->frequency, clock_class->offset_seconds,
+                       clock_class->offset_cycles, ns);
+}
+
+static
+struct ctf_fs_ds_index *build_index_from_idx_file(
+               struct ctf_fs_ds_file *ds_file)
+{
+       int ret;
+       gchar *directory = NULL;
+       gchar *basename = NULL;
+       GString *index_basename = NULL;
+       gchar *index_file_path = NULL;
+       GMappedFile *mapped_file = NULL;
+       gsize filesize;
+       const char *mmap_begin = NULL, *file_pos = NULL;
+       const struct ctf_packet_index_file_hdr *header = NULL;
+       struct ctf_fs_ds_index *index = NULL;
+       struct ctf_fs_ds_index_entry *index_entry = NULL;
+       uint64_t total_packets_size = 0;
+       size_t file_index_entry_size;
+       size_t file_entry_count;
+       size_t i;
+       struct ctf_stream_class *sc;
+       struct bt_msg_iter_packet_properties props;
+
+       BT_LOGD("Building index from .idx file of stream file %s",
+                       ds_file->file->path->str);
+       ret = bt_msg_iter_get_packet_properties(ds_file->msg_iter, &props);
+       if (ret) {
+               BT_LOGD_STR("Cannot read first packet's header and context fields.");
+               goto error;
+       }
+
+       sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
+               props.stream_class_id);
+       BT_ASSERT(sc);
+       if (!sc->default_clock_class) {
+               BT_LOGD_STR("Cannot find stream class's default clock class.");
+               goto error;
+       }
+
+       /* Look for index file in relative path index/name.idx. */
+       basename = g_path_get_basename(ds_file->file->path->str);
+       if (!basename) {
+               BT_LOGE("Cannot get the basename of datastream file %s",
+                               ds_file->file->path->str);
+               goto error;
+       }
+
+       directory = g_path_get_dirname(ds_file->file->path->str);
+       if (!directory) {
+               BT_LOGE("Cannot get dirname of datastream file %s",
+                               ds_file->file->path->str);
+               goto error;
+       }
+
+       index_basename = g_string_new(basename);
+       if (!index_basename) {
+               BT_LOGE_STR("Cannot allocate index file basename string");
+               goto error;
+       }
+
+       g_string_append(index_basename, ".idx");
+       index_file_path = g_build_filename(directory, "index",
+                       index_basename->str, NULL);
+       mapped_file = g_mapped_file_new(index_file_path, FALSE, NULL);
+       if (!mapped_file) {
+               BT_LOGD("Cannot create new mapped file %s",
+                               index_file_path);
+               goto error;
+       }
+
+       /*
+        * The g_mapped_file API limits us to 4GB files on 32-bit.
+        * Traces with such large indexes have never been seen in the wild,
+        * but this would need to be adjusted to support them.
+        */
+       filesize = g_mapped_file_get_length(mapped_file);
+       if (filesize < sizeof(*header)) {
+               BT_LOGW("Invalid LTTng trace index file: "
+                       "file size (%zu bytes) < header size (%zu bytes)",
+                       filesize, sizeof(*header));
+               goto error;
+       }
+
+       mmap_begin = g_mapped_file_get_contents(mapped_file);
+       header = (struct ctf_packet_index_file_hdr *) mmap_begin;
+
+       file_pos = g_mapped_file_get_contents(mapped_file) + sizeof(*header);
+       if (be32toh(header->magic) != CTF_INDEX_MAGIC) {
+               BT_LOGW_STR("Invalid LTTng trace index: \"magic\" field validation failed");
+               goto error;
+       }
+
+       file_index_entry_size = be32toh(header->packet_index_len);
+       file_entry_count = (filesize - sizeof(*header)) / file_index_entry_size;
+       if ((filesize - sizeof(*header)) % file_index_entry_size) {
+               BT_LOGW("Invalid LTTng trace index: the index's size after the header "
+                       "(%zu bytes) is not a multiple of the index entry size "
+                       "(%zu bytes)", (filesize - sizeof(*header)),
+                       sizeof(*header));
+               goto error;
+       }
+
+       index = ctf_fs_ds_index_create();
+       if (!index) {
+               goto error;
+       }
+
+       for (i = 0; i < file_entry_count; i++) {
+               struct ctf_packet_index *file_index =
+                               (struct ctf_packet_index *) file_pos;
+               uint64_t packet_size = be64toh(file_index->packet_size);
+
+               if (packet_size % CHAR_BIT) {
+                       BT_LOGW("Invalid packet size encountered in LTTng trace index file");
+                       goto error;
+               }
+
+               index_entry = g_new0(struct ctf_fs_ds_index_entry, 1);
+               if (!index_entry) {
+                       goto error;
+               }
+
+               /* Convert size in bits to bytes. */
+               packet_size /= CHAR_BIT;
+               index_entry->packet_size = packet_size;
+
+               index_entry->offset = be64toh(file_index->offset);
+               if (i != 0 && index_entry->offset < (index_entry - 1)->offset) {
+                       BT_LOGW("Invalid, non-monotonic, packet offset encountered in LTTng trace index file: "
+                               "previous offset=%" PRIu64 ", current offset=%" PRIu64,
+                               (index_entry - 1)->offset, index_entry->offset);
+                       goto error;
+               }
+
+               index_entry->timestamp_begin = be64toh(file_index->timestamp_begin);
+               index_entry->timestamp_end = be64toh(file_index->timestamp_end);
+               if (index_entry->timestamp_end < index_entry->timestamp_begin) {
+                       BT_LOGW("Invalid packet time bounds encountered in LTTng trace index file (begin > end): "
+                               "timestamp_begin=%" PRIu64 "timestamp_end=%" PRIu64,
+                               index_entry->timestamp_begin,
+                               index_entry->timestamp_end);
+                       goto error;
+               }
+
+               /* Convert the packet's bound to nanoseconds since Epoch. */
+               ret = convert_cycles_to_ns(sc->default_clock_class,
+                               index_entry->timestamp_begin,
+                               &index_entry->timestamp_begin_ns);
+               if (ret) {
+                       BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch during index parsing");
+                       goto error;
+               }
+               ret = convert_cycles_to_ns(sc->default_clock_class,
+                               index_entry->timestamp_end,
+                               &index_entry->timestamp_end_ns);
+               if (ret) {
+                       BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch during LTTng trace index parsing");
+                       goto error;
+               }
+
+               total_packets_size += packet_size;
+               file_pos += file_index_entry_size;
+
+               g_ptr_array_add(index->entries, index_entry);
+       }
+
+       /* Validate that the index addresses the complete stream. */
+       if (ds_file->file->size != total_packets_size) {
+               BT_LOGW("Invalid LTTng trace index file; indexed size != stream file size: "
+                       "file-size=%" PRIu64 ", total-packets-size=%" PRIu64,
+                       ds_file->file->size, total_packets_size);
+               goto error;
+       }
+end:
+       g_free(directory);
+       g_free(basename);
+       g_free(index_file_path);
+       if (index_basename) {
+               g_string_free(index_basename, TRUE);
+       }
+       if (mapped_file) {
+               g_mapped_file_unref(mapped_file);
+       }
+       return index;
+error:
+       ctf_fs_ds_index_destroy(index);
+       g_free(index_entry);
+       index = NULL;
+       goto end;
+}
+
+static
+int init_index_entry(struct ctf_fs_ds_index_entry *entry,
+               struct ctf_fs_ds_file *ds_file,
+               struct bt_msg_iter_packet_properties *props,
+               off_t packet_size, off_t packet_offset)
+{
+       int ret = 0;
+       struct ctf_stream_class *sc;
+
+       sc = ctf_trace_class_borrow_stream_class_by_id(ds_file->metadata->tc,
+               props->stream_class_id);
+       BT_ASSERT(sc);
+       BT_ASSERT(packet_offset >= 0);
+       entry->offset = packet_offset;
+       BT_ASSERT(packet_size >= 0);
+       entry->packet_size = packet_size;
+
+       if (props->snapshots.beginning_clock != UINT64_C(-1)) {
+               /* Convert the packet's bound to nanoseconds since Epoch. */
+               ret = convert_cycles_to_ns(sc->default_clock_class,
+                                          props->snapshots.beginning_clock,
+                                          &entry->timestamp_begin_ns);
+               if (ret) {
+                       BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
+                       goto end;
+               }
+       } else {
+               entry->timestamp_begin_ns = UINT64_C(-1);
+       }
+
+       if (props->snapshots.end_clock != UINT64_C(-1)) {
+               ret = convert_cycles_to_ns(sc->default_clock_class,
+                                          props->snapshots.end_clock,
+                                          &entry->timestamp_end_ns);
+               if (ret) {
+                       BT_LOGD_STR("Failed to convert raw timestamp to nanoseconds since Epoch.");
+                       goto end;
+               }
+       } else {
+               entry->timestamp_end_ns = UINT64_C(-1);
+       }
+
+end:
+       return ret;
+}
+
+static
+struct ctf_fs_ds_index *build_index_from_stream_file(
+               struct ctf_fs_ds_file *ds_file)
+{
+       int ret;
+       struct ctf_fs_ds_index *index = NULL;
+       enum bt_msg_iter_status iter_status = BT_MSG_ITER_STATUS_OK;
+       off_t current_packet_offset_bytes = 0;
+
+       BT_LOGD("Indexing stream file %s", ds_file->file->path->str);
+
+       index = ctf_fs_ds_index_create();
+       if (!index) {
+               goto error;
+       }
+
+       do {
+               off_t current_packet_size_bytes;
+               struct ctf_fs_ds_index_entry *index_entry;
+               struct bt_msg_iter_packet_properties props;
+
+               if (current_packet_offset_bytes < 0) {
+                       BT_LOGE_STR("Cannot get the current packet's offset.");
+                       goto error;
+               } else if (current_packet_offset_bytes > ds_file->file->size) {
+                       BT_LOGE_STR("Unexpected current packet's offset (larger than file).");
+                       goto error;
+               } else if (current_packet_offset_bytes == ds_file->file->size) {
+                       /* No more data */
+                       break;
+               }
+
+               iter_status = bt_msg_iter_seek(ds_file->msg_iter,
+                               current_packet_offset_bytes);
+               if (iter_status != BT_MSG_ITER_STATUS_OK) {
+                       goto error;
+               }
+
+               iter_status = bt_msg_iter_get_packet_properties(
+                       ds_file->msg_iter, &props);
+               if (iter_status != BT_MSG_ITER_STATUS_OK) {
+                       goto error;
+               }
+
+               if (props.exp_packet_total_size >= 0) {
+                       current_packet_size_bytes =
+                               (uint64_t) props.exp_packet_total_size / 8;
+               } else {
+                       current_packet_size_bytes = ds_file->file->size;
+               }
+
+               if (current_packet_offset_bytes + current_packet_size_bytes >
+                               ds_file->file->size) {
+                       BT_LOGW("Invalid packet size reported in file: stream=\"%s\", "
+                                       "packet-offset=%jd, packet-size-bytes=%jd, "
+                                       "file-size=%jd",
+                                       ds_file->file->path->str,
+                                       current_packet_offset_bytes,
+                                       current_packet_size_bytes,
+                                       ds_file->file->size);
+                       goto error;
+               }
+
+               index_entry = g_new0(struct ctf_fs_ds_index_entry, 1);
+               if (!index_entry) {
+                       BT_LOGE_STR("Failed to allocate a new index entry.");
+                       goto error;
+               }
+
+               ret = init_index_entry(index_entry, ds_file, &props,
+                       current_packet_size_bytes, current_packet_offset_bytes);
+               if (ret) {
+                       g_free(index_entry);
+                       goto error;
+               }
+
+               g_ptr_array_add(index->entries, index_entry);
+
+               current_packet_offset_bytes += current_packet_size_bytes;
+               BT_LOGD("Seeking to next packet: current-packet-offset=%jd, "
+                       "next-packet-offset=%jd",
+                       current_packet_offset_bytes - current_packet_size_bytes,
+                       current_packet_offset_bytes);
+
+       } while (iter_status == BT_MSG_ITER_STATUS_OK);
+
+       if (iter_status != BT_MSG_ITER_STATUS_OK) {
+               goto error;
+       }
+
+end:
+       return index;
+
+error:
+       ctf_fs_ds_index_destroy(index);
+       index = NULL;
+       goto end;
+}
+
+BT_HIDDEN
+struct ctf_fs_ds_file *ctf_fs_ds_file_create(
+               struct ctf_fs_trace *ctf_fs_trace,
+               bt_self_message_iterator *pc_msg_iter,
+               struct bt_msg_iter *msg_iter,
+               bt_stream *stream, const char *path)
+{
+       int ret;
+       const size_t page_size = bt_common_get_page_size();
+       struct ctf_fs_ds_file *ds_file = g_new0(struct ctf_fs_ds_file, 1);
+
+       if (!ds_file) {
+               goto error;
+       }
+
+       ds_file->pc_msg_iter = pc_msg_iter;
+       ds_file->file = ctf_fs_file_create();
+       if (!ds_file->file) {
+               goto error;
+       }
+
+       ds_file->stream = stream;
+       bt_stream_get_ref(ds_file->stream);
+       ds_file->metadata = ctf_fs_trace->metadata;
+       g_string_assign(ds_file->file->path, path);
+       ret = ctf_fs_file_open(ds_file->file, "rb");
+       if (ret) {
+               goto error;
+       }
+
+       ds_file->msg_iter = msg_iter;
+       bt_msg_iter_set_medops_data(ds_file->msg_iter, ds_file);
+       if (!ds_file->msg_iter) {
+               goto error;
+       }
+
+       ds_file->mmap_max_len = page_size * 2048;
+
+       goto end;
+
+error:
+       /* Do not touch "borrowed" file. */
+       ctf_fs_ds_file_destroy(ds_file);
+       ds_file = NULL;
+
+end:
+       return ds_file;
+}
+
+BT_HIDDEN
+struct ctf_fs_ds_index *ctf_fs_ds_file_build_index(
+               struct ctf_fs_ds_file *ds_file)
+{
+       struct ctf_fs_ds_index *index;
+
+       index = build_index_from_idx_file(ds_file);
+       if (index) {
+               goto end;
+       }
+
+       BT_LOGD("Failed to build index from .index file; "
+               "falling back to stream indexing.");
+       index = build_index_from_stream_file(ds_file);
+end:
+       return index;
+}
+
+BT_HIDDEN
+struct ctf_fs_ds_index *ctf_fs_ds_index_create()
+{
+       struct ctf_fs_ds_index *index = g_new0(struct ctf_fs_ds_index, 1);
+
+       if (!index) {
+               BT_LOGE_STR("Failed to allocate index");
+               goto error;
+       }
+
+       index->entries = g_ptr_array_new_with_free_func((GDestroyNotify) g_free);
+       if (!index->entries) {
+               BT_LOGE("Failed to allocate index entries.");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ctf_fs_ds_index_destroy(index);
+       index = NULL;
+end:
+       return index;
+}
+
+BT_HIDDEN
+void ctf_fs_ds_file_destroy(struct ctf_fs_ds_file *ds_file)
+{
+       if (!ds_file) {
+               return;
+       }
+
+       bt_stream_put_ref(ds_file->stream);
+       (void) ds_file_munmap(ds_file);
+
+       if (ds_file->file) {
+               ctf_fs_file_destroy(ds_file->file);
+       }
+
+       g_free(ds_file);
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status ctf_fs_ds_file_next(
+               struct ctf_fs_ds_file *ds_file,
+               bt_message **msg)
+{
+       enum bt_msg_iter_status msg_iter_status;
+       bt_self_message_iterator_status status;
+
+       msg_iter_status = bt_msg_iter_get_next_message(
+               ds_file->msg_iter, ds_file->pc_msg_iter, msg);
+
+       switch (msg_iter_status) {
+       case BT_MSG_ITER_STATUS_EOF:
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+               break;
+       case BT_MSG_ITER_STATUS_OK:
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+               break;
+       case BT_MSG_ITER_STATUS_AGAIN:
+               /*
+                * Should not make it this far as this is
+                * medium-specific; there is nothing for the user to do
+                * and it should have been handled upstream.
+                */
+               abort();
+       case BT_MSG_ITER_STATUS_INVAL:
+       case BT_MSG_ITER_STATUS_ERROR:
+       default:
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               break;
+       }
+       return status;
+}
+
+BT_HIDDEN
+void ctf_fs_ds_index_destroy(struct ctf_fs_ds_index *index)
+{
+       if (!index) {
+               return;
+       }
+
+       if (index->entries) {
+               g_ptr_array_free(index->entries, TRUE);
+       }
+       g_free(index);
+}
diff --git a/src/plugins/ctf/fs-src/data-stream-file.h b/src/plugins/ctf/fs-src/data-stream-file.h
new file mode 100644 (file)
index 0000000..c826a65
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef CTF_FS_DS_FILE_H
+#define CTF_FS_DS_FILE_H
+
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "../common/msg-iter/msg-iter.h"
+#include "lttng-index.h"
+
+struct ctf_fs_component;
+struct ctf_fs_file;
+struct ctf_fs_trace;
+struct ctf_fs_ds_file;
+
+struct ctf_fs_ds_file_info {
+       /* Owned by this. */
+       GString *path;
+
+       /* Guaranteed to be set, as opposed to the index. */
+       int64_t begin_ns;
+};
+
+struct ctf_fs_metadata;
+
+struct ctf_fs_ds_file {
+       /* Weak */
+       struct ctf_fs_metadata *metadata;
+
+       /* Weak */
+       bt_self_message_iterator *pc_msg_iter;
+
+       /* Owned by this */
+       struct ctf_fs_file *file;
+
+       /* Owned by this */
+       bt_stream *stream;
+
+       /* Weak */
+       struct bt_msg_iter *msg_iter;
+
+       void *mmap_addr;
+
+       /*
+        * Max length of chunk to mmap() when updating the current mapping.
+        * This value must be page-aligned.
+        */
+       size_t mmap_max_len;
+
+       /* Length of the current mapping. Never exceeds the file's length. */
+       size_t mmap_len;
+
+       /* Offset in the file where the current mapping starts. */
+       off_t mmap_offset;
+
+       /*
+        * Offset, in the current mapping, of the address to return on the next
+        * request.
+        */
+       off_t request_offset;
+
+       bool end_reached;
+};
+
+BT_HIDDEN
+struct ctf_fs_ds_file *ctf_fs_ds_file_create(
+               struct ctf_fs_trace *ctf_fs_trace,
+               bt_self_message_iterator *pc_msg_iter,
+               struct bt_msg_iter *msg_iter,
+               bt_stream *stream, const char *path);
+
+BT_HIDDEN
+void ctf_fs_ds_file_destroy(struct ctf_fs_ds_file *stream);
+
+BT_HIDDEN
+bt_self_message_iterator_status ctf_fs_ds_file_next(
+               struct ctf_fs_ds_file *ds_file,
+               bt_message **msg);
+
+BT_HIDDEN
+struct ctf_fs_ds_index *ctf_fs_ds_file_build_index(
+               struct ctf_fs_ds_file *ds_file);
+
+BT_HIDDEN
+struct ctf_fs_ds_index *ctf_fs_ds_index_create();
+
+BT_HIDDEN
+void ctf_fs_ds_index_destroy(struct ctf_fs_ds_index *index);
+
+extern struct bt_msg_iter_medium_ops ctf_fs_ds_file_medops;
+
+#endif /* CTF_FS_DS_FILE_H */
diff --git a/src/plugins/ctf/fs-src/file.c b/src/plugins/ctf/fs-src/file.c
new file mode 100644 (file)
index 0000000..585faef
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <glib.h>
+#include "file.h"
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-FILE-SRC"
+#include "logging.h"
+
+BT_HIDDEN
+void ctf_fs_file_destroy(struct ctf_fs_file *file)
+{
+       if (!file) {
+               return;
+       }
+
+       if (file->fp) {
+               BT_LOGD("Closing file \"%s\" (%p)",
+                               file->path ? file->path->str : NULL, file->fp);
+
+               if (fclose(file->fp)) {
+                       BT_LOGE("Cannot close file \"%s\": %s",
+                                       file->path ? file->path->str : "NULL",
+                                       strerror(errno));
+               }
+       }
+
+       if (file->path) {
+               g_string_free(file->path, TRUE);
+       }
+
+       g_free(file);
+}
+
+BT_HIDDEN
+struct ctf_fs_file *ctf_fs_file_create(void)
+{
+       struct ctf_fs_file *file = g_new0(struct ctf_fs_file, 1);
+
+       if (!file) {
+               goto error;
+       }
+
+       file->path = g_string_new(NULL);
+       if (!file->path) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ctf_fs_file_destroy(file);
+       file = NULL;
+
+end:
+       return file;
+}
+
+BT_HIDDEN
+int ctf_fs_file_open(struct ctf_fs_file *file, const char *mode)
+{
+       int ret = 0;
+       struct stat stat;
+
+       BT_LOGD("Opening file \"%s\" with mode \"%s\"", file->path->str, mode);
+       file->fp = fopen(file->path->str, mode);
+       if (!file->fp) {
+               BT_LOGE("Cannot open file \"%s\" with mode \"%s\": %s",
+                       file->path->str, mode, strerror(errno));
+               goto error;
+       }
+
+       BT_LOGD("Opened file: %p", file->fp);
+
+       if (fstat(fileno(file->fp), &stat)) {
+               BT_LOGE("Cannot get file information: %s", strerror(errno));
+               goto error;
+       }
+
+       file->size = stat.st_size;
+       BT_LOGD("File is %jd bytes", (intmax_t) file->size);
+       goto end;
+
+error:
+       ret = -1;
+
+       if (file->fp) {
+               if (fclose(file->fp)) {
+                       BT_LOGE("Cannot close file \"%s\": %s", file->path->str,
+                               strerror(errno));
+               }
+       }
+
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/fs-src/file.h b/src/plugins/ctf/fs-src/file.h
new file mode 100644 (file)
index 0000000..509b1e4
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef CTF_FS_FILE_H
+#define CTF_FS_FILE_H
+
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "common/babeltrace.h"
+#include "fs.h"
+
+BT_HIDDEN
+void ctf_fs_file_destroy(struct ctf_fs_file *file);
+
+BT_HIDDEN
+struct ctf_fs_file *ctf_fs_file_create(void);
+
+BT_HIDDEN
+int ctf_fs_file_open(struct ctf_fs_file *file, const char *mode);
+
+#endif /* CTF_FS_FILE_H */
diff --git a/src/plugins/ctf/fs-src/fs.c b/src/plugins/ctf/fs-src/fs.c
new file mode 100644 (file)
index 0000000..5ff6d35
--- /dev/null
@@ -0,0 +1,1964 @@
+/*
+ * fs.c
+ *
+ * Babeltrace CTF file system Reader Component
+ *
+ * Copyright 2015-2017 Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/common.h"
+#include <babeltrace2/babeltrace.h>
+#include "compat/uuid.h"
+#include "plugins/plugins-common.h"
+#include <glib.h>
+#include "common/assert.h"
+#include <inttypes.h>
+#include <stdbool.h>
+#include "fs.h"
+#include "metadata.h"
+#include "data-stream-file.h"
+#include "file.h"
+#include "../common/metadata/decoder.h"
+#include "../common/msg-iter/msg-iter.h"
+#include "../common/utils/utils.h"
+#include "query.h"
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-SRC"
+#include "logging.h"
+
+static
+int msg_iter_data_set_current_ds_file(struct ctf_fs_msg_iter_data *msg_iter_data)
+{
+       struct ctf_fs_ds_file_info *ds_file_info;
+       int ret = 0;
+
+       BT_ASSERT(msg_iter_data->ds_file_info_index <
+               msg_iter_data->ds_file_group->ds_file_infos->len);
+       ds_file_info = g_ptr_array_index(
+               msg_iter_data->ds_file_group->ds_file_infos,
+               msg_iter_data->ds_file_info_index);
+
+       ctf_fs_ds_file_destroy(msg_iter_data->ds_file);
+       msg_iter_data->ds_file = ctf_fs_ds_file_create(
+               msg_iter_data->ds_file_group->ctf_fs_trace,
+               msg_iter_data->pc_msg_iter,
+               msg_iter_data->msg_iter,
+               msg_iter_data->ds_file_group->stream,
+               ds_file_info->path->str);
+       if (!msg_iter_data->ds_file) {
+               ret = -1;
+       }
+
+       return ret;
+}
+
+static
+void ctf_fs_msg_iter_data_destroy(
+               struct ctf_fs_msg_iter_data *msg_iter_data)
+{
+       if (!msg_iter_data) {
+               return;
+       }
+
+       ctf_fs_ds_file_destroy(msg_iter_data->ds_file);
+
+       if (msg_iter_data->msg_iter) {
+               bt_msg_iter_destroy(msg_iter_data->msg_iter);
+       }
+
+       g_free(msg_iter_data);
+}
+
+static
+void set_msg_iter_emits_stream_beginning_end_messages(
+               struct ctf_fs_msg_iter_data *msg_iter_data)
+{
+       bt_msg_iter_set_emit_stream_beginning_message(
+               msg_iter_data->ds_file->msg_iter,
+               msg_iter_data->ds_file_info_index == 0);
+       bt_msg_iter_set_emit_stream_end_message(
+               msg_iter_data->ds_file->msg_iter,
+               msg_iter_data->ds_file_info_index ==
+                       msg_iter_data->ds_file_group->ds_file_infos->len - 1);
+}
+
+static
+bt_self_message_iterator_status ctf_fs_iterator_next_one(
+               struct ctf_fs_msg_iter_data *msg_iter_data,
+               const bt_message **out_msg)
+{
+       bt_self_message_iterator_status status;
+
+       BT_ASSERT(msg_iter_data->ds_file);
+
+       while (true) {
+               bt_message *msg;
+
+               status = ctf_fs_ds_file_next(msg_iter_data->ds_file, &msg);
+               switch (status) {
+               case BT_SELF_MESSAGE_ITERATOR_STATUS_OK:
+                       *out_msg = msg;
+                       msg = NULL;
+                       goto end;
+               case BT_SELF_MESSAGE_ITERATOR_STATUS_END:
+               {
+                       int ret;
+
+                       if (msg_iter_data->ds_file_info_index ==
+                                       msg_iter_data->ds_file_group->ds_file_infos->len - 1) {
+                               /* End of all group's stream files */
+                               goto end;
+                       }
+
+                       msg_iter_data->ds_file_info_index++;
+                       bt_msg_iter_reset_for_next_stream_file(
+                               msg_iter_data->msg_iter);
+                       set_msg_iter_emits_stream_beginning_end_messages(
+                               msg_iter_data);
+
+                       /*
+                        * Open and start reading the next stream file
+                        * within our stream file group.
+                        */
+                       ret = msg_iter_data_set_current_ds_file(msg_iter_data);
+                       if (ret) {
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       /* Continue the loop to get the next message */
+                       break;
+               }
+               default:
+                       goto end;
+               }
+       }
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status ctf_fs_iterator_next(
+               bt_self_message_iterator *iterator,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       struct ctf_fs_msg_iter_data *msg_iter_data =
+               bt_self_message_iterator_get_data(iterator);
+       uint64_t i = 0;
+
+       while (i < capacity && status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+               status = ctf_fs_iterator_next_one(msg_iter_data, &msgs[i]);
+               if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                       i++;
+               }
+       }
+
+       if (i > 0) {
+               /*
+                * Even if ctf_fs_iterator_next_one() returned something
+                * else than BT_SELF_MESSAGE_ITERATOR_STATUS_OK, we
+                * accumulated message objects in the output
+                * message array, so we need to return
+                * BT_SELF_MESSAGE_ITERATOR_STATUS_OK so that they are
+                * transfered to downstream. This other status occurs
+                * again the next time muxer_msg_iter_do_next() is
+                * called, possibly without any accumulated
+                * message, in which case we'll return it.
+                */
+               *count = i;
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       }
+
+       return status;
+}
+
+static
+int ctf_fs_iterator_reset(struct ctf_fs_msg_iter_data *msg_iter_data)
+{
+       int ret;
+
+       msg_iter_data->ds_file_info_index = 0;
+       ret = msg_iter_data_set_current_ds_file(msg_iter_data);
+       if (ret) {
+               goto end;
+       }
+
+       bt_msg_iter_reset(msg_iter_data->msg_iter);
+       set_msg_iter_emits_stream_beginning_end_messages(msg_iter_data);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status ctf_fs_iterator_seek_beginning(
+               bt_self_message_iterator *it)
+{
+       struct ctf_fs_msg_iter_data *msg_iter_data =
+               bt_self_message_iterator_get_data(it);
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_ASSERT(msg_iter_data);
+       if (ctf_fs_iterator_reset(msg_iter_data)) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+void ctf_fs_iterator_finalize(bt_self_message_iterator *it)
+{
+       ctf_fs_msg_iter_data_destroy(
+               bt_self_message_iterator_get_data(it));
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status ctf_fs_iterator_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_source *self_comp,
+               bt_self_component_port_output *self_port)
+{
+       struct ctf_fs_port_data *port_data;
+       struct ctf_fs_msg_iter_data *msg_iter_data = NULL;
+       bt_self_message_iterator_status ret =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       port_data = bt_self_component_port_get_data(
+               bt_self_component_port_output_as_self_component_port(
+                       self_port));
+       BT_ASSERT(port_data);
+       msg_iter_data = g_new0(struct ctf_fs_msg_iter_data, 1);
+       if (!msg_iter_data) {
+               ret = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto error;
+       }
+
+       msg_iter_data->pc_msg_iter = self_msg_iter;
+       msg_iter_data->msg_iter = bt_msg_iter_create(
+               port_data->ds_file_group->ctf_fs_trace->metadata->tc,
+               bt_common_get_page_size() * 8,
+               ctf_fs_ds_file_medops, NULL);
+       if (!msg_iter_data->msg_iter) {
+               BT_LOGE_STR("Cannot create a CTF message iterator.");
+               ret = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto error;
+       }
+
+       msg_iter_data->ds_file_group = port_data->ds_file_group;
+       if (ctf_fs_iterator_reset(msg_iter_data)) {
+               ret = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto error;
+       }
+
+       bt_self_message_iterator_set_data(self_msg_iter,
+               msg_iter_data);
+       if (ret != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+               goto error;
+       }
+
+       msg_iter_data = NULL;
+       goto end;
+
+error:
+       bt_self_message_iterator_set_data(self_msg_iter, NULL);
+
+end:
+       ctf_fs_msg_iter_data_destroy(msg_iter_data);
+       return ret;
+}
+
+BT_HIDDEN
+void ctf_fs_destroy(struct ctf_fs_component *ctf_fs)
+{
+       if (!ctf_fs) {
+               return;
+       }
+
+       if (ctf_fs->traces) {
+               g_ptr_array_free(ctf_fs->traces, TRUE);
+       }
+
+       if (ctf_fs->port_data) {
+               g_ptr_array_free(ctf_fs->port_data, TRUE);
+       }
+
+       g_free(ctf_fs);
+}
+
+static
+void port_data_destroy(struct ctf_fs_port_data *port_data)
+{
+       if (!port_data) {
+               return;
+       }
+
+       g_free(port_data);
+}
+
+static
+void port_data_destroy_notifier(void *data) {
+       port_data_destroy(data);
+}
+
+static
+void ctf_fs_trace_destroy(struct ctf_fs_trace *ctf_fs_trace)
+{
+       if (!ctf_fs_trace) {
+               return;
+       }
+
+       if (ctf_fs_trace->ds_file_groups) {
+               g_ptr_array_free(ctf_fs_trace->ds_file_groups, TRUE);
+       }
+
+       BT_TRACE_PUT_REF_AND_RESET(ctf_fs_trace->trace);
+
+       if (ctf_fs_trace->path) {
+               g_string_free(ctf_fs_trace->path, TRUE);
+       }
+
+       if (ctf_fs_trace->name) {
+               g_string_free(ctf_fs_trace->name, TRUE);
+       }
+
+       if (ctf_fs_trace->metadata) {
+               ctf_fs_metadata_fini(ctf_fs_trace->metadata);
+               g_free(ctf_fs_trace->metadata);
+       }
+
+       g_free(ctf_fs_trace);
+}
+
+static
+void ctf_fs_trace_destroy_notifier(void *data)
+{
+       struct ctf_fs_trace *trace = data;
+       ctf_fs_trace_destroy(trace);
+}
+
+struct ctf_fs_component *ctf_fs_component_create(void)
+{
+       struct ctf_fs_component *ctf_fs;
+
+       ctf_fs = g_new0(struct ctf_fs_component, 1);
+       if (!ctf_fs) {
+               goto error;
+       }
+
+       ctf_fs->port_data =
+               g_ptr_array_new_with_free_func(port_data_destroy_notifier);
+       if (!ctf_fs->port_data) {
+               goto error;
+       }
+
+       ctf_fs->traces =
+               g_ptr_array_new_with_free_func(ctf_fs_trace_destroy_notifier);
+       if (!ctf_fs->traces) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (ctf_fs) {
+               ctf_fs_destroy(ctf_fs);
+       }
+
+end:
+       return ctf_fs;
+}
+
+void ctf_fs_finalize(bt_self_component_source *component)
+{
+       ctf_fs_destroy(bt_self_component_get_data(
+               bt_self_component_source_as_self_component(component)));
+}
+
+gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group)
+{
+       GString *name = g_string_new(NULL);
+
+       /*
+        * The unique port name is generated by concatenating unique identifiers
+        * for:
+        *
+        *   - the trace
+        *   - the stream class
+        *   - the stream
+        */
+
+       /* For the trace, use the uuid if present, else the path. */
+       if (ds_file_group->ctf_fs_trace->metadata->tc->is_uuid_set) {
+               char uuid_str[BABELTRACE_UUID_STR_LEN];
+
+               bt_uuid_unparse(ds_file_group->ctf_fs_trace->metadata->tc->uuid, uuid_str);
+               g_string_assign(name, uuid_str);
+       } else {
+               g_string_assign(name, ds_file_group->ctf_fs_trace->path->str);
+       }
+
+       /*
+        * For the stream class, use the id if present.  We can omit this field
+        * otherwise, as there will only be a single stream class.
+        */
+       if (ds_file_group->sc->id != UINT64_C(-1)) {
+               g_string_append_printf(name, " | %" PRIu64, ds_file_group->sc->id);
+       }
+
+       /* For the stream, use the id if present, else, use the path. */
+       if (ds_file_group->stream_id != UINT64_C(-1)) {
+               g_string_append_printf(name, " | %" PRIu64, ds_file_group->stream_id);
+       } else {
+               BT_ASSERT(ds_file_group->ds_file_infos->len == 1);
+               struct ctf_fs_ds_file_info *ds_file_info =
+                       g_ptr_array_index(ds_file_group->ds_file_infos, 0);
+               g_string_append_printf(name, " | %s", ds_file_info->path->str);
+       }
+
+       return g_string_free(name, FALSE);
+}
+
+static
+int create_one_port_for_trace(struct ctf_fs_component *ctf_fs,
+               struct ctf_fs_trace *ctf_fs_trace,
+               struct ctf_fs_ds_file_group *ds_file_group)
+{
+       int ret = 0;
+       struct ctf_fs_port_data *port_data = NULL;
+       gchar *port_name;
+
+       port_name = ctf_fs_make_port_name(ds_file_group);
+       if (!port_name) {
+               goto error;
+       }
+
+       BT_LOGD("Creating one port named `%s`", port_name);
+
+       /* Create output port for this file */
+       port_data = g_new0(struct ctf_fs_port_data, 1);
+       if (!port_data) {
+               goto error;
+       }
+
+       port_data->ctf_fs = ctf_fs;
+       port_data->ds_file_group = ds_file_group;
+       ret = bt_self_component_source_add_output_port(
+               ctf_fs->self_comp, port_name, port_data, NULL);
+       if (ret) {
+               goto error;
+       }
+
+       g_ptr_array_add(ctf_fs->port_data, port_data);
+       port_data = NULL;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       if (port_name) {
+               g_free(port_name);
+       }
+
+       port_data_destroy(port_data);
+       return ret;
+}
+
+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;
+}
+
+static
+void ctf_fs_ds_file_info_destroy(struct ctf_fs_ds_file_info *ds_file_info)
+{
+       if (!ds_file_info) {
+               return;
+       }
+
+       if (ds_file_info->path) {
+               g_string_free(ds_file_info->path, TRUE);
+       }
+
+       g_free(ds_file_info);
+}
+
+static
+struct ctf_fs_ds_file_info *ctf_fs_ds_file_info_create(const char *path,
+               int64_t begin_ns)
+{
+       struct ctf_fs_ds_file_info *ds_file_info;
+
+       ds_file_info = g_new0(struct ctf_fs_ds_file_info, 1);
+       if (!ds_file_info) {
+               goto end;
+       }
+
+       ds_file_info->path = g_string_new(path);
+       if (!ds_file_info->path) {
+               ctf_fs_ds_file_info_destroy(ds_file_info);
+               ds_file_info = NULL;
+               goto end;
+       }
+
+       ds_file_info->begin_ns = begin_ns;
+
+end:
+       return ds_file_info;
+}
+
+static
+void ctf_fs_ds_file_group_destroy(struct ctf_fs_ds_file_group *ds_file_group)
+{
+       if (!ds_file_group) {
+               return;
+       }
+
+       if (ds_file_group->ds_file_infos) {
+               g_ptr_array_free(ds_file_group->ds_file_infos, TRUE);
+       }
+
+       if (ds_file_group->index) {
+               if (ds_file_group->index->entries) {
+                       g_ptr_array_free(ds_file_group->index->entries, TRUE);
+               }
+               g_free(ds_file_group->index);
+       }
+
+       bt_stream_put_ref(ds_file_group->stream);
+       g_free(ds_file_group);
+}
+
+static
+struct ctf_fs_ds_file_group *ctf_fs_ds_file_group_create(
+               struct ctf_fs_trace *ctf_fs_trace,
+               struct ctf_stream_class *sc,
+               uint64_t stream_instance_id,
+               struct ctf_fs_ds_index *index)
+{
+       struct ctf_fs_ds_file_group *ds_file_group;
+
+       ds_file_group = g_new0(struct ctf_fs_ds_file_group, 1);
+       if (!ds_file_group) {
+               goto error;
+       }
+
+       ds_file_group->ds_file_infos = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) ctf_fs_ds_file_info_destroy);
+       if (!ds_file_group->ds_file_infos) {
+               goto error;
+       }
+
+       ds_file_group->index = index;
+
+       ds_file_group->stream_id = stream_instance_id;
+       BT_ASSERT(sc);
+       ds_file_group->sc = sc;
+       ds_file_group->ctf_fs_trace = ctf_fs_trace;
+       goto end;
+
+error:
+       ctf_fs_ds_file_group_destroy(ds_file_group);
+       ctf_fs_ds_index_destroy(index);
+       ds_file_group = NULL;
+
+end:
+       return ds_file_group;
+}
+
+/* Replace by g_ptr_array_insert when we depend on glib >= 2.40. */
+static
+void array_insert(GPtrArray *array, gpointer element, size_t pos)
+{
+       size_t original_array_len = array->len;
+
+       /* Allocate an unused element at the end of the array. */
+       g_ptr_array_add(array, NULL);
+
+       /* If we are not inserting at the end, move the elements by one. */
+       if (pos < original_array_len) {
+               memmove(&(array->pdata[pos + 1]),
+                       &(array->pdata[pos]),
+                       (original_array_len - pos) * sizeof(gpointer));
+       }
+
+       /* Insert the value. */
+       array->pdata[pos] = element;
+}
+
+/*
+ * Insert ds_file_info in ds_file_group's list of ds_file_infos at the right
+ * place to keep it sorted.
+ */
+
+static
+void ds_file_group_insert_ds_file_info_sorted(
+               struct ctf_fs_ds_file_group *ds_file_group,
+               struct ctf_fs_ds_file_info *ds_file_info)
+{
+       guint i;
+
+       /* Find the spot where to insert this ds_file_info. */
+       for (i = 0; i < ds_file_group->ds_file_infos->len; i++) {
+               struct ctf_fs_ds_file_info *other_ds_file_info =
+                       g_ptr_array_index(ds_file_group->ds_file_infos, i);
+
+               if (ds_file_info->begin_ns < other_ds_file_info->begin_ns) {
+                       break;
+               }
+       }
+
+       array_insert(ds_file_group->ds_file_infos, ds_file_info, i);
+}
+
+static
+void ds_file_group_insert_ds_index_entry_sorted(
+       struct ctf_fs_ds_file_group *ds_file_group,
+       struct ctf_fs_ds_index_entry *entry)
+{
+       guint i;
+
+       /* Find the spot where to insert this index entry. */
+       for (i = 0; i < ds_file_group->index->entries->len; i++) {
+               struct ctf_fs_ds_index_entry *other_entry = g_ptr_array_index(
+                       ds_file_group->index->entries, i);
+
+               if (entry->timestamp_begin_ns < other_entry->timestamp_begin_ns) {
+                       break;
+               }
+       }
+
+       array_insert(ds_file_group->index->entries, entry, i);
+}
+
+/*
+ * Create a new ds_file_info using the provided path, begin_ns and index, then
+ * add it to ds_file_group's list of ds_file_infos.
+ */
+
+static
+int ctf_fs_ds_file_group_add_ds_file_info(
+               struct ctf_fs_ds_file_group *ds_file_group,
+               const char *path, int64_t begin_ns)
+{
+       struct ctf_fs_ds_file_info *ds_file_info;
+       int ret = 0;
+
+       ds_file_info = ctf_fs_ds_file_info_create(path, begin_ns);
+       if (!ds_file_info) {
+               goto error;
+       }
+
+       ds_file_group_insert_ds_file_info_sorted(ds_file_group, ds_file_info);
+
+       ds_file_info = NULL;
+       goto end;
+
+error:
+       ctf_fs_ds_file_info_destroy(ds_file_info);
+       ret = -1;
+end:
+       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), index);
+               /* Ownership of index is transferred. */
+               index = NULL;
+
+               if (!ds_file_group) {
+                       goto error;
+               }
+
+               ret = ctf_fs_ds_file_group_add_ds_file_info(ds_file_group,
+                       path, begin_ns);
+               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, index);
+               /* Ownership of index is transferred. */
+               index = NULL;
+               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);
+       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;
+}
+
+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 set_trace_name(bt_trace *trace, const char *name_suffix)
+{
+       int ret = 0;
+       const bt_trace_class *tc = bt_trace_borrow_class_const(trace);
+       const bt_value *val;
+       GString *name;
+
+       name = g_string_new(NULL);
+       if (!name) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Check if we have a trace environment string value named `hostname`.
+        * If so, use it as the trace name's prefix.
+        */
+       val = bt_trace_class_borrow_environment_entry_value_by_name_const(
+               tc, "hostname");
+       if (val && bt_value_is_string(val)) {
+               g_string_append(name, bt_value_string_get(val));
+
+               if (name_suffix) {
+                       g_string_append_c(name, G_DIR_SEPARATOR);
+               }
+       }
+
+       if (name_suffix) {
+               g_string_append(name, name_suffix);
+       }
+
+       ret = bt_trace_set_name(trace, name->str);
+       if (ret) {
+               goto end;
+       }
+
+       goto end;
+
+end:
+       if (name) {
+               g_string_free(name, TRUE);
+       }
+
+       return ret;
+}
+
+static
+struct ctf_fs_trace *ctf_fs_trace_create(bt_self_component_source *self_comp,
+               const char *path, const char *name,
+               struct ctf_fs_metadata_config *metadata_config)
+{
+       struct ctf_fs_trace *ctf_fs_trace;
+       int ret;
+
+       ctf_fs_trace = g_new0(struct ctf_fs_trace, 1);
+       if (!ctf_fs_trace) {
+               goto end;
+       }
+
+       ctf_fs_trace->path = g_string_new(path);
+       if (!ctf_fs_trace->path) {
+               goto error;
+       }
+
+       ctf_fs_trace->name = g_string_new(name);
+       if (!ctf_fs_trace->name) {
+               goto error;
+       }
+
+       ctf_fs_trace->metadata = g_new0(struct ctf_fs_metadata, 1);
+       if (!ctf_fs_trace->metadata) {
+               goto error;
+       }
+
+       ctf_fs_metadata_init(ctf_fs_trace->metadata);
+       ctf_fs_trace->ds_file_groups = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) ctf_fs_ds_file_group_destroy);
+       if (!ctf_fs_trace->ds_file_groups) {
+               goto error;
+       }
+
+       ret = ctf_fs_metadata_set_trace_class(self_comp,
+               ctf_fs_trace, metadata_config);
+       if (ret) {
+               goto error;
+       }
+
+       if (ctf_fs_trace->metadata->trace_class) {
+               ctf_fs_trace->trace =
+                       bt_trace_create(ctf_fs_trace->metadata->trace_class);
+               if (!ctf_fs_trace->trace) {
+                       goto error;
+               }
+       }
+
+       if (ctf_fs_trace->trace) {
+               ret = set_trace_name(ctf_fs_trace->trace, name);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       ret = create_ds_file_groups(ctf_fs_trace);
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ctf_fs_trace_destroy(ctf_fs_trace);
+       ctf_fs_trace = NULL;
+
+end:
+       return ctf_fs_trace;
+}
+
+static
+int path_is_ctf_trace(const char *path)
+{
+       GString *metadata_path = g_string_new(NULL);
+       int ret = 0;
+
+       if (!metadata_path) {
+               ret = -1;
+               goto end;
+       }
+
+       g_string_printf(metadata_path, "%s" G_DIR_SEPARATOR_S "%s", path, CTF_FS_METADATA_FILENAME);
+
+       if (g_file_test(metadata_path->str, G_FILE_TEST_IS_REGULAR)) {
+               ret = 1;
+               goto end;
+       }
+
+end:
+       g_string_free(metadata_path, TRUE);
+       return ret;
+}
+
+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;
+}
+
+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
+GList *ctf_fs_create_trace_names(GList *trace_paths, const char *base_path) {
+       GList *trace_names = NULL;
+       GList *node;
+       const char *last_sep;
+       size_t base_dist;
+
+       /*
+        * At this point we know that all the trace paths are
+        * normalized, and so is the base path. This means that
+        * they are absolute and they don't end with a separator.
+        * We can simply find the location of the last separator
+        * in the base path, which gives us the name of the actual
+        * directory to look into, and use this location as the
+        * start of each trace name within each trace path.
+        *
+        * For example:
+        *
+        *     Base path: /home/user/my-traces/some-trace
+        *     Trace paths:
+        *       - /home/user/my-traces/some-trace/host1/trace1
+        *       - /home/user/my-traces/some-trace/host1/trace2
+        *       - /home/user/my-traces/some-trace/host2/trace
+        *       - /home/user/my-traces/some-trace/other-trace
+        *
+        * In this case the trace names are:
+        *
+        *       - some-trace/host1/trace1
+        *       - some-trace/host1/trace2
+        *       - some-trace/host2/trace
+        *       - some-trace/other-trace
+        */
+       last_sep = strrchr(base_path, G_DIR_SEPARATOR);
+
+       /* We know there's at least one separator */
+       BT_ASSERT(last_sep);
+
+       /* Distance to base */
+       base_dist = last_sep - base_path + 1;
+
+       /* Create the trace names */
+       for (node = trace_paths; node; node = g_list_next(node)) {
+               GString *trace_name = g_string_new(NULL);
+               GString *trace_path = node->data;
+
+               BT_ASSERT(trace_name);
+               g_string_assign(trace_name, &trace_path->str[base_dist]);
+               trace_names = g_list_append(trace_names, trace_name);
+       }
+
+       return trace_names;
+}
+
+/* Helper for ctf_fs_component_create_ctf_fs_traces, to handle a single path/root. */
+
+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;
+}
+
+/* GCompareFunc to sort traces by UUID. */
+
+static
+gint sort_traces_by_uuid(gconstpointer a, gconstpointer b)
+{
+       const struct ctf_fs_trace *trace_a = *((const struct ctf_fs_trace **) a);
+       const struct ctf_fs_trace *trace_b = *((const struct ctf_fs_trace **) b);
+
+       bool trace_a_has_uuid = trace_a->metadata->tc->is_uuid_set;
+       bool trace_b_has_uuid = trace_b->metadata->tc->is_uuid_set;
+       gint ret;
+
+       /* Order traces without uuid first. */
+       if (!trace_a_has_uuid && trace_b_has_uuid) {
+               ret = -1;
+       } else if (trace_a_has_uuid && !trace_b_has_uuid) {
+               ret = 1;
+       } else if (!trace_a_has_uuid && !trace_b_has_uuid) {
+               ret = 0;
+       } else {
+               ret = bt_uuid_compare(trace_a->metadata->tc->uuid, trace_b->metadata->tc->uuid);
+       }
+
+       return ret;
+}
+
+/*
+ * Count the number of stream and event classes defined by this trace's metadata.
+ *
+ * This is used to determine which metadata is the "latest", out of multiple
+ * traces sharing the same UUID.  It is assumed that amongst all these metadatas,
+ * a bigger metadata is a superset of a smaller metadata.  Therefore, it is
+ * enough to just count the classes.
+ */
+
+static
+unsigned int metadata_count_stream_and_event_classes(struct ctf_fs_trace *trace)
+{
+       unsigned int num = trace->metadata->tc->stream_classes->len;
+       guint i;
+
+       for (i = 0; i < trace->metadata->tc->stream_classes->len; i++) {
+               struct ctf_stream_class *sc = trace->metadata->tc->stream_classes->pdata[i];
+               num += sc->event_classes->len;
+       }
+
+       return num;
+}
+
+/*
+ * Merge the src ds_file_group into dest.  This consists of merging their
+ * ds_file_infos, making sure to keep the result sorted.
+ */
+
+static
+void merge_ctf_fs_ds_file_groups(struct ctf_fs_ds_file_group *dest, struct ctf_fs_ds_file_group *src)
+{
+       guint i;
+
+       for (i = 0; i < src->ds_file_infos->len; i++) {
+               struct ctf_fs_ds_file_info *ds_file_info =
+                       g_ptr_array_index(src->ds_file_infos, i);
+
+               /* Ownership of the ds_file_info is transferred to dest. */
+               g_ptr_array_index(src->ds_file_infos, i) = NULL;
+
+               ds_file_group_insert_ds_file_info_sorted(dest, ds_file_info);
+       }
+
+       /* Merge both indexes. */
+       for (i = 0; i < src->index->entries->len; i++) {
+               struct ctf_fs_ds_index_entry *entry = g_ptr_array_index(
+                       src->index->entries, i);
+
+               /*
+                * Ownership of the ctf_fs_ds_index_entry is transferred to
+                * dest.
+                */
+               g_ptr_array_index(src->index->entries, i) = NULL;
+
+               ds_file_group_insert_ds_index_entry_sorted(dest, entry);
+       }
+}
+/* Merge src_trace's data stream file groups into dest_trace's. */
+
+static
+int merge_matching_ctf_fs_ds_file_groups(
+               struct ctf_fs_trace *dest_trace,
+               struct ctf_fs_trace *src_trace)
+{
+
+       GPtrArray *dest = dest_trace->ds_file_groups;
+       GPtrArray *src = src_trace->ds_file_groups;
+       guint s_i;
+       int ret = 0;
+
+       /*
+        * Save the initial length of dest: we only want to check against the
+        * original elements in the inner loop.
+        */
+       const guint dest_len = dest->len;
+
+       for (s_i = 0; s_i < src->len; s_i++) {
+               struct ctf_fs_ds_file_group *src_group = g_ptr_array_index(src, s_i);
+               struct ctf_fs_ds_file_group *dest_group = NULL;
+
+               /* A stream instance without ID can't match a stream in the other trace.  */
+               if (src_group->stream_id != -1) {
+                       guint d_i;
+
+                       /* Let's search for a matching ds_file_group in the destination.  */
+                       for (d_i = 0; d_i < dest_len; d_i++) {
+                               struct ctf_fs_ds_file_group *candidate_dest = g_ptr_array_index(dest, d_i);
+
+                               /* Can't match a stream instance without ID.  */
+                               if (candidate_dest->stream_id == -1) {
+                                       continue;
+                               }
+
+                               /*
+                                * If the two groups have the same stream instance id
+                                * and belong to the same stream class (stream instance
+                                * ids are per-stream class), they represent the same
+                                * stream instance.
+                                */
+                               if (candidate_dest->stream_id != src_group->stream_id ||
+                                               candidate_dest->sc->id != src_group->sc->id) {
+                                       continue;
+                               }
+
+                               dest_group = candidate_dest;
+                               break;
+                       }
+               }
+
+               /*
+                * Didn't find a friend in dest to merge our src_group into?
+                * Create a new empty one. This can happen if a stream was
+                * active in the source trace chunk but not in the destination
+                * trace chunk.
+                */
+               if (!dest_group) {
+                       struct ctf_stream_class *sc;
+                       struct ctf_fs_ds_index *index;
+
+                       sc = ctf_trace_class_borrow_stream_class_by_id(
+                               dest_trace->metadata->tc, src_group->sc->id);
+                       BT_ASSERT(sc);
+
+                       index = ctf_fs_ds_index_create();
+                       if (!index) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       dest_group = ctf_fs_ds_file_group_create(dest_trace, sc,
+                               src_group->stream_id, index);
+                       /* Ownership of index is transferred. */
+                       index = NULL;
+                       if (!dest_group) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       g_ptr_array_add(dest_trace->ds_file_groups, dest_group);
+               }
+
+               BT_ASSERT(dest_group);
+               merge_ctf_fs_ds_file_groups(dest_group, src_group);
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Collapse the given traces, which must all share the same UUID, in a single
+ * one.
+ *
+ * The trace with the most expansive metadata is chosen and all other traces
+ * are merged into that one.  The array slots of all the traces that get merged
+ * in the chosen one are set to NULL, so only the slot of the chosen trace
+ * remains non-NULL.
+ */
+
+static
+int merge_ctf_fs_traces(struct ctf_fs_trace **traces, unsigned int num_traces)
+{
+       unsigned int winner_count;
+       struct ctf_fs_trace *winner;
+       guint i;
+       int ret = 0;
+       char uuid_str[BABELTRACE_UUID_STR_LEN];
+
+       BT_ASSERT(num_traces >= 2);
+
+       winner_count = metadata_count_stream_and_event_classes(traces[0]);
+       winner = traces[0];
+
+       /* Find the trace with the largest metadata. */
+       for (i = 1; i < num_traces; i++) {
+               struct ctf_fs_trace *candidate;
+               unsigned int candidate_count;
+
+               candidate = traces[i];
+
+               /* A bit of sanity check. */
+               BT_ASSERT(bt_uuid_compare(winner->metadata->tc->uuid, candidate->metadata->tc->uuid) == 0);
+
+               candidate_count = metadata_count_stream_and_event_classes(candidate);
+
+               if (candidate_count > winner_count) {
+                       winner_count = candidate_count;
+                       winner = candidate;
+               }
+       }
+
+       /* Merge all the other traces in the winning trace. */
+       for (i = 0; i < num_traces; i++) {
+               struct ctf_fs_trace *trace = traces[i];
+
+               /* Don't merge the winner into itself. */
+               if (trace == winner) {
+                       continue;
+               }
+
+               /* Merge trace's data stream file groups into winner's. */
+               ret = merge_matching_ctf_fs_ds_file_groups(winner, trace);
+               if (ret) {
+                       goto end;
+               }
+
+               /* Free the trace that got merged into winner, clear the slot in the array. */
+               ctf_fs_trace_destroy(trace);
+               traces[i] = NULL;
+       }
+
+       /* Use the string representation of the UUID as the trace name. */
+       bt_uuid_unparse(winner->metadata->tc->uuid, uuid_str);
+       g_string_printf(winner->name, "%s", uuid_str);
+
+end:
+       return ret;
+}
+
+/*
+ * Merge all traces of `ctf_fs` that share the same UUID in a single trace.
+ * Traces with no UUID are not merged.
+ */
+
+static
+int merge_traces_with_same_uuid(struct ctf_fs_component *ctf_fs)
+{
+       GPtrArray *traces = ctf_fs->traces;
+       guint range_start_idx = 0;
+       unsigned int num_traces = 0;
+       guint i;
+       int ret = 0;
+
+       /* Sort the traces by uuid, then collapse traces with the same uuid in a single one. */
+       g_ptr_array_sort(traces, sort_traces_by_uuid);
+
+       /* Find ranges of consecutive traces that share the same UUID.  */
+       while (range_start_idx < traces->len) {
+               guint range_len;
+               struct ctf_fs_trace *range_start_trace = g_ptr_array_index(traces, range_start_idx);
+
+               /* Exclusive end of range. */
+               guint range_end_exc_idx = range_start_idx + 1;
+
+               while (range_end_exc_idx < traces->len) {
+                       struct ctf_fs_trace *this_trace = g_ptr_array_index(traces, range_end_exc_idx);
+
+                       if (!range_start_trace->metadata->tc->is_uuid_set ||
+                               (bt_uuid_compare(range_start_trace->metadata->tc->uuid, this_trace->metadata->tc->uuid) != 0)) {
+                               break;
+                       }
+
+                       range_end_exc_idx++;
+               }
+
+               /* If we have two or more traces with matching UUIDs, merge them. */
+               range_len = range_end_exc_idx - range_start_idx;
+               if (range_len > 1) {
+                       struct ctf_fs_trace **range_start = (struct ctf_fs_trace **) &traces->pdata[range_start_idx];
+                       ret = merge_ctf_fs_traces(range_start, range_len);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+
+               num_traces++;
+               range_start_idx = range_end_exc_idx;
+       }
+
+       /* Clear any NULL slot (traces that got merged in another one) in the array.  */
+       for (i = 0; i < traces->len;) {
+               if (g_ptr_array_index(traces, i) == NULL) {
+                       g_ptr_array_remove_index_fast(traces, i);
+               } else {
+                       i++;
+               }
+       }
+
+       BT_ASSERT(num_traces == traces->len);
+
+end:
+       return ret;
+}
+
+int ctf_fs_component_create_ctf_fs_traces(bt_self_component_source *self_comp,
+               struct ctf_fs_component *ctf_fs,
+               const bt_value *paths_value)
+{
+       int ret = 0;
+       uint64_t i;
+
+       for (i = 0; i < bt_value_array_get_size(paths_value); i++) {
+               const bt_value *path_value = bt_value_array_borrow_element_by_index_const(paths_value, i);
+               const char *path = bt_value_string_get(path_value);
+
+               ret = ctf_fs_component_create_ctf_fs_traces_one_root(self_comp, ctf_fs, path);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = merge_traces_with_same_uuid(ctf_fs);
+
+end:
+       return ret;
+}
+
+static
+GString *get_stream_instance_unique_name(
+               struct ctf_fs_ds_file_group *ds_file_group)
+{
+       GString *name;
+       struct ctf_fs_ds_file_info *ds_file_info;
+
+       name = g_string_new(NULL);
+       if (!name) {
+               goto end;
+       }
+
+       /*
+        * If there's more than one stream file in the stream file
+        * group, the first (earliest) stream file's path is used as
+        * the stream's unique name.
+        */
+       BT_ASSERT(ds_file_group->ds_file_infos->len > 0);
+       ds_file_info = g_ptr_array_index(ds_file_group->ds_file_infos, 0);
+       g_string_assign(name, ds_file_info->path->str);
+
+end:
+       return name;
+}
+
+/* Create the IR stream objects for ctf_fs_trace. */
+
+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;
+}
+
+/*
+ * Validate the "paths" parameter passed to this component.  It must be
+ * present, and it must be an array of strings.
+ */
+
+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;
+}
+
+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;
+}
+
+static
+struct ctf_fs_component *ctf_fs_create(
+               bt_self_component_source *self_comp,
+               const bt_value *params)
+{
+       struct ctf_fs_component *ctf_fs = NULL;
+       guint i;
+       const bt_value *paths_value;
+
+       ctf_fs = ctf_fs_component_create();
+       if (!ctf_fs) {
+               goto error;
+       }
+
+       if (!read_src_fs_parameters(params, &paths_value, ctf_fs)) {
+               goto error;
+       }
+
+       bt_self_component_set_data(
+               bt_self_component_source_as_self_component(self_comp),
+               ctf_fs);
+
+       /*
+        * We don't need to get a new reference here because as long as
+        * our private ctf_fs_component object exists, the containing
+        * private component should also exist.
+        */
+       ctf_fs->self_comp = self_comp;
+
+       if (ctf_fs_component_create_ctf_fs_traces(self_comp, ctf_fs, paths_value)) {
+               goto error;
+       }
+
+       for (i = 0; i < ctf_fs->traces->len; i++) {
+               struct ctf_fs_trace *trace = g_ptr_array_index(ctf_fs->traces, i);
+
+               if (create_streams_for_trace(trace)) {
+                       goto error;
+               }
+
+               if (create_ports_for_trace(ctf_fs, trace)) {
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       ctf_fs_destroy(ctf_fs);
+       ctf_fs = NULL;
+       bt_self_component_set_data(
+               bt_self_component_source_as_self_component(self_comp),
+               NULL);
+
+end:
+       return ctf_fs;
+}
+
+BT_HIDDEN
+bt_self_component_status ctf_fs_init(
+               bt_self_component_source *self_comp,
+               const bt_value *params, UNUSED_VAR void *init_method_data)
+{
+       struct ctf_fs_component *ctf_fs;
+       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
+
+       ctf_fs = ctf_fs_create(self_comp, params);
+       if (!ctf_fs) {
+               ret = BT_SELF_COMPONENT_STATUS_ERROR;
+       }
+
+       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;
+}
diff --git a/src/plugins/ctf/fs-src/fs.h b/src/plugins/ctf/fs-src/fs.h
new file mode 100644 (file)
index 0000000..33e1f56
--- /dev/null
@@ -0,0 +1,265 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_H
+#define BABELTRACE_PLUGIN_CTF_FS_H
+
+/*
+ * BabelTrace - CTF on File System Component
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+#include "data-stream-file.h"
+#include "metadata.h"
+#include "../common/metadata/decoder.h"
+
+BT_HIDDEN
+extern bool ctf_fs_debug;
+
+struct ctf_fs_file {
+       /* Owned by this */
+       GString *path;
+
+       /* Owned by this */
+       FILE *fp;
+
+       off_t size;
+};
+
+struct ctf_fs_metadata {
+       /* Owned by this */
+       struct ctf_metadata_decoder *decoder;
+
+       /* Owned by this */
+       bt_trace_class *trace_class;
+
+       /* Weak (owned by `decoder` above) */
+       struct ctf_trace_class *tc;
+
+       /* Owned by this */
+
+       /* Owned by this */
+       char *text;
+
+       int bo;
+};
+
+struct ctf_fs_component {
+       /* Weak, guaranteed to exist */
+       bt_self_component_source *self_comp;
+
+       /* Array of struct ctf_fs_port_data *, owned by this */
+       GPtrArray *port_data;
+
+       /* Array of struct ctf_fs_trace *, owned by this */
+       GPtrArray *traces;
+
+       struct ctf_fs_metadata_config metadata_config;
+};
+
+struct ctf_fs_trace {
+       /* Owned by this */
+       struct ctf_fs_metadata *metadata;
+
+       /* Owned by this */
+       bt_trace *trace;
+
+       /* Array of struct ctf_fs_ds_file_group *, owned by this */
+       GPtrArray *ds_file_groups;
+
+       /* Owned by this */
+       GString *path;
+
+       /* Owned by this */
+       GString *name;
+
+       /* Next automatic stream ID when not provided by packet header */
+       uint64_t next_stream_id;
+};
+
+struct ctf_fs_ds_index_entry {
+       /* Position, in bytes, of the packet from the beginning of the file. */
+       uint64_t offset;
+
+       /* Size of the packet, in bytes. */
+       uint64_t packet_size;
+
+       /*
+        * Extracted from the packet context, relative to the respective fields'
+        * mapped clock classes (in cycles).
+        */
+       uint64_t timestamp_begin, timestamp_end;
+
+       /*
+        * Converted from the packet context, relative to the trace's EPOCH
+        * (in ns since EPOCH).
+        */
+       int64_t timestamp_begin_ns, timestamp_end_ns;
+};
+
+struct ctf_fs_ds_index {
+       /* Array of pointer to struct ctf_fs_fd_index_entry. */
+       GPtrArray *entries;
+};
+
+struct ctf_fs_ds_file_group {
+       /*
+        * Array of struct ctf_fs_ds_file_info, owned by this.
+        *
+        * This is an _ordered_ array of data stream file infos which
+        * belong to this group (a single stream instance).
+        *
+        * You can call ctf_fs_ds_file_create() with one of those paths
+        * and the trace IR stream below.
+        */
+       GPtrArray *ds_file_infos;
+
+       /* Owned by this */
+       struct ctf_stream_class *sc;
+
+       /* Owned by this */
+       bt_stream *stream;
+
+       /* Stream (instance) ID; -1ULL means none */
+       uint64_t stream_id;
+
+       /* Weak, belongs to component */
+       struct ctf_fs_trace *ctf_fs_trace;
+
+       /*
+        * Owned by this. May be NULL.
+        *
+        * A stream cannot be assumed to be indexed as the indexing might have
+        * been skipped. Moreover, the index's fields may not all be available
+        * depending on the producer (e.g. timestamp_begin/end are not
+        * mandatory).
+        */
+       struct ctf_fs_ds_index *index;
+};
+
+struct ctf_fs_port_data {
+       /* Weak, belongs to ctf_fs_trace */
+       struct ctf_fs_ds_file_group *ds_file_group;
+
+       /* Weak */
+       struct ctf_fs_component *ctf_fs;
+};
+
+struct ctf_fs_msg_iter_data {
+       /* Weak */
+       bt_self_message_iterator *pc_msg_iter;
+
+       /* Weak, belongs to ctf_fs_trace */
+       struct ctf_fs_ds_file_group *ds_file_group;
+
+       /* Owned by this */
+       struct ctf_fs_ds_file *ds_file;
+
+       /* Which file the iterator is _currently_ operating on */
+       size_t ds_file_info_index;
+
+       /* Owned by this */
+       struct bt_msg_iter *msg_iter;
+};
+
+BT_HIDDEN
+bt_self_component_status ctf_fs_init(
+               bt_self_component_source *source,
+               const bt_value *params, void *init_method_data);
+
+BT_HIDDEN
+void ctf_fs_finalize(bt_self_component_source *component);
+
+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_HIDDEN
+bt_self_message_iterator_status ctf_fs_iterator_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_source *self_comp,
+               bt_self_component_port_output *self_port);
+
+BT_HIDDEN
+void ctf_fs_iterator_finalize(bt_self_message_iterator *it);
+
+BT_HIDDEN
+bt_self_message_iterator_status ctf_fs_iterator_next(
+               bt_self_message_iterator *iterator,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count);
+
+BT_HIDDEN
+bt_self_message_iterator_status ctf_fs_iterator_seek_beginning(
+               bt_self_message_iterator *message_iterator);
+
+/* Create and initialize a new, empty ctf_fs_component. */
+
+BT_HIDDEN
+struct ctf_fs_component *ctf_fs_component_create(void);
+
+/*
+ * Search recursively under all paths in `paths_value` (an array of strings),
+ * for CTF traces. For each CTF trace found, create a ctf_fs_trace in
+ * `ctf_fs` representing that trace.
+ */
+
+BT_HIDDEN
+int ctf_fs_component_create_ctf_fs_traces(bt_self_component_source *self_comp,
+               struct ctf_fs_component *ctf_fs,
+               const bt_value *paths_value);
+
+/* Free `ctf_fs` and everything it owns. */
+
+BT_HIDDEN
+void ctf_fs_destroy(struct ctf_fs_component *ctf_fs);
+
+/*
+ * Read and validate parameters taken by the src.ctf.fs plugin.
+ *
+ *  - The mandatory `paths` parameter is returned in `*paths`.
+ *  - The optional `clock-class-offset-s` and `clock-class-offset-ns`, if
+ *    present, are recorded in the `ctf_fs` structure.
+ *
+ * Return true on success, false if any parameter didn't pass validation.
+ */
+
+BT_HIDDEN
+bool read_src_fs_parameters(const bt_value *params,
+               const bt_value **paths, struct ctf_fs_component *ctf_fs);
+
+/*
+ * Generate the port name to be used for a given data stream file group.
+ *
+ * The result must be freed using g_free by the caller.
+ */
+
+BT_HIDDEN
+gchar *ctf_fs_make_port_name(struct ctf_fs_ds_file_group *ds_file_group);
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_H */
diff --git a/src/plugins/ctf/fs-src/logging.c b/src/plugins/ctf/fs-src/logging.c
new file mode 100644 (file)
index 0000000..e9e5862
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL ctf_fs_src_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(BT_LOG_OUTPUT_LEVEL, "BABELTRACE_SRC_CTF_FS_LOG_LEVEL");
diff --git a/src/plugins/ctf/fs-src/logging.h b/src/plugins/ctf/fs-src/logging.h
new file mode 100644 (file)
index 0000000..2f52057
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef CTF_FS_SRC_LOGGING_H
+#define CTF_FS_SRC_LOGGING_H
+
+#define BT_LOG_OUTPUT_LEVEL ctf_fs_src_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(ctf_fs_src_log_level);
+
+#endif /* CTF_FS_SRC_LOGGING_H */
diff --git a/src/plugins/ctf/fs-src/lttng-index.h b/src/plugins/ctf/fs-src/lttng-index.h
new file mode 100644 (file)
index 0000000..2374771
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
+ *                      Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *                      David Goulet <dgoulet@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef LTTNG_INDEX_H
+#define LTTNG_INDEX_H
+
+#include "compat/limits.h"
+
+#define CTF_INDEX_MAGIC 0xC1F1DCC1
+#define CTF_INDEX_MAJOR 1
+#define CTF_INDEX_MINOR 1
+
+/*
+ * Header at the beginning of each index file.
+ * All integer fields are stored in big endian.
+ */
+struct ctf_packet_index_file_hdr {
+       uint32_t magic;
+       uint32_t index_major;
+       uint32_t index_minor;
+       /* size of struct ctf_packet_index, in bytes. */
+       uint32_t packet_index_len;
+} __attribute__((__packed__));
+
+/*
+ * Packet index generated for each trace packet store in a trace file.
+ * All integer fields are stored in big endian.
+ */
+struct ctf_packet_index {
+       uint64_t offset;                /* offset of the packet in the file, in bytes */
+       uint64_t packet_size;           /* packet size, in bits */
+       uint64_t content_size;          /* content size, in bits */
+       uint64_t timestamp_begin;
+       uint64_t timestamp_end;
+       uint64_t events_discarded;
+       uint64_t stream_id;
+       /* CTF_INDEX 1.0 limit */
+       uint64_t stream_instance_id;    /* ID of the channel instance */
+       uint64_t packet_seq_num;        /* packet sequence number */
+} __attribute__((__packed__));
+
+#endif /* LTTNG_INDEX_H */
diff --git a/src/plugins/ctf/fs-src/metadata.c b/src/plugins/ctf/fs-src/metadata.c
new file mode 100644 (file)
index 0000000..3074461
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
+ *
+ * Some functions are based on older functions written by Mathieu Desnoyers.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "common/assert.h"
+#include <glib.h>
+#include "compat/uuid.h"
+#include "compat/memstream.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "fs.h"
+#include "file.h"
+#include "metadata.h"
+#include "../common/metadata/decoder.h"
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-METADATA-SRC"
+#include "logging.h"
+
+BT_HIDDEN
+FILE *ctf_fs_metadata_open_file(const char *trace_path)
+{
+       GString *metadata_path;
+       FILE *fp = NULL;
+
+       metadata_path = g_string_new(trace_path);
+       if (!metadata_path) {
+               goto end;
+       }
+
+       g_string_append(metadata_path, G_DIR_SEPARATOR_S CTF_FS_METADATA_FILENAME);
+       fp = fopen(metadata_path->str, "rb");
+       g_string_free(metadata_path, TRUE);
+end:
+       return fp;
+}
+
+static struct ctf_fs_file *get_file(const char *trace_path)
+{
+       struct ctf_fs_file *file = ctf_fs_file_create();
+
+       if (!file) {
+               goto error;
+       }
+
+       g_string_append(file->path, trace_path);
+       g_string_append(file->path, G_DIR_SEPARATOR_S CTF_FS_METADATA_FILENAME);
+
+       if (ctf_fs_file_open(file, "rb")) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       if (file) {
+               ctf_fs_file_destroy(file);
+               file = NULL;
+       }
+
+end:
+       return file;
+}
+
+BT_HIDDEN
+int ctf_fs_metadata_set_trace_class(
+               bt_self_component_source *self_comp,
+               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_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;
+       }
+
+       ctf_fs_trace->metadata->decoder = ctf_metadata_decoder_create(self_comp,
+               config ? &decoder_config : NULL);
+       if (!ctf_fs_trace->metadata->decoder) {
+               BT_LOGE("Cannot create metadata decoder object");
+               ret = -1;
+               goto end;
+       }
+
+       ret = ctf_metadata_decoder_decode(ctf_fs_trace->metadata->decoder,
+               file->fp);
+       if (ret) {
+               BT_LOGE("Cannot decode metadata file");
+               goto end;
+       }
+
+       ctf_fs_trace->metadata->trace_class =
+               ctf_metadata_decoder_get_ir_trace_class(
+                       ctf_fs_trace->metadata->decoder);
+       BT_ASSERT(!self_comp || ctf_fs_trace->metadata->trace_class);
+       ctf_fs_trace->metadata->tc =
+               ctf_metadata_decoder_borrow_ctf_trace_class(
+                       ctf_fs_trace->metadata->decoder);
+       BT_ASSERT(ctf_fs_trace->metadata->tc);
+
+end:
+       ctf_fs_file_destroy(file);
+       return ret;
+}
+
+BT_HIDDEN
+int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata)
+{
+       /* Nothing to initialize for the moment. */
+       return 0;
+}
+
+BT_HIDDEN
+void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata)
+{
+       if (metadata->text) {
+               free(metadata->text);
+       }
+
+       if (metadata->trace_class) {
+               BT_TRACE_CLASS_PUT_REF_AND_RESET(metadata->trace_class);
+       }
+
+       if (metadata->decoder) {
+               ctf_metadata_decoder_destroy(metadata->decoder);
+       }
+}
diff --git a/src/plugins/ctf/fs-src/metadata.h b/src/plugins/ctf/fs-src/metadata.h
new file mode 100644 (file)
index 0000000..414b875
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef CTF_FS_METADATA_H
+#define CTF_FS_METADATA_H
+
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+#define CTF_FS_METADATA_FILENAME       "metadata"
+
+struct ctf_fs_trace;
+struct ctf_fs_metadata;
+
+struct ctf_fs_metadata_config {
+       int64_t clock_class_offset_s;
+       int64_t clock_class_offset_ns;
+};
+
+BT_HIDDEN
+int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata);
+
+BT_HIDDEN
+void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata);
+
+BT_HIDDEN
+int ctf_fs_metadata_set_trace_class(bt_self_component_source *self_comp,
+               struct ctf_fs_trace *ctf_fs_trace,
+               struct ctf_fs_metadata_config *config);
+
+BT_HIDDEN
+FILE *ctf_fs_metadata_open_file(const char *trace_path);
+
+BT_HIDDEN
+bool ctf_metadata_is_packetized(FILE *fp, int *byte_order);
+
+#endif /* CTF_FS_METADATA_H */
diff --git a/src/plugins/ctf/fs-src/query.c b/src/plugins/ctf/fs-src/query.c
new file mode 100644 (file)
index 0000000..3fa28b8
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ * query.c
+ *
+ * Babeltrace CTF file system Reader Component queries
+ *
+ * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "query.h"
+#include <stdbool.h>
+#include "common/assert.h"
+#include "metadata.h"
+#include "../common/metadata/decoder.h"
+#include "common/common.h"
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+#include "fs.h"
+
+#define BT_LOG_TAG "PLUGIN-CTF-FS-QUERY-SRC"
+#include "logging.h"
+
+#define METADATA_TEXT_SIG      "/* CTF 1.8"
+
+struct range {
+       int64_t begin_ns;
+       int64_t end_ns;
+       bool set;
+};
+
+BT_HIDDEN
+bt_query_status metadata_info_query(
+               bt_self_component_class_source *comp_class,
+               const bt_value *params,
+               const bt_value **user_result)
+{
+       bt_query_status status = BT_QUERY_STATUS_OK;
+       bt_value *result = NULL;
+       const bt_value *path_value = NULL;
+       char *metadata_text = NULL;
+       FILE *metadata_fp = NULL;
+       GString *g_metadata_text = NULL;
+       int ret;
+       int bo;
+       const char *path;
+       bool is_packetized;
+
+       result = bt_value_map_create();
+       if (!result) {
+               status = BT_QUERY_STATUS_NOMEM;
+               goto error;
+       }
+
+       BT_ASSERT(params);
+
+       if (!bt_value_is_map(params)) {
+               BT_LOGE_STR("Query parameters is not a map value object.");
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+               goto error;
+       }
+
+       path_value = bt_value_map_borrow_entry_value_const(params, "path");
+       if (!path_value) {
+               BT_LOGE_STR("Mandatory `path` parameter missing");
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+               goto error;
+       }
+
+       if (!bt_value_is_string(path_value)) {
+               BT_LOGE_STR("`path` parameter is required to be a string value");
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+               goto error;
+       }
+
+       path = bt_value_string_get(path_value);
+
+       BT_ASSERT(path);
+       metadata_fp = ctf_fs_metadata_open_file(path);
+       if (!metadata_fp) {
+               BT_LOGE("Cannot open trace metadata: path=\"%s\".", path);
+               goto error;
+       }
+
+       is_packetized = ctf_metadata_decoder_is_packetized(metadata_fp,
+               &bo);
+
+       if (is_packetized) {
+               ret = ctf_metadata_decoder_packetized_file_stream_to_buf(
+                       metadata_fp, &metadata_text, bo);
+               if (ret) {
+                       BT_LOGE("Cannot decode packetized metadata file: path=\"%s\"",
+                               path);
+                       goto error;
+               }
+       } else {
+               long filesize;
+
+               ret = fseek(metadata_fp, 0, SEEK_END);
+               if (ret) {
+                       BT_LOGE_ERRNO("Failed to seek to the end of the metadata file",
+                               ": path=\"%s\"", path);
+                       goto error;
+               }
+               filesize = ftell(metadata_fp);
+               if (filesize < 0) {
+                       BT_LOGE_ERRNO("Failed to get the current position in the metadata file",
+                               ": path=\"%s\"", path);
+                       goto error;
+               }
+               rewind(metadata_fp);
+               metadata_text = malloc(filesize + 1);
+               if (!metadata_text) {
+                       BT_LOGE_STR("Cannot allocate buffer for metadata text.");
+                       goto error;
+               }
+
+               if (fread(metadata_text, filesize, 1, metadata_fp) != 1) {
+                       BT_LOGE_ERRNO("Cannot read metadata file", ": path=\"%s\"",
+                               path);
+                       goto error;
+               }
+
+               metadata_text[filesize] = '\0';
+       }
+
+       g_metadata_text = g_string_new(NULL);
+       if (!g_metadata_text) {
+               goto error;
+       }
+
+       if (strncmp(metadata_text, METADATA_TEXT_SIG,
+                       sizeof(METADATA_TEXT_SIG) - 1) != 0) {
+               g_string_assign(g_metadata_text, METADATA_TEXT_SIG);
+               g_string_append(g_metadata_text, " */\n\n");
+       }
+
+       g_string_append(g_metadata_text, metadata_text);
+
+       ret = bt_value_map_insert_string_entry(result, "text",
+               g_metadata_text->str);
+       if (ret) {
+               BT_LOGE_STR("Cannot insert metadata text into query result.");
+               goto error;
+       }
+
+       ret = bt_value_map_insert_bool_entry(result, "is-packetized",
+               is_packetized);
+       if (ret) {
+               BT_LOGE_STR("Cannot insert \"is-packetized\" attribute into query result.");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_VALUE_PUT_REF_AND_RESET(result);
+       result = NULL;
+
+       if (status >= 0) {
+               status = BT_QUERY_STATUS_ERROR;
+       }
+
+end:
+       free(metadata_text);
+
+       if (g_metadata_text) {
+               g_string_free(g_metadata_text, TRUE);
+       }
+
+       if (metadata_fp) {
+               fclose(metadata_fp);
+       }
+
+       *user_result = result;
+       return status;
+}
+
+static
+int add_range(bt_value *info, struct range *range,
+               const char *range_name)
+{
+       int ret = 0;
+       bt_value_status status;
+       bt_value *range_map = NULL;
+
+       if (!range->set) {
+               /* Not an error. */
+               goto end;
+       }
+
+       range_map = bt_value_map_create();
+       if (!range_map) {
+               ret = -1;
+               goto end;
+       }
+
+       status = bt_value_map_insert_signed_integer_entry(range_map, "begin",
+                       range->begin_ns);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       status = bt_value_map_insert_signed_integer_entry(range_map, "end",
+                       range->end_ns);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       status = bt_value_map_insert_entry(info, range_name,
+               range_map);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+end:
+       bt_value_put_ref(range_map);
+       return ret;
+}
+
+static
+int add_stream_ids(bt_value *info, struct ctf_fs_ds_file_group *ds_file_group)
+{
+       int ret = 0;
+       bt_value_status status;
+
+       if (ds_file_group->stream_id != UINT64_C(-1)) {
+               status = bt_value_map_insert_unsigned_integer_entry(info, "id",
+                       ds_file_group->stream_id);
+               if (status != BT_VALUE_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       status = bt_value_map_insert_unsigned_integer_entry(info, "class-id",
+               ds_file_group->sc->id);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int populate_stream_info(struct ctf_fs_ds_file_group *group,
+               bt_value *group_info, struct range *stream_range)
+{
+       int ret = 0;
+       size_t file_idx;
+       bt_value_status status;
+       bt_value *file_paths;
+       struct ctf_fs_ds_index_entry *first_ds_index_entry, *last_ds_index_entry;
+       gchar *port_name = NULL;
+
+       file_paths = bt_value_array_create();
+       if (!file_paths) {
+               ret = -1;
+               goto end;
+       }
+
+       for (file_idx = 0; file_idx < group->ds_file_infos->len; file_idx++) {
+               struct ctf_fs_ds_file_info *info =
+                       g_ptr_array_index(group->ds_file_infos,
+                               file_idx);
+
+               status = bt_value_array_append_string_element(file_paths,
+                               info->path->str);
+               if (status != BT_VALUE_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /*
+        * Since each `struct ctf_fs_ds_file_group` has a sorted array of
+        * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
+        * the timestamp_begin of the first index entry and the timestamp_end
+        * of the last index entry.
+        */
+       BT_ASSERT(group->index);
+       BT_ASSERT(group->index->entries);
+       BT_ASSERT(group->index->entries->len > 0);
+
+       /* First entry. */
+       first_ds_index_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index(
+               group->index->entries, 0);
+
+       /* Last entry. */
+       last_ds_index_entry = (struct ctf_fs_ds_index_entry *) g_ptr_array_index(
+               group->index->entries, group->index->entries->len - 1);
+
+       stream_range->begin_ns = first_ds_index_entry->timestamp_begin_ns;
+       stream_range->end_ns = last_ds_index_entry->timestamp_end_ns;
+
+       /*
+        * If any of the begin and end timestamps is not set it means that
+        * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
+        * in their packet context so we can't set the range.
+        */
+       stream_range->set = stream_range->begin_ns != UINT64_C(-1) &&
+               stream_range->end_ns != UINT64_C(-1);
+
+       ret = add_range(group_info, stream_range, "range-ns");
+       if (ret) {
+               goto end;
+       }
+
+       status = bt_value_map_insert_entry(group_info, "paths",
+               file_paths);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = add_stream_ids(group_info, group);
+       if (ret) {
+               goto end;
+       }
+
+       port_name = ctf_fs_make_port_name(group);
+       if (!port_name) {
+               ret = -1;
+               goto end;
+       }
+
+       status = bt_value_map_insert_string_entry(group_info, "port-name",
+               port_name);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+end:
+       bt_value_put_ref(file_paths);
+       return ret;
+}
+
+static
+int populate_trace_info(const struct ctf_fs_trace *trace, bt_value *trace_info)
+{
+       int ret = 0;
+       size_t group_idx;
+       bt_value_status status;
+       bt_value *file_groups = NULL;
+       struct range trace_range = {
+               .begin_ns = INT64_MAX,
+               .end_ns = 0,
+               .set = false,
+       };
+       struct range trace_intersection = {
+               .begin_ns = 0,
+               .end_ns = INT64_MAX,
+               .set = false,
+       };
+
+       BT_ASSERT(trace->ds_file_groups);
+       /* Add trace range info only if it contains streams. */
+       if (trace->ds_file_groups->len == 0) {
+               ret = -1;
+               goto end;
+       }
+
+       file_groups = bt_value_array_create();
+       if (!file_groups) {
+               goto end;
+       }
+
+       status = bt_value_map_insert_string_entry(trace_info, "name",
+               trace->name->str);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+       status = bt_value_map_insert_string_entry(trace_info, "path",
+               trace->path->str);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Find range of all stream groups, and of the trace. */
+       for (group_idx = 0; group_idx < trace->ds_file_groups->len;
+                       group_idx++) {
+               bt_value *group_info;
+               struct range group_range = { .set = false };
+               struct ctf_fs_ds_file_group *group = g_ptr_array_index(
+                               trace->ds_file_groups, group_idx);
+
+               group_info = bt_value_map_create();
+               if (!group_info) {
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = populate_stream_info(group, group_info, &group_range);
+               if (ret) {
+                       bt_value_put_ref(group_info);
+                       goto end;
+               }
+
+               status = bt_value_array_append_element(file_groups, group_info);
+               bt_value_put_ref(group_info);
+               if (status != BT_VALUE_STATUS_OK) {
+                       goto end;
+               }
+
+               if (group_range.set) {
+                       trace_range.begin_ns = min(trace_range.begin_ns,
+                                       group_range.begin_ns);
+                       trace_range.end_ns = max(trace_range.end_ns,
+                                       group_range.end_ns);
+                       trace_range.set = true;
+
+                       trace_intersection.begin_ns = max(trace_intersection.begin_ns,
+                                       group_range.begin_ns);
+                       trace_intersection.end_ns = min(trace_intersection.end_ns,
+                                       group_range.end_ns);
+                       trace_intersection.set = true;
+               }
+       }
+
+       ret = add_range(trace_info, &trace_range, "range-ns");
+       if (ret) {
+               goto end;
+       }
+
+       if (trace_intersection.begin_ns < trace_intersection.end_ns) {
+               ret = add_range(trace_info, &trace_intersection,
+                               "intersection-range-ns");
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       status = bt_value_map_insert_entry(trace_info, "streams",
+               file_groups);
+       BT_VALUE_PUT_REF_AND_RESET(file_groups);
+       if (status != BT_VALUE_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+end:
+       bt_value_put_ref(file_groups);
+       return ret;
+}
+
+BT_HIDDEN
+bt_query_status trace_info_query(
+               bt_self_component_class_source *comp_class,
+               const bt_value *params,
+               const bt_value **user_result)
+{
+       struct ctf_fs_component *ctf_fs = NULL;
+       bt_query_status status = BT_QUERY_STATUS_OK;
+       bt_value *result = NULL;
+       const bt_value *paths_value = NULL;
+       int ret = 0;
+       guint i;
+
+       BT_ASSERT(params);
+
+       if (!bt_value_is_map(params)) {
+               BT_LOGE("Query parameters is not a map value object.");
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+               goto error;
+       }
+
+       ctf_fs = ctf_fs_component_create();
+       if (!ctf_fs) {
+               goto error;
+       }
+
+       if (!read_src_fs_parameters(params, &paths_value, ctf_fs)) {
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+               goto error;
+       }
+
+       if (ctf_fs_component_create_ctf_fs_traces(NULL, ctf_fs, paths_value)) {
+               goto error;
+       }
+
+       result = bt_value_array_create();
+       if (!result) {
+               status = BT_QUERY_STATUS_NOMEM;
+               goto error;
+       }
+
+       for (i = 0; i < ctf_fs->traces->len; i++) {
+               struct ctf_fs_trace *trace;
+               bt_value *trace_info;
+               bt_value_status status;
+
+               trace = g_ptr_array_index(ctf_fs->traces, i);
+               BT_ASSERT(trace);
+
+               trace_info = bt_value_map_create();
+               if (!trace_info) {
+                       BT_LOGE("Failed to create trace info map.");
+                       goto error;
+               }
+
+               ret = populate_trace_info(trace, trace_info);
+               if (ret) {
+                       bt_value_put_ref(trace_info);
+                       goto error;
+               }
+
+               status = bt_value_array_append_element(result, trace_info);
+               bt_value_put_ref(trace_info);
+               if (status != BT_VALUE_STATUS_OK) {
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       BT_VALUE_PUT_REF_AND_RESET(result);
+       result = NULL;
+
+       if (status >= 0) {
+               status = BT_QUERY_STATUS_ERROR;
+       }
+
+end:
+       if (ctf_fs) {
+               ctf_fs_destroy(ctf_fs);
+               ctf_fs = NULL;
+       }
+
+       *user_result = result;
+       return status;
+}
diff --git a/src/plugins/ctf/fs-src/query.h b/src/plugins/ctf/fs-src/query.h
new file mode 100644 (file)
index 0000000..4125e4a
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef BABELTRACE_PLUGIN_CTF_FS_QUERY_H
+#define BABELTRACE_PLUGIN_CTF_FS_QUERY_H
+
+/*
+ * BabelTrace - CTF on File System Component
+ *
+ * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+BT_HIDDEN
+bt_query_status metadata_info_query(
+               bt_self_component_class_source *comp_class,
+               const bt_value *params, const bt_value **result);
+
+BT_HIDDEN
+bt_query_status trace_info_query(
+               bt_self_component_class_source *comp_class,
+               const bt_value *params, const bt_value **result);
+
+#endif /* BABELTRACE_PLUGIN_CTF_FS_QUERY_H */
diff --git a/src/plugins/ctf/lttng-live/Makefile.am b/src/plugins/ctf/lttng-live/Makefile.am
new file mode 100644 (file)
index 0000000..853f47d
--- /dev/null
@@ -0,0 +1,18 @@
+libbabeltrace2_plugin_ctf_lttng_live_la_SOURCES = \
+               lttng-live.c \
+               lttng-live.h \
+               data-stream.c \
+               data-stream.h \
+               metadata.c \
+               metadata.h \
+               viewer-connection.c \
+               viewer-connection.h \
+               lttng-viewer-abi.h \
+               logging.c \
+               logging.h
+
+if BABELTRACE_BUILD_WITH_MINGW
+libbabeltrace2_plugin_ctf_lttng_live_la_LIBADD = -lws2_32
+endif
+
+noinst_LTLIBRARIES = libbabeltrace2-plugin-ctf-lttng-live.la
diff --git a/src/plugins/ctf/lttng-live/data-stream.c b/src/plugins/ctf/lttng-live/data-stream.c
new file mode 100644 (file)
index 0000000..25a8e4c
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-LIVE-SRC-DS"
+#include "logging.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <inttypes.h>
+#include "compat/mman.h"
+#include <babeltrace2/babeltrace.h>
+#include "../common/msg-iter/msg-iter.h"
+#include "common/assert.h"
+
+#include "data-stream.h"
+
+#define STREAM_NAME_PREFIX     "stream-"
+
+static
+enum bt_msg_iter_medium_status medop_request_bytes(
+               size_t request_sz, uint8_t **buffer_addr,
+               size_t *buffer_sz, void *data)
+{
+       enum bt_msg_iter_medium_status status =
+               BT_MSG_ITER_MEDIUM_STATUS_OK;
+       struct lttng_live_stream_iterator *stream = data;
+       struct lttng_live_trace *trace = stream->trace;
+       struct lttng_live_session *session = trace->session;
+       struct lttng_live_msg_iter *live_msg_iter = session->lttng_live_msg_iter;
+       uint64_t recv_len = 0;
+       uint64_t len_left;
+       uint64_t read_len;
+
+       len_left = stream->base_offset + stream->len - stream->offset;
+       if (!len_left) {
+               stream->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
+               status = BT_MSG_ITER_MEDIUM_STATUS_AGAIN;
+               return status;
+       }
+       read_len = MIN(request_sz, stream->buflen);
+       read_len = MIN(read_len, len_left);
+       status = lttng_live_get_stream_bytes(live_msg_iter,
+                       stream, stream->buf, stream->offset,
+                       read_len, &recv_len);
+       *buffer_addr = stream->buf;
+       *buffer_sz = recv_len;
+       stream->offset += recv_len;
+       return status;
+}
+
+static
+bt_stream *medop_borrow_stream(bt_stream_class *stream_class,
+               int64_t stream_id, void *data)
+{
+       struct lttng_live_stream_iterator *lttng_live_stream = data;
+
+       if (!lttng_live_stream->stream) {
+               uint64_t stream_class_id = bt_stream_class_get_id(stream_class);
+
+               BT_LOGD("Creating stream %s (ID: %" PRIu64 ") out of stream "
+                       "class %" PRId64, lttng_live_stream->name->str,
+                       stream_id, stream_class_id);
+
+               if (stream_id < 0) {
+                       /*
+                        * No stream instance ID in the stream. It's possible
+                        * to encounter this situation with older version of
+                        * LTTng. In these cases, use the viewer_stream_id that
+                        * is unique for a live viewer session.
+                        */
+                       lttng_live_stream->stream = bt_stream_create_with_id(
+                               stream_class, lttng_live_stream->trace->trace,
+                               lttng_live_stream->viewer_stream_id);
+               } else {
+                       lttng_live_stream->stream = bt_stream_create_with_id(
+                               stream_class, lttng_live_stream->trace->trace,
+                               (uint64_t) stream_id);
+               }
+
+               if (!lttng_live_stream->stream) {
+                       BT_LOGE("Cannot create stream %s (stream class ID "
+                               "%" PRId64 ", stream ID %" PRIu64 ")",
+                               lttng_live_stream->name->str,
+                               stream_class_id, stream_id);
+               }
+               bt_stream_set_name(lttng_live_stream->stream,
+                       lttng_live_stream->name->str);
+       }
+
+       return lttng_live_stream->stream;
+}
+
+static struct bt_msg_iter_medium_ops medops = {
+       .request_bytes = medop_request_bytes,
+       .seek = NULL,
+       .borrow_stream = medop_borrow_stream,
+};
+
+BT_HIDDEN
+enum lttng_live_iterator_status lttng_live_lazy_msg_init(
+               struct lttng_live_session *session)
+{
+       struct lttng_live_component *lttng_live =
+               session->lttng_live_msg_iter->lttng_live_comp;
+       uint64_t trace_idx, stream_iter_idx;
+
+       if (!session->lazy_stream_msg_init) {
+               return LTTNG_LIVE_ITERATOR_STATUS_OK;
+       }
+
+       for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
+               struct lttng_live_trace *trace =
+                       g_ptr_array_index(session->traces, trace_idx);
+
+               for (stream_iter_idx = 0;
+                               stream_iter_idx < trace->stream_iterators->len;
+                               stream_iter_idx++) {
+                       struct ctf_trace_class *ctf_tc;
+                       struct lttng_live_stream_iterator *stream_iter =
+                               g_ptr_array_index(trace->stream_iterators,
+                                               stream_iter_idx);
+
+                       if (stream_iter->msg_iter) {
+                               continue;
+                       }
+                       ctf_tc = ctf_metadata_decoder_borrow_ctf_trace_class(
+                                               trace->metadata->decoder);
+                       stream_iter->msg_iter = bt_msg_iter_create(ctf_tc,
+                                       lttng_live->max_query_size, medops,
+                                       stream_iter);
+                       if (!stream_iter->msg_iter) {
+                               goto error;
+                       }
+               }
+       }
+
+       session->lazy_stream_msg_init = false;
+
+       return LTTNG_LIVE_ITERATOR_STATUS_OK;
+
+error:
+       return LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+}
+
+BT_HIDDEN
+struct lttng_live_stream_iterator *lttng_live_stream_iterator_create(
+               struct lttng_live_session *session,
+               uint64_t ctf_trace_id,
+               uint64_t stream_id)
+{
+       struct lttng_live_stream_iterator *stream_iter;
+       struct lttng_live_component *lttng_live;
+       struct lttng_live_trace *trace;
+
+       BT_ASSERT(session);
+       BT_ASSERT(session->lttng_live_msg_iter);
+       BT_ASSERT(session->lttng_live_msg_iter->lttng_live_comp);
+
+       lttng_live = session->lttng_live_msg_iter->lttng_live_comp;
+
+       stream_iter = g_new0(struct lttng_live_stream_iterator, 1);
+       if (!stream_iter) {
+               goto error;
+       }
+
+       trace = lttng_live_borrow_trace(session, ctf_trace_id);
+       if (!trace) {
+               goto error;
+       }
+
+       stream_iter->trace = trace;
+       stream_iter->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
+       stream_iter->viewer_stream_id = stream_id;
+       stream_iter->ctf_stream_class_id = -1ULL;
+       stream_iter->last_inactivity_ts = INT64_MIN;
+
+       if (trace->trace) {
+               struct ctf_trace_class *ctf_tc =
+                       ctf_metadata_decoder_borrow_ctf_trace_class(
+                                       trace->metadata->decoder);
+               BT_ASSERT(!stream_iter->msg_iter);
+               stream_iter->msg_iter = bt_msg_iter_create(ctf_tc,
+                               lttng_live->max_query_size, medops,
+                               stream_iter);
+               if (!stream_iter->msg_iter) {
+                       goto error;
+               }
+       }
+       stream_iter->buf = g_new0(uint8_t, lttng_live->max_query_size);
+       if (!stream_iter->buf) {
+               goto error;
+       }
+
+       stream_iter->buflen = lttng_live->max_query_size;
+       stream_iter->name = g_string_new(NULL);
+       if (!stream_iter->name) {
+               goto error;
+       }
+
+       g_string_printf(stream_iter->name, STREAM_NAME_PREFIX "%" PRIu64,
+                       stream_iter->viewer_stream_id);
+       g_ptr_array_add(trace->stream_iterators, stream_iter);
+
+       /* Track the number of active stream iterator. */
+       session->lttng_live_msg_iter->active_stream_iter++;
+
+       goto end;
+error:
+       lttng_live_stream_iterator_destroy(stream_iter);
+       stream_iter = NULL;
+end:
+       return stream_iter;
+}
+
+BT_HIDDEN
+void lttng_live_stream_iterator_destroy(
+               struct lttng_live_stream_iterator *stream_iter)
+{
+       if (!stream_iter) {
+               return;
+       }
+
+       if (stream_iter->stream) {
+               BT_STREAM_PUT_REF_AND_RESET(stream_iter->stream);
+       }
+
+       if (stream_iter->msg_iter) {
+               bt_msg_iter_destroy(stream_iter->msg_iter);
+       }
+       if (stream_iter->buf) {
+               g_free(stream_iter->buf);
+       }
+       if (stream_iter->name) {
+               g_string_free(stream_iter->name, TRUE);
+       }
+
+       bt_message_put_ref(stream_iter->current_msg);
+
+       /* Track the number of active stream iterator. */
+       stream_iter->trace->session->lttng_live_msg_iter->active_stream_iter--;
+
+       /*
+        * Ensure we poke the trace metadata in the future, which is
+        * required to release the metadata reference on the trace.
+        */
+       stream_iter->trace->new_metadata_needed = true;
+       g_free(stream_iter);
+}
diff --git a/src/plugins/ctf/lttng-live/data-stream.h b/src/plugins/ctf/lttng-live/data-stream.h
new file mode 100644 (file)
index 0000000..d9e273a
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef LTTNG_LIVE_DATA_STREAM_H
+#define LTTNG_LIVE_DATA_STREAM_H
+
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "lttng-live.h"
+#include "../common/msg-iter/msg-iter.h"
+
+enum lttng_live_iterator_status lttng_live_lazy_msg_init(
+               struct lttng_live_session *session);
+
+struct lttng_live_stream_iterator *lttng_live_stream_iterator_create(
+               struct lttng_live_session *session,
+               uint64_t ctf_trace_id,
+               uint64_t stream_id);
+
+void lttng_live_stream_iterator_destroy(
+               struct lttng_live_stream_iterator *stream);
+
+#endif /* LTTNG_LIVE_DATA_STREAM_H */
diff --git a/src/plugins/ctf/lttng-live/logging.c b/src/plugins/ctf/lttng-live/logging.c
new file mode 100644 (file)
index 0000000..98f1b63
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL lttng_live_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(lttng_live_log_level, "BABELTRACE_SRC_CTF_LTTNG_LIVE_LOG_LEVEL");
diff --git a/src/plugins/ctf/lttng-live/logging.h b/src/plugins/ctf/lttng-live/logging.h
new file mode 100644 (file)
index 0000000..de11a5e
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef LTTNG_LIVE_LOGGING_H
+#define LTTNG_LIVE_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL lttng_live_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(lttng_live_log_level);
+
+#endif /* LTTNG_LIVE_LOGGING_H */
diff --git a/src/plugins/ctf/lttng-live/lttng-live.c b/src/plugins/ctf/lttng-live/lttng-live.c
new file mode 100644 (file)
index 0000000..1a24a73
--- /dev/null
@@ -0,0 +1,1601 @@
+/*
+ * lttng-live.c
+ *
+ * Babeltrace CTF LTTng-live Client Component
+ *
+ * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-LIVE-SRC"
+#include "logging.h"
+
+#include <glib.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include "common/assert.h"
+#include <babeltrace2/babeltrace.h>
+#include "compat/compiler.h"
+#include <babeltrace2/types.h>
+#include "plugins/plugins-common.h"
+
+#include "data-stream.h"
+#include "metadata.h"
+#include "lttng-live.h"
+
+#define MAX_QUERY_SIZE                     (256*1024)
+#define URL_PARAM                          "url"
+#define SESS_NOT_FOUND_ACTION_PARAM        "session-not-found-action"
+#define SESS_NOT_FOUND_ACTION_CONTINUE_STR  "continue"
+#define SESS_NOT_FOUND_ACTION_FAIL_STR     "fail"
+#define SESS_NOT_FOUND_ACTION_END_STR      "end"
+
+#define print_dbg(fmt, ...)    BT_LOGD(fmt, ## __VA_ARGS__)
+
+static
+const char *print_live_iterator_status(enum lttng_live_iterator_status status)
+{
+       switch (status) {
+       case LTTNG_LIVE_ITERATOR_STATUS_CONTINUE:
+               return "LTTNG_LIVE_ITERATOR_STATUS_CONTINUE";
+       case LTTNG_LIVE_ITERATOR_STATUS_AGAIN:
+               return "LTTNG_LIVE_ITERATOR_STATUS_AGAIN";
+       case LTTNG_LIVE_ITERATOR_STATUS_END:
+               return "LTTNG_LIVE_ITERATOR_STATUS_END";
+       case LTTNG_LIVE_ITERATOR_STATUS_OK:
+               return "LTTNG_LIVE_ITERATOR_STATUS_OK";
+       case LTTNG_LIVE_ITERATOR_STATUS_INVAL:
+               return "LTTNG_LIVE_ITERATOR_STATUS_INVAL";
+       case LTTNG_LIVE_ITERATOR_STATUS_ERROR:
+               return "LTTNG_LIVE_ITERATOR_STATUS_ERROR";
+       case LTTNG_LIVE_ITERATOR_STATUS_NOMEM:
+               return "LTTNG_LIVE_ITERATOR_STATUS_NOMEM";
+       case LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED:
+               return "LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED";
+       default:
+               abort();
+       }
+}
+
+static
+const char *print_state(struct lttng_live_stream_iterator *s)
+{
+       switch (s->state) {
+       case LTTNG_LIVE_STREAM_ACTIVE_NO_DATA:
+               return "ACTIVE_NO_DATA";
+       case LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA:
+               return "QUIESCENT_NO_DATA";
+       case LTTNG_LIVE_STREAM_QUIESCENT:
+               return "QUIESCENT";
+       case LTTNG_LIVE_STREAM_ACTIVE_DATA:
+               return "ACTIVE_DATA";
+       case LTTNG_LIVE_STREAM_EOF:
+               return "EOF";
+       default:
+               return "ERROR";
+       }
+}
+
+#define print_stream_state(live_stream_iter) \
+       do { \
+               BT_LOGD("stream state %s last_inact_ts %" PRId64  \
+                       ", curr_inact_ts %" PRId64, \
+                       print_state(live_stream_iter), \
+                       live_stream_iter->last_inactivity_ts, \
+                       live_stream_iter->current_inactivity_ts); \
+       } while (0);
+
+BT_HIDDEN
+bool lttng_live_graph_is_canceled(struct lttng_live_component *lttng_live)
+{
+       const bt_component *component;
+       bool ret;
+
+       if (!lttng_live) {
+               ret = false;
+               goto end;
+       }
+
+       component = bt_component_source_as_component_const(
+               bt_self_component_source_as_component_source(
+               lttng_live->self_comp));
+
+       ret = bt_component_graph_is_canceled(component);
+
+end:
+       return ret;
+}
+
+static
+struct lttng_live_trace *lttng_live_find_trace(struct lttng_live_session *session,
+               uint64_t trace_id)
+{
+       uint64_t trace_idx;
+       struct lttng_live_trace *ret_trace = NULL;
+
+       for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
+               struct lttng_live_trace *trace =
+                       g_ptr_array_index(session->traces, trace_idx);
+               if (trace->id == trace_id) {
+                       ret_trace = trace;
+                       goto end;
+               }
+       }
+
+end:
+       return ret_trace;
+}
+
+static
+void lttng_live_destroy_trace(struct lttng_live_trace *trace)
+{
+       BT_LOGD("Destroy lttng_live_trace");
+
+       BT_ASSERT(trace->stream_iterators);
+       g_ptr_array_free(trace->stream_iterators, TRUE);
+
+       BT_TRACE_PUT_REF_AND_RESET(trace->trace);
+       BT_TRACE_CLASS_PUT_REF_AND_RESET(trace->trace_class);
+
+       lttng_live_metadata_fini(trace);
+       g_free(trace);
+}
+
+static
+struct lttng_live_trace *lttng_live_create_trace(struct lttng_live_session *session,
+               uint64_t trace_id)
+{
+       struct lttng_live_trace *trace = NULL;
+
+       trace = g_new0(struct lttng_live_trace, 1);
+       if (!trace) {
+               goto error;
+       }
+       trace->session = session;
+       trace->id = trace_id;
+       trace->trace_class = NULL;
+       trace->trace = NULL;
+       trace->stream_iterators = g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) lttng_live_stream_iterator_destroy);
+       BT_ASSERT(trace->stream_iterators);
+       trace->new_metadata_needed = true;
+       g_ptr_array_add(session->traces, trace);
+
+       BT_LOGI("Create trace");
+       goto end;
+error:
+       g_free(trace);
+       trace = NULL;
+end:
+       return trace;
+}
+
+BT_HIDDEN
+struct lttng_live_trace *lttng_live_borrow_trace(
+               struct lttng_live_session *session, uint64_t trace_id)
+{
+       struct lttng_live_trace *trace;
+
+       trace = lttng_live_find_trace(session, trace_id);
+       if (trace) {
+               goto end;
+       }
+
+       /* The session is the owner of the newly created trace. */
+       trace = lttng_live_create_trace(session, trace_id);
+
+end:
+       return trace;
+}
+
+BT_HIDDEN
+int lttng_live_add_session(struct lttng_live_msg_iter *lttng_live_msg_iter,
+               uint64_t session_id, const char *hostname,
+               const char *session_name)
+{
+       int ret = 0;
+       struct lttng_live_session *session;
+
+       session = g_new0(struct lttng_live_session, 1);
+       if (!session) {
+               goto error;
+       }
+
+       session->id = session_id;
+       session->traces = g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) lttng_live_destroy_trace);
+       BT_ASSERT(session->traces);
+       session->lttng_live_msg_iter = lttng_live_msg_iter;
+       session->new_streams_needed = true;
+       session->hostname = g_string_new(hostname);
+       BT_ASSERT(session->hostname);
+
+       session->session_name = g_string_new(session_name);
+       BT_ASSERT(session->session_name);
+
+       BT_LOGI("Reading from session: %" PRIu64 " hostname: %s session_name: %s",
+               session->id, hostname, session_name);
+       g_ptr_array_add(lttng_live_msg_iter->sessions, session);
+       goto end;
+error:
+       BT_LOGE("Error adding session");
+       g_free(session);
+       ret = -1;
+end:
+       return ret;
+}
+
+static
+void lttng_live_destroy_session(struct lttng_live_session *session)
+{
+       struct lttng_live_component *live_comp;
+
+       if (!session) {
+               goto end;
+       }
+
+       BT_LOGD("Destroy lttng live session");
+       if (session->id != -1ULL) {
+               if (lttng_live_detach_session(session)) {
+                       live_comp = session->lttng_live_msg_iter->lttng_live_comp;
+                       if (session->lttng_live_msg_iter &&
+                                       !lttng_live_graph_is_canceled(live_comp)) {
+                               /* Old relayd cannot detach sessions. */
+                               BT_LOGD("Unable to detach lttng live session %" PRIu64,
+                                       session->id);
+                       }
+               }
+               session->id = -1ULL;
+       }
+
+       if (session->traces) {
+               g_ptr_array_free(session->traces, TRUE);
+       }
+
+       if (session->hostname) {
+               g_string_free(session->hostname, TRUE);
+       }
+       if (session->session_name) {
+               g_string_free(session->session_name, TRUE);
+       }
+       g_free(session);
+
+end:
+       return;
+}
+
+static
+void lttng_live_msg_iter_destroy(struct lttng_live_msg_iter *lttng_live_msg_iter)
+{
+       if (!lttng_live_msg_iter) {
+               goto end;
+       }
+
+       if (lttng_live_msg_iter->sessions) {
+               g_ptr_array_free(lttng_live_msg_iter->sessions, TRUE);
+       }
+
+       BT_OBJECT_PUT_REF_AND_RESET(lttng_live_msg_iter->viewer_connection);
+       BT_ASSERT(lttng_live_msg_iter->lttng_live_comp);
+       BT_ASSERT(lttng_live_msg_iter->lttng_live_comp->has_msg_iter);
+
+       /* All stream iterators must be destroyed at this point. */
+       BT_ASSERT(lttng_live_msg_iter->active_stream_iter == 0);
+       lttng_live_msg_iter->lttng_live_comp->has_msg_iter = false;
+
+       g_free(lttng_live_msg_iter);
+
+end:
+       return;
+}
+
+BT_HIDDEN
+void lttng_live_msg_iter_finalize(bt_self_message_iterator *self_msg_iter)
+{
+       struct lttng_live_msg_iter *lttng_live_msg_iter;
+
+       BT_ASSERT(self_msg_iter);
+
+       lttng_live_msg_iter = bt_self_message_iterator_get_data(self_msg_iter);
+       BT_ASSERT(lttng_live_msg_iter);
+       lttng_live_msg_iter_destroy(lttng_live_msg_iter);
+}
+
+static
+enum lttng_live_iterator_status lttng_live_iterator_next_check_stream_state(
+               struct lttng_live_stream_iterator *lttng_live_stream)
+{
+       switch (lttng_live_stream->state) {
+       case LTTNG_LIVE_STREAM_QUIESCENT:
+       case LTTNG_LIVE_STREAM_ACTIVE_DATA:
+               break;
+       case LTTNG_LIVE_STREAM_ACTIVE_NO_DATA:
+               /* Invalid state. */
+               BT_LOGF("Unexpected stream state \"ACTIVE_NO_DATA\"");
+               abort();
+       case LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA:
+               /* Invalid state. */
+               BT_LOGF("Unexpected stream state \"QUIESCENT_NO_DATA\"");
+               abort();
+       case LTTNG_LIVE_STREAM_EOF:
+               break;
+       }
+       return LTTNG_LIVE_ITERATOR_STATUS_OK;
+}
+
+/*
+ * For active no data stream, fetch next data. It can be either:
+ * - quiescent: need to put it in the prio heap at quiescent end
+ *   timestamp,
+ * - have data: need to wire up first event into the prio heap,
+ * - have no data on this stream at this point: need to retry (AGAIN) or
+ *   return EOF.
+ */
+static
+enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_no_data_stream(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *lttng_live_stream)
+{
+       enum lttng_live_iterator_status ret =
+                       LTTNG_LIVE_ITERATOR_STATUS_OK;
+       struct packet_index index;
+       enum lttng_live_stream_state orig_state = lttng_live_stream->state;
+
+       if (lttng_live_stream->trace->new_metadata_needed) {
+               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
+               goto end;
+       }
+       if (lttng_live_stream->trace->session->new_streams_needed) {
+               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
+               goto end;
+       }
+       if (lttng_live_stream->state != LTTNG_LIVE_STREAM_ACTIVE_NO_DATA &&
+                       lttng_live_stream->state != LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA) {
+               goto end;
+       }
+       ret = lttng_live_get_next_index(lttng_live_msg_iter, lttng_live_stream,
+               &index);
+       if (ret != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+               goto end;
+       }
+       BT_ASSERT(lttng_live_stream->state != LTTNG_LIVE_STREAM_EOF);
+       if (lttng_live_stream->state == LTTNG_LIVE_STREAM_QUIESCENT) {
+               uint64_t last_inact_ts = lttng_live_stream->last_inactivity_ts,
+                        curr_inact_ts = lttng_live_stream->current_inactivity_ts;
+
+               if (orig_state == LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA &&
+                               last_inact_ts == curr_inact_ts) {
+                       ret = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+                       print_stream_state(lttng_live_stream);
+               } else {
+                       ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
+               }
+               goto end;
+       }
+       lttng_live_stream->base_offset = index.offset;
+       lttng_live_stream->offset = index.offset;
+       lttng_live_stream->len = index.packet_size / CHAR_BIT;
+end:
+       if (ret == LTTNG_LIVE_ITERATOR_STATUS_OK) {
+               ret = lttng_live_iterator_next_check_stream_state(lttng_live_stream);
+       }
+       return ret;
+}
+
+/*
+ * Creation of the message requires the ctf trace class to be created
+ * beforehand, but the live protocol gives us all streams (including metadata)
+ * at once. So we split it in three steps: getting streams, getting metadata
+ * (which creates the ctf trace class), and then creating the per-stream
+ * messages.
+ */
+static
+enum lttng_live_iterator_status lttng_live_get_session(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_session *session)
+{
+       enum lttng_live_iterator_status status;
+       uint64_t trace_idx;
+       int ret = 0;
+
+       if (!session->attached) {
+               ret = lttng_live_attach_session(session);
+               if (ret) {
+                       if (lttng_live_msg_iter && lttng_live_graph_is_canceled(
+                                               lttng_live_msg_iter->lttng_live_comp)) {
+                               status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+                       } else {
+                               status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+                       }
+                       goto end;
+               }
+       }
+
+       status = lttng_live_get_new_streams(session);
+       if (status != LTTNG_LIVE_ITERATOR_STATUS_OK &&
+                       status != LTTNG_LIVE_ITERATOR_STATUS_END) {
+               goto end;
+       }
+       for (trace_idx = 0; trace_idx < session->traces->len; trace_idx++) {
+               struct lttng_live_trace *trace =
+                       g_ptr_array_index(session->traces, trace_idx);
+
+               status = lttng_live_metadata_update(trace);
+               if (status != LTTNG_LIVE_ITERATOR_STATUS_OK &&
+                               status != LTTNG_LIVE_ITERATOR_STATUS_END) {
+                       goto end;
+               }
+       }
+       status = lttng_live_lazy_msg_init(session);
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+void lttng_live_need_new_streams(struct lttng_live_msg_iter *lttng_live_msg_iter)
+{
+       uint64_t session_idx;
+
+       for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len;
+                       session_idx++) {
+               struct lttng_live_session *session =
+                       g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
+               session->new_streams_needed = true;
+       }
+}
+
+static
+void lttng_live_force_new_streams_and_metadata(struct lttng_live_msg_iter *lttng_live_msg_iter)
+{
+       uint64_t session_idx, trace_idx;
+
+       for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len;
+                       session_idx++) {
+               struct lttng_live_session *session =
+                       g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
+               session->new_streams_needed = true;
+               for (trace_idx = 0; trace_idx < session->traces->len;
+                               trace_idx++) {
+                       struct lttng_live_trace *trace =
+                               g_ptr_array_index(session->traces, trace_idx);
+                       trace->new_metadata_needed = true;
+               }
+       }
+}
+
+static
+enum lttng_live_iterator_status
+lttng_live_iterator_handle_new_streams_and_metadata(
+               struct lttng_live_msg_iter *lttng_live_msg_iter)
+{
+       enum lttng_live_iterator_status ret =
+                       LTTNG_LIVE_ITERATOR_STATUS_OK;
+       uint64_t session_idx = 0, nr_sessions_opened = 0;
+       struct lttng_live_session *session;
+       enum session_not_found_action sess_not_found_act =
+               lttng_live_msg_iter->lttng_live_comp->params.sess_not_found_act;
+
+       /*
+        * In a remotely distant future, we could add a "new
+        * session" flag to the protocol, which would tell us that we
+        * need to query for new sessions even though we have sessions
+        * currently ongoing.
+        */
+       if (lttng_live_msg_iter->sessions->len == 0) {
+               if (sess_not_found_act != SESSION_NOT_FOUND_ACTION_CONTINUE) {
+                       ret = LTTNG_LIVE_ITERATOR_STATUS_END;
+                       goto end;
+               } else {
+                       /*
+                        * Retry to create a viewer session for the requested
+                        * session name.
+                        */
+                       if (lttng_live_create_viewer_session(lttng_live_msg_iter)) {
+                               ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+               }
+       }
+
+       for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len;
+                       session_idx++) {
+               session = g_ptr_array_index(lttng_live_msg_iter->sessions,
+                               session_idx);
+               ret = lttng_live_get_session(lttng_live_msg_iter, session);
+               switch (ret) {
+               case LTTNG_LIVE_ITERATOR_STATUS_OK:
+                       break;
+               case LTTNG_LIVE_ITERATOR_STATUS_END:
+                       ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
+                       break;
+               default:
+                       goto end;
+               }
+               if (!session->closed) {
+                       nr_sessions_opened++;
+               }
+       }
+end:
+       if (ret == LTTNG_LIVE_ITERATOR_STATUS_OK &&
+                       sess_not_found_act != SESSION_NOT_FOUND_ACTION_CONTINUE &&
+                       nr_sessions_opened == 0) {
+               ret = LTTNG_LIVE_ITERATOR_STATUS_END;
+       }
+       return ret;
+}
+
+static
+enum lttng_live_iterator_status emit_inactivity_message(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream_iter,
+               bt_message **message, uint64_t timestamp)
+{
+       enum lttng_live_iterator_status ret =
+                       LTTNG_LIVE_ITERATOR_STATUS_OK;
+       bt_message *msg = NULL;
+
+       BT_ASSERT(stream_iter->trace->clock_class);
+
+       msg = bt_message_message_iterator_inactivity_create(
+                       lttng_live_msg_iter->self_msg_iter,
+                       stream_iter->trace->clock_class,
+                       timestamp);
+       if (!msg) {
+               goto error;
+       }
+
+       *message = msg;
+end:
+       return ret;
+
+error:
+       ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+       bt_message_put_ref(msg);
+       goto end;
+}
+
+static
+enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_quiescent_stream(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *lttng_live_stream,
+               bt_message **message)
+{
+       enum lttng_live_iterator_status ret =
+                       LTTNG_LIVE_ITERATOR_STATUS_OK;
+
+       if (lttng_live_stream->state != LTTNG_LIVE_STREAM_QUIESCENT) {
+               return LTTNG_LIVE_ITERATOR_STATUS_OK;
+       }
+
+       if (lttng_live_stream->current_inactivity_ts ==
+                       lttng_live_stream->last_inactivity_ts) {
+               lttng_live_stream->state = LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA;
+               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
+               goto end;
+       }
+
+       ret = emit_inactivity_message(lttng_live_msg_iter, lttng_live_stream,
+                       message, lttng_live_stream->current_inactivity_ts);
+
+       lttng_live_stream->last_inactivity_ts =
+                       lttng_live_stream->current_inactivity_ts;
+end:
+       return ret;
+}
+
+static
+int live_get_msg_ts_ns(struct lttng_live_stream_iterator *stream_iter,
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               const bt_message *msg, int64_t last_msg_ts_ns,
+               int64_t *ts_ns)
+{
+       const bt_clock_class *clock_class = NULL;
+       const bt_clock_snapshot *clock_snapshot = NULL;
+       int ret = 0;
+       bt_message_stream_activity_clock_snapshot_state sa_cs_state;
+
+       BT_ASSERT(msg);
+       BT_ASSERT(ts_ns);
+
+       BT_LOGV("Getting message's timestamp: iter-data-addr=%p, msg-addr=%p, "
+               "last-msg-ts=%" PRId64, lttng_live_msg_iter, msg,
+               last_msg_ts_ns);
+
+       switch (bt_message_get_type(msg)) {
+       case BT_MESSAGE_TYPE_EVENT:
+               clock_class =
+                       bt_message_event_borrow_stream_class_default_clock_class_const(
+                               msg);
+               BT_ASSERT(clock_class);
+
+               clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+               clock_class =
+                       bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
+                       msg);
+               BT_ASSERT(clock_class);
+
+               clock_snapshot = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_PACKET_END:
+               clock_class =
+                       bt_message_packet_end_borrow_stream_class_default_clock_class_const(
+                       msg);
+               BT_ASSERT(clock_class);
+
+               clock_snapshot = bt_message_packet_end_borrow_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+               clock_class =
+                       bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
+                       msg);
+               BT_ASSERT(clock_class);
+
+               clock_snapshot = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+               clock_class =
+                       bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
+                       msg);
+               BT_ASSERT(clock_class);
+
+               clock_snapshot = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+               clock_class =
+                       bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
+                       msg);
+               BT_ASSERT(clock_class);
+
+               sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
+                       msg, &clock_snapshot);
+               if (sa_cs_state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+               clock_class =
+                       bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
+                       msg);
+               BT_ASSERT(clock_class);
+
+               sa_cs_state = bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
+                       msg, &clock_snapshot);
+               if (sa_cs_state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+               clock_snapshot =
+                       bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
+                               msg);
+               break;
+       default:
+               /* All the other messages have a higher priority */
+               BT_LOGV_STR("Message has no timestamp: using the last message timestamp.");
+               *ts_ns = last_msg_ts_ns;
+               goto end;
+       }
+
+       clock_class = bt_clock_snapshot_borrow_clock_class_const(clock_snapshot);
+       BT_ASSERT(clock_class);
+
+       ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot, ts_ns);
+       if (ret) {
+               BT_LOGE("Cannot get nanoseconds from Epoch of clock snapshot: "
+                       "clock-snapshot-addr=%p", clock_snapshot);
+               goto error;
+       }
+
+       goto end;
+
+no_clock_snapshot:
+       BT_LOGV_STR("Message's default clock snapshot is missing: "
+               "using the last message timestamp.");
+       *ts_ns = last_msg_ts_ns;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       if (ret == 0) {
+               BT_LOGV("Found message's timestamp: "
+                       "iter-data-addr=%p, msg-addr=%p, "
+                       "last-msg-ts=%" PRId64 ", ts=%" PRId64,
+                       lttng_live_msg_iter, msg, last_msg_ts_ns, *ts_ns);
+       }
+
+       return ret;
+}
+
+static
+enum lttng_live_iterator_status lttng_live_iterator_next_handle_one_active_data_stream(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *lttng_live_stream,
+               bt_message **message)
+{
+       enum lttng_live_iterator_status ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
+       enum bt_msg_iter_status status;
+       uint64_t session_idx, trace_idx;
+
+       for (session_idx = 0; session_idx < lttng_live_msg_iter->sessions->len;
+                       session_idx++) {
+               struct lttng_live_session *session =
+                       g_ptr_array_index(lttng_live_msg_iter->sessions, session_idx);
+
+               if (session->new_streams_needed) {
+                       ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
+                       goto end;
+               }
+               for (trace_idx = 0; trace_idx < session->traces->len;
+                               trace_idx++) {
+                       struct lttng_live_trace *trace =
+                               g_ptr_array_index(session->traces, trace_idx);
+                       if (trace->new_metadata_needed) {
+                               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
+                               goto end;
+                       }
+               }
+       }
+
+       if (lttng_live_stream->state != LTTNG_LIVE_STREAM_ACTIVE_DATA) {
+               ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       status = bt_msg_iter_get_next_message(lttng_live_stream->msg_iter,
+               lttng_live_msg_iter->self_msg_iter, message);
+       switch (status) {
+       case BT_MSG_ITER_STATUS_EOF:
+               ret = LTTNG_LIVE_ITERATOR_STATUS_END;
+               break;
+       case BT_MSG_ITER_STATUS_OK:
+               ret = LTTNG_LIVE_ITERATOR_STATUS_OK;
+               break;
+       case BT_MSG_ITER_STATUS_AGAIN:
+               /*
+                * Continue immediately (end of packet). The next
+                * get_index may return AGAIN to delay the following
+                * attempt.
+                */
+               ret = LTTNG_LIVE_ITERATOR_STATUS_CONTINUE;
+               break;
+       case BT_MSG_ITER_STATUS_INVAL:
+               /* No argument provided by the user, so don't return INVAL. */
+       case BT_MSG_ITER_STATUS_ERROR:
+       default:
+               ret = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+               BT_LOGW("CTF msg iterator return an error or failed msg_iter=%p",
+                       lttng_live_stream->msg_iter);
+               break;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * helper function:
+ *            handle_no_data_streams()
+ *              retry:
+ *                - for each ACTIVE_NO_DATA stream:
+ *                  - query relayd for stream data, or quiescence info.
+ *                    - if need metadata, get metadata, goto retry.
+ *                    - if new stream, get new stream as ACTIVE_NO_DATA, goto retry
+ *                  - if quiescent, move to QUIESCENT streams
+ *                  - if fetched data, move to ACTIVE_DATA streams
+ *                (at this point each stream either has data, or is quiescent)
+ *
+ *
+ * iterator_next:
+ *            handle_new_streams_and_metadata()
+ *                  - query relayd for known streams, add them as ACTIVE_NO_DATA
+ *                  - query relayd for metadata
+ *
+ *            call handle_active_no_data_streams()
+ *
+ *            handle_quiescent_streams()
+ *                - if at least one stream is ACTIVE_DATA:
+ *                  - peek stream event with lowest timestamp -> next_ts
+ *                  - for each quiescent stream
+ *                    - if next_ts >= quiescent end
+ *                      - set state to ACTIVE_NO_DATA
+ *                - else
+ *                  - for each quiescent stream
+ *                      - set state to ACTIVE_NO_DATA
+ *
+ *            call handle_active_no_data_streams()
+ *
+ *            handle_active_data_streams()
+ *                - if at least one stream is ACTIVE_DATA:
+ *                    - get stream event with lowest timestamp from heap
+ *                    - make that stream event the current message.
+ *                    - move this stream heap position to its next event
+ *                      - if we need to fetch data from relayd, move
+ *                        stream to ACTIVE_NO_DATA.
+ *                    - return OK
+ *                - return AGAIN
+ *
+ * end criterion: ctrl-c on client. If relayd exits or the session
+ * closes on the relay daemon side, we keep on waiting for streams.
+ * Eventually handle --end timestamp (also an end criterion).
+ *
+ * When disconnected from relayd: try to re-connect endlessly.
+ */
+static
+enum lttng_live_iterator_status lttng_live_iterator_next_on_stream(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream_iter,
+               bt_message **curr_msg)
+{
+       enum lttng_live_iterator_status live_status;
+
+retry:
+       print_stream_state(stream_iter);
+       live_status = lttng_live_iterator_handle_new_streams_and_metadata(
+                       lttng_live_msg_iter);
+       if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+               goto end;
+       }
+       live_status = lttng_live_iterator_next_handle_one_no_data_stream(
+                       lttng_live_msg_iter, stream_iter);
+       if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+               goto end;
+       }
+       live_status = lttng_live_iterator_next_handle_one_quiescent_stream(
+                       lttng_live_msg_iter, stream_iter, curr_msg);
+       if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+               BT_ASSERT(*curr_msg == NULL);
+               goto end;
+       }
+       if (*curr_msg) {
+               goto end;
+       }
+       live_status = lttng_live_iterator_next_handle_one_active_data_stream(
+                       lttng_live_msg_iter, stream_iter, curr_msg);
+       if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+               BT_ASSERT(*curr_msg == NULL);
+       }
+
+end:
+       if (live_status == LTTNG_LIVE_ITERATOR_STATUS_CONTINUE) {
+               goto retry;
+       }
+
+       return live_status;
+}
+
+static
+enum lttng_live_iterator_status next_stream_iterator_for_trace(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_trace *live_trace,
+               struct lttng_live_stream_iterator **candidate_stream_iter)
+{
+       struct lttng_live_stream_iterator *curr_candidate_stream_iter = NULL;
+       enum lttng_live_iterator_status stream_iter_status;;
+       int64_t curr_candidate_msg_ts = INT64_MAX;
+       uint64_t stream_iter_idx;
+
+       BT_ASSERT(live_trace);
+       BT_ASSERT(live_trace->stream_iterators);
+       /*
+        * Update the current message of every stream iterators of this trace.
+        * The current msg of every stream must have a timestamp equal or
+        * larger than the last message returned by this iterator. We must
+        * ensure monotonicity.
+        */
+       stream_iter_idx = 0;
+       while (stream_iter_idx < live_trace->stream_iterators->len) {
+               bool stream_iter_is_ended = false;
+               struct lttng_live_stream_iterator *stream_iter =
+                       g_ptr_array_index(live_trace->stream_iterators,
+                                       stream_iter_idx);
+
+               /*
+                * Find if there is are now current message for this stream
+                * iterator get it.
+                */
+               while (!stream_iter->current_msg) {
+                       bt_message *msg = NULL;
+                       int64_t curr_msg_ts_ns = INT64_MAX;
+                       stream_iter_status = lttng_live_iterator_next_on_stream(
+                                       lttng_live_msg_iter, stream_iter, &msg);
+
+                       BT_LOGD("live stream iterator returned status :%s",
+                                       print_live_iterator_status(stream_iter_status));
+                       if (stream_iter_status == LTTNG_LIVE_ITERATOR_STATUS_END) {
+                               stream_iter_is_ended = true;
+                               break;
+                       }
+
+                       if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       BT_ASSERT(msg);
+
+                       /*
+                        * Get the timestamp in nanoseconds from origin of this
+                        * messsage.
+                        */
+                       live_get_msg_ts_ns(stream_iter, lttng_live_msg_iter,
+                               msg, lttng_live_msg_iter->last_msg_ts_ns,
+                               &curr_msg_ts_ns);
+
+                       /*
+                        * Check if the message of the current live stream
+                        * iterator occured at the exact same time or after the
+                        * last message returned by this component's message
+                        * iterator. If not, we return an error.
+                        */
+                       if (curr_msg_ts_ns >= lttng_live_msg_iter->last_msg_ts_ns) {
+                               stream_iter->current_msg = msg;
+                               stream_iter->current_msg_ts_ns = curr_msg_ts_ns;
+                       } else {
+                               /*
+                                * We received a message in the past. To ensure
+                                * monotonicity, we can't send it forward.
+                                */
+                               BT_LOGE("Message's timestamp is less than "
+                                       "lttng-live's message iterator's last "
+                                       "returned timestamp: "
+                                       "lttng-live-msg-iter-addr=%p, ts=%" PRId64 ", "
+                                       "last-msg-ts=%" PRId64,
+                                       lttng_live_msg_iter, curr_msg_ts_ns,
+                                       lttng_live_msg_iter->last_msg_ts_ns);
+                               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+               }
+
+               if (!stream_iter_is_ended &&
+                               stream_iter->current_msg_ts_ns <= curr_candidate_msg_ts) {
+                       /*
+                        * Update the current best candidate message for the
+                        * stream iterator of thise live trace to be forwarded
+                        * downstream.
+                        */
+                       curr_candidate_msg_ts = stream_iter->current_msg_ts_ns;
+                       curr_candidate_stream_iter = stream_iter;
+               }
+
+               if (stream_iter_is_ended) {
+                       /*
+                        * The live stream iterator is ENDed. We remove that
+                        * iterator from the list and we restart the iteration
+                        * at the beginning of the live stream iterator array
+                        * to because the removal will shuffle the array.
+                        */
+                       g_ptr_array_remove_index_fast(live_trace->stream_iterators,
+                               stream_iter_idx);
+                       stream_iter_idx = 0;
+               } else {
+                       stream_iter_idx++;
+               }
+       }
+
+       if (curr_candidate_stream_iter) {
+               *candidate_stream_iter = curr_candidate_stream_iter;
+               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
+       } else {
+               /*
+                * The only case where we don't have a candidate for this trace
+                * is if we reached the end of all the iterators.
+                */
+               BT_ASSERT(live_trace->stream_iterators->len == 0);
+               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_END;
+       }
+
+end:
+       return stream_iter_status;
+}
+
+static
+enum lttng_live_iterator_status next_stream_iterator_for_session(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_session *session,
+               struct lttng_live_stream_iterator **candidate_session_stream_iter)
+{
+       enum lttng_live_iterator_status stream_iter_status;
+       uint64_t trace_idx = 0;
+       int64_t curr_candidate_msg_ts = INT64_MAX;
+       struct lttng_live_stream_iterator *curr_candidate_stream_iter = NULL;
+
+       /*
+        * Make sure we are attached to the session and look for new streams
+        * and metadata.
+        */
+       stream_iter_status = lttng_live_get_session(lttng_live_msg_iter, session);
+       if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK &&
+                       stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_CONTINUE &&
+                       stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_END) {
+               goto end;
+       }
+
+       BT_ASSERT(session->traces);
+
+       /*
+        * Use while loops here rather then for loops so we can restart the
+        * iteration if an element is removed from the array during the
+        * looping.
+        */
+       while (trace_idx < session->traces->len) {
+               bool trace_is_ended = false;
+               struct lttng_live_stream_iterator *stream_iter;
+               struct lttng_live_trace *trace =
+                       g_ptr_array_index(session->traces, trace_idx);
+
+               stream_iter_status = next_stream_iterator_for_trace(
+                       lttng_live_msg_iter, trace, &stream_iter);
+               if (stream_iter_status == LTTNG_LIVE_ITERATOR_STATUS_END) {
+                       /*
+                        * All the live stream iterators for this trace are
+                        * ENDed. Remove the trace from this session.
+                        */
+                       trace_is_ended = true;
+               } else if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+                       goto end;
+               }
+
+               if (!trace_is_ended) {
+                       BT_ASSERT(stream_iter);
+
+                       if (stream_iter->current_msg_ts_ns <= curr_candidate_msg_ts) {
+                               curr_candidate_msg_ts = stream_iter->current_msg_ts_ns;
+                               curr_candidate_stream_iter = stream_iter;
+                       }
+                       trace_idx++;
+               } else {
+                       g_ptr_array_remove_index_fast(session->traces, trace_idx);
+                       trace_idx = 0;
+               }
+       }
+       if (curr_candidate_stream_iter) {
+               *candidate_session_stream_iter = curr_candidate_stream_iter;
+               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
+       } else {
+               /*
+                * The only cases where we don't have a candidate for this
+                * trace is:
+                *  1. if we reached the end of all the iterators of all the
+                *  traces of this session,
+                *  2. if we never had live stream iterator in the first place.
+                *
+                * In either cases, we return END.
+                */
+               BT_ASSERT(session->traces->len == 0);
+               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_END;
+       }
+end:
+       return stream_iter_status;
+}
+
+static inline
+void put_messages(bt_message_array_const msgs, uint64_t count)
+{
+       uint64_t i;
+
+       for (i = 0; i < count; i++) {
+               BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
+       }
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status lttng_live_msg_iter_next(
+               bt_self_message_iterator *self_msg_it,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       bt_self_message_iterator_status status;
+       struct lttng_live_msg_iter *lttng_live_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_it);
+       struct lttng_live_component *lttng_live =
+               lttng_live_msg_iter->lttng_live_comp;
+       enum lttng_live_iterator_status stream_iter_status;
+       uint64_t session_idx;
+
+       *count = 0;
+
+       BT_ASSERT(lttng_live_msg_iter);
+
+       /*
+        * Clear all the invalid message reference that might be left over in
+        * the output array.
+        */
+       memset(msgs, 0, capacity * sizeof(*msgs));
+
+       /*
+        * If no session are exposed on the relay found at the url provided by
+        * the user, session count will be 0. In this case, we return status
+        * end to return gracefully.
+        */
+       if (lttng_live_msg_iter->sessions->len == 0) {
+               if (lttng_live->params.sess_not_found_act !=
+                               SESSION_NOT_FOUND_ACTION_CONTINUE) {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+                       goto no_session;
+               } else {
+                       /*
+                        * The are no more active session for this session
+                        * name. Retry to create a viewer session for the
+                        * requested session name.
+                        */
+                       if (lttng_live_create_viewer_session(lttng_live_msg_iter)) {
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto no_session;
+                       }
+               }
+       }
+
+       if (lttng_live_msg_iter->active_stream_iter == 0) {
+               lttng_live_force_new_streams_and_metadata(lttng_live_msg_iter);
+       }
+
+       /*
+        * Here the muxing of message is done.
+        *
+        * We need to iterate over all the streams of all the traces of all the
+        * viewer sessions in order to get the message with the smallest
+        * timestamp. In this case, a session is a viewer session and there is
+        * one viewer session per consumer daemon. (UST 32bit, UST 64bit and/or
+        * kernel). Each viewer session can have multiple traces, for example,
+        * 64bit UST viewer sessions could have multiple per-pid traces.
+        *
+        * We iterate over the streams of each traces to update and see what is
+        * their next message's timestamp. From those timestamps, we select the
+        * message with the smallest timestamp as the best candidate message
+        * for that trace and do the same thing across all the sessions.
+        *
+        * We then compare the timestamp of best candidate message of all the
+        * sessions to pick the message with the smallest timestamp and we
+        * return it.
+        */
+       while (*count < capacity) {
+               struct lttng_live_stream_iterator *next_stream_iter = NULL,
+                                                 *candidate_stream_iter = NULL;
+               int64_t next_msg_ts_ns = INT64_MAX;
+
+               BT_ASSERT(lttng_live_msg_iter->sessions);
+               session_idx = 0;
+               /*
+                * Use a while loop instead of a for loop so we can restart the
+                * iteration if we remove an element. We can safely call
+                * next_stream_iterator_for_session() multiple times on the
+                * same session as we only fetch a new message if there is no
+                * current next message for each live stream iterator.
+                * If all live stream iterator of that session already have a
+                * current next message, the function will simply exit return
+                * the same candidate live stream iterator every time.
+                */
+               while (session_idx < lttng_live_msg_iter->sessions->len) {
+                       struct lttng_live_session *session =
+                               g_ptr_array_index(lttng_live_msg_iter->sessions,
+                                       session_idx);
+
+                       /* Find the best candidate message to send downstream. */
+                       stream_iter_status = next_stream_iterator_for_session(
+                               lttng_live_msg_iter, session,
+                               &candidate_stream_iter);
+
+                       /* If we receive an END status, it means that either:
+                        * - Those traces never had active streams (UST with no
+                        *   data produced yet),
+                        * - All live stream iterators have ENDed.*/
+                       if (stream_iter_status == LTTNG_LIVE_ITERATOR_STATUS_END) {
+                               if (session->closed && session->traces->len == 0) {
+                                       /*
+                                        * Remove the session from the list and restart the
+                                        * iteration at the beginning of the array since the
+                                        * removal shuffle the elements of the array.
+                                        */
+                                       g_ptr_array_remove_index_fast(
+                                               lttng_live_msg_iter->sessions,
+                                               session_idx);
+                                       session_idx = 0;
+                               } else {
+                                       session_idx++;
+                               }
+                               continue;
+                       }
+
+                       if (stream_iter_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       if (candidate_stream_iter->current_msg_ts_ns <= next_msg_ts_ns) {
+                               next_msg_ts_ns = candidate_stream_iter->current_msg_ts_ns;
+                               next_stream_iter = candidate_stream_iter;
+                       }
+
+                       session_idx++;
+               }
+
+               if (!next_stream_iter) {
+                       stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+                       goto end;
+               }
+
+               BT_ASSERT(next_stream_iter->current_msg);
+               /* Ensure monotonicity. */
+               BT_ASSERT(lttng_live_msg_iter->last_msg_ts_ns <=
+                       next_stream_iter->current_msg_ts_ns);
+
+               /*
+                * Insert the next message to the message batch. This will set
+                * stream iterator current messsage to NULL so that next time
+                * we fetch the next message of that stream iterator
+                */
+               BT_MESSAGE_MOVE_REF(msgs[*count], next_stream_iter->current_msg);
+               (*count)++;
+
+               /* Update the last timestamp in nanoseconds sent downstream. */
+               lttng_live_msg_iter->last_msg_ts_ns = next_msg_ts_ns;
+               next_stream_iter->current_msg_ts_ns = INT64_MAX;
+
+               stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
+       }
+end:
+       switch (stream_iter_status) {
+       case LTTNG_LIVE_ITERATOR_STATUS_OK:
+       case LTTNG_LIVE_ITERATOR_STATUS_AGAIN:
+               if (*count > 0) {
+                       /*
+                        * We received a again status but we have some messages
+                        * to send downstream. We send them and return OK for
+                        * now. On the next call we return again if there are
+                        * still no new message to send.
+                        */
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+               } else {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN;
+               }
+               break;
+       case LTTNG_LIVE_ITERATOR_STATUS_END:
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+               break;
+       case LTTNG_LIVE_ITERATOR_STATUS_NOMEM:
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               break;
+       case LTTNG_LIVE_ITERATOR_STATUS_ERROR:
+       case LTTNG_LIVE_ITERATOR_STATUS_INVAL:
+       case LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED:
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               /* Put all existing messages on error. */
+               put_messages(msgs, *count);
+               break;
+       default:
+               abort();
+       }
+
+no_session:
+       return status;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status lttng_live_msg_iter_init(
+               bt_self_message_iterator *self_msg_it,
+               bt_self_component_source *self_comp_src,
+               bt_self_component_port_output *self_port)
+{
+       bt_self_message_iterator_status ret =
+                       BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       bt_self_component *self_comp =
+                       bt_self_component_source_as_self_component(self_comp_src);
+       struct lttng_live_component *lttng_live;
+       struct lttng_live_msg_iter *lttng_live_msg_iter;
+
+       BT_ASSERT(self_msg_it);
+
+       lttng_live = bt_self_component_get_data(self_comp);
+
+       /* There can be only one downstream iterator at the same time. */
+       BT_ASSERT(!lttng_live->has_msg_iter);
+       lttng_live->has_msg_iter = true;
+
+       lttng_live_msg_iter = g_new0(struct lttng_live_msg_iter, 1);
+       if (!lttng_live_msg_iter) {
+               ret = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       lttng_live_msg_iter->lttng_live_comp = lttng_live;
+       lttng_live_msg_iter->self_msg_iter = self_msg_it;
+
+       lttng_live_msg_iter->active_stream_iter = 0;
+       lttng_live_msg_iter->last_msg_ts_ns = INT64_MIN;
+       lttng_live_msg_iter->sessions = g_ptr_array_new_with_free_func(
+               (GDestroyNotify) lttng_live_destroy_session);
+       BT_ASSERT(lttng_live_msg_iter->sessions);
+
+       lttng_live_msg_iter->viewer_connection =
+               live_viewer_connection_create(lttng_live->params.url->str, false,
+                       lttng_live_msg_iter);
+       if (!lttng_live_msg_iter->viewer_connection) {
+               goto error;
+       }
+
+       if (lttng_live_create_viewer_session(lttng_live_msg_iter)) {
+               goto error;
+       }
+       if (lttng_live_msg_iter->sessions->len == 0) {
+               switch (lttng_live->params.sess_not_found_act) {
+               case SESSION_NOT_FOUND_ACTION_CONTINUE:
+                       BT_LOGI("Unable to connect to the requested live viewer "
+                               "session. Keep trying to connect because of "
+                               "%s=\"%s\" component parameter: url=\"%s\"",
+                               SESS_NOT_FOUND_ACTION_PARAM,
+                               SESS_NOT_FOUND_ACTION_CONTINUE_STR,
+                               lttng_live->params.url->str);
+                       break;
+               case SESSION_NOT_FOUND_ACTION_FAIL:
+                       BT_LOGE("Unable to connect to the requested live viewer "
+                               "session. Fail the message iterator"
+                               "initialization because of %s=\"%s\" "
+                               "component parameter: url =\"%s\"",
+                               SESS_NOT_FOUND_ACTION_PARAM,
+                               SESS_NOT_FOUND_ACTION_FAIL_STR,
+                               lttng_live->params.url->str);
+                       goto error;
+               case SESSION_NOT_FOUND_ACTION_END:
+                       BT_LOGI("Unable to connect to the requested live viewer "
+                               "session. End gracefully at the first _next() "
+                               "call because of %s=\"%s\" component parameter: "
+                               "url=\"%s\"", SESS_NOT_FOUND_ACTION_PARAM,
+                               SESS_NOT_FOUND_ACTION_END_STR,
+                               lttng_live->params.url->str);
+                       break;
+               }
+       }
+
+       bt_self_message_iterator_set_data(self_msg_it, lttng_live_msg_iter);
+
+       goto end;
+error:
+       ret = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+       lttng_live_msg_iter_destroy(lttng_live_msg_iter);
+end:
+       return ret;
+}
+
+static
+bt_query_status lttng_live_query_list_sessions(const bt_value *params,
+               const bt_value **result)
+{
+       bt_query_status status = BT_QUERY_STATUS_OK;
+       const bt_value *url_value = NULL;
+       const char *url;
+       struct live_viewer_connection *viewer_connection = NULL;
+
+       url_value = bt_value_map_borrow_entry_value_const(params, URL_PARAM);
+       if (!url_value) {
+               BT_LOGW("Mandatory `%s` parameter missing", URL_PARAM);
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+               goto error;
+       }
+
+       if (!bt_value_is_string(url_value)) {
+               BT_LOGW("`%s` parameter is required to be a string value",
+                       URL_PARAM);
+               status = BT_QUERY_STATUS_INVALID_PARAMS;
+               goto error;
+       }
+
+       url = bt_value_string_get(url_value);
+
+       viewer_connection = live_viewer_connection_create(url, true, NULL);
+       if (!viewer_connection) {
+               goto error;
+       }
+
+       status = live_viewer_connection_list_sessions(viewer_connection,
+                       result);
+       if (status != BT_QUERY_STATUS_OK) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_VALUE_PUT_REF_AND_RESET(*result);
+
+       if (status >= 0) {
+               status = BT_QUERY_STATUS_ERROR;
+       }
+
+end:
+       if (viewer_connection) {
+               live_viewer_connection_destroy(viewer_connection);
+       }
+       return status;
+}
+
+BT_HIDDEN
+bt_query_status lttng_live_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, "sessions") == 0) {
+               status = lttng_live_query_list_sessions(params, result);
+       } else {
+               BT_LOGW("Unknown query object `%s`", object);
+               status = BT_QUERY_STATUS_INVALID_OBJECT;
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+static
+void lttng_live_component_destroy_data(struct lttng_live_component *lttng_live)
+{
+       if (!lttng_live) {
+               return;
+       }
+       if (lttng_live->params.url) {
+               g_string_free(lttng_live->params.url, TRUE);
+       }
+       g_free(lttng_live);
+}
+
+BT_HIDDEN
+void lttng_live_component_finalize(bt_self_component_source *component)
+{
+       void *data = bt_self_component_get_data(
+                       bt_self_component_source_as_self_component(component));
+
+       if (!data) {
+               return;
+       }
+       lttng_live_component_destroy_data(data);
+}
+
+static
+enum session_not_found_action parse_session_not_found_action_param(
+       const bt_value *no_session_param)
+{
+       enum session_not_found_action action;
+       const char *no_session_act_str;
+       no_session_act_str = bt_value_string_get(no_session_param);
+       if (strcmp(no_session_act_str, SESS_NOT_FOUND_ACTION_CONTINUE_STR) == 0) {
+               action = SESSION_NOT_FOUND_ACTION_CONTINUE;
+       } else if (strcmp(no_session_act_str, SESS_NOT_FOUND_ACTION_FAIL_STR) == 0) {
+               action = SESSION_NOT_FOUND_ACTION_FAIL;
+       } else if (strcmp(no_session_act_str, SESS_NOT_FOUND_ACTION_END_STR) == 0) {
+               action = SESSION_NOT_FOUND_ACTION_END;
+       } else {
+               action = -1;
+       }
+
+       return action;
+}
+
+struct lttng_live_component *lttng_live_component_create(const bt_value *params)
+{
+       struct lttng_live_component *lttng_live;
+       const bt_value *value = NULL;
+       const char *url;
+
+       lttng_live = g_new0(struct lttng_live_component, 1);
+       if (!lttng_live) {
+               goto end;
+       }
+       lttng_live->max_query_size = MAX_QUERY_SIZE;
+       lttng_live->has_msg_iter = false;
+
+       value = bt_value_map_borrow_entry_value_const(params, URL_PARAM);
+       if (!value || !bt_value_is_string(value)) {
+               BT_LOGW("Mandatory `%s` parameter missing or not a string",
+                       URL_PARAM);
+               goto error;
+       }
+       url = bt_value_string_get(value);
+       lttng_live->params.url = g_string_new(url);
+       if (!lttng_live->params.url) {
+               goto error;
+       }
+
+       value = bt_value_map_borrow_entry_value_const(params,
+               SESS_NOT_FOUND_ACTION_PARAM);
+
+       if (value && bt_value_is_string(value)) {
+               lttng_live->params.sess_not_found_act =
+                       parse_session_not_found_action_param(value);
+               if (lttng_live->params.sess_not_found_act == -1) {
+                       BT_LOGE("Unexpected value for `%s` parameter: "
+                               "value=\"%s\"", SESS_NOT_FOUND_ACTION_PARAM,
+                               bt_value_string_get(value));
+                       goto error;
+               }
+       } else {
+               BT_LOGW("Optional `%s` parameter is missing or "
+                       "not a string value. Defaulting to %s=\"%s\".",
+                       SESS_NOT_FOUND_ACTION_PARAM,
+                       SESS_NOT_FOUND_ACTION_PARAM,
+                       SESS_NOT_FOUND_ACTION_CONTINUE_STR);
+               lttng_live->params.sess_not_found_act =
+                       SESSION_NOT_FOUND_ACTION_CONTINUE;
+       }
+
+       goto end;
+
+error:
+       lttng_live_component_destroy_data(lttng_live);
+       lttng_live = NULL;
+end:
+       return lttng_live;
+}
+
+BT_HIDDEN
+bt_self_component_status lttng_live_component_init(
+               bt_self_component_source *self_comp,
+               const bt_value *params, UNUSED_VAR void *init_method_data)
+{
+       struct lttng_live_component *lttng_live;
+       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
+
+       lttng_live = lttng_live_component_create(params);
+       if (!lttng_live) {
+               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto error;
+       }
+       lttng_live->self_comp = self_comp;
+
+       if (lttng_live_graph_is_canceled(lttng_live)) {
+               ret = BT_SELF_COMPONENT_STATUS_END;
+               goto error;
+       }
+
+       ret = bt_self_component_source_add_output_port(
+                               lttng_live->self_comp, "out",
+                               NULL, NULL);
+       if (ret != BT_SELF_COMPONENT_STATUS_OK) {
+               goto error;
+       }
+
+       bt_self_component_set_data(
+                       bt_self_component_source_as_self_component(self_comp),
+                       lttng_live);
+       goto end;
+
+error:
+       lttng_live_component_destroy_data(lttng_live);
+       lttng_live = NULL;
+end:
+       return ret;
+}
diff --git a/src/plugins/ctf/lttng-live/lttng-live.h b/src/plugins/ctf/lttng-live/lttng-live.h
new file mode 100644 (file)
index 0000000..5c8dc41
--- /dev/null
@@ -0,0 +1,300 @@
+#ifndef BABELTRACE_PLUGIN_CTF_LTTNG_LIVE_H
+#define BABELTRACE_PLUGIN_CTF_LTTNG_LIVE_H
+
+/*
+ * BabelTrace - LTTng-live client Component
+ *
+ * Copyright 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "../common/metadata/decoder.h"
+#include "../common/msg-iter/msg-iter.h"
+
+#include "viewer-connection.h"
+
+struct lttng_live_component;
+struct lttng_live_session;
+struct lttng_live_msg_iter;
+
+enum lttng_live_stream_state {
+       /* This stream won't have data until some known time in the future. */
+       LTTNG_LIVE_STREAM_QUIESCENT,
+       /*
+        * This stream won't have data until some known time in the future and
+        * the message iterator inactivity message was already sent downstream.
+        */
+       LTTNG_LIVE_STREAM_QUIESCENT_NO_DATA, /* */
+       /* This stream has data ready to be consumed. */
+       LTTNG_LIVE_STREAM_ACTIVE_DATA,
+       /*
+        * This stream has no data left to consume. We should asked the relay
+        * for more.
+        */
+       LTTNG_LIVE_STREAM_ACTIVE_NO_DATA,
+       /* This stream won't have anymore data, ever. */
+       LTTNG_LIVE_STREAM_EOF,
+};
+
+/* Iterator over a live stream. */
+struct lttng_live_stream_iterator {
+       /* Owned by this. */
+       bt_stream *stream;
+
+       /* Weak reference. */
+       struct lttng_live_trace *trace;
+
+       /*
+        * Since only a single iterator per viewer connection, we have
+        * only a single message iterator per stream.
+        */
+       struct bt_msg_iter *msg_iter;
+
+       uint64_t viewer_stream_id;
+
+       uint64_t ctf_stream_class_id;
+
+       /* base offset in current index. */
+       uint64_t base_offset;
+       /* len to read in current index. */
+       uint64_t len;
+       /* offset in current index. */
+       uint64_t offset;
+
+       /*
+        * Clock Snapshot value of the last message iterator inactivity message
+        * sent downstream.
+        */
+       uint64_t last_inactivity_ts;
+
+       /*
+        * Clock Snapshot value of the current message iterator inactivity
+        * message we might want to send downstream.
+        */
+       uint64_t current_inactivity_ts;
+
+       enum lttng_live_stream_state state;
+
+       /*
+        * The current message produced by this live stream iterator. Owned by
+        * this.
+        */
+       bt_message *current_msg;
+
+       /* Timestamp in nanoseconds of the current message (current_msg). */
+       int64_t current_msg_ts_ns;
+
+       /* Owned by this. */
+       uint8_t *buf;
+       size_t buflen;
+
+       /* Owned by this. */
+       GString *name;
+};
+
+struct lttng_live_metadata {
+       /* Weak reference. */
+       struct lttng_live_trace *trace;
+
+       uint64_t stream_id;
+       /* Weak reference. */
+       struct ctf_metadata_decoder *decoder;
+
+       bool closed;
+};
+
+struct lttng_live_trace {
+       /* Back reference to session. */
+       struct lttng_live_session *session;
+
+       /* ctf trace ID within the session. */
+       uint64_t id;
+
+       /* Owned by this. */
+       bt_trace *trace;
+
+       /* Weak reference. */
+       bt_trace_class *trace_class;
+
+       struct lttng_live_metadata *metadata;
+
+       const bt_clock_class *clock_class;
+
+       /* Array of pointers to struct lttng_live_stream_iterator. */
+       /* Owned by this. */
+       GPtrArray *stream_iterators;
+
+       bool new_metadata_needed;
+};
+
+struct lttng_live_session {
+       /* Weak reference. */
+       struct lttng_live_msg_iter *lttng_live_msg_iter;
+
+       /* Owned by this. */
+       GString *hostname;
+
+       /* Owned by this. */
+       GString *session_name;
+
+       uint64_t id;
+
+       /* Array of pointers to struct lttng_live_trace. */
+       GPtrArray *traces;
+
+       bool attached;
+       bool new_streams_needed;
+       bool lazy_stream_msg_init;
+       bool closed;
+};
+
+enum session_not_found_action {
+       SESSION_NOT_FOUND_ACTION_CONTINUE,
+       SESSION_NOT_FOUND_ACTION_FAIL,
+       SESSION_NOT_FOUND_ACTION_END,
+};
+
+/*
+ * A component instance is an iterator on a single session.
+ */
+struct lttng_live_component {
+       /* Weak reference. */
+       bt_self_component_source *self_comp;
+
+       struct {
+               GString *url;
+               enum session_not_found_action sess_not_found_act;
+       } params;
+
+       size_t max_query_size;
+
+       /*
+        * Keeps track of whether the downstream component already has a
+        * message iterator on this component.
+        */
+       bool has_msg_iter;
+};
+
+struct lttng_live_msg_iter {
+       /* Weak reference. */
+       struct lttng_live_component *lttng_live_comp;
+
+       /* Weak reference. */
+       bt_self_message_iterator *self_msg_iter;
+
+       /* Owned by this. */
+       struct live_viewer_connection *viewer_connection;
+
+       /* Array of pointers to struct lttng_live_session. */
+       GPtrArray *sessions;
+
+       /* Number of live stream iterator this message iterator has.*/
+       uint64_t active_stream_iter;
+
+       /* Timestamp in nanosecond of the last message sent downstream. */
+       int64_t last_msg_ts_ns;
+};
+
+enum lttng_live_iterator_status {
+       /** Iterator state has progressed. Continue iteration immediately. */
+       LTTNG_LIVE_ITERATOR_STATUS_CONTINUE = 3,
+       /** No message available for now. Try again later. */
+       LTTNG_LIVE_ITERATOR_STATUS_AGAIN = 2,
+       /** No more CTF_LTTNG_LIVEs to be delivered. */
+       LTTNG_LIVE_ITERATOR_STATUS_END = 1,
+       /** No error, okay. */
+       LTTNG_LIVE_ITERATOR_STATUS_OK = 0,
+       /** Invalid arguments. */
+       LTTNG_LIVE_ITERATOR_STATUS_INVAL = -1,
+       /** General error. */
+       LTTNG_LIVE_ITERATOR_STATUS_ERROR = -2,
+       /** Out of memory. */
+       LTTNG_LIVE_ITERATOR_STATUS_NOMEM = -3,
+       /** Unsupported iterator feature. */
+       LTTNG_LIVE_ITERATOR_STATUS_UNSUPPORTED = -4,
+};
+
+bt_self_component_status lttng_live_component_init(
+               bt_self_component_source *self_comp,
+               const bt_value *params, void *init_method_data);
+
+bt_query_status lttng_live_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);
+
+void lttng_live_component_finalize(bt_self_component_source *component);
+
+bt_self_message_iterator_status lttng_live_msg_iter_next(
+               bt_self_message_iterator *iterator,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count);
+
+bt_self_message_iterator_status lttng_live_msg_iter_init(
+               bt_self_message_iterator *self_msg_it,
+               bt_self_component_source *self_comp,
+               bt_self_component_port_output *self_port);
+
+void lttng_live_msg_iter_finalize(bt_self_message_iterator *it);
+
+int lttng_live_create_viewer_session(struct lttng_live_msg_iter *lttng_live_msg_iter);
+int lttng_live_attach_session(struct lttng_live_session *session);
+int lttng_live_detach_session(struct lttng_live_session *session);
+enum lttng_live_iterator_status lttng_live_get_new_streams(
+               struct lttng_live_session *session);
+
+int lttng_live_add_session(struct lttng_live_msg_iter *lttng_live_msg_iter,
+               uint64_t session_id,
+               const char *hostname,
+               const char *session_name);
+
+ssize_t lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace,
+               FILE *fp);
+enum lttng_live_iterator_status lttng_live_get_next_index(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream,
+               struct packet_index *index);
+
+enum bt_msg_iter_medium_status lttng_live_get_stream_bytes(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream, uint8_t *buf,
+               uint64_t offset, uint64_t req_len, uint64_t *recv_len);
+void lttng_live_add_stream_iterator(struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream_iter);
+void lttng_live_remove_stream_iterator(struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream_iter);
+
+struct lttng_live_trace *lttng_live_borrow_trace(
+               struct lttng_live_session *session, uint64_t trace_id);
+void lttng_live_need_new_streams(struct lttng_live_msg_iter *lttng_live_msg_iter);
+
+bool lttng_live_graph_is_canceled(struct lttng_live_component *lttng_live);
+
+#endif /* BABELTRACE_PLUGIN_CTF_LTTNG_LIVE_H */
diff --git a/src/plugins/ctf/lttng-live/lttng-viewer-abi.h b/src/plugins/ctf/lttng-live/lttng-viewer-abi.h
new file mode 100644 (file)
index 0000000..9f6154b
--- /dev/null
@@ -0,0 +1,254 @@
+#ifndef LTTNG_VIEWER_ABI_H
+#define LTTNG_VIEWER_ABI_H
+
+/*
+ * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
+ *                      Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *                      David Goulet <dgoulet@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "compat/limits.h"
+
+#define LTTNG_VIEWER_PATH_MAX          4096
+#define LTTNG_VIEWER_NAME_MAX          255
+#define LTTNG_VIEWER_HOST_NAME_MAX     64
+
+/* Flags in reply to get_next_index and get_packet. */
+enum {
+       /* New metadata is required to read this packet. */
+       LTTNG_VIEWER_FLAG_NEW_METADATA  = (1 << 0),
+       /* New stream got added to the trace. */
+       LTTNG_VIEWER_FLAG_NEW_STREAM    = (1 << 1),
+};
+
+enum lttng_viewer_command {
+       LTTNG_VIEWER_CONNECT            = 1,
+       LTTNG_VIEWER_LIST_SESSIONS      = 2,
+       LTTNG_VIEWER_ATTACH_SESSION     = 3,
+       LTTNG_VIEWER_GET_NEXT_INDEX     = 4,
+       LTTNG_VIEWER_GET_PACKET         = 5,
+       LTTNG_VIEWER_GET_METADATA       = 6,
+       LTTNG_VIEWER_GET_NEW_STREAMS    = 7,
+       LTTNG_VIEWER_CREATE_SESSION     = 8,
+       LTTNG_VIEWER_DETACH_SESSION     = 9,
+};
+
+enum lttng_viewer_attach_return_code {
+       LTTNG_VIEWER_ATTACH_OK          = 1, /* The attach command succeeded. */
+       LTTNG_VIEWER_ATTACH_ALREADY     = 2, /* A viewer is already attached. */
+       LTTNG_VIEWER_ATTACH_UNK         = 3, /* The session ID is unknown. */
+       LTTNG_VIEWER_ATTACH_NOT_LIVE    = 4, /* The session is not live. */
+       LTTNG_VIEWER_ATTACH_SEEK_ERR    = 5, /* Seek error. */
+       LTTNG_VIEWER_ATTACH_NO_SESSION  = 6, /* No viewer session created. */
+};
+
+enum lttng_viewer_detach_session_return_code {
+       LTTNG_VIEWER_DETACH_SESSION_OK          = 1,
+       LTTNG_VIEWER_DETACH_SESSION_UNK         = 2,
+       LTTNG_VIEWER_DETACH_SESSION_ERR         = 3,
+};
+
+enum lttng_viewer_next_index_return_code {
+       LTTNG_VIEWER_INDEX_OK           = 1, /* Index is available. */
+       LTTNG_VIEWER_INDEX_RETRY        = 2, /* Index not yet available. */
+       LTTNG_VIEWER_INDEX_HUP          = 3, /* Index closed (trace destroyed). */
+       LTTNG_VIEWER_INDEX_ERR          = 4, /* Unknow error. */
+       LTTNG_VIEWER_INDEX_INACTIVE     = 5, /* Inactive stream beacon. */
+       LTTNG_VIEWER_INDEX_EOF          = 6, /* End of index file. */
+};
+
+enum lttng_viewer_get_packet_return_code {
+       LTTNG_VIEWER_GET_PACKET_OK      = 1,
+       LTTNG_VIEWER_GET_PACKET_RETRY   = 2,
+       LTTNG_VIEWER_GET_PACKET_ERR     = 3,
+       LTTNG_VIEWER_GET_PACKET_EOF     = 4,
+};
+
+enum lttng_viewer_get_metadata_return_code {
+       LTTNG_VIEWER_METADATA_OK        = 1,
+       LTTNG_VIEWER_NO_NEW_METADATA    = 2,
+       LTTNG_VIEWER_METADATA_ERR       = 3,
+};
+
+enum lttng_viewer_connection_type {
+       LTTNG_VIEWER_CLIENT_COMMAND             = 1,
+       LTTNG_VIEWER_CLIENT_MESSAGE     = 2,
+};
+
+enum lttng_viewer_seek {
+       /* Receive the trace packets from the beginning. */
+       LTTNG_VIEWER_SEEK_BEGINNING     = 1,
+       /* Receive the trace packets from now. */
+       LTTNG_VIEWER_SEEK_LAST          = 2,
+};
+
+enum lttng_viewer_new_streams_return_code {
+       LTTNG_VIEWER_NEW_STREAMS_OK           = 1, /* If new streams are being sent. */
+       LTTNG_VIEWER_NEW_STREAMS_NO_NEW       = 2, /* If no new streams are available. */
+       LTTNG_VIEWER_NEW_STREAMS_ERR          = 3, /* Error. */
+       LTTNG_VIEWER_NEW_STREAMS_HUP          = 4, /* Session closed. */
+};
+
+enum lttng_viewer_create_session_return_code {
+       LTTNG_VIEWER_CREATE_SESSION_OK          = 1,
+       LTTNG_VIEWER_CREATE_SESSION_ERR         = 2,
+};
+
+struct lttng_viewer_session {
+       uint64_t id;
+       uint32_t live_timer;
+       uint32_t clients;
+       uint32_t streams;
+       char hostname[LTTNG_VIEWER_HOST_NAME_MAX];
+       char session_name[LTTNG_VIEWER_NAME_MAX];
+} __attribute__((__packed__));
+
+struct lttng_viewer_stream {
+       uint64_t id;
+       uint64_t ctf_trace_id;
+       uint32_t metadata_flag;
+       char path_name[LTTNG_VIEWER_PATH_MAX];
+       char channel_name[LTTNG_VIEWER_NAME_MAX];
+} __attribute__((__packed__));
+
+struct lttng_viewer_cmd {
+       uint64_t data_size;     /* data size following this header */
+       uint32_t cmd;           /* enum lttcomm_relayd_command */
+       uint32_t cmd_version;   /* command version */
+} __attribute__((__packed__));
+
+/*
+ * LTTNG_VIEWER_CONNECT payload.
+ */
+struct lttng_viewer_connect {
+       /* session ID assigned by the relay for command connections */
+       uint64_t viewer_session_id;
+       uint32_t major;
+       uint32_t minor;
+       uint32_t type;          /* enum lttng_viewer_connection_type */
+} __attribute__((__packed__));
+
+/*
+ * LTTNG_VIEWER_LIST_SESSIONS payload.
+ */
+struct lttng_viewer_list_sessions {
+       uint32_t sessions_count;
+       char session_list[];    /* struct lttng_viewer_session */
+} __attribute__((__packed__));
+
+/*
+ * LTTNG_VIEWER_ATTACH_SESSION payload.
+ */
+struct lttng_viewer_attach_session_request {
+       uint64_t session_id;
+       uint64_t offset;        /* unused for now */
+       uint32_t seek;          /* enum lttng_viewer_seek */
+} __attribute__((__packed__));
+
+struct lttng_viewer_attach_session_response {
+       /* enum lttng_viewer_attach_return_code */
+       uint32_t status;
+       uint32_t streams_count;
+       /* struct lttng_viewer_stream */
+       char stream_list[];
+} __attribute__((__packed__));
+
+/*
+ * LTTNG_VIEWER_GET_NEXT_INDEX payload.
+ */
+struct lttng_viewer_get_next_index {
+       uint64_t stream_id;
+} __attribute__ ((__packed__));
+
+struct lttng_viewer_index {
+       uint64_t offset;
+       uint64_t packet_size;
+       uint64_t content_size;
+       uint64_t timestamp_begin;
+       uint64_t timestamp_end;
+       uint64_t events_discarded;
+       uint64_t stream_id;
+       uint32_t status;        /* enum lttng_viewer_next_index_return_code */
+       uint32_t flags;         /* LTTNG_VIEWER_FLAG_* */
+} __attribute__ ((__packed__));
+
+/*
+ * LTTNG_VIEWER_GET_PACKET payload.
+ */
+struct lttng_viewer_get_packet {
+       uint64_t stream_id;
+       uint64_t offset;
+       uint32_t len;
+} __attribute__((__packed__));
+
+struct lttng_viewer_trace_packet {
+       uint32_t status;        /* enum lttng_viewer_get_packet_return_code */
+       uint32_t len;
+       uint32_t flags;         /* LTTNG_VIEWER_FLAG_* */
+       char data[];
+} __attribute__((__packed__));
+
+/*
+ * LTTNG_VIEWER_GET_METADATA payload.
+ */
+struct lttng_viewer_get_metadata {
+       uint64_t stream_id;
+} __attribute__((__packed__));
+
+struct lttng_viewer_metadata_packet {
+       uint64_t len;
+       uint32_t status;        /* enum lttng_viewer_get_metadata_return_code */
+       char data[];
+} __attribute__((__packed__));
+
+/*
+ * LTTNG_VIEWER_GET_NEW_STREAMS payload.
+ */
+struct lttng_viewer_new_streams_request {
+       uint64_t session_id;
+} __attribute__((__packed__));
+
+struct lttng_viewer_new_streams_response {
+       /* enum lttng_viewer_new_streams_return_code */
+       uint32_t status;
+       uint32_t streams_count;
+       /* struct lttng_viewer_stream */
+       char stream_list[];
+} __attribute__((__packed__));
+
+struct lttng_viewer_create_session_response {
+       /* enum lttng_viewer_create_session_return_code */
+       uint32_t status;
+} __attribute__((__packed__));
+
+/*
+ * LTTNG_VIEWER_DETACH_SESSION payload.
+ */
+struct lttng_viewer_detach_session_request {
+       uint64_t session_id;
+} __attribute__((__packed__));
+
+struct lttng_viewer_detach_session_response {
+       /* enum lttng_viewer_detach_session_return_code */
+       uint32_t status;
+} __attribute__((__packed__));
+
+#endif /* LTTNG_VIEWER_ABI_H */
diff --git a/src/plugins/ctf/lttng-live/metadata.c b/src/plugins/ctf/lttng-live/metadata.c
new file mode 100644 (file)
index 0000000..2d605e1
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2019 - Francis Deslauriers <francis.deslauriers@efficios.com>
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
+ *
+ * Some functions are based on older functions written by Mathieu Desnoyers.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-LIVE-SRC-METADATA"
+#include "logging.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <glib.h>
+#include "compat/memstream.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "metadata.h"
+#include "../common/metadata/decoder.h"
+
+#define TSDL_MAGIC     0x75d11d57
+
+struct packet_header {
+       uint32_t magic;
+       uint8_t  uuid[16];
+       uint32_t checksum;
+       uint32_t content_size;
+       uint32_t packet_size;
+       uint8_t  compression_scheme;
+       uint8_t  encryption_scheme;
+       uint8_t  checksum_scheme;
+       uint8_t  major;
+       uint8_t  minor;
+} __attribute__((__packed__));
+
+
+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;
+}
+/*
+ * Iterate over the stream classes and returns the first clock class
+ * encountered. This is useful to create message iterator inactivity message as
+ * we don't need a particular clock class.
+ */
+static
+const bt_clock_class *borrow_any_clock_class(bt_trace_class *tc)
+{
+       uint64_t i, sc_count;
+       const bt_clock_class *cc = NULL;
+       const bt_stream_class *sc;
+
+       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) {
+                       goto end;
+               }
+       }
+end:
+       BT_ASSERT(cc);
+       return cc;
+}
+
+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;
+}
+
+BT_HIDDEN
+int lttng_live_metadata_create_stream(struct lttng_live_session *session,
+               uint64_t ctf_trace_id,
+               uint64_t stream_id,
+               const char *trace_name)
+{
+       struct lttng_live_component *lttng_live =
+               session->lttng_live_msg_iter->lttng_live_comp;
+       struct lttng_live_metadata *metadata = NULL;
+       struct lttng_live_trace *trace;
+       const char *match;
+
+       metadata = g_new0(struct lttng_live_metadata, 1);
+       if (!metadata) {
+               return -1;
+       }
+       metadata->stream_id = stream_id;
+
+       match = strstr(trace_name, session->session_name->str);
+       if (!match) {
+               goto error;
+       }
+
+       metadata->decoder = ctf_metadata_decoder_create(
+                               lttng_live->self_comp, NULL);
+       if (!metadata->decoder) {
+               goto error;
+       }
+       trace = lttng_live_borrow_trace(session, ctf_trace_id);
+       if (!trace) {
+               goto error;
+       }
+       metadata->trace = trace;
+       trace->metadata = metadata;
+       return 0;
+
+error:
+       ctf_metadata_decoder_destroy(metadata->decoder);
+       g_free(metadata);
+       return -1;
+}
+
+BT_HIDDEN
+void lttng_live_metadata_fini(struct lttng_live_trace *trace)
+{
+       struct lttng_live_metadata *metadata = trace->metadata;
+
+       if (!metadata) {
+               return;
+       }
+       ctf_metadata_decoder_destroy(metadata->decoder);
+       trace->metadata = NULL;
+       g_free(metadata);
+}
diff --git a/src/plugins/ctf/lttng-live/metadata.h b/src/plugins/ctf/lttng-live/metadata.h
new file mode 100644 (file)
index 0000000..2cf8ae1
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef LTTNG_LIVE_METADATA_H
+#define LTTNG_LIVE_METADATA_H
+
+/*
+ * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+#include "lttng-live.h"
+
+int lttng_live_metadata_create_stream(struct lttng_live_session *session,
+               uint64_t ctf_trace_id, uint64_t stream_id,
+               const char *trace_name);
+
+enum lttng_live_iterator_status lttng_live_metadata_update(
+               struct lttng_live_trace *trace);
+
+void lttng_live_metadata_fini(struct lttng_live_trace *trace);
+
+#endif /* LTTNG_LIVE_METADATA_H */
diff --git a/src/plugins/ctf/lttng-live/viewer-connection.c b/src/plugins/ctf/lttng-live/viewer-connection.c
new file mode 100644 (file)
index 0000000..4a74ff9
--- /dev/null
@@ -0,0 +1,1524 @@
+/*
+ * Copyright 2019 - Francis Deslauriers <francis.deslauriers@efficios.com>
+ * Copyright 2016 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-LIVE-SRC-VIEWER"
+#include "logging.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <glib.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "compat/socket.h"
+#include "compat/endian.h"
+#include "compat/compiler.h"
+#include "common/common.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "lttng-live.h"
+#include "viewer-connection.h"
+#include "lttng-viewer-abi.h"
+#include "data-stream.h"
+#include "metadata.h"
+
+static
+ssize_t lttng_live_recv(struct live_viewer_connection *viewer_connection,
+               void *buf, size_t len)
+{
+       ssize_t ret;
+       size_t copied = 0, to_copy = len;
+       struct lttng_live_msg_iter *lttng_live_msg_iter =
+               viewer_connection->lttng_live_msg_iter;
+       BT_SOCKET sock = viewer_connection->control_sock;
+
+       do {
+               ret = bt_socket_recv(sock, buf + copied, to_copy, 0);
+               if (ret > 0) {
+                       BT_ASSERT(ret <= to_copy);
+                       copied += ret;
+                       to_copy -= ret;
+               }
+               if (ret == BT_SOCKET_ERROR && bt_socket_interrupted()) {
+                       if (!viewer_connection->in_query &&
+                                       lttng_live_graph_is_canceled(lttng_live_msg_iter->lttng_live_comp)) {
+                               break;
+                       } else {
+                               continue;
+                       }
+               }
+       } while (ret > 0 && to_copy > 0);
+       if (ret > 0)
+               ret = copied;
+       /* ret = 0 means orderly shutdown, ret == BT_SOCKET_ERROR is error. */
+       return ret;
+}
+
+static
+ssize_t lttng_live_send(struct live_viewer_connection *viewer_connection,
+               const void *buf, size_t len)
+{
+       struct lttng_live_msg_iter *lttng_live_msg_iter =
+               viewer_connection->lttng_live_msg_iter;
+       BT_SOCKET sock = viewer_connection->control_sock;
+       ssize_t ret;
+
+       for (;;) {
+               ret = bt_socket_send_nosigpipe(sock, buf, len);
+               if (ret == BT_SOCKET_ERROR && bt_socket_interrupted()) {
+                       if (!viewer_connection->in_query &&
+                                       lttng_live_graph_is_canceled(lttng_live_msg_iter->lttng_live_comp)) {
+                               break;
+                       } else {
+                               continue;
+                       }
+               } else {
+                       break;
+               }
+       }
+       return ret;
+}
+
+static
+int parse_url(struct live_viewer_connection *viewer_connection)
+{
+       char error_buf[256] = { 0 };
+       struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
+       int ret = -1;
+       const char *path = viewer_connection->url->str;
+
+       if (!path) {
+               goto end;
+       }
+
+       lttng_live_url_parts = bt_common_parse_lttng_live_url(path,
+                       error_buf, sizeof(error_buf));
+       if (!lttng_live_url_parts.proto) {
+               BT_LOGW("Invalid LTTng live URL format: %s", error_buf);
+               goto end;
+       }
+
+       viewer_connection->relay_hostname =
+                       lttng_live_url_parts.hostname;
+       lttng_live_url_parts.hostname = NULL;
+
+       if (lttng_live_url_parts.port >= 0) {
+               viewer_connection->port = lttng_live_url_parts.port;
+       } else {
+               viewer_connection->port = LTTNG_DEFAULT_NETWORK_VIEWER_PORT;
+       }
+
+       viewer_connection->target_hostname =
+                       lttng_live_url_parts.target_hostname;
+       lttng_live_url_parts.target_hostname = NULL;
+
+       if (lttng_live_url_parts.session_name) {
+               viewer_connection->session_name =
+                               lttng_live_url_parts.session_name;
+               lttng_live_url_parts.session_name = NULL;
+       }
+
+       BT_LOGD("Connecting to hostname : %s, port : %d, "
+                       "target hostname : %s, session name : %s, "
+                       "proto : %s",
+                       viewer_connection->relay_hostname->str,
+                       viewer_connection->port,
+                       viewer_connection->target_hostname == NULL ?
+                               "<none>" : viewer_connection->target_hostname->str,
+                       viewer_connection->session_name == NULL ?
+                               "<none>" : viewer_connection->session_name->str,
+                       lttng_live_url_parts.proto->str);
+       ret = 0;
+
+end:
+       bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
+       return ret;
+}
+
+static
+int lttng_live_handshake(struct live_viewer_connection *viewer_connection)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_connect connect;
+       const size_t cmd_buf_len = sizeof(cmd) + sizeof(connect);
+       char cmd_buf[cmd_buf_len];
+       int ret;
+       ssize_t ret_len;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT);
+       cmd.data_size = htobe64((uint64_t) sizeof(connect));
+       cmd.cmd_version = htobe32(0);
+
+       connect.viewer_session_id = -1ULL;      /* will be set on recv */
+       connect.major = htobe32(LTTNG_LIVE_MAJOR);
+       connect.minor = htobe32(LTTNG_LIVE_MINOR);
+       connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND);
+
+       /*
+        * Merge the cmd and connection request to prevent a write-write
+        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+        * second write to be performed quickly in presence of Nagle's algorithm
+        */
+       memcpy(cmd_buf, &cmd, sizeof(cmd));
+       memcpy(cmd_buf + sizeof(cmd), &connect, sizeof(connect));
+       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending version: %s", bt_socket_errormsg());
+               goto error;
+       }
+
+       BT_ASSERT(ret_len == cmd_buf_len);
+
+       ret_len = lttng_live_recv(viewer_connection, &connect, sizeof(connect));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving version: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(connect));
+
+       BT_LOGD("Received viewer session ID : %" PRIu64,
+                       (uint64_t) be64toh(connect.viewer_session_id));
+       BT_LOGD("Relayd version : %u.%u", be32toh(connect.major),
+                       be32toh(connect.minor));
+
+       if (LTTNG_LIVE_MAJOR != be32toh(connect.major)) {
+               BT_LOGE("Incompatible lttng-relayd protocol");
+               goto error;
+       }
+       /* Use the smallest protocol version implemented. */
+       if (LTTNG_LIVE_MINOR > be32toh(connect.minor)) {
+               viewer_connection->minor =  be32toh(connect.minor);
+       } else {
+               viewer_connection->minor =  LTTNG_LIVE_MINOR;
+       }
+       viewer_connection->major = LTTNG_LIVE_MAJOR;
+       ret = 0;
+       return ret;
+
+error:
+       BT_LOGE("Unable to establish connection");
+       return -1;
+}
+
+static
+int lttng_live_connect_viewer(struct live_viewer_connection *viewer_connection)
+{
+       struct hostent *host;
+       struct sockaddr_in server_addr;
+       int ret;
+
+       if (parse_url(viewer_connection)) {
+               goto error;
+       }
+
+       host = gethostbyname(viewer_connection->relay_hostname->str);
+       if (!host) {
+               BT_LOGE("Cannot lookup hostname %s",
+                       viewer_connection->relay_hostname->str);
+               goto error;
+       }
+
+       if ((viewer_connection->control_sock = socket(AF_INET, SOCK_STREAM, 0)) == BT_INVALID_SOCKET) {
+               BT_LOGE("Socket creation failed: %s", bt_socket_errormsg());
+               goto error;
+       }
+
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_port = htons(viewer_connection->port);
+       server_addr.sin_addr = *((struct in_addr *) host->h_addr);
+       memset(&(server_addr.sin_zero), 0, 8);
+
+       if (connect(viewer_connection->control_sock, (struct sockaddr *) &server_addr,
+                               sizeof(struct sockaddr)) == BT_SOCKET_ERROR) {
+               BT_LOGE("Connection failed: %s", bt_socket_errormsg());
+               goto error;
+       }
+       if (lttng_live_handshake(viewer_connection)) {
+               goto error;
+       }
+
+       ret = 0;
+
+       return ret;
+
+error:
+       if (viewer_connection->control_sock != BT_INVALID_SOCKET) {
+               if (bt_socket_close(viewer_connection->control_sock) == BT_SOCKET_ERROR) {
+                       BT_LOGE("Close: %s", bt_socket_errormsg());
+               }
+       }
+       viewer_connection->control_sock = BT_INVALID_SOCKET;
+       return -1;
+}
+
+static
+void lttng_live_disconnect_viewer(
+               struct live_viewer_connection *viewer_connection)
+{
+       if (viewer_connection->control_sock == BT_INVALID_SOCKET) {
+               return;
+       }
+       if (bt_socket_close(viewer_connection->control_sock) == BT_SOCKET_ERROR) {
+               BT_LOGE("Close: %s", bt_socket_errormsg());
+               viewer_connection->control_sock = BT_INVALID_SOCKET;
+       }
+}
+
+static
+void connection_release(bt_object *obj)
+{
+       struct live_viewer_connection *conn =
+               container_of(obj, struct live_viewer_connection, obj);
+
+       live_viewer_connection_destroy(conn);
+}
+
+static
+int list_update_session(bt_value *results,
+               const struct lttng_viewer_session *session,
+               bool *_found)
+{
+       int ret = 0;
+       bt_value *map = NULL;
+       bt_value *hostname = NULL;
+       bt_value *session_name = NULL;
+       bt_value *btval = NULL;
+       int i, len;
+       bool found = false;
+
+       len = bt_value_array_get_size(results);
+       if (len < 0) {
+               BT_LOGE_STR("Error getting size of array.");
+               ret = -1;
+               goto end;
+       }
+       for (i = 0; i < len; i++) {
+               const char *hostname_str = NULL;
+               const char *session_name_str = NULL;
+
+               map = bt_value_array_borrow_element_by_index(results, (size_t) i);
+               if (!map) {
+                       BT_LOGE_STR("Error borrowing map.");
+                       ret = -1;
+                       goto end;
+               }
+               hostname = bt_value_map_borrow_entry_value(map, "target-hostname");
+               if (!hostname) {
+                       BT_LOGE_STR("Error borrowing \"target-hostname\" entry.");
+                       ret = -1;
+                       goto end;
+               }
+               session_name = bt_value_map_borrow_entry_value(map, "session-name");
+               if (!session_name) {
+                       BT_LOGE_STR("Error borrowing \"session-name\" entry.");
+                       ret = -1;
+                       goto end;
+               }
+               hostname_str = bt_value_string_get(hostname);
+               session_name_str = bt_value_string_get(session_name);
+
+               if (!strcmp(session->hostname, hostname_str)
+                               && !strcmp(session->session_name,
+                                       session_name_str)) {
+                       int64_t val;
+                       uint32_t streams = be32toh(session->streams);
+                       uint32_t clients = be32toh(session->clients);
+
+                       found = true;
+
+                       btval = bt_value_map_borrow_entry_value(map, "stream-count");
+                       if (!btval) {
+                               BT_LOGE_STR("Error borrowing \"stream-count\" entry.");
+                               ret = -1;
+                               goto end;
+                       }
+                       val = bt_value_signed_integer_get(btval);
+                       /* sum */
+                       val += streams;
+                       bt_value_signed_integer_set(btval, val);
+
+                       btval = bt_value_map_borrow_entry_value(map, "client-count");
+                       if (!btval) {
+                               BT_LOGE_STR("Error borrowing \"client-count\" entry.");
+                               ret = -1;
+                               goto end;
+                       }
+                       val = bt_value_signed_integer_get(btval);
+                       /* max */
+                       val = max_t(int64_t, clients, val);
+                       bt_value_signed_integer_set(btval, val);
+               }
+
+               if (found) {
+                       break;
+               }
+       }
+end:
+       *_found = found;
+       return ret;
+}
+
+static
+int list_append_session(bt_value *results,
+               GString *base_url,
+               const struct lttng_viewer_session *session)
+{
+       int ret = 0;
+       bt_value_status ret_status;
+       bt_value *map = NULL;
+       GString *url = NULL;
+       bool found = false;
+
+       /*
+        * If the session already exists, add the stream count to it,
+        * and do max of client counts.
+        */
+       ret = list_update_session(results, session, &found);
+       if (ret || found) {
+               goto end;
+       }
+
+       map = bt_value_map_create();
+       if (!map) {
+               BT_LOGE_STR("Error creating map value.");
+               ret = -1;
+               goto end;
+       }
+
+       if (base_url->len < 1) {
+               BT_LOGE_STR("Error: base_url length smaller than 1.");
+               ret = -1;
+               goto end;
+       }
+       /*
+        * key = "url",
+        * value = <string>,
+        */
+       url = g_string_new(base_url->str);
+       g_string_append(url, "/host/");
+       g_string_append(url, session->hostname);
+       g_string_append_c(url, '/');
+       g_string_append(url, session->session_name);
+
+       ret_status = bt_value_map_insert_string_entry(map, "url", url->str);
+       if (ret_status != BT_VALUE_STATUS_OK) {
+               BT_LOGE_STR("Error inserting \"url\" entry.");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * key = "target-hostname",
+        * value = <string>,
+        */
+       ret_status = bt_value_map_insert_string_entry(map, "target-hostname",
+               session->hostname);
+       if (ret_status != BT_VALUE_STATUS_OK) {
+               BT_LOGE_STR("Error inserting \"target-hostname\" entry.");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * key = "session-name",
+        * value = <string>,
+        */
+       ret_status = bt_value_map_insert_string_entry(map, "session-name",
+               session->session_name);
+       if (ret_status != BT_VALUE_STATUS_OK) {
+               BT_LOGE_STR("Error inserting \"session-name\" entry.");
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * key = "timer-us",
+        * value = <integer>,
+        */
+       {
+               uint32_t live_timer = be32toh(session->live_timer);
+
+               ret_status = bt_value_map_insert_signed_integer_entry(
+                       map, "timer-us", live_timer);
+               if (ret_status != BT_VALUE_STATUS_OK) {
+                       BT_LOGE_STR("Error inserting \"timer-us\" entry.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /*
+        * key = "stream-count",
+        * value = <integer>,
+        */
+       {
+               uint32_t streams = be32toh(session->streams);
+
+               ret_status = bt_value_map_insert_signed_integer_entry(map,
+                       "stream-count", streams);
+               if (ret_status != BT_VALUE_STATUS_OK) {
+                       BT_LOGE_STR("Error inserting \"stream-count\" entry.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /*
+        * key = "client-count",
+        * value = <integer>,
+        */
+       {
+               uint32_t clients = be32toh(session->clients);
+
+               ret_status = bt_value_map_insert_signed_integer_entry(map,
+                       "client-count", clients);
+               if (ret_status != BT_VALUE_STATUS_OK) {
+                       BT_LOGE_STR("Error inserting \"client-count\" entry.");
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       ret_status = bt_value_array_append_element(results, map);
+       if (ret_status != BT_VALUE_STATUS_OK) {
+               BT_LOGE_STR("Error appending map to results.");
+               ret = -1;
+       }
+
+end:
+       if (url) {
+               g_string_free(url, true);
+       }
+       BT_VALUE_PUT_REF_AND_RESET(map);
+       return ret;
+}
+
+/*
+ * Data structure returned:
+ *
+ * {
+ *   <array> = {
+ *     [n] = {
+ *       <map> = {
+ *         {
+ *           key = "url",
+ *           value = <string>,
+ *         },
+ *         {
+ *           key = "target-hostname",
+ *           value = <string>,
+ *         },
+ *         {
+ *           key = "session-name",
+ *           value = <string>,
+ *         },
+ *         {
+ *           key = "timer-us",
+ *           value = <integer>,
+ *         },
+ *         {
+ *           key = "stream-count",
+ *           value = <integer>,
+ *         },
+ *         {
+ *           key = "client-count",
+ *           value = <integer>,
+ *         },
+ *       },
+ *     }
+ *   }
+ */
+
+BT_HIDDEN
+bt_query_status live_viewer_connection_list_sessions(
+               struct live_viewer_connection *viewer_connection,
+               const bt_value **user_result)
+{
+       bt_query_status status = BT_QUERY_STATUS_OK;
+       bt_value *result = NULL;
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_list_sessions list;
+       uint32_t i, sessions_count;
+       ssize_t ret_len;
+
+       if (lttng_live_handshake(viewer_connection)) {
+               goto error;
+       }
+
+       result = bt_value_array_create();
+       if (!result) {
+               BT_LOGE("Error creating array");
+               status = BT_QUERY_STATUS_NOMEM;
+               goto error;
+       }
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
+       cmd.data_size = htobe64((uint64_t) 0);
+       cmd.cmd_version = htobe32(0);
+
+       ret_len = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending cmd: %s", bt_socket_errormsg());
+               status = BT_QUERY_STATUS_ERROR;
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(cmd));
+
+       ret_len = lttng_live_recv(viewer_connection, &list, sizeof(list));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               status = BT_QUERY_STATUS_ERROR;
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving session list: %s", bt_socket_errormsg());
+               status = BT_QUERY_STATUS_ERROR;
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(list));
+
+       sessions_count = be32toh(list.sessions_count);
+       for (i = 0; i < sessions_count; i++) {
+               struct lttng_viewer_session lsession;
+
+               ret_len = lttng_live_recv(viewer_connection, &lsession,
+                       sizeof(lsession));
+               if (ret_len == 0) {
+                       BT_LOGI("Remote side has closed connection");
+                       status = BT_QUERY_STATUS_ERROR;
+                       goto error;
+               }
+               if (ret_len == BT_SOCKET_ERROR) {
+                       BT_LOGE("Error receiving session: %s", bt_socket_errormsg());
+                       status = BT_QUERY_STATUS_ERROR;
+                       goto error;
+               }
+               BT_ASSERT(ret_len == sizeof(lsession));
+               lsession.hostname[LTTNG_VIEWER_HOST_NAME_MAX - 1] = '\0';
+               lsession.session_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0';
+               if (list_append_session(result, viewer_connection->url,
+                               &lsession)) {
+                       status = BT_QUERY_STATUS_ERROR;
+                       goto error;
+               }
+       }
+
+       *user_result = result;
+       goto end;
+error:
+       BT_VALUE_PUT_REF_AND_RESET(result);
+end:
+       return status;
+}
+
+static
+int lttng_live_query_session_ids(struct lttng_live_msg_iter *lttng_live_msg_iter)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_list_sessions list;
+       struct lttng_viewer_session lsession;
+       uint32_t i, sessions_count;
+       ssize_t ret_len;
+       uint64_t session_id;
+       struct live_viewer_connection *viewer_connection =
+                       lttng_live_msg_iter->viewer_connection;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS);
+       cmd.data_size = htobe64((uint64_t) 0);
+       cmd.cmd_version = htobe32(0);
+
+       ret_len = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending cmd: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(cmd));
+
+       ret_len = lttng_live_recv(viewer_connection, &list, sizeof(list));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving session list: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(list));
+
+       sessions_count = be32toh(list.sessions_count);
+       for (i = 0; i < sessions_count; i++) {
+               ret_len = lttng_live_recv(viewer_connection,
+                               &lsession, sizeof(lsession));
+               if (ret_len == 0) {
+                       BT_LOGI("Remote side has closed connection");
+                       goto error;
+               }
+               if (ret_len == BT_SOCKET_ERROR) {
+                       BT_LOGE("Error receiving session: %s", bt_socket_errormsg());
+                       goto error;
+               }
+               BT_ASSERT(ret_len == sizeof(lsession));
+               lsession.hostname[LTTNG_VIEWER_HOST_NAME_MAX - 1] = '\0';
+               lsession.session_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0';
+               session_id = be64toh(lsession.id);
+
+               BT_LOGD("Adding session %" PRIu64 " hostname: %s session_name: %s",
+                       session_id, lsession.hostname, lsession.session_name);
+
+               if ((strncmp(lsession.session_name,
+                       viewer_connection->session_name->str,
+                       LTTNG_VIEWER_NAME_MAX) == 0) && (strncmp(lsession.hostname,
+                               viewer_connection->target_hostname->str,
+                               LTTNG_VIEWER_HOST_NAME_MAX) == 0)) {
+                       if (lttng_live_add_session(lttng_live_msg_iter, session_id,
+                                       lsession.hostname,
+                                       lsession.session_name)) {
+                               goto error;
+                       }
+               }
+       }
+
+       return 0;
+
+error:
+       BT_LOGE("Unable to query session ids");
+       return -1;
+}
+
+BT_HIDDEN
+int lttng_live_create_viewer_session(
+               struct lttng_live_msg_iter *lttng_live_msg_iter)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_create_session_response resp;
+       ssize_t ret_len;
+       struct live_viewer_connection *viewer_connection =
+                       lttng_live_msg_iter->viewer_connection;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_CREATE_SESSION);
+       cmd.data_size = htobe64((uint64_t) 0);
+       cmd.cmd_version = htobe32(0);
+
+       ret_len = lttng_live_send(viewer_connection, &cmd, sizeof(cmd));
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending cmd: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(cmd));
+
+       ret_len = lttng_live_recv(viewer_connection, &resp, sizeof(resp));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving create session reply: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(resp));
+
+       if (be32toh(resp.status) != LTTNG_VIEWER_CREATE_SESSION_OK) {
+               BT_LOGE("Error creating viewer session");
+               goto error;
+       }
+       if (lttng_live_query_session_ids(lttng_live_msg_iter)) {
+               goto error;
+       }
+
+       return 0;
+
+error:
+       return -1;
+}
+
+static
+int receive_streams(struct lttng_live_session *session,
+               uint32_t stream_count)
+{
+       ssize_t ret_len;
+       uint32_t i;
+       struct lttng_live_msg_iter *lttng_live_msg_iter =
+                       session->lttng_live_msg_iter;
+       struct live_viewer_connection *viewer_connection =
+                       lttng_live_msg_iter->viewer_connection;
+
+       BT_LOGD("Getting %" PRIu32 " new streams:", stream_count);
+       for (i = 0; i < stream_count; i++) {
+               struct lttng_viewer_stream stream;
+               struct lttng_live_stream_iterator *live_stream;
+               uint64_t stream_id;
+               uint64_t ctf_trace_id;
+
+               ret_len = lttng_live_recv(viewer_connection, &stream, sizeof(stream));
+               if (ret_len == 0) {
+                       BT_LOGI("Remote side has closed connection");
+                       goto error;
+               }
+               if (ret_len == BT_SOCKET_ERROR) {
+                       BT_LOGE("Error receiving stream");
+                       goto error;
+               }
+               BT_ASSERT(ret_len == sizeof(stream));
+               stream.path_name[LTTNG_VIEWER_PATH_MAX - 1] = '\0';
+               stream.channel_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0';
+               stream_id = be64toh(stream.id);
+               ctf_trace_id = be64toh(stream.ctf_trace_id);
+
+               if (stream.metadata_flag) {
+                       BT_LOGD("    metadata stream %" PRIu64 " : %s/%s",
+                                       stream_id, stream.path_name,
+                                       stream.channel_name);
+                       if (lttng_live_metadata_create_stream(session,
+                                       ctf_trace_id, stream_id,
+                                       stream.path_name)) {
+                               BT_LOGE("Error creating metadata stream");
+
+                               goto error;
+                       }
+                       session->lazy_stream_msg_init = true;
+               } else {
+                       BT_LOGD("    stream %" PRIu64 " : %s/%s",
+                                       stream_id, stream.path_name,
+                                       stream.channel_name);
+                       live_stream = lttng_live_stream_iterator_create(session,
+                               ctf_trace_id, stream_id);
+                       if (!live_stream) {
+                               BT_LOGE("Error creating streamn");
+                               goto error;
+                       }
+               }
+       }
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+int lttng_live_attach_session(struct lttng_live_session *session)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_attach_session_request rq;
+       struct lttng_viewer_attach_session_response rp;
+       ssize_t ret_len;
+       struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
+       struct live_viewer_connection *viewer_connection =
+                       lttng_live_msg_iter->viewer_connection;
+       uint64_t session_id = session->id;
+       uint32_t streams_count;
+       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+       char cmd_buf[cmd_buf_len];
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION);
+       cmd.data_size = htobe64((uint64_t) sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.session_id = htobe64(session_id);
+       // TODO: add cmd line parameter to select seek beginning
+       // rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING);
+       rq.seek = htobe32(LTTNG_VIEWER_SEEK_LAST);
+
+       /*
+        * Merge the cmd and connection request to prevent a write-write
+        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+        * second write to be performed quickly in presence of Nagle's algorithm.
+        */
+       memcpy(cmd_buf, &cmd, sizeof(cmd));
+       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
+       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending attach request: %s", bt_socket_errormsg());
+               goto error;
+       }
+
+       BT_ASSERT(ret_len == cmd_buf_len);
+       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving attach response: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(rp));
+
+       streams_count = be32toh(rp.streams_count);
+       switch(be32toh(rp.status)) {
+       case LTTNG_VIEWER_ATTACH_OK:
+               break;
+       case LTTNG_VIEWER_ATTACH_UNK:
+               BT_LOGW("Session id %" PRIu64 " is unknown", session_id);
+               goto error;
+       case LTTNG_VIEWER_ATTACH_ALREADY:
+               BT_LOGW("There is already a viewer attached to this session");
+               goto error;
+       case LTTNG_VIEWER_ATTACH_NOT_LIVE:
+               BT_LOGW("Not a live session");
+               goto error;
+       case LTTNG_VIEWER_ATTACH_SEEK_ERR:
+               BT_LOGE("Wrong seek parameter");
+               goto error;
+       default:
+               BT_LOGE("Unknown attach return code %u", be32toh(rp.status));
+               goto error;
+       }
+
+       /* We receive the initial list of streams. */
+       if (receive_streams(session, streams_count)) {
+               goto error;
+       }
+
+       session->attached = true;
+       session->new_streams_needed = false;
+
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+int lttng_live_detach_session(struct lttng_live_session *session)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_detach_session_request rq;
+       struct lttng_viewer_detach_session_response rp;
+       ssize_t ret_len;
+       struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
+       struct live_viewer_connection *viewer_connection =
+                       lttng_live_msg_iter->viewer_connection;
+       uint64_t session_id = session->id;
+       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+       char cmd_buf[cmd_buf_len];
+
+       if (!session->attached) {
+               return 0;
+       }
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_DETACH_SESSION);
+       cmd.data_size = htobe64((uint64_t) sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.session_id = htobe64(session_id);
+
+       /*
+        * Merge the cmd and connection request to prevent a write-write
+        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+        * second write to be performed quickly in presence of Nagle's algorithm.
+        */
+       memcpy(cmd_buf, &cmd, sizeof(cmd));
+       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
+       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending detach request: %s", bt_socket_errormsg());
+               goto error;
+       }
+
+       BT_ASSERT(ret_len == cmd_buf_len);
+       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving detach response: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(rp));
+
+       switch(be32toh(rp.status)) {
+       case LTTNG_VIEWER_DETACH_SESSION_OK:
+               break;
+       case LTTNG_VIEWER_DETACH_SESSION_UNK:
+               BT_LOGW("Session id %" PRIu64 " is unknown", session_id);
+               goto error;
+       case LTTNG_VIEWER_DETACH_SESSION_ERR:
+               BT_LOGW("Error detaching session id %" PRIu64 "", session_id);
+               goto error;
+       default:
+               BT_LOGE("Unknown detach return code %u", be32toh(rp.status));
+               goto error;
+       }
+
+       session->attached = false;
+
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+ssize_t lttng_live_get_one_metadata_packet(struct lttng_live_trace *trace,
+               FILE *fp)
+{
+       uint64_t len = 0;
+       int ret;
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_get_metadata rq;
+       struct lttng_viewer_metadata_packet rp;
+       char *data = NULL;
+       ssize_t ret_len;
+       struct lttng_live_session *session = trace->session;
+       struct lttng_live_msg_iter *lttng_live_msg_iter = session->lttng_live_msg_iter;
+       struct lttng_live_metadata *metadata = trace->metadata;
+       struct live_viewer_connection *viewer_connection =
+                       lttng_live_msg_iter->viewer_connection;
+       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+       char cmd_buf[cmd_buf_len];
+
+       rq.stream_id = htobe64(metadata->stream_id);
+       cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA);
+       cmd.data_size = htobe64((uint64_t) sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       /*
+        * Merge the cmd and connection request to prevent a write-write
+        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+        * second write to be performed quickly in presence of Nagle's algorithm.
+        */
+       memcpy(cmd_buf, &cmd, sizeof(cmd));
+       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
+       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending get_metadata request: %s", bt_socket_errormsg());
+               goto error;
+       }
+
+       BT_ASSERT(ret_len == cmd_buf_len);
+       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving get_metadata response: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(rp));
+
+       switch (be32toh(rp.status)) {
+               case LTTNG_VIEWER_METADATA_OK:
+                       BT_LOGD("get_metadata : OK");
+                       break;
+               case LTTNG_VIEWER_NO_NEW_METADATA:
+                       BT_LOGD("get_metadata : NO NEW");
+                       ret = 0;
+                       goto end;
+               case LTTNG_VIEWER_METADATA_ERR:
+                       BT_LOGD("get_metadata : ERR");
+                       goto error;
+               default:
+                       BT_LOGD("get_metadata : UNKNOWN");
+                       goto error;
+       }
+
+       len = be64toh(rp.len);
+       BT_LOGD("Writing %" PRIu64" bytes to metadata", len);
+       if (len <= 0) {
+               goto error;
+       }
+
+       data = zmalloc(len);
+       if (!data) {
+               BT_LOGE("relay data zmalloc: %s", strerror(errno));
+               goto error;
+       }
+       ret_len = lttng_live_recv(viewer_connection, data, len);
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error_free_data;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving trace packet: %s", bt_socket_errormsg());
+               goto error_free_data;
+       }
+       BT_ASSERT(ret_len == len);
+
+       do {
+               ret_len = fwrite(data, 1, len, fp);
+       } while (ret_len < 0 && errno == EINTR);
+       if (ret_len < 0) {
+               BT_LOGE("Writing in the metadata fp");
+               goto error_free_data;
+       }
+       BT_ASSERT(ret_len == len);
+       free(data);
+       ret = len;
+end:
+       return ret;
+
+error_free_data:
+       free(data);
+error:
+       return -1;
+}
+
+/*
+ * Assign the fields from a lttng_viewer_index to a packet_index.
+ */
+static
+void lttng_index_to_packet_index(struct lttng_viewer_index *lindex,
+               struct packet_index *pindex)
+{
+       BT_ASSERT(lindex);
+       BT_ASSERT(pindex);
+
+       pindex->offset = be64toh(lindex->offset);
+       pindex->packet_size = be64toh(lindex->packet_size);
+       pindex->content_size = be64toh(lindex->content_size);
+       pindex->ts_cycles.timestamp_begin = be64toh(lindex->timestamp_begin);
+       pindex->ts_cycles.timestamp_end = be64toh(lindex->timestamp_end);
+       pindex->events_discarded = be64toh(lindex->events_discarded);
+}
+
+BT_HIDDEN
+enum lttng_live_iterator_status lttng_live_get_next_index(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream,
+               struct packet_index *index)
+{
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_get_next_index rq;
+       ssize_t ret_len;
+       struct lttng_viewer_index rp;
+       uint32_t flags, status;
+       enum lttng_live_iterator_status retstatus =
+                       LTTNG_LIVE_ITERATOR_STATUS_OK;
+       struct live_viewer_connection *viewer_connection =
+                       lttng_live_msg_iter->viewer_connection;
+       struct lttng_live_trace *trace = stream->trace;
+       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+       char cmd_buf[cmd_buf_len];
+       struct lttng_live_component *lttng_live =
+               lttng_live_msg_iter->lttng_live_comp;
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX);
+       cmd.data_size = htobe64((uint64_t) sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+
+       memset(&rq, 0, sizeof(rq));
+       rq.stream_id = htobe64(stream->viewer_stream_id);
+
+       /*
+        * Merge the cmd and connection request to prevent a write-write
+        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+        * second write to be performed quickly in presence of Nagle's algorithm.
+        */
+       memcpy(cmd_buf, &cmd, sizeof(cmd));
+       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
+       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending get_next_index request: %s",
+                               bt_socket_errormsg());
+               goto error;
+       }
+
+       BT_ASSERT(ret_len == cmd_buf_len);
+       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving get_next_index response: %s",
+                               bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(rp));
+
+       flags = be32toh(rp.flags);
+       status = be32toh(rp.status);
+
+       switch (status) {
+       case LTTNG_VIEWER_INDEX_INACTIVE:
+       {
+               uint64_t ctf_stream_class_id;
+
+               BT_LOGD("get_next_index: inactive");
+               memset(index, 0, sizeof(struct packet_index));
+               index->ts_cycles.timestamp_end = be64toh(rp.timestamp_end);
+               stream->current_inactivity_ts = index->ts_cycles.timestamp_end;
+               ctf_stream_class_id = be64toh(rp.stream_id);
+               if (stream->ctf_stream_class_id != -1ULL) {
+                       BT_ASSERT(stream->ctf_stream_class_id ==
+                               ctf_stream_class_id);
+               } else {
+                       stream->ctf_stream_class_id = ctf_stream_class_id;
+               }
+               stream->state = LTTNG_LIVE_STREAM_QUIESCENT;
+               break;
+       }
+       case LTTNG_VIEWER_INDEX_OK:
+       {
+               uint64_t ctf_stream_class_id;
+
+               BT_LOGD("get_next_index: OK");
+               lttng_index_to_packet_index(&rp, index);
+               ctf_stream_class_id = be64toh(rp.stream_id);
+               if (stream->ctf_stream_class_id != -1ULL) {
+                       BT_ASSERT(stream->ctf_stream_class_id ==
+                               ctf_stream_class_id);
+               } else {
+                       stream->ctf_stream_class_id = ctf_stream_class_id;
+               }
+
+               stream->state = LTTNG_LIVE_STREAM_ACTIVE_DATA;
+
+               if (flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
+                       BT_LOGD("get_next_index: new metadata needed");
+                       trace->new_metadata_needed = true;
+               }
+               if (flags & LTTNG_VIEWER_FLAG_NEW_STREAM) {
+                       BT_LOGD("get_next_index: new streams needed");
+                       lttng_live_need_new_streams(lttng_live_msg_iter);
+               }
+               break;
+       }
+       case LTTNG_VIEWER_INDEX_RETRY:
+               BT_LOGD("get_next_index: retry");
+               memset(index, 0, sizeof(struct packet_index));
+               retstatus = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+               stream->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
+               goto end;
+       case LTTNG_VIEWER_INDEX_HUP:
+               BT_LOGD("get_next_index: stream hung up");
+               memset(index, 0, sizeof(struct packet_index));
+               index->offset = EOF;
+               retstatus = LTTNG_LIVE_ITERATOR_STATUS_END;
+               stream->state = LTTNG_LIVE_STREAM_EOF;
+               break;
+       case LTTNG_VIEWER_INDEX_ERR:
+               BT_LOGE("get_next_index: error");
+               memset(index, 0, sizeof(struct packet_index));
+               stream->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
+               goto error;
+       default:
+               BT_LOGE("get_next_index: unknown value");
+               memset(index, 0, sizeof(struct packet_index));
+               stream->state = LTTNG_LIVE_STREAM_ACTIVE_NO_DATA;
+               goto error;
+       }
+end:
+       return retstatus;
+
+error:
+       if (lttng_live_graph_is_canceled(lttng_live)) {
+               retstatus = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+       } else {
+               retstatus = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+       }
+       return retstatus;
+}
+
+BT_HIDDEN
+enum bt_msg_iter_medium_status lttng_live_get_stream_bytes(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream, uint8_t *buf,
+               uint64_t offset, uint64_t req_len, uint64_t *recv_len)
+{
+       enum bt_msg_iter_medium_status retstatus = BT_MSG_ITER_MEDIUM_STATUS_OK;
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_get_packet rq;
+       struct lttng_viewer_trace_packet rp;
+       ssize_t ret_len;
+       uint32_t flags, status;
+       struct live_viewer_connection *viewer_connection =
+                       lttng_live_msg_iter->viewer_connection;
+       struct lttng_live_trace *trace = stream->trace;
+       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+       char cmd_buf[cmd_buf_len];
+       struct lttng_live_component *lttng_live =
+               lttng_live_msg_iter->lttng_live_comp;
+
+       BT_LOGD("lttng_live_get_stream_bytes: offset=%" PRIu64 ", req_len=%" PRIu64,
+                       offset, req_len);
+       cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET);
+       cmd.data_size = htobe64((uint64_t) sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.stream_id = htobe64(stream->viewer_stream_id);
+       rq.offset = htobe64(offset);
+       rq.len = htobe32(req_len);
+
+       /*
+        * Merge the cmd and connection request to prevent a write-write
+        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+        * second write to be performed quickly in presence of Nagle's algorithm.
+        */
+       memcpy(cmd_buf, &cmd, sizeof(cmd));
+       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
+       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending get_data request: %s", bt_socket_errormsg());
+               goto error;
+       }
+
+       BT_ASSERT(ret_len == cmd_buf_len);
+       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving get_data response: %s", bt_socket_errormsg());
+               goto error;
+       }
+       if (ret_len != sizeof(rp)) {
+               BT_LOGE("get_data_packet: expected %zu"
+                               ", received %zd", sizeof(rp),
+                               ret_len);
+               goto error;
+       }
+
+       flags = be32toh(rp.flags);
+       status = be32toh(rp.status);
+
+       switch (status) {
+       case LTTNG_VIEWER_GET_PACKET_OK:
+               req_len = be32toh(rp.len);
+               BT_LOGD("get_data_packet: Ok, packet size : %" PRIu64 "", req_len);
+               break;
+       case LTTNG_VIEWER_GET_PACKET_RETRY:
+               /* Unimplemented by relay daemon */
+               BT_LOGD("get_data_packet: retry");
+               retstatus = BT_MSG_ITER_MEDIUM_STATUS_AGAIN;
+               goto end;
+       case LTTNG_VIEWER_GET_PACKET_ERR:
+               if (flags & LTTNG_VIEWER_FLAG_NEW_METADATA) {
+                       BT_LOGD("get_data_packet: new metadata needed, try again later");
+                       trace->new_metadata_needed = true;
+               }
+               if (flags & LTTNG_VIEWER_FLAG_NEW_STREAM) {
+                       BT_LOGD("get_data_packet: new streams needed, try again later");
+                       lttng_live_need_new_streams(lttng_live_msg_iter);
+               }
+               if (flags & (LTTNG_VIEWER_FLAG_NEW_METADATA
+                               | LTTNG_VIEWER_FLAG_NEW_STREAM)) {
+                       retstatus = BT_MSG_ITER_MEDIUM_STATUS_AGAIN;
+                       goto end;
+               }
+               BT_LOGE("get_data_packet: error");
+               goto error;
+       case LTTNG_VIEWER_GET_PACKET_EOF:
+               retstatus = BT_MSG_ITER_MEDIUM_STATUS_EOF;
+               goto end;
+       default:
+               BT_LOGE("get_data_packet: unknown");
+               goto error;
+       }
+
+       if (req_len == 0) {
+               goto error;
+       }
+
+       ret_len = lttng_live_recv(viewer_connection, buf, req_len);
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving trace packet: %s", bt_socket_errormsg());
+               goto error;
+       }
+       BT_ASSERT(ret_len == req_len);
+       *recv_len = ret_len;
+end:
+       return retstatus;
+
+error:
+       if (lttng_live_graph_is_canceled(lttng_live)) {
+               retstatus = BT_MSG_ITER_MEDIUM_STATUS_AGAIN;
+       } else {
+               retstatus = BT_MSG_ITER_MEDIUM_STATUS_ERROR;
+       }
+       return retstatus;
+}
+
+/*
+ * Request new streams for a session.
+ */
+BT_HIDDEN
+enum lttng_live_iterator_status lttng_live_get_new_streams(
+               struct lttng_live_session *session)
+{
+       enum lttng_live_iterator_status status =
+               LTTNG_LIVE_ITERATOR_STATUS_OK;
+       struct lttng_viewer_cmd cmd;
+       struct lttng_viewer_new_streams_request rq;
+       struct lttng_viewer_new_streams_response rp;
+       ssize_t ret_len;
+       struct lttng_live_msg_iter *lttng_live_msg_iter =
+               session->lttng_live_msg_iter;
+       struct live_viewer_connection *viewer_connection =
+               lttng_live_msg_iter->viewer_connection;
+       struct lttng_live_component *lttng_live =
+               lttng_live_msg_iter->lttng_live_comp;
+       uint32_t streams_count;
+       const size_t cmd_buf_len = sizeof(cmd) + sizeof(rq);
+       char cmd_buf[cmd_buf_len];
+
+       if (!session->new_streams_needed) {
+               return LTTNG_LIVE_ITERATOR_STATUS_OK;
+       }
+
+       cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEW_STREAMS);
+       cmd.data_size = htobe64((uint64_t) sizeof(rq));
+       cmd.cmd_version = htobe32(0);
+
+       memset(&rq, 0, sizeof(rq));
+       rq.session_id = htobe64(session->id);
+
+       /*
+        * Merge the cmd and connection request to prevent a write-write
+        * sequence on the TCP socket. Otherwise, a delayed ACK will prevent the
+        * second write to be performed quickly in presence of Nagle's algorithm.
+        */
+       memcpy(cmd_buf, &cmd, sizeof(cmd));
+       memcpy(cmd_buf + sizeof(cmd), &rq, sizeof(rq));
+       ret_len = lttng_live_send(viewer_connection, &cmd_buf, cmd_buf_len);
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error sending get_new_streams request: %s",
+                               bt_socket_errormsg());
+               goto error;
+       }
+
+       BT_ASSERT(ret_len == cmd_buf_len);
+       ret_len = lttng_live_recv(viewer_connection, &rp, sizeof(rp));
+       if (ret_len == 0) {
+               BT_LOGI("Remote side has closed connection");
+               goto error;
+       }
+       if (ret_len == BT_SOCKET_ERROR) {
+               BT_LOGE("Error receiving get_new_streams response");
+               goto error;
+       }
+       BT_ASSERT(ret_len == sizeof(rp));
+
+       streams_count = be32toh(rp.streams_count);
+
+       switch(be32toh(rp.status)) {
+       case LTTNG_VIEWER_NEW_STREAMS_OK:
+               session->new_streams_needed = false;
+               break;
+       case LTTNG_VIEWER_NEW_STREAMS_NO_NEW:
+               session->new_streams_needed = false;
+               goto end;
+       case LTTNG_VIEWER_NEW_STREAMS_HUP:
+               session->new_streams_needed = false;
+               session->closed = true;
+               status = LTTNG_LIVE_ITERATOR_STATUS_END;
+               goto end;
+       case LTTNG_VIEWER_NEW_STREAMS_ERR:
+               BT_LOGE("get_new_streams error");
+               goto error;
+       default:
+               BT_LOGE("Unknown return code %u", be32toh(rp.status));
+               goto error;
+       }
+
+       if (receive_streams(session, streams_count)) {
+               goto error;
+       }
+end:
+       return status;
+
+error:
+       if (lttng_live_graph_is_canceled(lttng_live)) {
+               status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
+       } else {
+               status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+       }
+       return status;
+}
+
+BT_HIDDEN
+struct live_viewer_connection *live_viewer_connection_create(
+               const char *url, bool in_query,
+               struct lttng_live_msg_iter *lttng_live_msg_iter)
+{
+       struct live_viewer_connection *viewer_connection;
+
+       viewer_connection = g_new0(struct live_viewer_connection, 1);
+
+       if (bt_socket_init() != 0) {
+               goto error;
+       }
+
+       bt_object_init_shared(&viewer_connection->obj, connection_release);
+       viewer_connection->control_sock = BT_INVALID_SOCKET;
+       viewer_connection->port = -1;
+       viewer_connection->in_query = in_query;
+       viewer_connection->lttng_live_msg_iter = lttng_live_msg_iter;
+       viewer_connection->url = g_string_new(url);
+       if (!viewer_connection->url) {
+               goto error;
+       }
+
+       BT_LOGD("Establishing connection to url \"%s\"...", url);
+       if (lttng_live_connect_viewer(viewer_connection)) {
+               goto error_report;
+       }
+       BT_LOGD("Connection to url \"%s\" is established", url);
+       return viewer_connection;
+
+error_report:
+       BT_LOGW("Failure to establish connection to url \"%s\"", url);
+error:
+       g_free(viewer_connection);
+       return NULL;
+}
+
+BT_HIDDEN
+void live_viewer_connection_destroy(
+               struct live_viewer_connection *viewer_connection)
+{
+       BT_LOGD("Closing connection to url \"%s\"", viewer_connection->url->str);
+       lttng_live_disconnect_viewer(viewer_connection);
+       g_string_free(viewer_connection->url, true);
+       if (viewer_connection->relay_hostname) {
+               g_string_free(viewer_connection->relay_hostname, true);
+       }
+       if (viewer_connection->target_hostname) {
+               g_string_free(viewer_connection->target_hostname, true);
+       }
+       if (viewer_connection->session_name) {
+               g_string_free(viewer_connection->session_name, true);
+       }
+       g_free(viewer_connection);
+
+       bt_socket_fini();
+}
diff --git a/src/plugins/ctf/lttng-live/viewer-connection.h b/src/plugins/ctf/lttng-live/viewer-connection.h
new file mode 100644 (file)
index 0000000..09adc6c
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef LTTNG_LIVE_VIEWER_CONNECTION_H
+#define LTTNG_LIVE_VIEWER_CONNECTION_H
+
+/*
+ * Copyright 2016 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+
+#include "common/babeltrace.h"
+#include "compat/socket.h"
+
+//TODO: this should not be used by plugins. Should copy code into plugin
+//instead.
+#include "lib/object.h"
+
+#define LTTNG_DEFAULT_NETWORK_VIEWER_PORT      5344
+
+#define LTTNG_LIVE_MAJOR                       2
+#define LTTNG_LIVE_MINOR                       4
+
+struct lttng_live_component;
+
+struct live_viewer_connection {
+       bt_object obj;
+
+       GString *url;
+
+       GString *relay_hostname;
+       GString *target_hostname;
+       GString *session_name;
+
+       BT_SOCKET control_sock;
+       int port;
+
+       int32_t major;
+       int32_t minor;
+
+       bool in_query;
+       struct lttng_live_msg_iter *lttng_live_msg_iter;
+};
+
+struct packet_index_time {
+       uint64_t timestamp_begin;
+       uint64_t timestamp_end;
+};
+
+struct packet_index {
+       off_t offset;           /* offset of the packet in the file, in bytes */
+       int64_t data_offset;    /* offset of data within the packet, in bits */
+       uint64_t packet_size;   /* packet size, in bits */
+       uint64_t content_size;  /* content size, in bits */
+       uint64_t events_discarded;
+       uint64_t events_discarded_len;  /* length of the field, in bits */
+       struct packet_index_time ts_cycles;     /* timestamp in cycles */
+       struct packet_index_time ts_real;       /* realtime timestamp */
+       /* CTF_INDEX 1.0 limit */
+       uint64_t stream_instance_id;    /* ID of the channel instance */
+       uint64_t packet_seq_num;        /* packet sequence number */
+};
+
+struct live_viewer_connection * live_viewer_connection_create(
+               const char *url, bool in_query,
+               struct lttng_live_msg_iter *lttng_live_msg_iter);
+
+void live_viewer_connection_destroy(
+               struct live_viewer_connection *conn);
+
+bt_query_status live_viewer_connection_list_sessions(
+               struct live_viewer_connection *viewer_connection,
+               const bt_value **user_result);
+
+#endif /* LTTNG_LIVE_VIEWER_CONNECTION_H */
diff --git a/src/plugins/ctf/plugin.c b/src/plugins/ctf/plugin.c
new file mode 100644 (file)
index 0000000..9597403
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * plugin.c
+ *
+ * Babeltrace CTF Plug-in Registration Symbols
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+
+#include "fs-src/fs.h"
+#include "fs-sink/fs-sink.h"
+#include "lttng-live/lttng-live.h"
+
+#ifndef BT_BUILT_IN_PLUGINS
+BT_PLUGIN_MODULE();
+#endif
+
+/* Initialize plug-in description. */
+BT_PLUGIN(ctf);
+BT_PLUGIN_DESCRIPTION("CTF source and sink support");
+BT_PLUGIN_AUTHOR("Julien Desfossez, Mathieu Desnoyers, Jérémie Galarneau, Philippe Proulx");
+BT_PLUGIN_LICENSE("MIT");
+
+/* ctf.fs source */
+BT_PLUGIN_SOURCE_COMPONENT_CLASS(fs, ctf_fs_iterator_next);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION(fs,
+       "Read CTF traces from the file system.");
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_INIT_METHOD(fs, ctf_fs_init);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_QUERY_METHOD(fs, ctf_fs_query);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD(fs, ctf_fs_finalize);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD(fs,
+       ctf_fs_iterator_init);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD(fs,
+       ctf_fs_iterator_finalize);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD(fs,
+       ctf_fs_iterator_seek_beginning);
+
+/* ctf.fs sink */
+BT_PLUGIN_SINK_COMPONENT_CLASS(fs, ctf_fs_sink_consume);
+BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(fs, ctf_fs_sink_init);
+BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(fs, ctf_fs_sink_finalize);
+BT_PLUGIN_SINK_COMPONENT_CLASS_GRAPH_IS_CONFIGURED_METHOD(fs,
+       ctf_fs_sink_graph_is_configured);
+BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(fs, "Write CTF traces to the file system.");
+
+/* ctf.lttng-live source */
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_WITH_ID(auto, lttng_live, "lttng-live",
+       lttng_live_msg_iter_next);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION_WITH_ID(auto, lttng_live,
+       "Connect to an LTTng relay daemon and receive CTF streams.");
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_INIT_METHOD_WITH_ID(auto, lttng_live,
+       lttng_live_component_init);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_QUERY_METHOD_WITH_ID(auto, lttng_live,
+       lttng_live_query);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD_WITH_ID(auto, lttng_live,
+       lttng_live_component_finalize);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD_WITH_ID(auto,
+       lttng_live, lttng_live_msg_iter_init);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD_WITH_ID(auto,
+       lttng_live, lttng_live_msg_iter_finalize);
diff --git a/src/plugins/ctf/print.h b/src/plugins/ctf/print.h
new file mode 100644 (file)
index 0000000..eab99d7
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef CTF_PRINT_H
+#define CTF_PRINT_H
+
+/*
+ * Define PRINT_PREFIX, PRINT_DBG_CHECK, and PRINT_ERR_STREAM, then
+ * include this file.
+ *
+ * Copyright (c) 2016 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+
+#define PERR(fmt, ...)                                                 \
+       do {                                                            \
+               if (PRINT_ERR_STREAM) {                                 \
+                       fprintf(PRINT_ERR_STREAM,                       \
+                               "[error " PRINT_PREFIX "] " fmt,        \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#define PWARN(fmt, ...)                                                        \
+       do {                                                            \
+               if (PRINT_ERR_STREAM) {                                 \
+                       fprintf(PRINT_ERR_STREAM,                       \
+                               "[warning " PRINT_PREFIX "] " fmt,      \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#define PDBG(fmt, ...)                                                 \
+       do {                                                            \
+               if (PRINT_DBG_CHECK) {                                  \
+                       fprintf(stderr,                                 \
+                               "[debug " PRINT_PREFIX "] " fmt,        \
+                               ##__VA_ARGS__);                         \
+               }                                                       \
+       } while (0)
+
+#endif /* CTF_PRINT_H */
diff --git a/src/plugins/lttng-utils/Makefile.am b/src/plugins/lttng-utils/Makefile.am
new file mode 100644 (file)
index 0000000..d7d980a
--- /dev/null
@@ -0,0 +1,27 @@
+SUBDIRS =
+
+babeltrace_plugin_lttng_utils_la_LIBADD =
+
+if ENABLE_DEBUG_INFO
+SUBDIRS += debug-info
+babeltrace_plugin_lttng_utils_la_LIBADD += \
+       debug-info/libdebug-info.la
+endif
+
+plugindir = "$(PLUGINSDIR)"
+plugin_LTLIBRARIES = babeltrace-plugin-lttng-utils.la
+
+babeltrace_plugin_lttng_utils_la_SOURCES = \
+       plugin.c
+
+babeltrace_plugin_lttng_utils_la_LDFLAGS = \
+       $(LT_NO_UNDEFINED) \
+       -avoid-version -module \
+       $(ELFUTILS_LIBS)
+
+if !ENABLE_BUILT_IN_PLUGINS
+babeltrace_plugin_lttng_utils_la_LIBADD += \
+       $(top_builddir)/src/lib/libbabeltrace2.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la
+endif
diff --git a/src/plugins/lttng-utils/debug-info/Makefile.am b/src/plugins/lttng-utils/debug-info/Makefile.am
new file mode 100644 (file)
index 0000000..a231785
--- /dev/null
@@ -0,0 +1,26 @@
+noinst_LTLIBRARIES = libdebug-info.la
+
+libdebug_info_la_LIBADD = \
+       $(top_builddir)/src/fd-cache/libbabeltrace2-fd-cache.la
+
+libdebug_info_la_SOURCES = \
+       bin-info.c \
+       bin-info.h \
+       crc32.c \
+       crc32.h \
+       debug-info.c \
+       debug-info.h \
+       dwarf.c \
+       dwarf.h \
+       logging.c \
+       logging.h \
+       trace-ir-data-copy.c \
+       trace-ir-data-copy.h \
+       trace-ir-mapping.c \
+       trace-ir-mapping.h \
+       trace-ir-metadata-copy.c \
+       trace-ir-metadata-copy.h \
+       trace-ir-metadata-field-class-copy.c \
+       trace-ir-metadata-field-class-copy.h \
+       utils.c \
+       utils.h
diff --git a/src/plugins/lttng-utils/debug-info/bin-info.c b/src/plugins/lttng-utils/debug-info/bin-info.c
new file mode 100644 (file)
index 0000000..2ecffdf
--- /dev/null
@@ -0,0 +1,1583 @@
+/*
+ * bin-info.c
+ *
+ * Babeltrace - Executable and Shared Object Debug Info Reader
+ *
+ * Copyright 2015 Antoine Busque <abusque@efficios.com>
+ *
+ * Author: Antoine Busque <abusque@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT-BIN-INFO"
+#include "logging.h"
+
+#include <dwarf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "common/common.h"
+
+#include "bin-info.h"
+#include "crc32.h"
+#include "dwarf.h"
+#include "utils.h"
+
+/*
+ * An address printed in hex is at most 20 bytes (16 for 64-bits +
+ * leading 0x + optional leading '+' if addr is an offset + null
+ * character).
+ */
+#define ADDR_STR_LEN 20
+#define BUILD_ID_NOTE_NAME "GNU"
+
+BT_HIDDEN
+int bin_info_init(void)
+{
+       int ret = 0;
+
+       if (elf_version(EV_CURRENT) == EV_NONE) {
+               BT_LOGD("ELF library initialization failed: %s.",
+                       elf_errmsg(-1));
+               ret = -1;
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path,
+               uint64_t low_addr, uint64_t memsz, bool is_pic,
+               const char *debug_info_dir, const char *target_prefix)
+{
+       struct bin_info *bin = NULL;
+
+       BT_ASSERT(fdc);
+
+       if (!path) {
+               goto error;
+       }
+
+       bin = g_new0(struct bin_info, 1);
+       if (!bin) {
+               goto error;
+       }
+
+       if (target_prefix) {
+               bin->elf_path = g_build_filename(target_prefix, path, NULL);
+       } else {
+               bin->elf_path = g_strdup(path);
+       }
+
+       if (!bin->elf_path) {
+               goto error;
+       }
+
+       if (debug_info_dir) {
+               bin->debug_info_dir = g_strdup(debug_info_dir);
+               if (!bin->debug_info_dir) {
+                       goto error;
+               }
+       }
+
+       bin->is_pic = is_pic;
+       bin->memsz = memsz;
+       bin->low_addr = low_addr;
+       bin->high_addr = bin->low_addr + bin->memsz;
+       bin->build_id = NULL;
+       bin->build_id_len = 0;
+       bin->file_build_id_matches = false;
+       bin->fd_cache = fdc;
+
+       return bin;
+
+error:
+       bin_info_destroy(bin);
+       return NULL;
+}
+
+BT_HIDDEN
+void bin_info_destroy(struct bin_info *bin)
+{
+       if (!bin) {
+               return;
+       }
+
+       dwarf_end(bin->dwarf_info);
+
+       g_free(bin->debug_info_dir);
+       g_free(bin->elf_path);
+       g_free(bin->dwarf_path);
+       g_free(bin->build_id);
+       g_free(bin->dbg_link_filename);
+
+       elf_end(bin->elf_file);
+
+       bt_fd_cache_put_handle(bin->fd_cache, bin->elf_handle);
+       bt_fd_cache_put_handle(bin->fd_cache, bin->dwarf_handle);
+
+       g_free(bin);
+}
+
+/**
+ * Initialize the ELF file for a given executable.
+ *
+ * @param bin  bin_info instance
+ * @returns    0 on success, negative value on error.
+ */
+static
+int bin_info_set_elf_file(struct bin_info *bin)
+{
+       struct bt_fd_cache_handle *elf_handle = NULL;
+       Elf *elf_file = NULL;
+
+       if (!bin) {
+               goto error;
+       }
+
+       elf_handle = bt_fd_cache_get_handle(bin->fd_cache, bin->elf_path);
+       if (!elf_handle) {
+               BT_LOGD("Failed to open %s", bin->elf_path);
+               goto error;
+       }
+       bin->elf_handle = elf_handle;
+
+       elf_file = elf_begin(bt_fd_cache_handle_get_fd(bin->elf_handle),
+               ELF_C_READ, NULL);
+       if (!elf_file) {
+               BT_LOGE("elf_begin failed: %s", elf_errmsg(-1));
+               goto error;
+       }
+
+       bin->elf_file = elf_file;
+
+       if (elf_kind(elf_file) != ELF_K_ELF) {
+               BT_LOGE("Error: %s is not an ELF object", bin->elf_path);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       bt_fd_cache_put_handle(bin->fd_cache, elf_handle);
+       elf_end(elf_file);
+       return -1;
+}
+
+/**
+ * From a note section data struct, check if it is a build id note.
+ *
+ * @param note_data            Pointer to a note section
+ *
+ * @returns                    1 on match, 0 if `buf` does not contain a
+ *                             valid build id note
+ */
+static
+int is_build_id_note_section(Elf_Data *note_data)
+{
+       size_t name_offset, desc_offset;
+       GElf_Nhdr note_header;
+       int ret = 0;
+
+       /*
+        * Discard the return value as it contains the size of the note section
+        * and we don't need it.
+        */
+       (void) gelf_getnote(note_data, 0, &note_header, &name_offset,
+               &desc_offset);
+
+       /*
+        * Check the note name length. The name_sz field includes the
+        * terminating null byte.
+        */
+       if (note_header.n_namesz != sizeof(BUILD_ID_NOTE_NAME)) {
+               goto invalid;
+       }
+
+       /* Check the note type. */
+       if (note_header.n_type != NT_GNU_BUILD_ID) {
+               goto invalid;
+       }
+
+       /* Check the note name. */
+       if (memcmp(note_data->d_buf + name_offset, BUILD_ID_NOTE_NAME,
+                       note_header.n_namesz) != 0) {
+               goto invalid;
+       }
+
+       ret = 1;
+
+invalid:
+       return ret;
+}
+
+/**
+ *  From a build id note section data struct, check if the build id it contains
+ *  is identical to the build id passed as parameter.
+ *
+ * @param note_data            Pointer to the file build id note section.
+ * @param build_id             Pointer to a build id to compare to.
+ * @param build_id_len         length of the build id.
+ *
+ * @returns                    1 on match, 0 otherwise.
+ */
+static
+int is_build_id_note_section_matching(Elf_Data *note_data,
+               uint8_t *build_id, size_t build_id_len)
+{
+       size_t name_offset, desc_offset;
+       GElf_Nhdr note_header;
+
+       if (build_id_len <= 0) {
+               goto end;
+       }
+
+       /*
+        * Discard the return value as it contains the size of the note section
+        * and we don't need it.
+        */
+       (void) gelf_getnote(note_data, 0, &note_header, &name_offset,
+               &desc_offset);
+
+       /*
+        * Compare the binary build id with the supplied build id.
+        */
+       if (memcmp(build_id, note_data->d_buf + desc_offset,
+                       build_id_len) == 0) {
+               return 1;
+       }
+end:
+       return 0;
+}
+
+/**
+ * Checks if the build id stored in `bin` (bin->build_id) is matching the build
+ * id of the ondisk file (bin->elf_file).
+ *
+ * @param bin                  bin_info instance
+ * @param build_id             build id to compare ot the on disk file
+ * @param build_id_len         length of the build id
+ *
+ * @returns                    1 on if the build id of stored in `bin` matches
+ *                             the build id of the ondisk file.
+ *                             0 on if they are different or an error occured.
+ */
+static
+int is_build_id_matching(struct bin_info *bin)
+{
+       int ret, is_build_id, is_matching = 0;
+       Elf_Scn *curr_section = NULL, *next_section = NULL;
+       GElf_Shdr curr_section_hdr;
+
+       if (!bin->build_id) {
+               goto error;
+       }
+
+       /* Set ELF file if it hasn't been accessed yet. */
+       if (!bin->elf_file) {
+               ret = bin_info_set_elf_file(bin);
+               if (ret) {
+                       /* Failed to set ELF file. */
+                       goto error;
+               }
+       }
+
+       next_section = elf_nextscn(bin->elf_file, curr_section);
+       if (!next_section) {
+               goto error;
+       }
+
+       while (next_section) {
+               Elf_Data *note_data = NULL;
+
+               curr_section = next_section;
+               next_section = elf_nextscn(bin->elf_file, curr_section);
+
+               if (!gelf_getshdr(curr_section, &curr_section_hdr)) {
+                       goto error;
+               }
+
+               if (curr_section_hdr.sh_type != SHT_NOTE) {
+                       continue;
+               }
+
+               /*
+                * elf_getdata() translates the data to native byte order.
+                */
+               note_data = elf_getdata(curr_section, NULL);
+               if (!note_data) {
+                       goto error;
+               }
+
+               /* Check if the note is of the build-id type. */
+               is_build_id = is_build_id_note_section(note_data);
+               if (!is_build_id) {
+                       continue;
+               }
+
+               /*
+                * Compare the build id of the on-disk file and
+                * the build id recorded in the trace.
+                */
+               is_matching = is_build_id_note_section_matching(
+                       note_data, bin->build_id, bin->build_id_len);
+               if (!is_matching) {
+                       break;
+               }
+       }
+error:
+       return is_matching;
+}
+
+BT_HIDDEN
+int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id,
+               size_t build_id_len)
+{
+       if (!bin || !build_id) {
+               goto error;
+       }
+
+       /* Set the build id. */
+       bin->build_id = g_new0(uint8_t, build_id_len);
+       if (!bin->build_id) {
+               goto error;
+       }
+
+       memcpy(bin->build_id, build_id, build_id_len);
+       bin->build_id_len = build_id_len;
+
+       /*
+        * Check if the file found on the file system has the same build id
+        * that what was recorded in the trace.
+        */
+       bin->file_build_id_matches = is_build_id_matching(bin);
+       if (!bin->file_build_id_matches) {
+               BT_LOGD_STR("Supplied Build ID does not match Build ID of the "
+                               "binary or library found on the file system.");
+               goto error;
+       }
+
+       /*
+        * Reset the is_elf_only flag in case it had been set
+        * previously, because we might find separate debug info using
+        * the new build id information.
+        */
+       bin->is_elf_only = false;
+
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+int bin_info_set_debug_link(struct bin_info *bin, const char *filename,
+               uint32_t crc)
+{
+       if (!bin || !filename) {
+               goto error;
+       }
+
+       bin->dbg_link_filename = g_strdup(filename);
+       if (!bin->dbg_link_filename) {
+               goto error;
+       }
+
+       bin->dbg_link_crc = crc;
+
+       /*
+        * Reset the is_elf_only flag in case it had been set
+        * previously, because we might find separate debug info using
+        * the new build id information.
+        */
+       bin->is_elf_only = false;
+
+       return 0;
+
+error:
+
+       return -1;
+}
+
+/**
+ * Tries to read DWARF info from the location given by path, and
+ * attach it to the given bin_info instance if it exists.
+ *
+ * @param bin  bin_info instance for which to set DWARF info
+ * @param path Presumed location of the DWARF info
+ * @returns    0 on success, negative value on failure
+ */
+static
+int bin_info_set_dwarf_info_from_path(struct bin_info *bin, char *path)
+{
+       int ret = 0;
+       struct bt_fd_cache_handle *dwarf_handle = NULL;
+       struct bt_dwarf_cu *cu = NULL;
+       Dwarf *dwarf_info = NULL;
+
+       if (!bin || !path) {
+               goto error;
+       }
+
+       dwarf_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
+       if (!dwarf_handle) {
+               goto error;
+       }
+
+       dwarf_info = dwarf_begin(bt_fd_cache_handle_get_fd(dwarf_handle),
+               DWARF_C_READ);
+       if (!dwarf_info) {
+               goto error;
+       }
+
+       /*
+        * Check if the dwarf info has any CU. If not, the
+        * executable's object file contains no DWARF info.
+        */
+       cu = bt_dwarf_cu_create(dwarf_info);
+       if (!cu) {
+               goto error;
+       }
+
+       ret = bt_dwarf_cu_next(cu);
+       if (ret) {
+               goto error;
+       }
+
+       bin->dwarf_handle = dwarf_handle;
+       bin->dwarf_path = g_strdup(path);
+       if (!bin->dwarf_path) {
+               goto error;
+       }
+       bin->dwarf_info = dwarf_info;
+       free(cu);
+
+       return 0;
+
+error:
+       bt_fd_cache_put_handle(bin->fd_cache, dwarf_handle);
+       dwarf_end(dwarf_info);
+       g_free(dwarf_info);
+       free(cu);
+
+       return -1;
+}
+
+/**
+ * Try to set the dwarf_info for a given bin_info instance via the
+ * build ID method.
+ *
+ * @param bin          bin_info instance for which to retrieve the
+ *                     DWARF info via build ID
+ * @returns            0 on success (i.e. dwarf_info set), -1 on failure
+ */
+static
+int bin_info_set_dwarf_info_build_id(struct bin_info *bin)
+{
+       int i = 0, ret = 0;
+       char *path = NULL, *build_id_prefix_dir = NULL, *build_id_file = NULL;
+       const char *dbg_dir = NULL;
+       size_t build_id_char_len, build_id_suffix_char_len, build_id_file_len;
+
+       if (!bin || !bin->build_id) {
+               goto error;
+       }
+
+       dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR;
+
+       /*
+        * The prefix dir is the first byte of the build id, represented in
+        * lowercase hex as two characters per byte, +1 for '\0'.
+        */
+       build_id_prefix_dir = g_new0(gchar, BUILD_ID_PREFIX_DIR_LEN + 1);
+       if (!build_id_prefix_dir) {
+               goto error;
+       }
+       g_snprintf(build_id_prefix_dir, BUILD_ID_PREFIX_DIR_LEN + 1, "%02x", bin->build_id[0]);
+
+       /*
+        * The build id file is the remaining bytes of the build id,
+        * represented in lowercase hex, as two characters per byte.
+        */
+       build_id_char_len = (2 * (bin->build_id_len - 1));
+
+       /* To which the build id suffix is added, +1 for '\0'. */
+       build_id_suffix_char_len = strlen(BUILD_ID_SUFFIX) + 1;
+
+       /*
+        * The resulting filename string is the concatenation of the
+        * hex build id and the suffix.
+        */
+       build_id_file_len =  build_id_char_len + build_id_suffix_char_len;
+       build_id_file = g_new0(gchar, build_id_file_len);
+       if (!build_id_file) {
+               goto error;
+       }
+
+       /*
+        * For each byte, starting at offset 1, append two characters
+        * in lowercase hex.
+        */
+       for (i = 1; i < bin->build_id_len; ++i) {
+               int path_idx = 2 * (i - 1);
+
+               g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]);
+       }
+       /* Append the suffix to the generated string, including the '\0'. */
+       g_snprintf(&build_id_file[build_id_char_len], build_id_suffix_char_len,
+               BUILD_ID_SUFFIX);
+
+       path = g_build_filename(dbg_dir, BUILD_ID_SUBDIR, build_id_prefix_dir, build_id_file, NULL);
+       if (!path) {
+               goto error;
+       }
+
+       ret = bin_info_set_dwarf_info_from_path(bin, path);
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+end:
+       g_free(build_id_prefix_dir);
+       g_free(build_id_file);
+       g_free(path);
+
+       return ret;
+}
+
+/**
+ * Tests whether the file located at path exists and has the expected
+ * checksum.
+ *
+ * This predicate is used when looking up separate debug info via the
+ * GNU debuglink method. The expected crc can be found .gnu_debuglink
+ * section in the original ELF file, along with the filename for the
+ * file containing the debug info.
+ *
+ * @param path Full path at which to look for the debug file
+ * @param crc  Expected checksum for the debug file
+ * @returns    1 if the file exists and has the correct checksum,
+ *             0 otherwise
+ */
+static
+int is_valid_debug_file(struct bin_info *bin, char *path, uint32_t crc)
+{
+       int ret = 0;
+       struct bt_fd_cache_handle *debug_handle = NULL;
+       uint32_t _crc = 0;
+
+       if (!path) {
+               goto end;
+       }
+
+       debug_handle = bt_fd_cache_get_handle(bin->fd_cache, path);
+       if (!debug_handle) {
+               goto end;
+       }
+
+       ret = crc32(bt_fd_cache_handle_get_fd(debug_handle), &_crc);
+       if (ret) {
+               ret = 0;
+               goto end;
+       }
+
+       ret = (crc == _crc);
+
+end:
+       bt_fd_cache_put_handle(bin->fd_cache, debug_handle);
+       return ret;
+}
+
+/**
+ * Try to set the dwarf_info for a given bin_info instance via the
+ * debug-link method.
+ *
+ * @param bin          bin_info instance for which to retrieve the
+ *                     DWARF info via debug link
+ * @returns            0 on success (i.e. dwarf_info set), -1 on failure
+ */
+static
+int bin_info_set_dwarf_info_debug_link(struct bin_info *bin)
+{
+       int ret = 0;
+       const gchar *dbg_dir = NULL;
+       gchar *bin_dir = NULL, *path = NULL;
+
+       if (!bin || !bin->dbg_link_filename) {
+               goto error;
+       }
+
+       dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR;
+       bin_dir = g_path_get_dirname(bin->elf_path);
+
+       /* First look in the executable's dir */
+       path = g_build_filename(bin_dir, bin->dbg_link_filename, NULL);
+
+       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
+               goto found;
+       }
+
+       /* If not found, look in .debug subdir */
+       g_free(path);
+       path = g_build_filename(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL);
+
+       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
+               goto found;
+       }
+
+       /* Lastly, look under the global debug directory */
+       g_free(path);
+
+       path = g_build_filename(dbg_dir, bin_dir, bin->dbg_link_filename, NULL);
+       if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
+               goto found;
+       }
+
+error:
+       ret = -1;
+end:
+       g_free(bin_dir);
+       g_free(path);
+
+       return ret;
+
+found:
+       ret = bin_info_set_dwarf_info_from_path(bin, path);
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+}
+
+/**
+ * Initialize the DWARF info for a given executable.
+ *
+ * @param bin  bin_info instance
+ * @returns    0 on success, negative value on failure
+ */
+static
+int bin_info_set_dwarf_info(struct bin_info *bin)
+{
+       int ret = 0;
+
+       if (!bin) {
+               ret = -1;
+               goto end;
+       }
+
+       /* First try to set the DWARF info from the ELF file */
+       ret = bin_info_set_dwarf_info_from_path(bin, bin->elf_path);
+       if (!ret) {
+               goto end;
+       }
+
+       /*
+        * If that fails, try to find separate debug info via build ID
+        * and debug link.
+        */
+       ret = bin_info_set_dwarf_info_build_id(bin);
+       if (!ret) {
+               goto end;
+       }
+
+       ret = bin_info_set_dwarf_info_debug_link(bin);
+       if (!ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+void source_location_destroy(struct source_location *src_loc)
+{
+       if (!src_loc) {
+               return;
+       }
+
+       free(src_loc->filename);
+       g_free(src_loc);
+}
+
+/**
+ * Append a string representation of an address offset to an existing
+ * string.
+ *
+ * On success, the out parameter `result` will contain the base string
+ * followed by the offset string of the form "+0x1234". On failure,
+ * `result` remains unchanged.
+ *
+ * @param base_str     The string to which to append an offset string
+ * @param low_addr     The lower virtual memory address, the base from
+ *                     which the offset is computed
+ * @param high_addr    The higher virtual memory address
+ * @param result       Out parameter, the base string followed by the
+ *                     offset string
+ * @returns            0 on success, -1 on failure
+ */
+static
+int bin_info_append_offset_str(const char *base_str, uint64_t low_addr,
+                               uint64_t high_addr, char **result)
+{
+       uint64_t offset;
+       char *_result = NULL;
+
+       if (!base_str || !result) {
+               goto error;
+       }
+
+       offset = high_addr - low_addr;
+
+       _result = g_strdup_printf("%s+%#0" PRIx64, base_str, offset);
+       if (!_result) {
+               goto error;
+       }
+       *result = _result;
+
+       return 0;
+
+error:
+       free(_result);
+       return -1;
+}
+
+/**
+ * Try to find the symbol closest to an address within a given ELF
+ * section.
+ *
+ * Only function symbols are taken into account. The symbol's address
+ * must precede `addr`. A symbol with a closer address might exist
+ * after `addr` but is irrelevant because it cannot encompass `addr`.
+ *
+ * On success, if found, the out parameters `sym` and `shdr` are
+ * set. On failure or if none are found, they remain unchanged.
+ *
+ * @param scn          ELF section in which to look for the address
+ * @param addr         Virtual memory address for which to find the
+ *                     nearest function symbol
+ * @param sym          Out parameter, the nearest function symbol
+ * @param shdr         Out parameter, the section header for scn
+ * @returns            0 on success, -1 on failure
+ */
+static
+int bin_info_get_nearest_symbol_from_section(Elf_Scn *scn, uint64_t addr,
+               GElf_Sym **sym, GElf_Shdr **shdr)
+{
+       int i;
+       size_t symbol_count;
+       Elf_Data *data = NULL;
+       GElf_Shdr *_shdr = NULL;
+       GElf_Sym *nearest_sym = NULL;
+
+       if (!scn || !sym || !shdr) {
+               goto error;
+       }
+
+       _shdr = g_new0(GElf_Shdr, 1);
+       if (!_shdr) {
+               goto error;
+       }
+
+       _shdr = gelf_getshdr(scn, _shdr);
+       if (!_shdr) {
+               goto error;
+       }
+
+       if (_shdr->sh_type != SHT_SYMTAB) {
+               /*
+                * We are only interested in symbol table (symtab)
+                * sections, skip this one.
+                */
+               goto end;
+       }
+
+       data = elf_getdata(scn, NULL);
+       if (!data) {
+               goto error;
+       }
+
+       symbol_count = _shdr->sh_size / _shdr->sh_entsize;
+
+       for (i = 0; i < symbol_count; ++i) {
+               GElf_Sym *cur_sym = NULL;
+
+               cur_sym = g_new0(GElf_Sym, 1);
+               if (!cur_sym) {
+                       goto error;
+               }
+               cur_sym = gelf_getsym(data, i, cur_sym);
+               if (!cur_sym) {
+                       goto error;
+               }
+               if (GELF_ST_TYPE(cur_sym->st_info) != STT_FUNC) {
+                       /* We're only interested in the functions. */
+                       g_free(cur_sym);
+                       continue;
+               }
+
+               if (cur_sym->st_value <= addr &&
+                               (!nearest_sym ||
+                               cur_sym->st_value > nearest_sym->st_value)) {
+                       g_free(nearest_sym);
+                       nearest_sym = cur_sym;
+               } else {
+                       g_free(cur_sym);
+               }
+       }
+
+end:
+       if (nearest_sym) {
+               *sym = nearest_sym;
+               *shdr = _shdr;
+       } else {
+               g_free(_shdr);
+       }
+
+       return 0;
+
+error:
+       g_free(nearest_sym);
+       g_free(_shdr);
+       return -1;
+}
+
+/**
+ * Get the name of the function containing a given address within an
+ * executable using ELF symbols.
+ *
+ * The function name is in fact the name of the nearest ELF symbol,
+ * followed by the offset in bytes between the address and the symbol
+ * (in hex), separated by a '+' character.
+ *
+ * If found, the out parameter `func_name` is set on success. On failure,
+ * it remains unchanged.
+ *
+ * @param bin          bin_info instance for the executable containing
+ *                     the address
+ * @param addr         Virtual memory address for which to find the
+ *                     function name
+ * @param func_name    Out parameter, the function name
+ * @returns            0 on success, -1 on failure
+ */
+static
+int bin_info_lookup_elf_function_name(struct bin_info *bin, uint64_t addr,
+               char **func_name)
+{
+       /*
+        * TODO (possible optimisation): if an ELF has no symtab
+        * section, it has been stripped. Therefore, it would be wise
+        * to store a flag indicating the stripped status after the
+        * first iteration to prevent subsequent ones.
+        */
+       int ret = 0;
+       Elf_Scn *scn = NULL;
+       GElf_Sym *sym = NULL;
+       GElf_Shdr *shdr = NULL;
+       char *sym_name = NULL;
+
+       /* Set ELF file if it hasn't been accessed yet. */
+       if (!bin->elf_file) {
+               ret = bin_info_set_elf_file(bin);
+               if (ret) {
+                       /* Failed to set ELF file. */
+                       goto error;
+               }
+       }
+
+       scn = elf_nextscn(bin->elf_file, scn);
+       if (!scn) {
+               goto error;
+       }
+
+       while (scn && !sym) {
+               ret = bin_info_get_nearest_symbol_from_section(
+                               scn, addr, &sym, &shdr);
+               if (ret) {
+                       goto error;
+               }
+
+               scn = elf_nextscn(bin->elf_file, scn);
+       }
+
+       if (sym) {
+               sym_name = elf_strptr(bin->elf_file, shdr->sh_link,
+                               sym->st_name);
+               if (!sym_name) {
+                       goto error;
+               }
+
+               ret = bin_info_append_offset_str(sym_name, sym->st_value, addr,
+                                               func_name);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       g_free(shdr);
+       g_free(sym);
+       return 0;
+
+error:
+       g_free(shdr);
+       g_free(sym);
+       return ret;
+}
+
+/**
+ * Get the name of the function containing a given address within a
+ * given compile unit (CU).
+ *
+ * If found, the out parameter `func_name` is set on success. On
+ * failure, it remains unchanged.
+ *
+ * @param cu           bt_dwarf_cu instance which may contain the address
+ * @param addr         Virtual memory address for which to find the
+ *                     function name
+ * @param func_name    Out parameter, the function name
+ * @returns            0 on success, -1 on failure
+ */
+static
+int bin_info_lookup_cu_function_name(struct bt_dwarf_cu *cu, uint64_t addr,
+               char **func_name)
+{
+       int ret = 0;
+       bool found = false;
+       struct bt_dwarf_die *die = NULL;
+
+       if (!cu || !func_name) {
+               goto error;
+       }
+
+       die = bt_dwarf_die_create(cu);
+       if (!die) {
+               goto error;
+       }
+
+       while (bt_dwarf_die_next(die) == 0) {
+               int tag;
+
+               ret = bt_dwarf_die_get_tag(die, &tag);
+               if (ret) {
+                       goto error;
+               }
+
+               if (tag == DW_TAG_subprogram) {
+                       ret = bt_dwarf_die_contains_addr(die, addr, &found);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (found) {
+                               break;
+                       }
+               }
+       }
+
+       if (found) {
+               uint64_t low_addr = 0;
+               char *die_name = NULL;
+
+               ret = bt_dwarf_die_get_name(die, &die_name);
+               if (ret) {
+                       goto error;
+               }
+
+               ret = dwarf_lowpc(die->dwarf_die, &low_addr);
+               if (ret) {
+                       free(die_name);
+                       goto error;
+               }
+
+               ret = bin_info_append_offset_str(die_name, low_addr, addr,
+                                               func_name);
+               free(die_name);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       bt_dwarf_die_destroy(die);
+       return 0;
+
+error:
+       bt_dwarf_die_destroy(die);
+       return -1;
+}
+
+/**
+ * Get the name of the function containing a given address within an
+ * executable using DWARF debug info.
+ *
+ * If found, the out parameter `func_name` is set on success. On
+ * failure, it remains unchanged.
+ *
+ * @param bin          bin_info instance for the executable containing
+ *                     the address
+ * @param addr         Virtual memory address for which to find the
+ *                     function name
+ * @param func_name    Out parameter, the function name
+ * @returns            0 on success, -1 on failure
+ */
+static
+int bin_info_lookup_dwarf_function_name(struct bin_info *bin, uint64_t addr,
+               char **func_name)
+{
+       int ret = 0;
+       char *_func_name = NULL;
+       struct bt_dwarf_cu *cu = NULL;
+
+       if (!bin || !func_name) {
+               goto error;
+       }
+
+       cu = bt_dwarf_cu_create(bin->dwarf_info);
+       if (!cu) {
+               goto error;
+       }
+
+       while (bt_dwarf_cu_next(cu) == 0) {
+               ret = bin_info_lookup_cu_function_name(cu, addr, &_func_name);
+               if (ret) {
+                       goto error;
+               }
+
+               if (_func_name) {
+                       break;
+               }
+       }
+
+       if (_func_name) {
+               *func_name = _func_name;
+       } else {
+               goto error;
+       }
+
+       bt_dwarf_cu_destroy(cu);
+       return 0;
+
+error:
+       bt_dwarf_cu_destroy(cu);
+       return -1;
+}
+
+BT_HIDDEN
+int bin_info_lookup_function_name(struct bin_info *bin,
+               uint64_t addr, char **func_name)
+{
+       int ret = 0;
+       char *_func_name = NULL;
+
+       if (!bin || !func_name) {
+               goto error;
+       }
+
+       /*
+        * If the bin_info has a build id but it does not match the build id
+        * that was found on the file system, return an error.
+        */
+       if (bin->build_id && !bin->file_build_id_matches) {
+               goto error;
+       }
+
+       /* Set DWARF info if it hasn't been accessed yet. */
+       if (!bin->dwarf_info && !bin->is_elf_only) {
+               ret = bin_info_set_dwarf_info(bin);
+               if (ret) {
+                       BT_LOGD_STR("Failed to set bin dwarf info, falling "
+                                       "back to ELF lookup.");
+                       /* Failed to set DWARF info, fallback to ELF. */
+                       bin->is_elf_only = true;
+               }
+       }
+
+       if (!bin_info_has_address(bin, addr)) {
+               goto error;
+       }
+
+       /*
+        * Addresses in ELF and DWARF are relative to base address for
+        * PIC, so make the address argument relative too if needed.
+        */
+       if (bin->is_pic) {
+               addr -= bin->low_addr;
+       }
+
+       if (bin->is_elf_only) {
+               ret = bin_info_lookup_elf_function_name(bin, addr,
+                               &_func_name);
+               if (ret) {
+                       BT_LOGD("Failed to lookup function name (ELF): "
+                               "ret=%d", ret);
+               }
+       } else {
+               ret = bin_info_lookup_dwarf_function_name(bin, addr,
+                               &_func_name);
+               if (ret) {
+                       BT_LOGD("Failed to lookup function name (DWARF): "
+                               "ret=%d", ret);
+               }
+       }
+
+       *func_name = _func_name;
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc)
+{
+       gchar *_bin_loc = NULL;
+
+       if (!bin || !bin_loc) {
+               goto error;
+       }
+
+       /*
+        * If the bin_info has a build id but it does not match the build id
+        * that was found on the file system, return an error.
+        */
+       if (bin->build_id && !bin->file_build_id_matches) {
+               goto error;
+       }
+
+       if (bin->is_pic) {
+               addr -= bin->low_addr;
+               _bin_loc = g_strdup_printf("+%#0" PRIx64, addr);
+       } else {
+               _bin_loc = g_strdup_printf("@%#0" PRIx64, addr);
+       }
+
+       if (!_bin_loc) {
+               goto error;
+       }
+
+       *bin_loc = _bin_loc;
+       return 0;
+
+error:
+       return -1;
+}
+
+/**
+ * Predicate used to determine whether the children of a given DIE
+ * contain a specific address.
+ *
+ * More specifically, the parameter `die` is expected to be a
+ * subprogram (function) DIE, and this predicate tells whether any
+ * subroutines are inlined within this function and would contain
+ * `addr`.
+ *
+ * On success, the out parameter `contains` is set with the boolean
+ * value indicating whether the DIE's range covers `addr`. On failure,
+ * it remains unchanged.
+ *
+ * Do note that this function advances the position of `die`. If the
+ * address is found within one of its children, `die` will be pointing
+ * to that child upon returning from the function, allowing to extract
+ * the information deemed necessary.
+ *
+ * @param die          The parent DIE in whose children the address will be
+ *                     looked for
+ * @param addr         The address for which to look for in the DIEs
+ * @param contains     Out parameter, true if addr is contained,
+ *                     false if not
+ * @returns            Returns 0 on success, -1 on failure
+ */
+static
+int bin_info_child_die_has_address(struct bt_dwarf_die *die, uint64_t addr, bool *contains)
+{
+       int ret = 0;
+       bool _contains = false;
+
+       if (!die) {
+               goto error;
+       }
+
+       ret = bt_dwarf_die_child(die);
+       if (ret) {
+               goto error;
+       }
+
+       do {
+               ret = bt_dwarf_die_contains_addr(die, addr, &_contains);
+               if (ret) {
+                       goto error;
+               }
+
+               if (_contains) {
+                       /*
+                        * The address is within the range of the current DIE
+                        * or its children.
+                        */
+                       int tag;
+
+                       ret = bt_dwarf_die_get_tag(die, &tag);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (tag == DW_TAG_inlined_subroutine) {
+                               /* Found the tracepoint. */
+                               goto end;
+                       }
+
+                       if (bt_dwarf_die_has_children(die)) {
+                               /*
+                                * Look for the address in the children DIEs.
+                                */
+                               ret = bt_dwarf_die_child(die);
+                               if (ret) {
+                                       goto error;
+                               }
+                       }
+               }
+       } while (bt_dwarf_die_next(die) == 0);
+
+end:
+       *contains = _contains;
+       return 0;
+
+error:
+       return -1;
+}
+
+/**
+ * Lookup the source location for a given address within a CU, making
+ * the assumption that it is contained within an inline routine in a
+ * function.
+ *
+ * @param cu           bt_dwarf_cu instance in which to look for the address
+ * @param addr         The address for which to look for
+ * @param src_loc      Out parameter, the source location (filename and
+ *                     line number) for the address
+ * @returns            0 on success, -1 on failure
+ */
+static
+int bin_info_lookup_cu_src_loc_inl(struct bt_dwarf_cu *cu, uint64_t addr,
+               struct source_location **src_loc)
+{
+       int ret = 0;
+       bool found = false;
+       struct bt_dwarf_die *die = NULL;
+       struct source_location *_src_loc = NULL;
+
+       if (!cu || !src_loc) {
+               goto error;
+       }
+
+       die = bt_dwarf_die_create(cu);
+       if (!die) {
+               goto error;
+       }
+
+       while (bt_dwarf_die_next(die) == 0) {
+               int tag;
+
+               ret = bt_dwarf_die_get_tag(die, &tag);
+               if (ret) {
+                       goto error;
+               }
+
+               if (tag == DW_TAG_subprogram) {
+                       bool contains = false;
+
+                       ret = bt_dwarf_die_contains_addr(die, addr, &contains);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (contains) {
+                               /*
+                                * Try to find an inlined subroutine
+                                * child of this DIE containing addr.
+                                */
+                               ret = bin_info_child_die_has_address(die, addr,
+                                               &found);
+                               if(ret) {
+                                       goto error;
+                               }
+
+                               goto end;
+                       }
+               }
+       }
+
+end:
+       if (found) {
+               char *filename = NULL;
+               uint64_t line_no;
+
+               _src_loc = g_new0(struct source_location, 1);
+               if (!_src_loc) {
+                       goto error;
+               }
+
+               ret = bt_dwarf_die_get_call_file(die, &filename);
+               if (ret) {
+                       goto error;
+               }
+               ret = bt_dwarf_die_get_call_line(die, &line_no);
+               if (ret) {
+                       free(filename);
+                       goto error;
+               }
+
+               _src_loc->filename = filename;
+               _src_loc->line_no = line_no;
+               *src_loc = _src_loc;
+       }
+
+       bt_dwarf_die_destroy(die);
+       return 0;
+
+error:
+       source_location_destroy(_src_loc);
+       bt_dwarf_die_destroy(die);
+       return -1;
+}
+
+/**
+ * Lookup the source location for a given address within a CU,
+ * assuming that it is contained within an inlined function.
+ *
+ * A source location can be found regardless of inlining status for
+ * this method, but in the case of an inlined function, the returned
+ * source location will point not to the callsite but rather to the
+ * definition site of the inline function.
+ *
+ * @param cu           bt_dwarf_cu instance in which to look for the address
+ * @param addr         The address for which to look for
+ * @param src_loc      Out parameter, the source location (filename and
+ *                     line number) for the address. Set only if the address
+ *                     is found and resolved successfully
+ *
+ * @returns            0 on success, -1 on failure
+ */
+static
+int bin_info_lookup_cu_src_loc_no_inl(struct bt_dwarf_cu *cu, uint64_t addr,
+               struct source_location **src_loc)
+{
+       struct source_location *_src_loc = NULL;
+       struct bt_dwarf_die *die = NULL;
+       const char *filename = NULL;
+       Dwarf_Line *line = NULL;
+       Dwarf_Addr line_addr;
+       int ret = 0, line_no;
+
+       if (!cu || !src_loc) {
+               goto error;
+       }
+
+       die = bt_dwarf_die_create(cu);
+       if (!die) {
+               goto error;
+       }
+
+       line = dwarf_getsrc_die(die->dwarf_die, addr);
+       if (!line) {
+               /* This is not an error. The caller needs to keep looking. */
+               goto end;
+       }
+
+       ret = dwarf_lineaddr(line, &line_addr);
+       if (ret) {
+               goto error;
+       }
+
+       filename = dwarf_linesrc(line, NULL, NULL);
+       if (!filename) {
+               goto error;
+       }
+
+       if (addr == line_addr) {
+               _src_loc = g_new0(struct source_location, 1);
+               if (!_src_loc) {
+                       goto error;
+               }
+
+               ret = dwarf_lineno(line, &line_no);
+               if (ret) {
+                       goto error;
+               }
+
+               _src_loc->line_no = line_no;
+               _src_loc->filename = g_strdup(filename);
+       }
+
+       if (_src_loc) {
+               *src_loc = _src_loc;
+       }
+
+       goto end;
+
+error:
+       source_location_destroy(_src_loc);
+       ret = -1;
+end:
+       bt_dwarf_die_destroy(die);
+       return ret;
+}
+
+/**
+ * Get the source location (file name and line number) for a given
+ * address within a compile unit (CU).
+ *
+ * On success, the out parameter `src_loc` is set if found. On
+ * failure, it remains unchanged.
+ *
+ * @param cu           bt_dwarf_cu instance for the compile unit which
+ *                     may contain the address
+ * @param addr         Virtual memory address for which to find the
+ *                     source location
+ * @param src_loc      Out parameter, the source location
+ * @returns            0 on success, -1 on failure
+ */
+static
+int bin_info_lookup_cu_src_loc(struct bt_dwarf_cu *cu, uint64_t addr,
+               struct source_location **src_loc)
+{
+       int ret = 0;
+       struct source_location *_src_loc = NULL;
+
+       if (!cu || !src_loc) {
+               goto error;
+       }
+
+       ret = bin_info_lookup_cu_src_loc_inl(cu, addr, &_src_loc);
+       if (ret) {
+               goto error;
+       }
+
+       if (_src_loc) {
+               goto end;
+       }
+
+       ret = bin_info_lookup_cu_src_loc_no_inl(cu, addr, &_src_loc);
+       if (ret) {
+               goto error;
+       }
+
+       if (_src_loc) {
+               goto end;
+       }
+
+end:
+       if (_src_loc) {
+               *src_loc = _src_loc;
+       }
+
+       return 0;
+
+error:
+       source_location_destroy(_src_loc);
+       return -1;
+}
+
+BT_HIDDEN
+int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr,
+               struct source_location **src_loc)
+{
+       struct bt_dwarf_cu *cu = NULL;
+       struct source_location *_src_loc = NULL;
+
+       if (!bin || !src_loc) {
+               goto error;
+       }
+
+       /*
+        * If the bin_info has a build id but it does not match the build id
+        * that was found on the file system, return an error.
+        */
+       if (bin->build_id && !bin->file_build_id_matches) {
+               goto error;
+       }
+
+       /* Set DWARF info if it hasn't been accessed yet. */
+       if (!bin->dwarf_info && !bin->is_elf_only) {
+               if (bin_info_set_dwarf_info(bin)) {
+                       /* Failed to set DWARF info. */
+                       bin->is_elf_only = true;
+               }
+       }
+
+       if (bin->is_elf_only) {
+               /* We cannot lookup source location without DWARF info. */
+               goto error;
+       }
+
+       if (!bin_info_has_address(bin, addr)) {
+               goto error;
+       }
+
+       /*
+        * Addresses in ELF and DWARF are relative to base address for
+        * PIC, so make the address argument relative too if needed.
+        */
+       if (bin->is_pic) {
+               addr -= bin->low_addr;
+       }
+
+       cu = bt_dwarf_cu_create(bin->dwarf_info);
+       if (!cu) {
+               goto error;
+       }
+
+       while (bt_dwarf_cu_next(cu) == 0) {
+               int ret;
+
+               ret = bin_info_lookup_cu_src_loc(cu, addr, &_src_loc);
+               if (ret) {
+                       goto error;
+               }
+
+               if (_src_loc) {
+                       break;
+               }
+       }
+
+       bt_dwarf_cu_destroy(cu);
+       if (_src_loc) {
+               *src_loc = _src_loc;
+       }
+
+       return 0;
+
+error:
+       source_location_destroy(_src_loc);
+       bt_dwarf_cu_destroy(cu);
+       return -1;
+}
diff --git a/src/plugins/lttng-utils/debug-info/bin-info.h b/src/plugins/lttng-utils/debug-info/bin-info.h
new file mode 100644 (file)
index 0000000..bf47369
--- /dev/null
@@ -0,0 +1,240 @@
+#ifndef _BABELTRACE_BIN_INFO_H
+#define _BABELTRACE_BIN_INFO_H
+
+/*
+ * Babeltrace - Executable and Shared Object Debug Info Reader
+ *
+ * Copyright 2015 Antoine Busque <abusque@efficios.com>
+ *
+ * Author: Antoine Busque <abusque@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <gelf.h>
+#include <elfutils/libdw.h>
+#include "common/babeltrace.h"
+#include "fd-cache/fd-cache.h"
+
+#define DEFAULT_DEBUG_DIR "/usr/lib/debug"
+#define DEBUG_SUBDIR ".debug"
+#define BUILD_ID_SUBDIR ".build-id"
+#define BUILD_ID_SUFFIX ".debug"
+#define BUILD_ID_PREFIX_DIR_LEN 2
+
+struct bin_info {
+       /* Base virtual memory address. */
+       uint64_t low_addr;
+       /* Upper bound of exec address space. */
+       uint64_t high_addr;
+       /* Size of exec address space. */
+       uint64_t memsz;
+       /* Paths to ELF and DWARF files. */
+       gchar *elf_path;
+       gchar *dwarf_path;
+       /* libelf and libdw objects representing the files. */
+       Elf *elf_file;
+       Dwarf *dwarf_info;
+       /* Optional build ID info. */
+       uint8_t *build_id;
+       size_t build_id_len;
+
+       /* Optional debug link info. */
+       gchar *dbg_link_filename;
+       uint32_t dbg_link_crc;
+       /* fd cache handles to ELF and DWARF files. */
+       struct bt_fd_cache_handle *elf_handle;
+       struct bt_fd_cache_handle *dwarf_handle;
+       /* Configuration. */
+       gchar *debug_info_dir;
+       /* Denotes whether the executable is position independent code. */
+       bool is_pic:1;
+       /* Denotes whether the build id in the trace matches to one on disk. */
+       bool file_build_id_matches:1;
+       /*
+        * Denotes whether the executable only has ELF symbols and no
+        * DWARF info.
+        */
+       bool is_elf_only:1;
+       /* Weak ref. Owned by the iterator. */
+       struct bt_fd_cache *fd_cache;
+};
+
+struct source_location {
+       uint64_t line_no;
+       gchar *filename;
+};
+
+/**
+ * Initializes the bin_info framework. Call this before calling
+ * anything else.
+ *
+ * @returns            0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bin_info_init(void);
+
+/**
+ * Instantiate a structure representing an ELF executable, possibly
+ * with DWARF info, located at the given path.
+ *
+ * @param path         Path to the ELF file
+ * @param low_addr     Base address of the executable
+ * @param memsz        In-memory size of the executable
+ * @param is_pic       Whether the executable is position independent
+ *                     code (PIC)
+ * @param debug_info_dir Directory containing debug info or NULL.
+ * @param target_prefix  Path to the root file system of the target
+ *                       or NULL.
+ * @returns            Pointer to the new bin_info on success,
+ *                     NULL on failure.
+ */
+BT_HIDDEN
+struct bin_info *bin_info_create(struct bt_fd_cache *fdc, const char *path,
+               uint64_t low_addr, uint64_t memsz, bool is_pic,
+               const char *debug_info_dir, const char *target_prefix);
+
+/**
+ * Destroy the given bin_info instance
+ *
+ * @param bin  bin_info instance to destroy
+ */
+BT_HIDDEN
+void bin_info_destroy(struct bin_info *bin);
+
+/**
+ * Sets the build ID information for a given bin_info instance.
+ *
+ * @param bin          The bin_info instance for which to set
+ *                     the build ID
+ * @param build_id     Array of bytes containing the actual ID
+ * @param build_id_len Length in bytes of the build_id
+ * @returns            0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bin_info_set_build_id(struct bin_info *bin, uint8_t *build_id,
+               size_t build_id_len);
+
+/**
+ * Sets the debug link information for a given bin_info instance.
+ *
+ * @param bin          The bin_info instance for which to set
+ *                     the debug link
+ * @param filename     Name of the separate debug info file
+ * @param crc          Checksum for the debug info file
+ * @returns            0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bin_info_set_debug_link(struct bin_info *bin, const char *filename,
+               uint32_t crc);
+
+/**
+ * Returns whether or not the given bin info \p bin contains the
+ * address \p addr.
+ *
+ * @param bin          bin_info instance
+ * @param addr         Address to lookup
+ * @returns            1 if \p bin contains \p addr, 0 if it does not,
+ *                     -1 on failure
+ */
+static inline
+int bin_info_has_address(struct bin_info *bin, uint64_t addr)
+{
+       if (!bin) {
+               return -1;
+       }
+
+       return addr >= bin->low_addr && addr < bin->high_addr;
+}
+
+/**
+ * Get the name of the function containing a given address within an
+ * executable.
+ *
+ * If no DWARF info is available, the function falls back to ELF
+ * symbols and the "function name" is in fact the name of the closest
+ * symbol, followed by the offset between the symbol and the address.
+ *
+ * On success, if found, the out parameter `func_name` is set. The ownership
+ * of `func_name` is passed to the caller. On failure, `func_name` remains
+ * unchanged.
+ *
+ * @param bin          bin_info instance for the executable containing
+ *                     the address
+ * @param addr         Virtual memory address for which to find the
+ *                     function name
+ * @param func_name    Out parameter, the function name.
+ * @returns            0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bin_info_lookup_function_name(struct bin_info *bin, uint64_t addr,
+               char **func_name);
+
+/**
+ * Get the source location (file name and line number) for a given
+ * address within an executable.
+ *
+ * If no DWARF info is available, the source location cannot be found
+ * and the function will return unsuccessfully.
+ *
+ * On success, if found, the out parameter `src_loc` is set. The ownership
+ * of `src_loc` is passed to the caller. On failure, `src_loc` remains
+ * unchanged.
+ *
+ * @param bin          bin_info instance for the executable containing
+ *                     the address
+ * @param addr         Virtual memory address for which to find the
+ *                     source location
+ * @param src_loc      Out parameter, the source location
+ * @returns            0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bin_info_lookup_source_location(struct bin_info *bin, uint64_t addr,
+               struct source_location **src_loc);
+/**
+ * Get a string representing the location within the binary of a given
+ * address.
+ *
+ * In the  case of a PIC binary, the location is relative (+0x1234).
+ * For a non-PIC binary, the location is absolute (@0x1234)
+ *
+ * On success, the out parameter `bin_loc` is set. The ownership is
+ * passed to the caller. On failure, `bin_loc` remains unchanged.
+ *
+ * @param bin          bin_info instance for the executable containing
+ *                     the address
+ * @param addr         Virtual memory address for which to find the
+ *                     binary location
+ * @param bin_loc      Out parameter, the binary location
+ * @returns            0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bin_info_get_bin_loc(struct bin_info *bin, uint64_t addr, char **bin_loc);
+
+/**
+ * Destroy the given source_location instance
+ *
+ * @param src_loc      source_location instance to destroy
+ */
+BT_HIDDEN
+void source_location_destroy(struct source_location *src_loc);
+
+#endif /* _BABELTRACE_BIN_INFO_H */
diff --git a/src/plugins/lttng-utils/debug-info/crc32.c b/src/plugins/lttng-utils/debug-info/crc32.c
new file mode 100644 (file)
index 0000000..e68c043
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "crc32.h"
+
+#define CRC(crc, ch)    (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
+
+/* generated using the AUTODIN II polynomial
+ *     x^32 + x^26 + x^23 + x^22 + x^16 +
+ *     x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+ */
+static const uint32_t crctab[256] = {
+       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+       0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+       0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+       0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+       0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+       0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+       0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+       0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+       0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+       0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+       0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+       0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+       0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+       0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+       0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+       0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+       0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+       0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+int crc32(int fd, uint32_t *crc)
+{
+       int nr;
+       uint32_t _crc = ~0;
+       char buf[BUFSIZ], *p;
+
+       if (fd < 0 || !crc) {
+               goto error;
+       }
+
+       while ((nr = read(fd, buf, sizeof(buf))) > 0) {
+               for (p = buf; nr--; ++p) {
+                       CRC(_crc, *p);
+               }
+       }
+
+       if (nr < 0) {
+               goto error;
+       }
+
+       *crc = ~_crc;
+       return 0;
+
+error:
+       return -1;
+}
diff --git a/src/plugins/lttng-utils/debug-info/crc32.h b/src/plugins/lttng-utils/debug-info/crc32.h
new file mode 100644 (file)
index 0000000..7343819
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef _BABELTRACE_CRC32_H
+#define _BABELTRACE_CRC32_H
+
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the University of
+ *    California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "common/babeltrace.h"
+
+/**
+ * Compute a 32-bit cyclic redundancy checksum for a given file.
+ *
+ * On success, the out parameter crc is set with the computed checksum
+ * value,
+ *
+ * @param fd   File descriptor for the file for which to compute the CRC
+ * @param crc  Out parameter, the computed checksum
+ * @returns    0 on success, -1 on failure.
+ */
+BT_HIDDEN
+int crc32(int fd, uint32_t *crc);
+
+#endif /* _BABELTRACE_CRC32_H */
diff --git a/src/plugins/lttng-utils/debug-info/debug-info.c b/src/plugins/lttng-utils/debug-info/debug-info.c
new file mode 100644 (file)
index 0000000..297be24
--- /dev/null
@@ -0,0 +1,2061 @@
+/*
+ * Babeltrace - Debug Information State Tracker
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2015 Philippe Proulx <pproulx@efficios.com>
+ * Copyright (c) 2015 Antoine Busque <abusque@efficios.com>
+ * Copyright (c) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-CTF-LTTNG-UTILS-DEBUG-INFO-FLT"
+#include "logging.h"
+
+#include <glib.h>
+#include "plugins/plugins-common.h"
+
+#include "common/assert.h"
+#include "common/common.h"
+#include "fd-cache/fd-cache.h"
+
+#include "bin-info.h"
+#include "debug-info.h"
+#include "trace-ir-data-copy.h"
+#include "trace-ir-mapping.h"
+#include "trace-ir-metadata-copy.h"
+#include "utils.h"
+
+#define DEFAULT_DEBUG_INFO_FIELD_NAME  "debug_info"
+#define LTTNG_UST_STATEDUMP_PREFIX     "lttng_ust"
+#define VPID_FIELD_NAME                        "vpid"
+#define IP_FIELD_NAME                  "ip"
+#define BADDR_FIELD_NAME               "baddr"
+#define CRC32_FIELD_NAME               "crc"
+#define BUILD_ID_FIELD_NAME            "build_id"
+#define FILENAME_FIELD_NAME            "filename"
+#define IS_PIC_FIELD_NAME              "is_pic"
+#define MEMSZ_FIELD_NAME               "memsz"
+#define PATH_FIELD_NAME                        "path"
+
+struct debug_info_component {
+       gchar *arg_debug_dir;
+       gchar *arg_debug_info_field_name;
+       gchar *arg_target_prefix;
+       bt_bool arg_full_path;
+};
+
+struct debug_info_msg_iter {
+       struct debug_info_component *debug_info_component;
+       bt_self_message_iterator *input_iterator;
+       bt_self_component *self_comp;
+       bt_self_component_port_input_message_iterator *msg_iter;
+
+       struct trace_ir_maps *ir_maps;
+       /* in_trace -> debug_info_mapping. */
+       GHashTable *debug_info_map;
+
+       struct bt_fd_cache fd_cache;
+};
+
+struct debug_info_source {
+       /* Strings are owned by debug_info_source. */
+       gchar *func;
+       /*
+        * Store the line number as a string so that the allocation and
+        * conversion to string is only done once.
+        */
+       gchar *line_no;
+       gchar *src_path;
+       /* short_src_path points inside src_path, no need to free. */
+       const gchar *short_src_path;
+       gchar *bin_path;
+       /* short_bin_path points inside bin_path, no need to free. */
+       const gchar *short_bin_path;
+       /*
+        * Location within the binary. Either absolute (@0x1234) or
+        * relative (+0x4321).
+        */
+       gchar *bin_loc;
+};
+
+struct proc_debug_info_sources {
+       /*
+        * Hash table: base address (pointer to uint64_t) to bin info; owned by
+        * proc_debug_info_sources.
+        */
+       GHashTable *baddr_to_bin_info;
+
+       /*
+        * Hash table: IP (pointer to uint64_t) to (struct debug_info_source *);
+        * owned by proc_debug_info_sources.
+        */
+       GHashTable *ip_to_debug_info_src;
+};
+
+struct debug_info {
+       struct debug_info_component *comp;
+       const bt_trace *input_trace;
+       uint64_t destruction_listener_id;
+
+       /*
+        * Hash table of VPIDs (pointer to int64_t) to
+        * (struct proc_debug_info_sources*); owned by debug_info.
+        */
+       GHashTable *vpid_to_proc_dbg_info_src;
+       GQuark q_statedump_bin_info;
+       GQuark q_statedump_debug_link;
+       GQuark q_statedump_build_id;
+       GQuark q_statedump_start;
+       GQuark q_dl_open;
+       GQuark q_lib_load;
+       GQuark q_lib_unload;
+       struct bt_fd_cache *fd_cache; /* Weak ref. Owned by the iterator. */
+};
+
+static
+int debug_info_init(struct debug_info *info)
+{
+       info->q_statedump_bin_info = g_quark_from_string(
+                       "lttng_ust_statedump:bin_info");
+       info->q_statedump_debug_link = g_quark_from_string(
+                       "lttng_ust_statedump:debug_link");
+       info->q_statedump_build_id = g_quark_from_string(
+                       "lttng_ust_statedump:build_id");
+       info->q_statedump_start = g_quark_from_string(
+                       "lttng_ust_statedump:start");
+       info->q_dl_open = g_quark_from_string("lttng_ust_dl:dlopen");
+       info->q_lib_load = g_quark_from_string("lttng_ust_lib:load");
+       info->q_lib_unload = g_quark_from_string("lttng_ust_lib:unload");
+
+       return bin_info_init();
+}
+
+static
+void debug_info_source_destroy(struct debug_info_source *debug_info_src)
+{
+       if (!debug_info_src) {
+               return;
+       }
+
+       g_free(debug_info_src->func);
+       g_free(debug_info_src->line_no);
+       g_free(debug_info_src->src_path);
+       g_free(debug_info_src->bin_path);
+       g_free(debug_info_src->bin_loc);
+       g_free(debug_info_src);
+}
+
+static
+struct debug_info_source *debug_info_source_create_from_bin(
+               struct bin_info *bin, uint64_t ip)
+{
+       int ret;
+       struct debug_info_source *debug_info_src = NULL;
+       struct source_location *src_loc = NULL;
+
+       debug_info_src = g_new0(struct debug_info_source, 1);
+
+       if (!debug_info_src) {
+               goto end;
+       }
+
+       /* Lookup function name */
+       ret = bin_info_lookup_function_name(bin, ip, &debug_info_src->func);
+       if (ret) {
+               goto error;
+       }
+
+       /* Can't retrieve src_loc from ELF, or could not find binary, skip. */
+       if (!bin->is_elf_only || !debug_info_src->func) {
+               /* Lookup source location */
+               ret = bin_info_lookup_source_location(bin, ip, &src_loc);
+               if (ret) {
+                       BT_LOGD("Failed to lookup source location: ret=%d", ret);
+               }
+       }
+
+       if (src_loc) {
+               debug_info_src->line_no =
+                       g_strdup_printf("%"PRId64, src_loc->line_no);
+               if (!debug_info_src->line_no) {
+                       BT_LOGD("Error occured when setting line_no field.");
+                       goto error;
+               }
+
+               if (src_loc->filename) {
+                       debug_info_src->src_path = g_strdup(src_loc->filename);
+                       if (!debug_info_src->src_path) {
+                               goto error;
+                       }
+
+                       debug_info_src->short_src_path = get_filename_from_path(
+                                       debug_info_src->src_path);
+               }
+               source_location_destroy(src_loc);
+       }
+
+       if (bin->elf_path) {
+               debug_info_src->bin_path = g_strdup(bin->elf_path);
+               if (!debug_info_src->bin_path) {
+                       goto error;
+               }
+
+               debug_info_src->short_bin_path = get_filename_from_path(
+                               debug_info_src->bin_path);
+
+               ret = bin_info_get_bin_loc(bin, ip, &(debug_info_src->bin_loc));
+               if (ret) {
+                       goto error;
+               }
+       }
+
+end:
+       return debug_info_src;
+
+error:
+       debug_info_source_destroy(debug_info_src);
+       return NULL;
+}
+
+static
+void proc_debug_info_sources_destroy(
+               struct proc_debug_info_sources *proc_dbg_info_src)
+{
+       if (!proc_dbg_info_src) {
+               return;
+       }
+
+       if (proc_dbg_info_src->baddr_to_bin_info) {
+               g_hash_table_destroy(proc_dbg_info_src->baddr_to_bin_info);
+       }
+
+       if (proc_dbg_info_src->ip_to_debug_info_src) {
+               g_hash_table_destroy(proc_dbg_info_src->ip_to_debug_info_src);
+       }
+
+       g_free(proc_dbg_info_src);
+}
+
+static
+struct proc_debug_info_sources *proc_debug_info_sources_create(void)
+{
+       struct proc_debug_info_sources *proc_dbg_info_src = NULL;
+
+       proc_dbg_info_src = g_new0(struct proc_debug_info_sources, 1);
+       if (!proc_dbg_info_src) {
+               goto end;
+       }
+
+       proc_dbg_info_src->baddr_to_bin_info = g_hash_table_new_full(
+                       g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
+                       (GDestroyNotify) bin_info_destroy);
+       if (!proc_dbg_info_src->baddr_to_bin_info) {
+               goto error;
+       }
+
+       proc_dbg_info_src->ip_to_debug_info_src = g_hash_table_new_full(
+                       g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
+                       (GDestroyNotify) debug_info_source_destroy);
+       if (!proc_dbg_info_src->ip_to_debug_info_src) {
+               goto error;
+       }
+
+end:
+       return proc_dbg_info_src;
+
+error:
+       proc_debug_info_sources_destroy(proc_dbg_info_src);
+       return NULL;
+}
+
+static
+struct proc_debug_info_sources *proc_debug_info_sources_ht_get_entry(
+               GHashTable *ht, int64_t vpid)
+{
+       gpointer key = g_new0(int64_t, 1);
+       struct proc_debug_info_sources *proc_dbg_info_src = NULL;
+
+       if (!key) {
+               goto end;
+       }
+
+       *((int64_t *) key) = vpid;
+
+       /* Exists? Return it */
+       proc_dbg_info_src = g_hash_table_lookup(ht, key);
+       if (proc_dbg_info_src) {
+               goto end;
+       }
+
+       /* Otherwise, create and return it */
+       proc_dbg_info_src = proc_debug_info_sources_create();
+       if (!proc_dbg_info_src) {
+               goto end;
+       }
+
+       g_hash_table_insert(ht, key, proc_dbg_info_src);
+       /* Ownership passed to ht */
+       key = NULL;
+end:
+       g_free(key);
+       return proc_dbg_info_src;
+}
+
+static inline
+const bt_field *event_borrow_payload_field(const bt_event *event,
+               const char *field_name)
+{
+       const bt_field *event_payload, *field;
+
+       event_payload =  bt_event_borrow_payload_field_const(event);
+       BT_ASSERT(event_payload);
+
+       field = bt_field_structure_borrow_member_field_by_name_const(
+                       event_payload, field_name);
+       return field;
+}
+
+static inline
+const bt_field *event_borrow_common_context_field(const bt_event *event,
+               const char *field_name)
+{
+       const bt_field *event_common_ctx, *field = NULL;
+
+       event_common_ctx =  bt_event_borrow_common_context_field_const(event);
+       if (!event_common_ctx) {
+               goto end;
+       }
+
+       field = bt_field_structure_borrow_member_field_by_name_const(
+                       event_common_ctx, field_name);
+
+end:
+       return field;
+}
+
+static inline
+void event_get_common_context_signed_integer_field_value(
+               const bt_event *event, const char *field_name, int64_t *value)
+{
+       *value = bt_field_signed_integer_get_value(
+                       event_borrow_common_context_field(event, field_name));
+}
+
+static inline
+int event_get_payload_build_id_length(const bt_event *event,
+               const char *field_name, uint64_t *build_id_len)
+{
+       const bt_field *build_id_field;
+       const bt_field_class *build_id_field_class;
+
+       build_id_field = event_borrow_payload_field(event, field_name);
+       build_id_field_class = bt_field_borrow_class_const(build_id_field);
+
+       BT_ASSERT(bt_field_class_get_type(build_id_field_class) ==
+                       BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY);
+       BT_ASSERT(bt_field_class_get_type(
+                       bt_field_class_array_borrow_element_field_class_const(
+                               build_id_field_class)) ==
+                       BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER);
+
+       *build_id_len = bt_field_array_get_length(build_id_field);
+
+       return 0;
+}
+
+static inline
+int event_get_payload_build_id_value(const bt_event *event,
+               const char *field_name, uint8_t *build_id)
+{
+       const bt_field *curr_field, *build_id_field;
+       const bt_field_class *build_id_field_class;
+       uint64_t i, build_id_len;
+       int ret;
+
+       ret = 0;
+
+       build_id_field = event_borrow_payload_field(event, field_name);
+       build_id_field_class = bt_field_borrow_class_const(build_id_field);
+
+       BT_ASSERT(bt_field_class_get_type(build_id_field_class) ==
+                       BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY);
+       BT_ASSERT(bt_field_class_get_type(
+                       bt_field_class_array_borrow_element_field_class_const(
+                               build_id_field_class)) ==
+                       BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER);
+
+       build_id_len = bt_field_array_get_length(build_id_field);
+
+       for (i = 0; i < build_id_len; i++) {
+               curr_field =
+                       bt_field_array_borrow_element_field_by_index_const(
+                                       build_id_field, i);
+
+               build_id[i] = bt_field_unsigned_integer_get_value(curr_field);
+       }
+
+       return ret;
+}
+
+static
+void event_get_payload_unsigned_integer_field_value(const bt_event *event,
+               const char *field_name, uint64_t *value)
+{
+       *value = bt_field_unsigned_integer_get_value(
+                       event_borrow_payload_field(event, field_name));
+}
+
+static
+void event_get_payload_string_field_value(const bt_event *event,
+               const char *field_name, const char **value)
+{
+       *value = bt_field_string_get_value(
+                       event_borrow_payload_field(event, field_name));
+}
+
+static inline
+bool event_has_payload_field(const bt_event *event,
+               const char *field_name)
+{
+       return event_borrow_payload_field(event, field_name) != NULL;
+}
+
+static
+struct debug_info_source *proc_debug_info_sources_get_entry(
+               struct proc_debug_info_sources *proc_dbg_info_src, uint64_t ip)
+{
+       struct debug_info_source *debug_info_src = NULL;
+       gpointer key = g_new0(uint64_t, 1);
+       GHashTableIter iter;
+       gpointer baddr, value;
+
+       if (!key) {
+               goto end;
+       }
+
+       *((uint64_t *) key) = ip;
+
+       /* Look in IP to debug infos hash table first. */
+       debug_info_src = g_hash_table_lookup(
+                       proc_dbg_info_src->ip_to_debug_info_src,
+                       key);
+       if (debug_info_src) {
+               goto end;
+       }
+
+       /* Check in all bin_infos. */
+       g_hash_table_iter_init(&iter, proc_dbg_info_src->baddr_to_bin_info);
+
+       while (g_hash_table_iter_next(&iter, &baddr, &value))
+       {
+               struct bin_info *bin = value;
+
+               if (!bin_info_has_address(value, ip)) {
+                       continue;
+               }
+
+               /*
+                * Found; add it to cache.
+                *
+                * FIXME: this should be bounded in size (and implement
+                * a caching policy), and entries should be prunned when
+                * libraries are unmapped.
+                */
+               debug_info_src = debug_info_source_create_from_bin(bin, ip);
+               if (debug_info_src) {
+                       g_hash_table_insert(
+                                       proc_dbg_info_src->ip_to_debug_info_src,
+                                       key, debug_info_src);
+                       /* Ownership passed to ht. */
+                       key = NULL;
+               }
+               break;
+       }
+
+end:
+       free(key);
+       return debug_info_src;
+}
+
+static
+struct debug_info_source *debug_info_query(struct debug_info *debug_info,
+               int64_t vpid, uint64_t ip)
+{
+       struct debug_info_source *dbg_info_src = NULL;
+       struct proc_debug_info_sources *proc_dbg_info_src;
+
+       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
+                       debug_info->vpid_to_proc_dbg_info_src, vpid);
+       if (!proc_dbg_info_src) {
+               goto end;
+       }
+
+       dbg_info_src = proc_debug_info_sources_get_entry(proc_dbg_info_src, ip);
+
+end:
+       return dbg_info_src;
+}
+
+static
+struct debug_info *debug_info_create(struct debug_info_component *comp,
+               const bt_trace *trace, struct bt_fd_cache *fdc)
+{
+       int ret;
+       struct debug_info *debug_info;
+
+       BT_ASSERT(comp);
+       BT_ASSERT(trace);
+       BT_ASSERT(fdc);
+
+       debug_info = g_new0(struct debug_info, 1);
+       if (!debug_info) {
+               goto end;
+       }
+
+       debug_info->vpid_to_proc_dbg_info_src = g_hash_table_new_full(
+                       g_int64_hash, g_int64_equal, (GDestroyNotify) g_free,
+                       (GDestroyNotify) proc_debug_info_sources_destroy);
+       if (!debug_info->vpid_to_proc_dbg_info_src) {
+               goto error;
+       }
+
+       debug_info->comp = comp;
+       ret = debug_info_init(debug_info);
+       if (ret) {
+               goto error;
+       }
+
+       debug_info->input_trace = trace;
+       debug_info->fd_cache = fdc;
+
+end:
+       return debug_info;
+error:
+       g_free(debug_info);
+       return NULL;
+}
+
+static
+void debug_info_destroy(struct debug_info *debug_info)
+{
+       bt_trace_status status;
+       if (!debug_info) {
+               goto end;
+       }
+
+       if (debug_info->vpid_to_proc_dbg_info_src) {
+               g_hash_table_destroy(debug_info->vpid_to_proc_dbg_info_src);
+       }
+
+       status = bt_trace_remove_destruction_listener(debug_info->input_trace,
+                       debug_info->destruction_listener_id);
+       if (status != BT_TRACE_STATUS_OK) {
+               BT_LOGD("Trace destruction listener removal failed.");
+       }
+
+       g_free(debug_info);
+end:
+       return;
+}
+
+static
+void handle_event_statedump_build_id(struct debug_info *debug_info,
+               const bt_event *event)
+{
+       struct proc_debug_info_sources *proc_dbg_info_src;
+       uint64_t build_id_len, baddr;
+       uint8_t *build_id = NULL;
+       struct bin_info *bin;
+       int64_t vpid;
+       int ret = 0;
+
+       event_get_common_context_signed_integer_field_value(event,
+                       VPID_FIELD_NAME, &vpid);
+       event_get_payload_unsigned_integer_field_value(event,
+                       BADDR_FIELD_NAME, &baddr);
+
+       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
+                       debug_info->vpid_to_proc_dbg_info_src, vpid);
+       if (!proc_dbg_info_src) {
+               goto end;
+       }
+
+       bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info,
+                       (gpointer) &baddr);
+       if (!bin) {
+               /*
+                * The build_id event comes after the bin has been
+                * created. If it isn't found, just ignore this event.
+                */
+               goto end;
+       }
+       ret = event_get_payload_build_id_length(event, BUILD_ID_FIELD_NAME,
+                       &build_id_len);
+
+       build_id = g_new0(uint8_t, build_id_len);
+       if (!build_id) {
+               goto end;
+       }
+
+       ret = event_get_payload_build_id_value(event, BUILD_ID_FIELD_NAME,
+                       build_id);
+       if (ret) {
+               goto end;
+       }
+
+       ret = bin_info_set_build_id(bin, build_id, build_id_len);
+       if (ret) {
+               goto end;
+       }
+
+       /*
+        * Reset the is_elf_only flag in case it had been set
+        * previously, because we might find separate debug info using
+        * the new build id information.
+        */
+       bin->is_elf_only = false;
+
+end:
+       g_free(build_id);
+       return;
+}
+
+static
+void handle_event_statedump_debug_link(struct debug_info *debug_info,
+               const bt_event *event)
+{
+       struct proc_debug_info_sources *proc_dbg_info_src;
+       struct bin_info *bin = NULL;
+       int64_t vpid;
+       uint64_t baddr;
+       const char *filename = NULL;
+       uint32_t crc32;
+       uint64_t crc_field_value;
+
+       event_get_common_context_signed_integer_field_value(event,
+                       VPID_FIELD_NAME, &vpid);
+
+       event_get_payload_unsigned_integer_field_value(event,
+                       BADDR_FIELD_NAME, &baddr);
+
+       event_get_payload_unsigned_integer_field_value(event,
+                       CRC32_FIELD_NAME, &crc_field_value);
+
+       crc32 = (uint32_t) crc_field_value;
+
+       event_get_payload_string_field_value(event,
+                       FILENAME_FIELD_NAME, &filename);
+
+       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
+                       debug_info->vpid_to_proc_dbg_info_src, vpid);
+       if (!proc_dbg_info_src) {
+               goto end;
+       }
+
+       bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info,
+                       (gpointer) &baddr);
+       if (!bin) {
+               /*
+                * The debug_link event comes after the bin has been
+                * created. If it isn't found, just ignore this event.
+                */
+               goto end;
+       }
+
+       bin_info_set_debug_link(bin, filename, crc32);
+
+end:
+       return;
+}
+
+static
+void handle_bin_info_event(struct debug_info *debug_info,
+               const bt_event *event, bool has_pic_field)
+{
+       struct proc_debug_info_sources *proc_dbg_info_src;
+       struct bin_info *bin;
+       uint64_t baddr, memsz;
+       int64_t vpid;
+       const char *path;
+       gpointer key = NULL;
+       bool is_pic;
+
+       event_get_payload_unsigned_integer_field_value(event,
+                       MEMSZ_FIELD_NAME, &memsz);
+       if (memsz == 0) {
+               /* Ignore VDSO. */
+               goto end;
+       }
+
+       event_get_payload_unsigned_integer_field_value(event,
+                       BADDR_FIELD_NAME, &baddr);
+
+       /*
+        * This field is not produced by the dlopen event emitted before
+        * lttng-ust 2.9.
+        */
+       if (!event_has_payload_field(event, PATH_FIELD_NAME)) {
+               goto end;
+       }
+       event_get_payload_string_field_value(event, PATH_FIELD_NAME, &path);
+
+       if (has_pic_field) {
+               uint64_t is_pic_field_value;
+
+               event_get_payload_unsigned_integer_field_value(event,
+                       IS_PIC_FIELD_NAME, &is_pic_field_value);
+               is_pic = is_pic_field_value == 1;
+       } else {
+               /*
+                * dlopen has no is_pic field, because the shared
+                * object is always PIC.
+                */
+               is_pic = true;
+       }
+
+       event_get_common_context_signed_integer_field_value(event,
+               VPID_FIELD_NAME, &vpid);
+
+       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
+               debug_info->vpid_to_proc_dbg_info_src, vpid);
+       if (!proc_dbg_info_src) {
+               goto end;
+       }
+
+       key = g_new0(uint64_t, 1);
+       if (!key) {
+               goto end;
+       }
+
+       *((uint64_t *) key) = baddr;
+
+       bin = g_hash_table_lookup(proc_dbg_info_src->baddr_to_bin_info, key);
+       if (bin) {
+               goto end;
+       }
+
+       bin = bin_info_create(debug_info->fd_cache, path, baddr, memsz, is_pic,
+               debug_info->comp->arg_debug_dir,
+               debug_info->comp->arg_target_prefix);
+       if (!bin) {
+               goto end;
+       }
+
+       g_hash_table_insert(proc_dbg_info_src->baddr_to_bin_info, key, bin);
+       /* Ownership passed to ht. */
+       key = NULL;
+
+end:
+       g_free(key);
+       return;
+}
+
+static inline
+void handle_event_statedump_bin_info(struct debug_info *debug_info,
+               const bt_event *event)
+{
+       handle_bin_info_event(debug_info, event, true);
+}
+
+static inline
+void handle_event_lib_load(struct debug_info *debug_info,
+               const bt_event *event)
+{
+       handle_bin_info_event(debug_info, event, false);
+}
+
+static
+void handle_event_lib_unload(struct debug_info *debug_info,
+               const bt_event *event)
+{
+       gboolean ret;
+       struct proc_debug_info_sources *proc_dbg_info_src;
+       uint64_t baddr;
+       int64_t vpid;
+
+       event_get_payload_unsigned_integer_field_value(event, BADDR_FIELD_NAME,
+                       &baddr);
+
+       event_get_common_context_signed_integer_field_value(event,
+                       VPID_FIELD_NAME, &vpid);
+
+       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
+                       debug_info->vpid_to_proc_dbg_info_src, vpid);
+       if (!proc_dbg_info_src) {
+               /*
+                * It's an unload event for a library for which no load event
+                * was previously received.
+                */
+               goto end;
+       }
+
+       ret = g_hash_table_remove(proc_dbg_info_src->baddr_to_bin_info,
+                       (gpointer) &baddr);
+       BT_ASSERT(ret);
+end:
+       return;
+}
+
+static
+void handle_event_statedump_start(struct debug_info *debug_info,
+               const bt_event *event)
+{
+       struct proc_debug_info_sources *proc_dbg_info_src;
+       int64_t vpid;
+
+       event_get_common_context_signed_integer_field_value(
+                       event, VPID_FIELD_NAME, &vpid);
+
+       proc_dbg_info_src = proc_debug_info_sources_ht_get_entry(
+                       debug_info->vpid_to_proc_dbg_info_src, vpid);
+       if (!proc_dbg_info_src) {
+               goto end;
+       }
+
+       g_hash_table_remove_all(proc_dbg_info_src->baddr_to_bin_info);
+       g_hash_table_remove_all(proc_dbg_info_src->ip_to_debug_info_src);
+
+end:
+       return;
+}
+
+void trace_debug_info_remove_func(const bt_trace *in_trace, void *data)
+{
+       struct debug_info_msg_iter *debug_it = data;
+       if (debug_it->debug_info_map) {
+               gboolean ret;
+               ret = g_hash_table_remove(debug_it->debug_info_map,
+                               (gpointer) in_trace);
+               BT_ASSERT(ret);
+       }
+}
+
+static
+void handle_event_statedump(struct debug_info_msg_iter *debug_it,
+               const bt_event *event)
+{
+       const bt_event_class *event_class;
+       const char *event_name;
+       GQuark q_event_name;
+       const bt_trace *trace;
+       struct debug_info *debug_info;
+
+       BT_ASSERT(debug_it);
+       BT_ASSERT(event);
+
+       event_class = bt_event_borrow_class_const(event);
+
+       event_name = bt_event_class_get_name(event_class);
+
+       trace = bt_stream_borrow_trace_const(
+                       bt_event_borrow_stream_const(event));
+
+       debug_info = g_hash_table_lookup(debug_it->debug_info_map, trace);
+       if (!debug_info) {
+               debug_info = debug_info_create(debug_it->debug_info_component,
+                               trace, &debug_it->fd_cache);
+               g_hash_table_insert(debug_it->debug_info_map, (gpointer) trace,
+                               debug_info);
+               bt_trace_add_destruction_listener(trace,
+                               trace_debug_info_remove_func, debug_it,
+                               &debug_info->destruction_listener_id);
+       }
+
+       q_event_name = g_quark_try_string(event_name);
+
+       if (q_event_name == debug_info->q_statedump_bin_info) {
+               /* State dump */
+               handle_event_statedump_bin_info(debug_info, event);
+       } else if (q_event_name == debug_info->q_dl_open ||
+                       q_event_name == debug_info->q_lib_load) {
+               /*
+                * dl_open and lib_load events are both checked for since
+                * only dl_open was produced as of lttng-ust 2.8.
+                *
+                * lib_load, which is produced from lttng-ust 2.9+, is a lot
+                * more reliable since it will be emitted when other functions
+                * of the dlopen family are called (e.g. dlmopen) and when
+                * library are transitively loaded.
+                */
+               handle_event_lib_load(debug_info, event);
+       } else if (q_event_name == debug_info->q_statedump_start) {
+               /* Start state dump */
+               handle_event_statedump_start(debug_info, event);
+       } else if (q_event_name == debug_info->q_statedump_debug_link) {
+               /* Debug link info */
+               handle_event_statedump_debug_link(debug_info, event);
+       } else if (q_event_name == debug_info->q_statedump_build_id) {
+               /* Build ID info */
+               handle_event_statedump_build_id(debug_info, event);
+       } else if (q_event_name == debug_info-> q_lib_unload) {
+               handle_event_lib_unload(debug_info, event);
+       }
+
+       return;
+}
+
+static
+void destroy_debug_info_comp(struct debug_info_component *debug_info)
+{
+       if (!debug_info) {
+               return;
+       }
+
+       g_free(debug_info->arg_debug_dir);
+       g_free(debug_info->arg_debug_info_field_name);
+       g_free(debug_info->arg_target_prefix);
+       g_free(debug_info);
+}
+
+static
+void fill_debug_info_bin_field(struct debug_info_source *dbg_info_src,
+               bool full_path, bt_field *curr_field)
+{
+       bt_field_status status;
+
+       BT_ASSERT(bt_field_get_class_type(curr_field) ==
+                       BT_FIELD_CLASS_TYPE_STRING);
+
+       if (dbg_info_src) {
+               if (full_path) {
+                       status = bt_field_string_set_value(curr_field,
+                                       dbg_info_src->bin_path);
+               } else {
+                       status = bt_field_string_set_value(curr_field,
+                                       dbg_info_src->short_bin_path);
+               }
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot set path component of \"bin\" "
+                               "curr_field field's value: str-fc-addr=%p",
+                               curr_field);
+               }
+
+               status = bt_field_string_append(curr_field, dbg_info_src->bin_loc);
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot set bin location component of \"bin\" "
+                               "curr_field field's value: str-fc-addr=%p",
+                               curr_field);
+               }
+       } else {
+               status = bt_field_string_set_value(curr_field, "");
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot set \"bin\" curr_field field's value: "
+                               "str-fc-addr=%p", curr_field);
+               }
+       }
+}
+
+static
+void fill_debug_info_func_field(struct debug_info_source *dbg_info_src,
+               bt_field *curr_field)
+{
+       bt_field_status status;
+
+       BT_ASSERT(bt_field_get_class_type(curr_field) ==
+                       BT_FIELD_CLASS_TYPE_STRING);
+       if (dbg_info_src && dbg_info_src->func) {
+               status = bt_field_string_set_value(curr_field,
+                               dbg_info_src->func);
+       } else {
+               status = bt_field_string_set_value(curr_field, "");
+       }
+       if (status != BT_FIELD_STATUS_OK) {
+               BT_LOGE("Cannot set \"func\" curr_field field's value: "
+                       "str-fc-addr=%p", curr_field);
+       }
+}
+
+static
+void fill_debug_info_src_field(struct debug_info_source *dbg_info_src,
+               bool full_path, bt_field *curr_field)
+{
+       bt_field_status status;
+
+       BT_ASSERT(bt_field_get_class_type(curr_field) ==
+                       BT_FIELD_CLASS_TYPE_STRING);
+
+       if (dbg_info_src && dbg_info_src->src_path) {
+               if (full_path) {
+                       status = bt_field_string_set_value(curr_field,
+                                       dbg_info_src->src_path);
+               } else {
+                       status = bt_field_string_set_value(curr_field,
+                                       dbg_info_src->short_src_path);
+               }
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot set path component of \"src\" "
+                               "curr_field field's value: str-fc-addr=%p",
+                               curr_field);
+               }
+
+               status = bt_field_string_append(curr_field, ":");
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot set colon component of \"src\" "
+                               "curr_field field's value: str-fc-addr=%p",
+                               curr_field);
+               }
+
+               status = bt_field_string_append(curr_field, dbg_info_src->line_no);
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot set line number component of \"src\" "
+                               "curr_field field's value: str-fc-addr=%p",
+                               curr_field);
+               }
+       } else {
+               status = bt_field_string_set_value(curr_field, "");
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot set \"src\" curr_field field's value: "
+                               "str-fc-addr=%p", curr_field);
+               }
+       }
+}
+
+void fill_debug_info_field_empty(bt_field *debug_info_field)
+{
+       bt_field_status status;
+       bt_field *bin_field, *func_field, *src_field;
+
+       BT_ASSERT(bt_field_get_class_type(debug_info_field) ==
+                       BT_FIELD_CLASS_TYPE_STRUCTURE);
+
+       bin_field = bt_field_structure_borrow_member_field_by_name(
+                       debug_info_field, "bin");
+       func_field = bt_field_structure_borrow_member_field_by_name(
+                       debug_info_field, "func");
+       src_field = bt_field_structure_borrow_member_field_by_name(
+                       debug_info_field, "src");
+
+       BT_ASSERT(bt_field_get_class_type(bin_field) ==
+                       BT_FIELD_CLASS_TYPE_STRING);
+       BT_ASSERT(bt_field_get_class_type(func_field) ==
+                       BT_FIELD_CLASS_TYPE_STRING);
+       BT_ASSERT(bt_field_get_class_type(src_field) ==
+                       BT_FIELD_CLASS_TYPE_STRING);
+
+       status = bt_field_string_set_value(bin_field, "");
+       if (status != BT_FIELD_STATUS_OK) {
+               BT_LOGE("Cannot set \"bin\" bin_field field's value: "
+                       "str-fc-addr=%p", bin_field);
+       }
+
+       status = bt_field_string_set_value(func_field, "");
+       if (status != BT_FIELD_STATUS_OK) {
+               BT_LOGE("Cannot set \"func\" func_field field's value: "
+                       "str-fc-addr=%p", func_field);
+       }
+
+       status = bt_field_string_set_value(src_field, "");
+       if (status != BT_FIELD_STATUS_OK) {
+               BT_LOGE("Cannot set \"src\" src_field field's value: "
+                       "str-fc-addr=%p", src_field);
+       }
+}
+static
+void fill_debug_info_field(struct debug_info *debug_info, int64_t vpid,
+               uint64_t ip, bt_field *debug_info_field)
+{
+       struct debug_info_source *dbg_info_src;
+       const bt_field_class *debug_info_fc;
+
+       BT_ASSERT(bt_field_get_class_type(debug_info_field) ==
+                       BT_FIELD_CLASS_TYPE_STRUCTURE);
+
+       debug_info_fc = bt_field_borrow_class_const(debug_info_field);
+
+       BT_ASSERT(bt_field_class_structure_get_member_count(debug_info_fc) == 3);
+
+       dbg_info_src = debug_info_query(debug_info, vpid, ip);
+
+       fill_debug_info_bin_field(dbg_info_src, debug_info->comp->arg_full_path,
+                       bt_field_structure_borrow_member_field_by_name(
+                               debug_info_field, "bin"));
+       fill_debug_info_func_field(dbg_info_src,
+                       bt_field_structure_borrow_member_field_by_name(
+                               debug_info_field, "func"));
+       fill_debug_info_src_field(dbg_info_src, debug_info->comp->arg_full_path,
+                       bt_field_structure_borrow_member_field_by_name(
+                               debug_info_field, "src"));
+}
+
+static
+void fill_debug_info_event_if_needed(struct debug_info_msg_iter *debug_it,
+               const bt_event *in_event, bt_event *out_event)
+{
+       bt_field *out_common_ctx_field, *out_debug_info_field;
+       const bt_field *vpid_field, *ip_field, *in_common_ctx_field;
+       const bt_field_class *in_common_ctx_fc;
+       struct debug_info *debug_info;
+       uint64_t vpid;
+       int64_t ip;
+       gchar *debug_info_field_name =
+               debug_it->debug_info_component->arg_debug_info_field_name;
+
+       in_common_ctx_field = bt_event_borrow_common_context_field_const(
+                       in_event);
+       if (!in_common_ctx_field) {
+               /*
+                * There is no event common context so no need to add debug
+                * info field.
+                */
+               goto end;
+       }
+
+       in_common_ctx_fc = bt_field_borrow_class_const(in_common_ctx_field);
+       if (!is_event_common_ctx_dbg_info_compatible(in_common_ctx_fc,
+                               debug_it->ir_maps->debug_info_field_class_name)) {
+               /*
+                * The input event common context does not have the necessary
+                * fields to resolve debug information.
+                */
+               goto end;
+       }
+
+       /* Borrow the debug-info field. */
+       out_common_ctx_field = bt_event_borrow_common_context_field(out_event);
+       if (!out_common_ctx_field) {
+               goto end;
+       }
+
+       out_debug_info_field = bt_field_structure_borrow_member_field_by_name(
+                               out_common_ctx_field, debug_info_field_name);
+
+       vpid_field = bt_field_structure_borrow_member_field_by_name_const(
+                       out_common_ctx_field, VPID_FIELD_NAME);
+       ip_field = bt_field_structure_borrow_member_field_by_name_const(
+                       out_common_ctx_field, IP_FIELD_NAME);
+
+       vpid = bt_field_signed_integer_get_value(vpid_field);
+       ip = bt_field_unsigned_integer_get_value(ip_field);
+
+       /*
+        * Borrow the debug_info structure needed for the source
+        * resolving.
+        */
+       debug_info = g_hash_table_lookup(debug_it->debug_info_map,
+                       bt_stream_borrow_trace_const(
+                               bt_event_borrow_stream_const(in_event)));
+
+       if (debug_info) {
+               /*
+                * Perform the debug-info resolving and set the event fields
+                * accordingly.
+                */
+               fill_debug_info_field(debug_info, vpid, ip, out_debug_info_field);
+       } else {
+               BT_LOGD("No debug information for this trace. Setting debug "
+                       "info fields to empty strings.");
+               fill_debug_info_field_empty(out_debug_info_field);
+       }
+end:
+       return;
+}
+
+static
+void update_event_statedump_if_needed(struct debug_info_msg_iter *debug_it,
+               const bt_event *in_event)
+{
+       const bt_field *event_common_ctx;
+       const bt_field_class *event_common_ctx_fc;
+       const bt_event_class *in_event_class = bt_event_borrow_class_const(in_event);
+
+       /*
+        * If the event is an lttng_ust_statedump event AND has the right event
+        * common context fields update the debug-info view for this process.
+        */
+       event_common_ctx = bt_event_borrow_common_context_field_const(in_event);
+       if (!event_common_ctx) {
+               goto end;
+       }
+
+       event_common_ctx_fc = bt_field_borrow_class_const(event_common_ctx);
+       if (is_event_common_ctx_dbg_info_compatible(event_common_ctx_fc,
+                               debug_it->ir_maps->debug_info_field_class_name)) {
+               /* Checkout if it might be a one of lttng ust statedump events. */
+               const char *in_event_name = bt_event_class_get_name(in_event_class);
+               if (strncmp(in_event_name, LTTNG_UST_STATEDUMP_PREFIX,
+                               strlen(LTTNG_UST_STATEDUMP_PREFIX)) == 0) {
+                       /* Handle statedump events. */
+                       handle_event_statedump(debug_it, in_event);
+               }
+       }
+end:
+       return;
+}
+
+static
+bt_message *handle_event_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       const bt_clock_snapshot *cs;
+       const bt_clock_class *default_cc;
+       const bt_packet *in_packet;
+       bt_event_class *out_event_class;
+       bt_packet *out_packet;
+       bt_event *out_event;
+
+       bt_message *out_message = NULL;
+
+       /* Borrow the input event and its event class. */
+       const bt_event *in_event =
+               bt_message_event_borrow_event_const(in_message);
+       const bt_event_class *in_event_class =
+               bt_event_borrow_class_const(in_event);
+
+       update_event_statedump_if_needed(debug_it, in_event);
+
+       out_event_class = trace_ir_mapping_borrow_mapped_event_class(
+                       debug_it->ir_maps, in_event_class);
+       if (!out_event_class) {
+               out_event_class = trace_ir_mapping_create_new_mapped_event_class(
+                                       debug_it->ir_maps, in_event_class);
+       }
+       BT_ASSERT(out_event_class);
+
+       /* Borrow the input and output packets. */
+       in_packet = bt_event_borrow_packet_const(in_event);
+       out_packet = trace_ir_mapping_borrow_mapped_packet(debug_it->ir_maps,
+                       in_packet);
+
+       default_cc = bt_stream_class_borrow_default_clock_class_const(
+                       bt_event_class_borrow_stream_class_const(in_event_class));
+       if (default_cc) {
+               /* Borrow event clock snapshot. */
+               cs = bt_message_event_borrow_default_clock_snapshot_const(
+                               in_message);
+
+               /* Create an output event message. */
+               out_message = bt_message_event_create_with_default_clock_snapshot(
+                                       debug_it->input_iterator,
+                                       out_event_class, out_packet,
+                                       bt_clock_snapshot_get_value(cs));
+       } else {
+               out_message = bt_message_event_create(debug_it->input_iterator,
+                               out_event_class, out_packet);
+       }
+
+       if (!out_message) {
+               BT_LOGE("Error creating output event message.");
+               goto error;
+       }
+
+       out_event = bt_message_event_borrow_event(out_message);
+
+       /* Copy the original fields to the output event. */
+       copy_event_content(in_event, out_event);
+
+       /*
+        * Try to set the debug-info fields based on debug information that is
+        * gathered so far.
+        */
+       fill_debug_info_event_if_needed(debug_it, in_event, out_event);
+
+error:
+       return out_message;
+}
+
+static
+bt_message *handle_stream_begin_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       const bt_stream *in_stream;
+       bt_message *out_message;
+       bt_stream *out_stream;
+
+       in_stream = bt_message_stream_beginning_borrow_stream_const(in_message);
+       BT_ASSERT(in_stream);
+
+       /* Create a duplicated output stream. */
+       out_stream = trace_ir_mapping_create_new_mapped_stream(
+                       debug_it->ir_maps, in_stream);
+       if (!out_stream) {
+               out_message = NULL;
+               goto error;
+       }
+
+       /* Create an output stream beginning message. */
+       out_message = bt_message_stream_beginning_create(
+                       debug_it->input_iterator, out_stream);
+       if (!out_message) {
+               BT_LOGE("Error creating output stream beginning message: "
+                       "out-s-addr=%p", out_stream);
+       }
+error:
+       return out_message;
+}
+
+static
+bt_message *handle_stream_end_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       const bt_stream *in_stream;
+       bt_message *out_message = NULL;
+       bt_stream *out_stream;
+
+       in_stream = bt_message_stream_end_borrow_stream_const(in_message);
+       BT_ASSERT(in_stream);
+
+       out_stream = trace_ir_mapping_borrow_mapped_stream(
+                       debug_it->ir_maps, in_stream);
+       BT_ASSERT(out_stream);
+
+       /* Create an output stream end message. */
+       out_message = bt_message_stream_end_create(debug_it->input_iterator,
+                       out_stream);
+       if (!out_message) {
+               BT_LOGE("Error creating output stream end message: out-s-addr=%p",
+                               out_stream);
+       }
+
+       /* Remove stream from trace mapping hashtable. */
+       trace_ir_mapping_remove_mapped_stream(debug_it->ir_maps, in_stream);
+
+       return out_message;
+}
+
+static
+bt_message *handle_packet_begin_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       bool has_default_clock_snapshot;
+       const bt_clock_snapshot *cs;
+       bt_message *out_message = NULL;
+       bt_packet *out_packet;
+
+       const bt_packet *in_packet =
+               bt_message_packet_beginning_borrow_packet_const(in_message);
+       BT_ASSERT(in_packet);
+
+       /* This packet should not be already mapped. */
+       BT_ASSERT(!trace_ir_mapping_borrow_mapped_packet(
+                               debug_it->ir_maps, in_packet));
+
+       out_packet = trace_ir_mapping_create_new_mapped_packet(debug_it->ir_maps,
+                       in_packet);
+
+       BT_ASSERT(out_packet);
+
+       has_default_clock_snapshot =
+               bt_stream_class_packets_have_beginning_default_clock_snapshot(
+                       bt_stream_borrow_class_const(
+                               bt_packet_borrow_stream_const(in_packet)));
+       if (has_default_clock_snapshot) {
+               /* Borrow clock snapshot. */
+               cs = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
+                                       in_message);
+
+               /* Create an output packet beginning message. */
+               out_message = bt_message_packet_beginning_create_with_default_clock_snapshot(
+                               debug_it->input_iterator, out_packet,
+                               bt_clock_snapshot_get_value(cs));
+       } else {
+               out_message = bt_message_packet_beginning_create(
+                               debug_it->input_iterator, out_packet);
+       }
+       if (!out_message) {
+               BT_LOGE("Error creating output packet beginning message: "
+                       "out-p-addr=%p", out_packet);
+       }
+
+       return out_message;
+}
+
+static
+bt_message *handle_packet_end_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       bool has_default_clock_snapshot;
+       const bt_clock_snapshot *cs;
+       const bt_packet *in_packet;
+       bt_message *out_message = NULL;
+       bt_packet *out_packet;
+
+       in_packet = bt_message_packet_end_borrow_packet_const(in_message);
+       BT_ASSERT(in_packet);
+
+       out_packet = trace_ir_mapping_borrow_mapped_packet(debug_it->ir_maps, in_packet);
+       BT_ASSERT(out_packet);
+
+       has_default_clock_snapshot =
+               bt_stream_class_packets_have_end_default_clock_snapshot(
+                       bt_stream_borrow_class_const(
+                               bt_packet_borrow_stream_const(in_packet)));
+       if (has_default_clock_snapshot) {
+               /* Borrow clock snapshot. */
+               cs = bt_message_packet_end_borrow_default_clock_snapshot_const(
+                                       in_message);
+
+               /* Create an outpute packet end message. */
+               out_message = bt_message_packet_end_create_with_default_clock_snapshot(
+                               debug_it->input_iterator, out_packet,
+                               bt_clock_snapshot_get_value(cs));
+       } else {
+               out_message = bt_message_packet_end_create(
+                               debug_it->input_iterator, out_packet);
+       }
+
+       if (!out_message) {
+               BT_LOGE("Error creating output packet end message: "
+                       "out-p-addr=%p", out_packet);
+       }
+
+       /* Remove packet from data mapping hashtable. */
+       trace_ir_mapping_remove_mapped_packet(debug_it->ir_maps, in_packet);
+
+       return out_message;
+}
+
+static
+bt_message *handle_msg_iterator_inactivity(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       /*
+        * This message type can be forwarded directly because it does
+        * not refer to any objects in the trace class.
+        */
+       bt_message_get_ref(in_message);
+       return (bt_message*) in_message;
+}
+
+static
+bt_message *handle_stream_act_begin_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       const bt_clock_snapshot *cs;
+       const bt_clock_class *default_cc;
+       bt_message *out_message = NULL;
+       bt_stream *out_stream;
+       uint64_t cs_value;
+       bt_message_stream_activity_clock_snapshot_state cs_state;
+
+       const bt_stream *in_stream =
+               bt_message_stream_activity_beginning_borrow_stream_const(
+                       in_message);
+       BT_ASSERT(in_stream);
+
+       out_stream = trace_ir_mapping_borrow_mapped_stream(debug_it->ir_maps,
+                       in_stream);
+       BT_ASSERT(out_stream);
+
+       out_message = bt_message_stream_activity_beginning_create(
+                       debug_it->input_iterator, out_stream);
+       if (!out_message) {
+               BT_LOGE("Error creating output stream activity beginning "
+                       "message: out-s-addr=%p", out_stream);
+               goto error;
+       }
+
+       default_cc = bt_stream_class_borrow_default_clock_class_const(
+                       bt_stream_borrow_class_const(in_stream));
+       if (default_cc) {
+               /* Borrow clock snapshot. */
+               cs_state =
+                       bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
+                                       in_message, &cs);
+
+               if (cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
+                       cs_value = bt_clock_snapshot_get_value(cs);
+                       bt_message_stream_activity_beginning_set_default_clock_snapshot(
+                                       out_message, cs_value);
+               } else {
+                       bt_message_stream_activity_beginning_set_default_clock_snapshot_state(
+                                       out_message, cs_state);
+               }
+       }
+
+error:
+       return out_message;
+}
+
+static
+bt_message *handle_stream_act_end_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       const bt_clock_snapshot *cs;
+       const bt_clock_class *default_cc;
+       const bt_stream *in_stream;
+       bt_message *out_message;
+       bt_stream *out_stream;
+       uint64_t cs_value;
+       bt_message_stream_activity_clock_snapshot_state cs_state;
+
+       in_stream = bt_message_stream_activity_end_borrow_stream_const(
+                       in_message);
+       BT_ASSERT(in_stream);
+
+       out_stream = trace_ir_mapping_borrow_mapped_stream(debug_it->ir_maps,
+               in_stream);
+       BT_ASSERT(out_stream);
+
+       out_message = bt_message_stream_activity_end_create(
+                       debug_it->input_iterator, out_stream);
+       if (!out_message) {
+               BT_LOGE("Error creating output stream activity end message: "
+                       "out-s-addr=%p", out_stream);
+               goto error;
+       }
+
+       default_cc = bt_stream_class_borrow_default_clock_class_const(
+                       bt_stream_borrow_class_const(in_stream));
+
+       if (default_cc) {
+               cs_state =
+                       bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
+                                       in_message, &cs);
+
+               if (cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN ) {
+                       cs_value = bt_clock_snapshot_get_value(cs);
+                       bt_message_stream_activity_end_set_default_clock_snapshot(
+                                       out_message, cs_value);
+               } else {
+                       bt_message_stream_activity_end_set_default_clock_snapshot_state(
+                                       out_message, cs_state);
+               }
+       }
+
+error:
+       return out_message;
+}
+
+static
+bt_message *handle_discarded_events_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       const bt_clock_snapshot *begin_cs, *end_cs;
+       const bt_stream *in_stream;
+       bool has_default_clock_snapshots;
+       uint64_t discarded_events, begin_cs_value, end_cs_value;
+       bt_property_availability prop_avail;
+       bt_message *out_message = NULL;
+       bt_stream *out_stream;
+
+       in_stream = bt_message_discarded_events_borrow_stream_const(
+                       in_message);
+       BT_ASSERT(in_stream);
+
+       out_stream = trace_ir_mapping_borrow_mapped_stream(
+                               debug_it->ir_maps, in_stream);
+       BT_ASSERT(out_stream);
+
+       has_default_clock_snapshots =
+               bt_stream_class_discarded_events_have_default_clock_snapshots(
+                       bt_stream_borrow_class_const(in_stream));
+       if (has_default_clock_snapshots) {
+               begin_cs =
+                       bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+                               in_message);
+               end_cs =
+                       bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
+                               in_message);
+
+               begin_cs_value = bt_clock_snapshot_get_value(begin_cs);
+               end_cs_value = bt_clock_snapshot_get_value(end_cs);
+
+               out_message =
+                       bt_message_discarded_events_create_with_default_clock_snapshots(
+                                       debug_it->input_iterator, out_stream,
+                                       begin_cs_value, end_cs_value);
+       } else {
+               out_message = bt_message_discarded_events_create(
+                               debug_it->input_iterator, out_stream);
+       }
+       if (!out_message) {
+               BT_LOGE("Error creating output discarded events message: "
+                       "out-s-addr=%p", out_stream);
+               goto error;
+       }
+
+       prop_avail = bt_message_discarded_events_get_count(in_message,
+                       &discarded_events);
+
+       if (prop_avail == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
+               bt_message_discarded_events_set_count(out_message,
+                               discarded_events);
+       }
+
+error:
+       return out_message;
+}
+
+static
+bt_message *handle_discarded_packets_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       const bt_clock_snapshot *begin_cs, *end_cs;
+       bool has_default_clock_snapshots;
+       const bt_stream *in_stream;
+       uint64_t discarded_packets, begin_cs_value, end_cs_value;
+       bt_property_availability prop_avail;
+       bt_message *out_message = NULL;
+       bt_stream *out_stream;
+
+       in_stream = bt_message_discarded_packets_borrow_stream_const(
+                       in_message);
+       BT_ASSERT(in_stream);
+
+       out_stream = trace_ir_mapping_borrow_mapped_stream(
+                       debug_it->ir_maps, in_stream);
+       BT_ASSERT(out_stream);
+
+       has_default_clock_snapshots =
+               bt_stream_class_discarded_packets_have_default_clock_snapshots(
+                       bt_stream_borrow_class_const(in_stream));
+       if (has_default_clock_snapshots) {
+               begin_cs =
+                       bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+                               in_message);
+
+               end_cs =
+                       bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
+                               in_message);
+
+               begin_cs_value = bt_clock_snapshot_get_value(begin_cs);
+               end_cs_value = bt_clock_snapshot_get_value(end_cs);
+
+               out_message = bt_message_discarded_packets_create_with_default_clock_snapshots(
+                                       debug_it->input_iterator, out_stream,
+                                       begin_cs_value, end_cs_value);
+       } else {
+               out_message = bt_message_discarded_packets_create(
+                               debug_it->input_iterator, out_stream);
+       }
+       if (!out_message) {
+               BT_LOGE("Error creating output discarded packet message: "
+                       "out-s-addr=%p", out_stream);
+               goto error;
+       }
+
+       prop_avail = bt_message_discarded_packets_get_count(in_message,
+                       &discarded_packets);
+       if (prop_avail == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
+               bt_message_discarded_packets_set_count(out_message,
+                               discarded_packets);
+       }
+
+error:
+       return out_message;
+}
+
+static
+const bt_message *handle_message(struct debug_info_msg_iter *debug_it,
+               const bt_message *in_message)
+{
+       bt_message *out_message = NULL;
+
+       switch (bt_message_get_type(in_message)) {
+       case BT_MESSAGE_TYPE_EVENT:
+               out_message = handle_event_message(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+               out_message = handle_packet_begin_message(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_PACKET_END:
+               out_message = handle_packet_end_message(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
+               out_message = handle_stream_begin_message(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_END:
+               out_message = handle_stream_end_message(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+               out_message = handle_msg_iterator_inactivity(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+               out_message = handle_stream_act_begin_message(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+               out_message = handle_stream_act_end_message(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+               out_message = handle_discarded_events_message(debug_it,
+                               in_message);
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+               out_message = handle_discarded_packets_message(debug_it,
+                               in_message);
+               break;
+       default:
+               abort();
+               break;
+       }
+
+       return out_message;
+}
+
+static
+int init_from_params(struct debug_info_component *debug_info_component,
+               const bt_value *params)
+{
+       const bt_value *value = NULL;
+       int ret = 0;
+
+       BT_ASSERT(params);
+
+       value = bt_value_map_borrow_entry_value_const(params,
+                       "debug-info-field-name");
+       if (value) {
+               debug_info_component->arg_debug_info_field_name =
+                       g_strdup(bt_value_string_get(value));
+       } else {
+               debug_info_component->arg_debug_info_field_name =
+                       g_strdup(DEFAULT_DEBUG_INFO_FIELD_NAME);
+       }
+
+       value = bt_value_map_borrow_entry_value_const(params, "debug-info-dir");
+       if (value) {
+               debug_info_component->arg_debug_dir =
+                       g_strdup(bt_value_string_get(value));
+       } else {
+               debug_info_component->arg_debug_dir = NULL;
+       }
+
+
+       value = bt_value_map_borrow_entry_value_const(params, "target-prefix");
+       if (value) {
+               debug_info_component->arg_target_prefix =
+                       g_strdup(bt_value_string_get(value));
+       } else {
+               debug_info_component->arg_target_prefix = NULL;
+       }
+
+       value = bt_value_map_borrow_entry_value_const(params, "full-path");
+       if (value) {
+               debug_info_component->arg_full_path = bt_value_bool_get(value);
+       } else {
+               debug_info_component->arg_full_path = BT_FALSE;
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+bt_self_component_status debug_info_comp_init(
+               bt_self_component_filter *self_comp,
+               const bt_value *params, UNUSED_VAR void *init_method_data)
+{
+       int ret;
+       struct debug_info_component *debug_info_comp;
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+
+       BT_LOGD("Initializing debug_info component: "
+               "comp-addr=%p, params-addr=%p", self_comp, params);
+
+       debug_info_comp = g_new0(struct debug_info_component, 1);
+       if (!debug_info_comp) {
+               BT_LOGE_STR("Failed to allocate one debug_info component.");
+               goto error;
+       }
+
+       bt_self_component_set_data(
+                       bt_self_component_filter_as_self_component(self_comp),
+                       debug_info_comp);
+
+       status = bt_self_component_filter_add_input_port(self_comp, "in",
+                       NULL, NULL);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto error;
+       }
+
+       status = bt_self_component_filter_add_output_port(self_comp, "out",
+                       NULL, NULL);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto error;
+       }
+
+       ret = init_from_params(debug_info_comp, params);
+       if (ret) {
+               BT_LOGE("Cannot configure debug_info component: "
+                       "debug_info-comp-addr=%p, params-addr=%p",
+                       debug_info_comp, params);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       destroy_debug_info_comp(debug_info_comp);
+       bt_self_component_set_data(
+               bt_self_component_filter_as_self_component(self_comp),
+               NULL);
+
+       if (status == BT_SELF_COMPONENT_STATUS_OK) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+       }
+end:
+       return status;
+}
+
+BT_HIDDEN
+void debug_info_comp_finalize(bt_self_component_filter *self_comp)
+{
+       struct debug_info_component *debug_info =
+               bt_self_component_get_data(
+                               bt_self_component_filter_as_self_component(
+                                       self_comp));
+       BT_LOGD("Finalizing debug_info self_component: comp-addr=%p",
+               self_comp);
+
+       destroy_debug_info_comp(debug_info);
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status debug_info_msg_iter_next(
+               bt_self_message_iterator *self_msg_iter,
+               const bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       bt_self_component_port_input_message_iterator *upstream_iterator = NULL;
+       bt_message_iterator_status upstream_iterator_ret_status;
+       struct debug_info_msg_iter *debug_info_msg_iter;
+       struct debug_info_component *debug_info = NULL;
+       bt_self_message_iterator_status status;
+       bt_self_component *self_comp = NULL;
+       bt_message_array_const input_msgs;
+       const bt_message *out_message;
+       uint64_t curr_msg_idx, i;
+
+       status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       self_comp = bt_self_message_iterator_borrow_component(self_msg_iter);
+       BT_ASSERT(self_comp);
+
+       debug_info = bt_self_component_get_data(self_comp);
+       BT_ASSERT(debug_info);
+
+       debug_info_msg_iter = bt_self_message_iterator_get_data(self_msg_iter);
+       BT_ASSERT(debug_info_msg_iter);
+
+       upstream_iterator = debug_info_msg_iter->msg_iter;
+       BT_ASSERT(upstream_iterator);
+
+       upstream_iterator_ret_status =
+               bt_self_component_port_input_message_iterator_next(
+                               upstream_iterator, &input_msgs, count);
+       if (upstream_iterator_ret_status != BT_MESSAGE_ITERATOR_STATUS_OK) {
+               /*
+                * No messages were returned. Not necessarily an error. Convert
+                * the upstream message iterator status to a self status.
+                */
+               status = bt_common_message_iterator_status_to_self(
+                               upstream_iterator_ret_status);
+               goto end;
+       }
+
+       /*
+        * There should never be more received messages than the capacity we
+        * provided.
+        */
+       BT_ASSERT(*count <= capacity);
+
+       for (curr_msg_idx = 0; curr_msg_idx < *count; curr_msg_idx++) {
+               out_message = handle_message(debug_info_msg_iter,
+                               input_msgs[curr_msg_idx]);
+               if (!out_message) {
+                       goto handle_msg_error;
+               }
+
+               msgs[curr_msg_idx] = out_message;
+               /*
+                * Drop our reference of the input message as we are done with
+                * it and created a output copy.
+                */
+               bt_message_put_ref(input_msgs[curr_msg_idx]);
+       }
+
+       goto end;
+
+handle_msg_error:
+       /*
+        * Drop references of all the output messages created before the
+        * failure.
+        */
+       for (i = 0; i < curr_msg_idx; i++) {
+               bt_message_put_ref(msgs[i]);
+       }
+
+       status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+end:
+       return status;
+}
+
+static
+void debug_info_msg_iter_destroy(struct debug_info_msg_iter *debug_info_msg_iter)
+{
+       if (!debug_info_msg_iter) {
+               goto end;
+       }
+
+       if (debug_info_msg_iter->msg_iter) {
+               bt_self_component_port_input_message_iterator_put_ref(
+                               debug_info_msg_iter->msg_iter);
+       }
+
+       if (debug_info_msg_iter->ir_maps) {
+               trace_ir_maps_destroy(debug_info_msg_iter->ir_maps);
+       }
+
+       if (debug_info_msg_iter->debug_info_map) {
+               g_hash_table_destroy(debug_info_msg_iter->debug_info_map);
+       }
+
+       bt_fd_cache_fini(&debug_info_msg_iter->fd_cache);
+       g_free(debug_info_msg_iter);
+
+end:
+       return;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status debug_info_msg_iter_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_filter *self_comp,
+               bt_self_component_port_output *self_port)
+{
+       bt_self_message_iterator_status status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       struct bt_self_component_port_input *input_port = NULL;
+       bt_self_component_port_input_message_iterator *upstream_iterator = NULL;
+       struct debug_info_msg_iter *debug_info_msg_iter = NULL;
+       gchar *debug_info_field_name;
+       int ret;
+
+       /* Borrow the upstream input port. */
+       input_port = bt_self_component_filter_borrow_input_port_by_name(
+               self_comp, "in");
+       if (!input_port) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto error;
+       }
+
+       debug_info_msg_iter = g_new0(struct debug_info_msg_iter, 1);
+       if (!debug_info_msg_iter) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto error;
+       }
+
+       /* Create an iterator on the upstream component. */
+       upstream_iterator = bt_self_component_port_input_message_iterator_create(
+               input_port);
+       if (!upstream_iterator) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto error;
+       }
+
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF(
+               debug_info_msg_iter->msg_iter, upstream_iterator);
+
+       /* Create hashtable that will contain debug info mapping. */
+       debug_info_msg_iter->debug_info_map = g_hash_table_new_full(
+               g_direct_hash, g_direct_equal, (GDestroyNotify) NULL,
+               (GDestroyNotify) debug_info_destroy);
+       if (!debug_info_msg_iter->debug_info_map) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto error;
+       }
+
+       debug_info_msg_iter->self_comp =
+               bt_self_component_filter_as_self_component(self_comp);
+
+       debug_info_msg_iter->debug_info_component = bt_self_component_get_data(
+               bt_self_component_filter_as_self_component(
+                       self_comp));
+
+       debug_info_field_name =
+               debug_info_msg_iter->debug_info_component->arg_debug_info_field_name;
+
+       debug_info_msg_iter->ir_maps = trace_ir_maps_create(
+               bt_self_component_filter_as_self_component(self_comp),
+               debug_info_field_name);
+       if (!debug_info_msg_iter->ir_maps) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto error;
+       }
+
+       ret = bt_fd_cache_init(&debug_info_msg_iter->fd_cache);
+       if (ret) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto error;
+       }
+
+       bt_self_message_iterator_set_data(self_msg_iter, debug_info_msg_iter);
+       debug_info_msg_iter->input_iterator = self_msg_iter;
+
+       goto end;
+
+error:
+       debug_info_msg_iter_destroy(debug_info_msg_iter);
+end:
+       return status;
+}
+
+BT_HIDDEN
+bt_bool debug_info_msg_iter_can_seek_beginning(
+               bt_self_message_iterator *self_msg_iter)
+{
+       struct debug_info_msg_iter *debug_info_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_iter);
+       BT_ASSERT(debug_info_msg_iter);
+
+       return bt_self_component_port_input_message_iterator_can_seek_beginning(
+                       debug_info_msg_iter->msg_iter);
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status debug_info_msg_iter_seek_beginning(
+               bt_self_message_iterator *self_msg_iter)
+{
+       struct debug_info_msg_iter *debug_info_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_iter);
+       bt_message_iterator_status status = BT_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_ASSERT(debug_info_msg_iter);
+
+       /* Ask the upstream component to seek to the beginning. */
+       status = bt_self_component_port_input_message_iterator_seek_beginning(
+               debug_info_msg_iter->msg_iter);
+       if (status != BT_MESSAGE_ITERATOR_STATUS_OK) {
+               goto end;
+       }
+
+       /* Clear this iterator data. */
+       trace_ir_maps_clear(debug_info_msg_iter->ir_maps);
+       g_hash_table_remove_all(debug_info_msg_iter->debug_info_map);
+end:
+       return bt_common_message_iterator_status_to_self(status);
+}
+
+BT_HIDDEN
+void debug_info_msg_iter_finalize(bt_self_message_iterator *it)
+{
+       struct debug_info_msg_iter *debug_info_msg_iter;
+
+       debug_info_msg_iter = bt_self_message_iterator_get_data(it);
+       BT_ASSERT(debug_info_msg_iter);
+
+       debug_info_msg_iter_destroy(debug_info_msg_iter);
+}
diff --git a/src/plugins/lttng-utils/debug-info/debug-info.h b/src/plugins/lttng-utils/debug-info/debug-info.h
new file mode 100644 (file)
index 0000000..ef99f71
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_H
+#define BABELTRACE_PLUGIN_DEBUG_INFO_H
+
+/*
+ * Babeltrace - Debug information Plugin
+ *
+ * Copyright (c) 2015-2019 EfficiOS Inc.
+ * Copyright (c) 2015 Antoine Busque <abusque@efficios.com>
+ * Copyright (c) 2019 Francis Deslauriers francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+
+#define VPID_FIELD_NAME                "vpid"
+#define IP_FIELD_NAME          "ip"
+
+BT_HIDDEN
+bt_self_component_status debug_info_comp_init(
+               bt_self_component_filter *self_comp,
+               const bt_value *params, void *init_method_data);
+
+BT_HIDDEN
+void debug_info_comp_finalize(bt_self_component_filter *self_comp);
+
+BT_HIDDEN
+bt_self_message_iterator_status debug_info_msg_iter_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_filter *self_comp,
+               bt_self_component_port_output *self_port);
+
+BT_HIDDEN
+bt_self_message_iterator_status debug_info_msg_iter_next(
+               bt_self_message_iterator *self_msg_iter,
+               const bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count);
+
+BT_HIDDEN
+bt_bool debug_info_msg_iter_can_seek_beginning(
+               bt_self_message_iterator *message_iterator);
+
+BT_HIDDEN
+bt_self_message_iterator_status debug_info_msg_iter_seek_beginning(
+               bt_self_message_iterator *message_iterator);
+
+BT_HIDDEN
+void debug_info_msg_iter_finalize(bt_self_message_iterator *it);
+
+#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_H */
diff --git a/src/plugins/lttng-utils/debug-info/dwarf.c b/src/plugins/lttng-utils/debug-info/dwarf.c
new file mode 100644 (file)
index 0000000..534d288
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * dwarf.c
+ *
+ * Babeltrace - DWARF Information Reader
+ *
+ * Copyright 2015 Antoine Busque <abusque@efficios.com>
+ *
+ * Author: Antoine Busque <abusque@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include "dwarf.h"
+
+BT_HIDDEN
+struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info)
+{
+       struct bt_dwarf_cu *cu;
+
+       if (!dwarf_info) {
+               goto error;
+       }
+
+       cu = g_new0(struct bt_dwarf_cu, 1);
+       if (!cu) {
+               goto error;
+       }
+       cu->dwarf_info = dwarf_info;
+       return cu;
+
+error:
+       return NULL;
+}
+
+BT_HIDDEN
+void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu)
+{
+       g_free(cu);
+}
+
+BT_HIDDEN
+int bt_dwarf_cu_next(struct bt_dwarf_cu *cu)
+{
+       int ret;
+       Dwarf_Off next_offset;
+       size_t cu_header_size;
+
+       if (!cu) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = dwarf_nextcu(cu->dwarf_info, cu->next_offset, &next_offset,
+                       &cu_header_size, NULL, NULL, NULL);
+       if (ret) {
+               /* ret is -1 on error, 1 if no next CU. */
+               goto end;
+       }
+
+       cu->offset = cu->next_offset;
+       cu->next_offset = next_offset;
+       cu->header_size = cu_header_size;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+struct bt_dwarf_die *bt_dwarf_die_create(struct bt_dwarf_cu *cu)
+{
+       Dwarf_Die *dwarf_die = NULL;
+       struct bt_dwarf_die *die = NULL;
+
+       if (!cu) {
+               goto error;
+       }
+
+       dwarf_die = g_new0(Dwarf_Die, 1);
+       if (!dwarf_die) {
+               goto error;
+       }
+
+       dwarf_die = dwarf_offdie(cu->dwarf_info, cu->offset + cu->header_size,
+                       dwarf_die);
+       if (!dwarf_die) {
+               goto error;
+       }
+
+       die = g_new0(struct bt_dwarf_die, 1);
+       if (!die) {
+               goto error;
+       }
+
+       die->cu = cu;
+       die->dwarf_die = dwarf_die;
+       die->depth = 0;
+
+       return die;
+
+error:
+       g_free(dwarf_die);
+       g_free(die);
+       return NULL;
+}
+
+BT_HIDDEN
+void bt_dwarf_die_destroy(struct bt_dwarf_die *die)
+{
+       if (!die) {
+               return;
+       }
+
+       g_free(die->dwarf_die);
+       g_free(die);
+}
+
+BT_HIDDEN
+int bt_dwarf_die_has_children(struct bt_dwarf_die *die)
+{
+       return dwarf_haschildren(die->dwarf_die);
+}
+
+BT_HIDDEN
+int bt_dwarf_die_child(struct bt_dwarf_die *die)
+{
+       int ret;
+       Dwarf_Die *child_die = NULL;
+
+       if (!die) {
+               ret = -1;
+               goto error;
+       }
+
+       child_die = g_new0(Dwarf_Die, 1);
+       if (!child_die) {
+               ret = -1;
+               goto error;
+       }
+
+       ret = dwarf_child(die->dwarf_die, child_die);
+       if (ret) {
+               /* ret is -1 on error, 1 if no child DIE. */
+               goto error;
+       }
+
+       g_free(die->dwarf_die);
+       die->dwarf_die = child_die;
+       die->depth++;
+       return 0;
+
+error:
+       g_free(child_die);
+       return ret;
+}
+
+BT_HIDDEN
+int bt_dwarf_die_next(struct bt_dwarf_die *die)
+{
+       int ret;
+       Dwarf_Die *next_die = NULL;
+
+       if (!die) {
+               ret = -1;
+               goto error;
+       }
+
+       next_die = g_new0(Dwarf_Die, 1);
+       if (!next_die) {
+               ret = -1;
+               goto error;
+       }
+
+       if (die->depth == 0) {
+               ret = dwarf_child(die->dwarf_die, next_die);
+               if (ret) {
+                       /* ret is -1 on error, 1 if no child DIE. */
+                       goto error;
+               }
+
+               die->depth = 1;
+       } else {
+               ret = dwarf_siblingof(die->dwarf_die, next_die);
+               if (ret) {
+                       /* ret is -1 on error, 1 if we reached end of
+                        * DIEs at this depth. */
+                       goto error;
+               }
+       }
+
+       g_free(die->dwarf_die);
+       die->dwarf_die = next_die;
+       return 0;
+
+error:
+       g_free(next_die);
+       return ret;
+}
+
+BT_HIDDEN
+int bt_dwarf_die_get_tag(struct bt_dwarf_die *die, int *tag)
+{
+       int _tag;
+
+       if (!die || !tag) {
+               goto error;
+       }
+
+       _tag = dwarf_tag(die->dwarf_die);
+       if (_tag == DW_TAG_invalid) {
+               goto error;
+       }
+
+       *tag = _tag;
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+int bt_dwarf_die_get_name(struct bt_dwarf_die *die, char **name)
+{
+       const char *_name;
+
+       if (!die || !name) {
+               goto error;
+       }
+
+       _name = dwarf_diename(die->dwarf_die);
+       if (!_name) {
+               goto error;
+       }
+
+       *name = g_strdup(_name);
+       if (!*name) {
+               goto error;
+       }
+
+       return 0;
+
+error:
+       return -1;
+}
+
+BT_HIDDEN
+int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename)
+{
+       int ret;
+       Dwarf_Sword file_no;
+       const char *_filename = NULL;
+       Dwarf_Files *src_files = NULL;
+       Dwarf_Attribute *file_attr = NULL;
+       struct bt_dwarf_die *cu_die = NULL;
+
+       if (!die || !filename) {
+               goto error;
+       }
+
+       file_attr = g_new0(Dwarf_Attribute, 1);
+       if (!file_attr) {
+               goto error;
+       }
+
+       file_attr = dwarf_attr(die->dwarf_die, DW_AT_call_file, file_attr);
+       if (!file_attr) {
+               goto error;
+       }
+
+       ret = dwarf_formsdata(file_attr, &file_no);
+       if (ret) {
+               goto error;
+       }
+
+       cu_die = bt_dwarf_die_create(die->cu);
+       if (!cu_die) {
+               goto error;
+       }
+
+       ret = dwarf_getsrcfiles(cu_die->dwarf_die, &src_files, NULL);
+       if (ret) {
+               goto error;
+       }
+
+       _filename = dwarf_filesrc(src_files, file_no, NULL, NULL);
+       if (!_filename) {
+               goto error;
+       }
+
+       *filename = g_strdup(_filename);
+
+       bt_dwarf_die_destroy(cu_die);
+       g_free(file_attr);
+
+       return 0;
+
+error:
+       bt_dwarf_die_destroy(cu_die);
+       g_free(file_attr);
+
+       return -1;
+}
+
+BT_HIDDEN
+int bt_dwarf_die_get_call_line(struct bt_dwarf_die *die,
+               uint64_t *line_no)
+{
+       int ret = 0;
+       Dwarf_Attribute *line_attr = NULL;
+       uint64_t _line_no;
+
+       if (!die || !line_no) {
+               goto error;
+       }
+
+       line_attr = g_new0(Dwarf_Attribute, 1);
+       if (!line_attr) {
+               goto error;
+       }
+
+       line_attr = dwarf_attr(die->dwarf_die, DW_AT_call_line, line_attr);
+       if (!line_attr) {
+               goto error;
+       }
+
+       ret = dwarf_formudata(line_attr, &_line_no);
+       if (ret) {
+               goto error;
+       }
+
+       *line_no = _line_no;
+       g_free(line_attr);
+
+       return 0;
+
+error:
+       g_free(line_attr);
+
+       return -1;
+}
+
+BT_HIDDEN
+int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr,
+               bool *contains)
+{
+       int ret;
+
+       ret = dwarf_haspc(die->dwarf_die, addr);
+       if (ret == -1) {
+               goto error;
+       }
+
+       *contains = (ret == 1);
+
+       return 0;
+
+error:
+       return -1;
+}
diff --git a/src/plugins/lttng-utils/debug-info/dwarf.h b/src/plugins/lttng-utils/debug-info/dwarf.h
new file mode 100644 (file)
index 0000000..4ab527b
--- /dev/null
@@ -0,0 +1,235 @@
+#ifndef _BABELTRACE_DWARF_H
+#define _BABELTRACE_DWARF_H
+
+/*
+ * Babeltrace - DWARF Information Reader
+ *
+ * Copyright 2015 Antoine Busque <abusque@efficios.com>
+ *
+ * Author: Antoine Busque <abusque@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <dwarf.h>
+#include <elfutils/libdw.h>
+#include "common/babeltrace.h"
+
+/*
+ * bt_dwarf is a wrapper over libdw providing a nicer, higher-level
+ * interface, to access basic debug information.
+ */
+
+/*
+ * This structure corresponds to a single compilation unit (CU) for a
+ * given set of debug information (Dwarf type).
+ */
+struct bt_dwarf_cu {
+       Dwarf *dwarf_info;
+       /* Offset in bytes in the DWARF file to current CU header. */
+       Dwarf_Off offset;
+       /* Offset in bytes in the DWARF file to next CU header. */
+       Dwarf_Off next_offset;
+       /* Size in bytes of CU header */
+       size_t header_size;
+};
+
+/*
+ * This structure represents a single debug information entry (DIE),
+ * within a compilation unit (CU).
+ */
+struct bt_dwarf_die {
+       struct bt_dwarf_cu *cu;
+       Dwarf_Die *dwarf_die;
+       /*
+        * A depth of 0 represents a root DIE, located in the DWARF
+        * layout on the same level as its corresponding CU entry. Its
+        * children DIEs will have a depth of 1, and so forth.
+        */
+       unsigned int depth;
+};
+
+/**
+ * Instantiate a structure to access compile units (CU) from a given
+ * `dwarf_info`.
+ *
+ * @param dwarf_info   Dwarf instance
+ * @returns            Pointer to the new bt_dwarf_cu on success,
+ *                     NULL on failure.
+ */
+BT_HIDDEN
+struct bt_dwarf_cu *bt_dwarf_cu_create(Dwarf *dwarf_info);
+
+/**
+ * Destroy the given bt_dwarf_cu instance.
+ *
+ * @param cu   bt_dwarf_cu instance
+ */
+BT_HIDDEN
+void bt_dwarf_cu_destroy(struct bt_dwarf_cu *cu);
+
+/**
+ * Advance the compile unit `cu` to the next one.
+ *
+ * On success, `cu`'s offset is set to that of the current compile
+ * unit in the executable. On failure, `cu` remains unchanged.
+ *
+ * @param cu   bt_dwarf_cu instance
+ * @returns    0 on success, 1 if no next CU is available,
+ *             -1 on failure
+ */
+BT_HIDDEN
+int bt_dwarf_cu_next(struct bt_dwarf_cu *cu);
+
+/**
+ * Instantiate a structure to access debug information entries (DIE)
+ * for the given compile unit `cu`.
+ *
+ * @param cu   bt_dwarf_cu instance
+ * @returns    Pointer to the new bt_dwarf_die on success,
+ *             NULL on failure.
+ */
+BT_HIDDEN
+struct bt_dwarf_die *bt_dwarf_die_create(struct bt_dwarf_cu *cu);
+
+/**
+ * Destroy the given bt_dwarf_die instance.
+ *
+ * @param die  bt_dwarf_die instance
+ */
+BT_HIDDEN
+void bt_dwarf_die_destroy(struct bt_dwarf_die *die);
+
+/**
+ * Indicates if the debug information entry `die` has children DIEs.
+ *
+ * @param die  bt_dwarf_die instance
+ * @returns    0 if the die no child, 1 otherwise
+ */
+BT_HIDDEN
+int bt_dwarf_die_has_children(struct bt_dwarf_die *die);
+
+/**
+ * Advance the debug information entry `die` to its first child, if
+ * any.
+ *
+ * @param die  bt_dwarf_die instance
+ * @returns    0 on success, 1 if no child DIE is available,
+ *             -1 on failure
+ */
+BT_HIDDEN
+int bt_dwarf_die_child(struct bt_dwarf_die *die);
+
+/**
+ * Advance the debug information entry `die` to the next one.
+ *
+ * The next DIE is considered to be its sibling on the same level. The
+ * only exception is when the depth of the given DIE is 0, i.e. a
+ * newly created bt_dwarf_die, in which case next returns the first
+ * DIE at depth 1.
+ *
+ * The reason for staying at a depth of 1 is that this is where all
+ * the function DIEs (those with a tag value of DW_TAG_subprogram) are
+ * located, from which more specific child DIEs can then be accessed
+ * if needed via bt_dwarf_die_child.
+ *
+ * @param die  bt_dwarf_die instance
+ * @returns    0 on success, 1 if no other siblings are available, -1 on
+ *             failure
+ */
+BT_HIDDEN
+int bt_dwarf_die_next(struct bt_dwarf_die *die);
+
+/**
+ * Get a DIE's tag.
+ *
+ * On success, the `tag` out parameter is set to the `die`'s tag's
+ * value. It remains unchanged on failure.
+ *
+ * @param die  bt_dwarf_die instance
+ * @param tag  Out parameter, the DIE's tag value
+ * @returns    0 on success, -1 on failure.
+ */
+BT_HIDDEN
+int bt_dwarf_die_get_tag(struct bt_dwarf_die *die, int *tag);
+
+/**
+ * Get a DIE's name.
+ *
+ * On success, the `name` out parameter is set to the DIE's name. It
+ * remains unchanged on failure.
+ *
+ * @param die  bt_dwarf_die instance
+ * @param name Out parameter, the DIE's name
+ * @returns    0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bt_dwarf_die_get_name(struct bt_dwarf_die *die, char **name);
+
+/**
+ * Get the full path to the DIE's callsite file.
+ *
+ * Only applies to DW_TAG_inlined_subroutine entries. The out
+ * parameter `filename` is set on success, unchanged on failure.
+ *
+ * @param die          bt_dwarf_die instance
+ * @param filename     Out parameter, the filename for the subroutine's
+ *                     callsite
+ * @returns            0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bt_dwarf_die_get_call_file(struct bt_dwarf_die *die, char **filename);
+
+/**
+ * Get line number for the DIE's callsite.
+ *
+ * Only applies to DW_TAG_inlined_subroutine entries. The out
+ * parameter `line_no` is set on success, unchanged on failure.
+ *
+ * @param die          bt_dwarf_die instance
+ * @param line_no      Out parameter, the line number for the
+ *                     subroutine's callsite
+ * @returns            0 on success, -1 on failure
+ */
+BT_HIDDEN
+int bt_dwarf_die_get_call_line(struct bt_dwarf_die *die,
+               uint64_t *line_no);
+
+/**
+ * Verifies whether a given DIE contains the virtual memory address
+ * `addr`.
+ *
+ * On success, the out parameter `contains` is set with the boolean
+ * value indicating whether the DIE's range covers `addr`. On failure,
+ * it remains unchanged.
+ *
+ * @param die          bt_dwarf_die instance
+ * @param addr         The memory address to verify
+ * @param contains     Out parameter, true if addr is contained,
+ *                     false if not
+ * @returns            0 on succes, -1 on failure
+ */
+BT_HIDDEN
+int bt_dwarf_die_contains_addr(struct bt_dwarf_die *die, uint64_t addr,
+               bool *contains);
+
+#endif /* _BABELTRACE_DWARF_H */
diff --git a/src/plugins/lttng-utils/debug-info/logging.c b/src/plugins/lttng-utils/debug-info/logging.c
new file mode 100644 (file)
index 0000000..a872d57
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_lttng_utils_debug_info_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_plugin_lttng_utils_debug_info_log_level,
+       "BABELTRACE_FLT_LTTNG_UTILS_DEBUG_INFO_LOG_LEVEL");
diff --git a/src/plugins/lttng-utils/debug-info/logging.h b/src/plugins/lttng-utils/debug-info/logging.h
new file mode 100644 (file)
index 0000000..fa298d5
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H
+#define PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_lttng_utils_debug_info_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_lttng_utils_debug_info_log_level);
+
+#endif /* PLUGINS_LTTNG_UTILS_DEBUG_INFO_LOGGING_H */
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.c
new file mode 100644 (file)
index 0000000..c677770
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Babeltrace - Trace IR data object copy
+ *
+ * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-DATA-COPY"
+#include "logging.h"
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#include "common/assert.h"
+
+#include "trace-ir-data-copy.h"
+
+BT_HIDDEN
+void copy_trace_content(const bt_trace *in_trace, bt_trace *out_trace)
+{
+       bt_trace_status status;
+       const char *trace_name;
+
+       BT_LOGD("Copying content of trace: in-t-addr=%p, out-t-addr=%p",
+                       in_trace, out_trace);
+
+       trace_name = bt_trace_get_name(in_trace);
+       /* Copy the trace name. */
+       if (trace_name) {
+               status = bt_trace_set_name(out_trace, trace_name);
+               if (status != BT_TRACE_STATUS_OK) {
+                       BT_LOGE("Cannot set trace's name: trace-addr=%p, name=\"%s\"",
+                                       out_trace, trace_name);
+                       goto end;
+               }
+       }
+
+       BT_LOGD("Copied content of trace: in-t-addr=%p, out-t-addr=%p",
+                       in_trace, out_trace);
+end:
+       return;
+}
+
+BT_HIDDEN
+void copy_stream_content(const bt_stream *in_stream, bt_stream *out_stream)
+{
+       const char *stream_name;
+       bt_stream_status status;
+
+       BT_LOGD("Copying content of stream: in-s-addr=%p, out-s-addr=%p",
+                       in_stream, out_stream);
+
+       stream_name = bt_stream_get_name(in_stream);
+       if (stream_name) {
+               status = bt_stream_set_name(out_stream, stream_name);
+               if (status != BT_STREAM_STATUS_OK) {
+                       BT_LOGE("Cannot set stream's name: stream-addr=%p, "
+                               "name=%s", out_stream, stream_name);
+                       goto end;
+               }
+       }
+
+       BT_LOGD("Copied content of stream: in-s-addr=%p, out-s-addr=%p",
+                       in_stream, out_stream);
+end:
+       return;
+}
+
+BT_HIDDEN
+void copy_packet_content(const bt_packet *in_packet, bt_packet *out_packet)
+{
+       const bt_field *in_context_field;
+       bt_field *out_context_field;
+
+       BT_LOGD("Copying content of packet: in-p-addr=%p, out-p-addr=%p",
+                       in_packet, out_packet);
+
+       /* Copy context field. */
+       in_context_field = bt_packet_borrow_context_field_const(in_packet);
+       if (in_context_field) {
+               out_context_field = bt_packet_borrow_context_field(out_packet);
+               BT_ASSERT(out_context_field);
+               copy_field_content(in_context_field, out_context_field);
+       }
+
+       BT_LOGD("Copied content of packet: in-p-addr=%p, out-p-addr=%p",
+                       in_packet, out_packet);
+       return;
+}
+
+BT_HIDDEN
+void copy_event_content(const bt_event *in_event, bt_event *out_event)
+{
+       const bt_field *in_common_ctx_field, *in_specific_ctx_field,
+             *in_payload_field;
+       bt_field *out_common_ctx_field, *out_specific_ctx_field,
+                *out_payload_field;
+
+       BT_LOGD("Copying content of event: in-e-addr=%p, out-e-addr=%p",
+                       in_event, out_event);
+       in_common_ctx_field =
+               bt_event_borrow_common_context_field_const(in_event);
+       if (in_common_ctx_field) {
+               out_common_ctx_field =
+                       bt_event_borrow_common_context_field(out_event);
+               BT_ASSERT(out_common_ctx_field);
+               copy_field_content(in_common_ctx_field,
+                               out_common_ctx_field);
+       }
+
+       in_specific_ctx_field =
+               bt_event_borrow_specific_context_field_const(in_event);
+       if (in_specific_ctx_field) {
+               out_specific_ctx_field =
+                       bt_event_borrow_specific_context_field(out_event);
+               BT_ASSERT(out_specific_ctx_field);
+               copy_field_content(in_specific_ctx_field,
+                               out_specific_ctx_field);
+       }
+
+       in_payload_field = bt_event_borrow_payload_field_const(in_event);
+       if (in_payload_field) {
+               out_payload_field = bt_event_borrow_payload_field(out_event);
+               BT_ASSERT(out_payload_field);
+               copy_field_content(in_payload_field,
+                               out_payload_field);
+       }
+
+       BT_LOGD("Copied content of event: in-e-addr=%p, out-e-addr=%p",
+                       in_event, out_event);
+}
+
+BT_HIDDEN
+void copy_field_content(const bt_field *in_field, bt_field *out_field)
+{
+       bt_field_class_type in_fc_type, out_fc_type;
+
+       in_fc_type = bt_field_get_class_type(in_field);
+       out_fc_type = bt_field_get_class_type(out_field);
+       BT_ASSERT(in_fc_type == out_fc_type);
+
+       BT_LOGD("Copying content of field: in-f-addr=%p, out-f-addr=%p",
+                       in_field, out_field);
+       switch (in_fc_type) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+               bt_field_unsigned_integer_set_value(out_field,
+                               bt_field_unsigned_integer_get_value(in_field));
+               break;
+       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+               bt_field_signed_integer_set_value(out_field,
+                               bt_field_signed_integer_get_value(in_field));
+               break;
+       case BT_FIELD_CLASS_TYPE_REAL:
+               bt_field_real_set_value(out_field,
+                               bt_field_real_get_value(in_field));
+               break;
+       case BT_FIELD_CLASS_TYPE_STRING:
+       {
+               const char *str = bt_field_string_get_value(in_field);
+               bt_field_status status = bt_field_string_set_value(out_field, str);
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot set string field's value: "
+                               "str-field-addr=%p, str=%s" PRId64,
+                               out_field, str);
+               }
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+       {
+               uint64_t i, nb_member_struct;
+               const bt_field *in_member_field;
+               bt_field *out_member_field;
+               const bt_field_class *in_field_class;
+               const char *in_member_name;
+
+               in_field_class = bt_field_borrow_class_const(in_field);
+               nb_member_struct = bt_field_class_structure_get_member_count(
+                               in_field_class);
+
+               /*
+                * Iterate over the fields by names in the input field to avoid
+                * problem if the struct fields are not in the same order after
+                * the debug-info was added.
+                */
+               for (i = 0; i < nb_member_struct; i++) {
+                       const bt_field_class_structure_member *member =
+                               bt_field_class_structure_borrow_member_by_index_const(
+                                       in_field_class, i);
+
+                       in_member_name =
+                               bt_field_class_structure_member_get_name(
+                                       member);
+                       in_member_field =
+                               bt_field_structure_borrow_member_field_by_name_const(
+                                               in_field, in_member_name);
+                       out_member_field =
+                               bt_field_structure_borrow_member_field_by_name(
+                                               out_field, in_member_name);
+
+                       copy_field_content(in_member_field,
+                                       out_member_field);
+               }
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+               /* fall through */
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       {
+               const bt_field *in_element_field;
+               bt_field *out_element_field;
+               uint64_t i, array_len;
+               bt_field_status status;
+
+               array_len = bt_field_array_get_length(in_field);
+
+               if (in_fc_type == BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY) {
+                       status = bt_field_dynamic_array_set_length(out_field,
+                                       array_len);
+                       if (status != BT_FIELD_STATUS_OK) {
+                               BT_LOGE("Cannot set dynamic array field's "
+                                       "length field: field-addr=%p, "
+                                       "length=%" PRIu64, out_field, array_len);
+                       }
+               }
+
+               for (i = 0; i < array_len; i++) {
+                       in_element_field =
+                               bt_field_array_borrow_element_field_by_index_const(
+                                               in_field, i);
+                       out_element_field =
+                               bt_field_array_borrow_element_field_by_index(
+                                               out_field, i);
+                       copy_field_content(in_element_field, out_element_field);
+               }
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+       {
+               bt_field_status status;
+               uint64_t in_selected_option_idx;
+               const bt_field *in_option_field;
+               bt_field *out_option_field;
+
+               in_selected_option_idx =
+                       bt_field_variant_get_selected_option_field_index(
+                                       in_field);
+               status = bt_field_variant_select_option_field(out_field,
+                               in_selected_option_idx);
+               if (status != BT_FIELD_STATUS_OK) {
+                       BT_LOGE("Cannot select variant field's option field: "
+                               "var-field-addr=%p, opt-index=%" PRId64,
+                               out_field, in_selected_option_idx);
+               }
+
+               in_option_field = bt_field_variant_borrow_selected_option_field_const(in_field);
+               out_option_field = bt_field_variant_borrow_selected_option_field(out_field);
+
+               copy_field_content(in_option_field, out_option_field);
+
+               break;
+       }
+       default:
+               abort();
+       }
+       BT_LOGD("Copied content of field: in-f-addr=%p, out-f-addr=%p",
+                       in_field, out_field);
+}
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.h b/src/plugins/lttng-utils/debug-info/trace-ir-data-copy.h
new file mode 100644 (file)
index 0000000..b925976
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H
+#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H
+
+/*
+ * Babeltrace - Trace IR data object copy
+ *
+ * Copyright (c) 2019 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+
+#include "trace-ir-mapping.h"
+
+BT_HIDDEN
+void copy_trace_content(const bt_trace *in_trace, bt_trace *out_trace);
+BT_HIDDEN
+void copy_stream_content(const bt_stream *in_stream, bt_stream *out_stream);
+BT_HIDDEN
+void copy_packet_content(const bt_packet *in_packet, bt_packet *out_packet);
+BT_HIDDEN
+void copy_event_content(const bt_event *in_event, bt_event *out_event);
+BT_HIDDEN
+void copy_field_content(const bt_field *in_field, bt_field *out_field);
+
+#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_DATA_COPY_H */
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-mapping.c b/src/plugins/lttng-utils/debug-info/trace-ir-mapping.c
new file mode 100644 (file)
index 0000000..67b24f8
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * Babeltrace - Mapping of IR metadata and data object between input and output
+ *             trace
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-MAPPING"
+#include "logging.h"
+
+#include <stdbool.h>
+
+#include "common/assert.h"
+#include <babeltrace2/babeltrace.h>
+/* For bt_property_availability */
+#include <babeltrace2/property.h>
+
+#include "debug-info.h"
+#include "trace-ir-data-copy.h"
+#include "trace-ir-mapping.h"
+#include "trace-ir-metadata-copy.h"
+
+static
+bt_trace_class *create_new_mapped_trace_class(struct trace_ir_maps *ir_maps,
+               const bt_trace_class *in_trace_class)
+{
+       int ret;
+       bt_trace_class *out_trace_class;
+
+       BT_LOGD("Creating new mapped trace class: in-tc-addr=%p", in_trace_class);
+
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_trace_class);
+
+       /* Create the ouput trace class. */
+       out_trace_class = bt_trace_class_create(ir_maps->self_comp);
+       if (!out_trace_class) {
+               BT_LOGE_STR("Error create output trace class");
+               goto end;
+       }
+
+       /* If not, create a new one and add it to the mapping. */
+       ret = copy_trace_class_content(in_trace_class, out_trace_class);
+       if (ret) {
+               BT_LOGE_STR("Error copy content to output trace class");
+               out_trace_class = NULL;
+               goto end;
+       }
+
+       BT_LOGD("Created new mapped trace class: in-tc-addr=%p, out-tc-addr=%p",
+                       in_trace_class, out_trace_class);
+
+end:
+       return out_trace_class;
+}
+
+static
+bt_trace *create_new_mapped_trace(struct trace_ir_maps *ir_maps,
+               const bt_trace *in_trace)
+{
+       bt_trace *out_trace;
+       const bt_trace_class *in_trace_class;
+       struct trace_ir_metadata_maps *metadata_maps;
+
+       BT_LOGD("Creating new mapped trace: in-t-addr=%p", in_trace);
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_trace);
+
+       in_trace_class = bt_trace_borrow_class_const(in_trace);
+       metadata_maps = borrow_metadata_maps_from_input_trace_class(ir_maps,
+                       in_trace_class);
+
+       if (!metadata_maps->output_trace_class) {
+               metadata_maps->output_trace_class =
+                       create_new_mapped_trace_class(ir_maps, in_trace_class);
+               if (!metadata_maps->output_trace_class) {
+                       out_trace = NULL;
+                       goto end;
+               }
+       }
+
+       out_trace = bt_trace_create(metadata_maps->output_trace_class);
+       if (!out_trace) {
+               BT_LOGE_STR("Error create output trace");
+               goto end;
+       }
+
+       /* If not, create a new one and add it to the mapping. */
+       copy_trace_content(in_trace, out_trace);
+
+       BT_LOGD("Created new mapped trace: in-t-addr=%p, out-t-addr=%p",
+                       in_trace, out_trace);
+end:
+       return out_trace;
+}
+
+static
+bt_stream_class *borrow_mapped_stream_class(struct trace_ir_metadata_maps *md_maps,
+               const bt_stream_class *in_stream_class)
+{
+       BT_ASSERT(md_maps);
+       BT_ASSERT(in_stream_class);
+
+       return g_hash_table_lookup(md_maps->stream_class_map,
+                       (gpointer) in_stream_class);
+}
+
+static
+bt_stream_class *create_new_mapped_stream_class(struct trace_ir_maps *ir_maps,
+               const bt_stream_class *in_stream_class)
+{
+       int ret;
+       bt_stream_class *out_stream_class;
+       struct trace_ir_metadata_maps *md_maps;
+
+       BT_LOGD("Creating new mapped stream class: in-sc-addr=%p",
+                       in_stream_class);
+
+       md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps,
+                       in_stream_class);
+
+       BT_ASSERT(md_maps);
+       BT_ASSERT(in_stream_class);
+       BT_ASSERT(!borrow_mapped_stream_class(md_maps, in_stream_class));
+
+       /* Create an out_stream_class. */
+       out_stream_class = bt_stream_class_create_with_id(
+                       md_maps->output_trace_class,
+                       bt_stream_class_get_id(in_stream_class));
+       if (!out_stream_class) {
+               BT_LOGE_STR("Error create output stream class");
+               goto end;
+       }
+
+       /* If not, create a new one and add it to the mapping. */
+       ret = copy_stream_class_content(ir_maps, in_stream_class,
+                       out_stream_class);
+       if (ret) {
+               BT_LOGE_STR("Error copy content to output stream class");
+               out_stream_class = NULL;
+               goto end;
+       }
+
+       g_hash_table_insert(md_maps->stream_class_map,
+                       (gpointer) in_stream_class, out_stream_class);
+
+       BT_LOGD("Created new mapped stream class: in-sc-addr=%p, out-sc-addr=%p",
+                       in_stream_class, out_stream_class);
+
+end:
+       return out_stream_class;
+}
+
+static
+bt_stream *borrow_mapped_stream(struct trace_ir_data_maps *d_maps,
+               const bt_stream *in_stream)
+{
+       BT_ASSERT(d_maps);
+       BT_ASSERT(in_stream);
+
+       return g_hash_table_lookup(d_maps->stream_map, (gpointer) in_stream);
+}
+
+BT_HIDDEN
+bt_stream *trace_ir_mapping_create_new_mapped_stream(
+               struct trace_ir_maps *ir_maps,
+               const bt_stream *in_stream)
+{
+       struct trace_ir_data_maps *d_maps;
+       struct trace_ir_metadata_maps *md_maps;
+       const bt_stream_class *in_stream_class;
+       const bt_trace *in_trace;
+       bt_stream_class *out_stream_class;
+       bt_stream *out_stream = NULL;
+
+       BT_LOGD("Creating new mapped stream: in-s-addr=%p", in_stream);
+
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_stream);
+
+       in_trace = bt_stream_borrow_trace_const(in_stream);
+
+       d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace);
+       if (!d_maps->output_trace) {
+               d_maps->output_trace = create_new_mapped_trace(ir_maps, in_trace);
+               if (!d_maps->output_trace) {
+                       goto end;
+               }
+       }
+
+       BT_ASSERT(d_maps->output_trace);
+       BT_ASSERT(!borrow_mapped_stream(d_maps, in_stream));
+
+       in_stream_class = bt_stream_borrow_class_const(in_stream);
+       md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class);
+       out_stream_class = borrow_mapped_stream_class(md_maps, in_stream_class);
+       if (!out_stream_class) {
+               out_stream_class = create_new_mapped_stream_class(ir_maps,
+                               in_stream_class);
+               if (!out_stream_class) {
+                       goto end;
+               }
+       }
+       BT_ASSERT(out_stream_class);
+
+       out_stream = bt_stream_create_with_id(out_stream_class,
+                       d_maps->output_trace, bt_stream_get_id(in_stream));
+       if (!out_stream) {
+               BT_LOGE_STR("Error creating output stream");
+               goto end;
+       }
+       /*
+        * Release our ref since the trace object will be managing the life
+        * time of the stream objects.
+        */
+
+       copy_stream_content(in_stream, out_stream);
+
+       g_hash_table_insert(d_maps->stream_map, (gpointer) in_stream,
+                       out_stream);
+
+       BT_LOGD("Created new mapped stream: in-s-addr=%p, out-s-addr=%p",
+                       in_stream, out_stream);
+
+end:
+       return out_stream;
+}
+
+BT_HIDDEN
+bt_stream *trace_ir_mapping_borrow_mapped_stream(struct trace_ir_maps *ir_maps,
+               const bt_stream *in_stream)
+{
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_stream);
+       struct trace_ir_data_maps *d_maps;
+
+       d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream);
+       /* Return the mapped stream. */
+       return borrow_mapped_stream(d_maps, in_stream);
+}
+
+static inline
+bt_event_class *borrow_mapped_event_class(struct trace_ir_metadata_maps *md_maps,
+               const bt_event_class *in_event_class)
+{
+       return g_hash_table_lookup(md_maps->event_class_map,
+                       (gpointer) in_event_class);
+}
+
+BT_HIDDEN
+bt_event_class *trace_ir_mapping_create_new_mapped_event_class(
+               struct trace_ir_maps *ir_maps,
+               const bt_event_class *in_event_class)
+{
+       bt_event_class *out_event_class;
+       const bt_trace_class *in_trace_class;
+       const bt_stream_class *in_stream_class;
+       bt_stream_class *out_stream_class;
+       struct trace_ir_metadata_maps *md_maps;
+       int ret;
+
+       BT_LOGD("Creating new mapped event class: in-ec-addr=%p",
+                       in_event_class);
+
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_event_class);
+
+       in_trace_class = bt_stream_class_borrow_trace_class_const(
+                               bt_event_class_borrow_stream_class_const(
+                                       in_event_class));
+
+       md_maps = borrow_metadata_maps_from_input_trace_class(ir_maps, in_trace_class);
+
+       BT_ASSERT(!borrow_mapped_event_class(md_maps, in_event_class));
+
+       in_stream_class =
+               bt_event_class_borrow_stream_class_const(in_event_class);
+       BT_ASSERT(in_stream_class);
+
+       /* Get the right output stream class to add the new event class to. */
+       out_stream_class = borrow_mapped_stream_class(md_maps, in_stream_class);
+       BT_ASSERT(out_stream_class);
+
+       /* Create an output event class. */
+       out_event_class = bt_event_class_create_with_id(out_stream_class,
+                       bt_event_class_get_id(in_event_class));
+       if (!out_event_class) {
+               BT_LOGE_STR("Error creating output event class");
+               goto end;
+       }
+
+       /* If not, create a new one and add it to the mapping. */
+       ret = copy_event_class_content(ir_maps, in_event_class,
+                       out_event_class);
+       if (ret) {
+               BT_LOGE_STR("Error copy content to output event class");
+               out_event_class = NULL;
+               goto end;
+       }
+
+       g_hash_table_insert(md_maps->event_class_map,
+                       (gpointer) in_event_class, out_event_class);
+
+       BT_LOGD("Created new mapped event class: in-ec-addr=%p, out-ec-addr=%p",
+                       in_event_class, out_event_class);
+
+end:
+       return out_event_class;
+}
+
+BT_HIDDEN
+bt_event_class *trace_ir_mapping_borrow_mapped_event_class(
+               struct trace_ir_maps *ir_maps,
+               const bt_event_class *in_event_class)
+{
+       struct trace_ir_metadata_maps *md_maps;
+
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_event_class);
+
+       md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, in_event_class);
+
+       /* Return the mapped event_class. */
+       return borrow_mapped_event_class(md_maps, in_event_class);
+}
+
+static inline
+bt_packet *borrow_mapped_packet(struct trace_ir_data_maps *d_maps,
+               const bt_packet *in_packet)
+{
+       BT_ASSERT(d_maps);
+       BT_ASSERT(in_packet);
+
+       return g_hash_table_lookup(d_maps->packet_map,
+                       (gpointer) in_packet);
+}
+
+BT_HIDDEN
+bt_packet *trace_ir_mapping_create_new_mapped_packet(
+               struct trace_ir_maps *ir_maps,
+               const bt_packet *in_packet)
+{
+       struct trace_ir_data_maps *d_maps;
+       const bt_trace *in_trace;
+       const bt_stream *in_stream;
+       bt_packet *out_packet;
+       bt_stream *out_stream;
+
+       BT_LOGD("Creating new mapped packet: in-p-addr=%p", in_packet);
+
+       in_stream = bt_packet_borrow_stream_const(in_packet);
+       in_trace = bt_stream_borrow_trace_const(in_stream);
+       d_maps = borrow_data_maps_from_input_trace(ir_maps, in_trace);
+
+       /* There should never be a mapped packet. */
+       BT_ASSERT(!borrow_mapped_packet(d_maps, in_packet));
+
+       BT_ASSERT(in_stream);
+
+       /* Get output stream corresponding to this input stream. */
+       out_stream = borrow_mapped_stream(d_maps, in_stream);
+       BT_ASSERT(out_stream);
+
+       /* Create the output packet. */
+       out_packet = bt_packet_create(out_stream);
+       if (!out_packet) {
+               BT_LOGE_STR("Error create output packet");
+               goto end;
+       }
+
+       /*
+        * Release our ref since the stream object will be managing the life
+        * time of the packet objects.
+        */
+       copy_packet_content(in_packet, out_packet);
+
+       g_hash_table_insert(d_maps->packet_map,
+                       (gpointer) in_packet, out_packet);
+
+       BT_LOGD("Created new mapped packet: in-p-addr=%p, out-p-addr=%p",
+                       in_packet, out_packet);
+
+end:
+       return out_packet;
+}
+
+BT_HIDDEN
+bt_packet *trace_ir_mapping_borrow_mapped_packet(struct trace_ir_maps *ir_maps,
+               const bt_packet *in_packet)
+{
+       struct trace_ir_data_maps *d_maps;
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_packet);
+
+       d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet);
+
+       return borrow_mapped_packet(d_maps, in_packet);
+}
+
+BT_HIDDEN
+void trace_ir_mapping_remove_mapped_packet(struct trace_ir_maps *ir_maps,
+               const bt_packet *in_packet)
+{
+       gboolean ret;
+
+       struct trace_ir_data_maps *d_maps;
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_packet);
+
+       d_maps = borrow_data_maps_from_input_packet(ir_maps, in_packet);
+
+       ret = g_hash_table_remove(d_maps->packet_map, in_packet);
+
+       BT_ASSERT(ret);
+}
+
+BT_HIDDEN
+void trace_ir_mapping_remove_mapped_stream(struct trace_ir_maps *ir_maps,
+               const bt_stream *in_stream)
+{
+       gboolean ret;
+       struct trace_ir_data_maps *d_maps;
+
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_stream);
+
+       d_maps = borrow_data_maps_from_input_stream(ir_maps, in_stream);
+
+       ret = g_hash_table_remove(d_maps->stream_map, in_stream);
+
+       BT_ASSERT(ret);
+}
+
+static
+void trace_ir_metadata_maps_remove_func(const bt_trace_class *in_trace_class,
+               void *data)
+{
+       struct trace_ir_maps *maps = (struct trace_ir_maps *) data;
+       if (maps->metadata_maps) {
+               gboolean ret;
+               ret = g_hash_table_remove(maps->metadata_maps,
+                               (gpointer) in_trace_class);
+               BT_ASSERT(ret);
+       }
+}
+
+static
+void trace_ir_data_maps_remove_func(const bt_trace *in_trace, void *data)
+{
+       struct trace_ir_maps *maps = (struct trace_ir_maps *) data;
+       if (maps->data_maps) {
+               gboolean ret;
+               ret = g_hash_table_remove(maps->data_maps, (gpointer) in_trace);
+               BT_ASSERT(ret);
+       }
+}
+
+struct trace_ir_data_maps *trace_ir_data_maps_create(struct trace_ir_maps *ir_maps,
+               const bt_trace *in_trace)
+{
+       struct trace_ir_data_maps *d_maps =
+               g_new0(struct trace_ir_data_maps, 1);
+       if (!d_maps) {
+               BT_LOGE_STR("Error allocating trace_ir_maps");
+               goto error;
+       }
+
+       d_maps->input_trace = in_trace;
+
+       /* Create the hashtables used to map data objects. */
+       d_maps->stream_map = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL,(GDestroyNotify) bt_stream_put_ref);
+       d_maps->packet_map = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL,(GDestroyNotify) bt_packet_put_ref);
+
+       bt_trace_add_destruction_listener(in_trace, trace_ir_data_maps_remove_func,
+                       ir_maps, &d_maps->destruction_listener_id);
+error:
+       return d_maps;
+}
+
+struct trace_ir_metadata_maps *trace_ir_metadata_maps_create(
+               struct trace_ir_maps *ir_maps,
+               const bt_trace_class *in_trace_class)
+{
+       struct trace_ir_metadata_maps *md_maps =
+               g_new0(struct trace_ir_metadata_maps, 1);
+       if (!md_maps) {
+               BT_LOGE_STR("Error allocating trace_ir_maps");
+               goto error;
+       }
+
+       md_maps->input_trace_class = in_trace_class;
+       /*
+        * Create the field class resolving context. This is needed to keep
+        * track of the field class already copied in order to do the field
+        * path resolution correctly.
+        */
+       md_maps->fc_resolving_ctx =
+               g_new0(struct field_class_resolving_context, 1);
+       if (!md_maps->fc_resolving_ctx) {
+               BT_LOGE_STR("Error allocating field_class_resolving_context");
+               goto error;
+       }
+
+       /* Create the hashtables used to map metadata objects. */
+       md_maps->stream_class_map = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL, (GDestroyNotify) bt_stream_class_put_ref);
+       md_maps->event_class_map = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL, (GDestroyNotify) bt_event_class_put_ref);
+       md_maps->field_class_map = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL, (GDestroyNotify) bt_field_class_put_ref);
+       md_maps->clock_class_map = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, NULL, (GDestroyNotify) bt_clock_class_put_ref);
+
+       bt_trace_class_add_destruction_listener(in_trace_class,
+                       trace_ir_metadata_maps_remove_func,
+                       ir_maps, &md_maps->destruction_listener_id);
+error:
+       return md_maps;
+}
+
+BT_HIDDEN
+void trace_ir_data_maps_destroy(struct trace_ir_data_maps *maps)
+{
+       bt_trace_status status;
+       if (!maps) {
+               return;
+       }
+
+       if (maps->packet_map) {
+               g_hash_table_destroy(maps->packet_map);
+       }
+
+       if (maps->stream_map) {
+               g_hash_table_destroy(maps->stream_map);
+       }
+
+       if (maps->output_trace) {
+               bt_trace_put_ref(maps->output_trace);
+       }
+
+       status = bt_trace_remove_destruction_listener(maps->input_trace,
+                       maps->destruction_listener_id);
+       if (status != BT_TRACE_STATUS_OK) {
+               BT_LOGD("Trace destruction listener removal failed.");
+       }
+
+       g_free(maps);
+}
+
+BT_HIDDEN
+void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *maps)
+{
+       bt_trace_class_status status;
+       if (!maps) {
+               return;
+       }
+
+       if (maps->stream_class_map) {
+               g_hash_table_destroy(maps->stream_class_map);
+       }
+
+       if (maps->event_class_map) {
+               g_hash_table_destroy(maps->event_class_map);
+       }
+
+       if (maps->field_class_map) {
+               g_hash_table_destroy(maps->field_class_map);
+       }
+
+       if (maps->clock_class_map) {
+               g_hash_table_destroy(maps->clock_class_map);
+       }
+
+       if (maps->fc_resolving_ctx) {
+               g_free(maps->fc_resolving_ctx);
+       }
+
+       if (maps->output_trace_class) {
+               bt_trace_class_put_ref(maps->output_trace_class);
+       }
+
+       status = bt_trace_class_remove_destruction_listener(maps->input_trace_class,
+                       maps->destruction_listener_id);
+       if (status != BT_TRACE_CLASS_STATUS_OK) {
+               BT_LOGD("Trace destruction listener removal failed.");
+       }
+
+       g_free(maps);
+}
+
+void trace_ir_maps_clear(struct trace_ir_maps *maps)
+{
+       if (maps->data_maps) {
+               g_hash_table_remove_all(maps->data_maps);
+       }
+
+       if (maps->metadata_maps) {
+               g_hash_table_remove_all(maps->metadata_maps);
+       }
+}
+
+BT_HIDDEN
+void trace_ir_maps_destroy(struct trace_ir_maps *maps)
+{
+       if (!maps) {
+               return;
+       }
+
+       if (maps->debug_info_field_class_name) {
+               g_free(maps->debug_info_field_class_name);
+       }
+
+       if (maps->data_maps) {
+               g_hash_table_destroy(maps->data_maps);
+               maps->data_maps = NULL;
+       }
+
+       if (maps->metadata_maps) {
+               g_hash_table_destroy(maps->metadata_maps);
+               maps->metadata_maps = NULL;
+       }
+
+       g_free(maps);
+}
+
+BT_HIDDEN
+struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp,
+               const char *debug_info_field_name)
+{
+       struct trace_ir_maps *trace_ir_maps =
+               g_new0(struct trace_ir_maps, 1);
+       if (!trace_ir_maps) {
+               BT_LOGE_STR("Error allocating trace_ir_maps");
+               goto error;
+       }
+
+       /* Copy debug info field name received from the user. */
+       trace_ir_maps->debug_info_field_class_name =
+               g_strdup(debug_info_field_name);
+       if (!trace_ir_maps->debug_info_field_class_name) {
+               BT_LOGE_STR("Cannot copy debug info field name");
+               goto error;
+       }
+
+       trace_ir_maps->self_comp = self_comp;
+
+       trace_ir_maps->data_maps = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, (GDestroyNotify) NULL,
+                       (GDestroyNotify) trace_ir_data_maps_destroy);
+
+       trace_ir_maps->metadata_maps = g_hash_table_new_full(g_direct_hash,
+                       g_direct_equal, (GDestroyNotify) NULL,
+                       (GDestroyNotify) trace_ir_metadata_maps_destroy);
+
+       goto end;
+error:
+       trace_ir_maps_destroy(trace_ir_maps);
+       trace_ir_maps = NULL;
+end:
+       return trace_ir_maps;
+}
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-mapping.h b/src/plugins/lttng-utils/debug-info/trace-ir-mapping.h
new file mode 100644 (file)
index 0000000..9691785
--- /dev/null
@@ -0,0 +1,274 @@
+#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H
+#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H
+/*
+ * Copyright 2019 Francis Deslauriers francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+
+#include "common/assert.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "debug-info.h"
+
+/* Used to resolve field paths for dynamic arrays and variant field classes. */
+struct field_class_resolving_context {
+       /* Weak reference. Owned by input stream class. */
+       const bt_field_class *packet_context;
+       /* Weak reference. Owned by input stream class. */
+       const bt_field_class *event_common_context;
+       /* Weak reference. Owned by input event class. */
+       const bt_field_class *event_specific_context;
+       /* Weak reference. Owned by input event class. */
+       const bt_field_class *event_payload;
+};
+
+struct trace_ir_metadata_maps {
+       const bt_trace_class *input_trace_class;
+       bt_trace_class *output_trace_class;
+
+       /*
+        * Map between input stream class and its corresponding output stream
+        * class.
+        * input stream class: weak reference. Owned by an upstream
+        * component.
+        * output stream class: owned by this structure.
+        */
+       GHashTable *stream_class_map;
+
+       /*
+        * Map between input event class and its corresponding output event
+        * class.
+        * input event class: weak reference. Owned by an upstream component.
+        * output event class: owned by this structure.
+        */
+       GHashTable *event_class_map;
+
+       /*
+        * Map between input field class and its corresponding output field
+        * class.
+        * input field class: weak reference. Owned by an upstream component.
+        * output field class: owned by this structure.
+        */
+       GHashTable *field_class_map;
+
+       /*
+        * Map between input clock class and its corresponding output clock
+        * class.
+        * input clock class: weak reference. Owned by an upstream component.
+        * output clock class: owned by this structure.
+        */
+       GHashTable *clock_class_map;
+
+       struct field_class_resolving_context *fc_resolving_ctx;
+
+       uint64_t destruction_listener_id;
+};
+
+struct trace_ir_data_maps {
+       const bt_trace *input_trace;
+       bt_trace *output_trace;
+
+       /*
+        * Map between input stream its corresponding output stream.
+        * input stream: weak reference. Owned by an upstream component.
+        * output stream: owned by this structure.
+        */
+       GHashTable *stream_map;
+
+       /*
+        * Map between input packet its corresponding output packet.
+        * input packet: weak reference. Owned by an upstream packet component.
+        * output packet: owned by this structure.
+        */
+       GHashTable *packet_map;
+
+       uint64_t destruction_listener_id;
+};
+
+struct trace_ir_maps {
+       /*
+        * input trace -> trace_ir_data_maps.
+        * input trace: weak reference. Owned by an upstream component.
+        * trace_ir_data_maps: Owned by this structure.
+        */
+       GHashTable *data_maps;
+
+       /*
+        * input trace class -> trace_ir_metadata_maps.
+        * input trace class: weak reference. Owned by an upstream component.
+        * trace_ir_metadata_maps: Owned by this structure.
+        */
+       GHashTable *metadata_maps;
+
+       char *debug_info_field_class_name;
+
+       bt_self_component *self_comp;
+};
+
+BT_HIDDEN
+struct trace_ir_maps *trace_ir_maps_create(bt_self_component *self_comp,
+               const char *debug_info_field_name);
+
+BT_HIDDEN
+void trace_ir_maps_clear(struct trace_ir_maps *maps);
+
+BT_HIDDEN
+void trace_ir_maps_destroy(struct trace_ir_maps *maps);
+
+BT_HIDDEN
+struct trace_ir_data_maps *trace_ir_data_maps_create(
+               struct trace_ir_maps *ir_maps,
+               const bt_trace *in_trace);
+
+BT_HIDDEN
+void trace_ir_data_maps_destroy(struct trace_ir_data_maps *d_maps);
+
+BT_HIDDEN
+struct trace_ir_metadata_maps *trace_ir_metadata_maps_create(
+               struct trace_ir_maps *ir_maps,
+               const bt_trace_class *in_trace_class);
+
+BT_HIDDEN
+void trace_ir_metadata_maps_destroy(struct trace_ir_metadata_maps *md_maps);
+
+BT_HIDDEN
+bt_stream *trace_ir_mapping_create_new_mapped_stream(
+               struct trace_ir_maps *ir_maps,
+               const bt_stream *in_stream);
+
+BT_HIDDEN
+bt_stream *trace_ir_mapping_borrow_mapped_stream(
+               struct trace_ir_maps *ir_maps,
+               const bt_stream *in_stream);
+
+BT_HIDDEN
+void trace_ir_mapping_remove_mapped_stream(
+               struct trace_ir_maps *ir_maps,
+               const bt_stream *in_stream);
+
+BT_HIDDEN
+bt_event_class *trace_ir_mapping_create_new_mapped_event_class(
+               struct trace_ir_maps *ir_maps,
+               const bt_event_class *in_event_class);
+
+BT_HIDDEN
+bt_event_class *trace_ir_mapping_borrow_mapped_event_class(
+               struct trace_ir_maps *ir_maps,
+               const bt_event_class *in_event_class);
+
+BT_HIDDEN
+bt_packet *trace_ir_mapping_create_new_mapped_packet(
+               struct trace_ir_maps *ir_maps,
+               const bt_packet *in_packet);
+
+BT_HIDDEN
+bt_packet *trace_ir_mapping_borrow_mapped_packet(
+               struct trace_ir_maps *ir_maps,
+               const bt_packet *in_packet);
+
+BT_HIDDEN
+void trace_ir_mapping_remove_mapped_packet(
+               struct trace_ir_maps *ir_maps,
+               const bt_packet *in_packet);
+
+static inline
+struct trace_ir_data_maps *borrow_data_maps_from_input_trace(
+               struct trace_ir_maps *ir_maps, const bt_trace *in_trace)
+{
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_trace);
+
+       struct trace_ir_data_maps *d_maps =
+               g_hash_table_lookup(ir_maps->data_maps, (gpointer) in_trace);
+       if (!d_maps) {
+               d_maps = trace_ir_data_maps_create(ir_maps, in_trace);
+               g_hash_table_insert(ir_maps->data_maps, (gpointer) in_trace, d_maps);
+       }
+
+       return d_maps;
+}
+
+static inline
+struct trace_ir_data_maps *borrow_data_maps_from_input_stream(
+               struct trace_ir_maps *ir_maps, const bt_stream *in_stream)
+{
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_stream);
+
+       return borrow_data_maps_from_input_trace(ir_maps,
+                       bt_stream_borrow_trace_const(in_stream));
+}
+
+static inline
+struct trace_ir_data_maps *borrow_data_maps_from_input_packet(
+               struct trace_ir_maps *ir_maps, const bt_packet *in_packet)
+{
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_packet);
+
+       return borrow_data_maps_from_input_stream(ir_maps,
+                       bt_packet_borrow_stream_const(in_packet));
+}
+
+static inline
+struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_trace_class(
+               struct trace_ir_maps *ir_maps,
+               const bt_trace_class *in_trace_class)
+{
+       BT_ASSERT(ir_maps);
+       BT_ASSERT(in_trace_class);
+
+       struct trace_ir_metadata_maps *md_maps =
+               g_hash_table_lookup(ir_maps->metadata_maps,
+                               (gpointer) in_trace_class);
+       if (!md_maps) {
+               md_maps = trace_ir_metadata_maps_create(ir_maps, in_trace_class);
+               g_hash_table_insert(ir_maps->metadata_maps,
+                               (gpointer) in_trace_class, md_maps);
+       }
+
+       return md_maps;
+}
+
+static inline
+struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_stream_class(
+               struct trace_ir_maps *ir_maps,
+               const bt_stream_class *in_stream_class) {
+
+       BT_ASSERT(in_stream_class);
+
+       return borrow_metadata_maps_from_input_trace_class(ir_maps,
+                       bt_stream_class_borrow_trace_class_const(in_stream_class));
+}
+
+static inline
+struct trace_ir_metadata_maps *borrow_metadata_maps_from_input_event_class(
+               struct trace_ir_maps *ir_maps,
+               const bt_event_class *in_event_class) {
+
+       BT_ASSERT(in_event_class);
+
+       return borrow_metadata_maps_from_input_stream_class(ir_maps,
+                       bt_event_class_borrow_stream_class_const(in_event_class));
+}
+
+#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_IR_MAPPING_H */
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.c
new file mode 100644 (file)
index 0000000..92bc3de
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ * Babeltrace - Trace IR metadata object copy
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-METADATA-COPY"
+#include "logging.h"
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#include "common/assert.h"
+
+#include "trace-ir-metadata-copy.h"
+#include "trace-ir-metadata-field-class-copy.h"
+#include "utils.h"
+
+BT_HIDDEN
+int copy_trace_class_content(const bt_trace_class *in_trace_class,
+               bt_trace_class *out_trace_class)
+{
+       int ret = 0;
+       uint64_t i, env_field_count;
+       const char *in_trace_class_name;
+
+       BT_LOGD("Copying content of trace class: in-tc-addr=%p, out-tc-addr=%p",
+                       in_trace_class, out_trace_class);
+
+       /* Use the same stream class ids as in the origin trace class. */
+       bt_trace_class_set_assigns_automatic_stream_class_id(out_trace_class,
+                       BT_FALSE);
+
+       in_trace_class_name = bt_trace_class_get_name(in_trace_class);
+       if (in_trace_class_name) {
+               bt_trace_class_set_name(out_trace_class, in_trace_class_name);
+       }
+
+       /*
+        * Do not copy the trace class UUID as it may be modified and should no
+        * longer have the same UUID.
+        */
+
+       /*
+        * Go over all the entries in the environment section of the trace class
+        * and copy the content to the new trace class.
+        */
+       env_field_count = bt_trace_class_get_environment_entry_count(in_trace_class);
+       for (i = 0; i < env_field_count; i++) {
+               const char *value_name;
+               const bt_value *value = NULL;
+               bt_trace_class_status trace_class_status;
+
+               bt_trace_class_borrow_environment_entry_by_index_const(
+                       in_trace_class, i, &value_name, &value);
+
+               BT_LOGD("Copying trace class environnement entry: "
+                       "index=%" PRId64 ", value-addr=%p, value-name=%s",
+                       i, value, value_name);
+
+               BT_ASSERT(value_name);
+               BT_ASSERT(value);
+
+               if (bt_value_is_signed_integer(value)) {
+                       trace_class_status =
+                               bt_trace_class_set_environment_entry_integer(
+                                               out_trace_class, value_name,
+                                               bt_value_signed_integer_get(
+                                                       value));
+               } else if (bt_value_is_string(value)) {
+                       trace_class_status =
+                               bt_trace_class_set_environment_entry_string(
+                                       out_trace_class, value_name,
+                                       bt_value_string_get(value));
+               } else {
+                       abort();
+               }
+
+               if (trace_class_status != BT_TRACE_CLASS_STATUS_OK) {
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Copied content of trace class: in-tc-addr=%p, out-tc-addr=%p",
+                       in_trace_class, out_trace_class);
+error:
+       return ret;
+}
+
+static
+int copy_clock_class_content(const bt_clock_class *in_clock_class,
+               bt_clock_class *out_clock_class)
+{
+       bt_clock_class_status status;
+       const char *clock_class_name, *clock_class_description;
+       int64_t seconds;
+       uint64_t cycles;
+       bt_uuid in_uuid;
+       int ret = 0;
+
+       BT_LOGD("Copying content of clock class: in-cc-addr=%p, out-cc-addr=%p",
+                       in_clock_class, out_clock_class);
+
+       clock_class_name = bt_clock_class_get_name(in_clock_class);
+
+       if (clock_class_name) {
+               status = bt_clock_class_set_name(out_clock_class, clock_class_name);
+               if (status != BT_CLOCK_CLASS_STATUS_OK) {
+                       BT_LOGE("Error setting clock class' name cc-addr=%p, name=%p",
+                               out_clock_class, clock_class_name);
+                       out_clock_class = NULL;
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       clock_class_description = bt_clock_class_get_description(in_clock_class);
+
+       if (clock_class_description) {
+               status = bt_clock_class_set_description(out_clock_class,
+                               clock_class_description);
+               if (status != BT_CLOCK_CLASS_STATUS_OK) {
+                       BT_LOGE("Error setting clock class' description cc-addr=%p, "
+                               "name=%p", out_clock_class, clock_class_description);
+                       out_clock_class = NULL;
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       in_uuid = bt_clock_class_get_uuid(in_clock_class);
+       if (in_uuid) {
+               bt_clock_class_set_uuid(out_clock_class, in_uuid);
+       }
+
+       bt_clock_class_set_frequency(out_clock_class,
+                       bt_clock_class_get_frequency(in_clock_class));
+       bt_clock_class_set_precision(out_clock_class,
+                       bt_clock_class_get_precision(in_clock_class));
+       bt_clock_class_get_offset(in_clock_class, &seconds, &cycles);
+       bt_clock_class_set_offset(out_clock_class, seconds, cycles);
+       bt_clock_class_set_origin_is_unix_epoch(out_clock_class,
+                       bt_clock_class_origin_is_unix_epoch(in_clock_class));
+
+       BT_LOGD("Copied content of clock class: in-cc-addr=%p, out-cc-addr=%p",
+                       in_clock_class, out_clock_class);
+
+error:
+       return ret;
+}
+
+static
+bt_clock_class *borrow_mapped_clock_class(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_clock_class *in_clock_class)
+{
+       BT_ASSERT(md_maps);
+       BT_ASSERT(in_clock_class);
+
+       return g_hash_table_lookup(md_maps->clock_class_map,
+                       (gpointer) in_clock_class);
+}
+
+static
+bt_clock_class *create_new_mapped_clock_class(
+               bt_self_component *self_comp,
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_clock_class *in_clock_class)
+{
+       bt_clock_class *out_clock_class;
+       int ret;
+
+       BT_LOGD("Creating new mapped clock class: in-cc-addr=%p",
+                       in_clock_class);
+
+       BT_ASSERT(md_maps);
+       BT_ASSERT(in_clock_class);
+
+       BT_ASSERT(!borrow_mapped_clock_class(md_maps, in_clock_class));
+
+       out_clock_class = bt_clock_class_create(self_comp);
+       if (!out_clock_class) {
+               BT_LOGE_STR("Cannot create clock class");
+               goto end;
+       }
+       /* If not, create a new one and add it to the mapping. */
+       ret = copy_clock_class_content(in_clock_class, out_clock_class);
+       if (ret) {
+               BT_LOGE_STR("Cannot copy clock class");
+               goto end;
+       }
+
+       g_hash_table_insert(md_maps->clock_class_map,
+                       (gpointer) in_clock_class, out_clock_class);
+
+       BT_LOGD("Created new mapped clock class: in-cc-addr=%p, out-cc-addr=%p",
+                       in_clock_class, out_clock_class);
+end:
+       return out_clock_class;
+}
+
+BT_HIDDEN
+int copy_stream_class_content(struct trace_ir_maps *ir_maps,
+               const bt_stream_class *in_stream_class,
+               bt_stream_class *out_stream_class)
+{
+       struct trace_ir_metadata_maps *md_maps;
+       const bt_clock_class *in_clock_class;
+       bt_clock_class *out_clock_class;
+       const bt_field_class *in_packet_context_fc, *in_common_context_fc;
+       bt_field_class *out_packet_context_fc, *out_common_context_fc;
+       bt_stream_class_status status;
+       const char *in_name;
+       int ret = 0;
+
+       BT_LOGD("Copying content of stream class: in-sc-addr=%p, out-sc-addr=%p",
+                       in_stream_class, out_stream_class);
+
+       md_maps = borrow_metadata_maps_from_input_stream_class(ir_maps, in_stream_class);
+       in_clock_class = bt_stream_class_borrow_default_clock_class_const(
+                               in_stream_class);
+
+       if (in_clock_class) {
+               /* Copy the clock class. */
+               out_clock_class =
+                       borrow_mapped_clock_class(md_maps, in_clock_class);
+               if (!out_clock_class) {
+                       out_clock_class = create_new_mapped_clock_class(
+                                       ir_maps->self_comp, md_maps,
+                                       in_clock_class);
+               }
+               bt_stream_class_set_default_clock_class(out_stream_class,
+                               out_clock_class);
+
+       }
+
+       bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
+               out_stream_class,
+               bt_stream_class_packets_have_beginning_default_clock_snapshot(
+                       in_stream_class));
+       bt_stream_class_set_packets_have_end_default_clock_snapshot(
+               out_stream_class,
+               bt_stream_class_packets_have_end_default_clock_snapshot(
+                       in_stream_class));
+       bt_stream_class_set_supports_discarded_events(
+               out_stream_class,
+               bt_stream_class_supports_discarded_events(in_stream_class),
+               bt_stream_class_discarded_events_have_default_clock_snapshots(
+                       in_stream_class));
+       bt_stream_class_set_supports_discarded_packets(
+               out_stream_class,
+               bt_stream_class_supports_discarded_packets(in_stream_class),
+               bt_stream_class_discarded_packets_have_default_clock_snapshots(
+                       in_stream_class));
+
+       in_name = bt_stream_class_get_name(in_stream_class);
+       if (in_name) {
+               status = bt_stream_class_set_name(out_stream_class, in_name);
+               if (status != BT_STREAM_CLASS_STATUS_OK) {
+                       BT_LOGE("Error set stream class name: out-sc-addr=%p, "
+                               "name=%s", out_stream_class, in_name);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       bt_stream_class_set_assigns_automatic_stream_id(out_stream_class,
+                       BT_FALSE);
+       bt_stream_class_set_assigns_automatic_event_class_id(out_stream_class,
+                       BT_FALSE);
+
+       /*
+        * Add the input packet context field class to the context to
+        * resolution in the further steps.
+        */
+       in_packet_context_fc =
+               bt_stream_class_borrow_packet_context_field_class_const(
+                               in_stream_class);
+       md_maps->fc_resolving_ctx->packet_context =
+               in_packet_context_fc;
+
+       if (in_packet_context_fc) {
+               /* Copy packet context. */
+               out_packet_context_fc = create_field_class_copy(
+                               md_maps, in_packet_context_fc);
+
+               ret = copy_field_class_content(md_maps,
+                       in_packet_context_fc, out_packet_context_fc);
+               if (ret) {
+                       ret = -1;
+                       goto error;
+               }
+
+               status = bt_stream_class_set_packet_context_field_class(
+                               out_stream_class, out_packet_context_fc);
+               if (status !=  BT_STREAM_CLASS_STATUS_OK) {
+                       BT_LOGE("Error setting stream class' packet context "
+                               "field class: sc-addr=%p, packet-fc-addr=%p",
+                               out_stream_class, out_packet_context_fc);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       /*
+        * Add the input common context field class to the context to
+        * resolution in the further steps.
+        */
+       in_common_context_fc =
+               bt_stream_class_borrow_event_common_context_field_class_const(
+                               in_stream_class);
+       md_maps->fc_resolving_ctx->event_common_context =
+               in_common_context_fc;
+
+       if (in_common_context_fc) {
+               /* Copy common context. */
+               /* TODO: I find it a bit awkward to have this special function
+                * here to add the debug-info field class. I would like to
+                * abstract that.*/
+               out_common_context_fc = create_field_class_copy(
+                               md_maps, in_common_context_fc);
+
+               ret = copy_event_common_context_field_class_content(
+                               md_maps, ir_maps->debug_info_field_class_name,
+                               in_common_context_fc, out_common_context_fc);
+               if (ret) {
+                       goto error;
+               }
+
+               status = bt_stream_class_set_event_common_context_field_class(
+                               out_stream_class, out_common_context_fc);
+               if (status !=  BT_STREAM_CLASS_STATUS_OK) {
+                       BT_LOGE("Error setting stream class' packet context "
+                               "field class: sc-addr=%p, packet-fc-addr=%p",
+                               out_stream_class, out_common_context_fc);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       /* Set packet snapshot boolean fields. */
+       BT_LOGD("Copied content of stream class: in-sc-addr=%p, out-sc-addr=%p",
+                       in_stream_class, out_stream_class);
+error:
+       return ret;
+}
+
+BT_HIDDEN
+int copy_event_class_content(struct trace_ir_maps *ir_maps,
+               const bt_event_class *in_event_class,
+               bt_event_class *out_event_class)
+{
+       struct trace_ir_metadata_maps *md_maps;
+       const char *in_event_class_name, *in_emf_uri;
+       bt_property_availability prop_avail;
+       bt_event_class_log_level log_level;
+       bt_event_class_status status;
+       bt_field_class *out_specific_context_fc, *out_payload_fc;
+       const bt_field_class *in_event_specific_context, *in_event_payload;
+       int ret = 0;
+
+       BT_LOGD("Copying content of event class: in-ec-addr=%p, out-ec-addr=%p",
+                       in_event_class, out_event_class);
+
+       /* Copy event class name. */
+       in_event_class_name = bt_event_class_get_name(in_event_class);
+       if (in_event_class_name) {
+               status = bt_event_class_set_name(out_event_class, in_event_class_name);
+               if (status != BT_EVENT_CLASS_STATUS_OK) {
+                       BT_LOGE("Error setting event class' name: ec-addr=%p, "
+                               "name=%s", out_event_class, in_event_class_name);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       /* Copy event class loglevel. */
+       prop_avail = bt_event_class_get_log_level(in_event_class, &log_level);
+       if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
+               bt_event_class_set_log_level(out_event_class,
+                               log_level);
+       }
+
+       /* Copy event class emf uri. */
+       in_emf_uri = bt_event_class_get_emf_uri(in_event_class);
+       if (in_emf_uri) {
+               status = bt_event_class_set_emf_uri(out_event_class, in_emf_uri);
+               if (status != BT_EVENT_CLASS_STATUS_OK) {
+                       BT_LOGE("Error setting event class' emf uri: ec-addr=%p, "
+                               "emf uri=%s", out_event_class, in_emf_uri);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       md_maps = borrow_metadata_maps_from_input_event_class(ir_maps, in_event_class);
+       /*
+        * Add the input event class' specific ctx to te
+        * context.
+        */
+       in_event_specific_context =
+               bt_event_class_borrow_specific_context_field_class_const(
+                               in_event_class);
+
+       md_maps->fc_resolving_ctx->event_specific_context =
+               in_event_specific_context;
+
+       if (in_event_specific_context) {
+               /* Copy the specific context of this event class. */
+               out_specific_context_fc = create_field_class_copy(md_maps,
+                               in_event_specific_context);
+
+               ret = copy_field_class_content(md_maps,
+                               in_event_specific_context, out_specific_context_fc);
+               if (ret) {
+                       goto error;
+               }
+               /*
+                * Add the output specific context to the output event
+                * class.
+                */
+               status = bt_event_class_set_specific_context_field_class(
+                               out_event_class, out_specific_context_fc);
+               if (status != BT_EVENT_CLASS_STATUS_OK) {
+                       BT_LOGE("Error setting event class' specific context "
+                               "field class: ec-addr=%p, ctx-fc-addr=%p",
+                               out_event_class, out_specific_context_fc);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       /*
+        * Add the input event class' payload field class to
+        * the context.
+        */
+       in_event_payload = bt_event_class_borrow_payload_field_class_const(
+                               in_event_class);
+
+       md_maps->fc_resolving_ctx->event_payload = in_event_payload;
+
+       if (in_event_payload) {
+       /* Copy the payload of this event class. */
+               out_payload_fc = create_field_class_copy(md_maps,
+                               in_event_payload);
+               ret = copy_field_class_content(md_maps,
+                               in_event_payload, out_payload_fc);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Add the output payload to the output event class. */
+               status = bt_event_class_set_payload_field_class(
+                               out_event_class, out_payload_fc);
+               if (status != BT_EVENT_CLASS_STATUS_OK) {
+                       BT_LOGE("Error setting event class' payload "
+                               "field class: ec-addr=%p, payload-fc-addr=%p",
+                               out_event_class, out_payload_fc);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Copied content of event class: in-ec-addr=%p, out-ec-addr=%p",
+                       in_event_class, out_event_class);
+error:
+       return ret;
+}
+
+BT_HIDDEN
+int copy_event_common_context_field_class_content(
+               struct trace_ir_metadata_maps *md_maps,
+               const char *debug_info_fc_name,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       bt_field_class_status status;
+       bt_field_class *debug_field_class = NULL, *bin_field_class = NULL,
+                      *func_field_class = NULL, *src_field_class = NULL;
+       int ret = 0;
+
+       BT_LOGD("Copying content of event common context field class: "
+               "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class);
+
+       /* Copy the content of the input common context. */
+       ret = copy_field_class_content(md_maps, in_field_class, out_field_class);
+       if (ret) {
+               goto error;
+       }
+
+       /*
+        * If this event common context has the necessary fields to compute the
+        * debug information append the debug-info field class to the event
+        * common context.
+        */
+       if (is_event_common_ctx_dbg_info_compatible(in_field_class, debug_info_fc_name)) {
+               /*
+                * The struct field and 3 sub-fields are not stored in the
+                * field class map because they don't have input equivalent.
+                * We need to put our reference each of these field classes
+                * once they are added to their respective containing field
+                * classes.
+                */
+               debug_field_class = bt_field_class_structure_create(
+                               md_maps->output_trace_class);
+               if (!debug_field_class) {
+                       BT_LOGE_STR("Failed to create debug_info structure.");
+                       ret = -1;
+                       goto error;
+               }
+
+               bin_field_class = bt_field_class_string_create(
+                               md_maps->output_trace_class);
+               if (!bin_field_class) {
+                       BT_LOGE_STR("Failed to create string for field=bin.");
+                       ret = -1;
+                       goto error;
+               }
+
+               func_field_class = bt_field_class_string_create(
+                               md_maps->output_trace_class);
+               if (!func_field_class) {
+                       BT_LOGE_STR("Failed to create string for field=func.");
+                       ret = -1;
+                       goto error;
+               }
+
+               src_field_class = bt_field_class_string_create(
+                               md_maps->output_trace_class);
+               if (!src_field_class) {
+                       BT_LOGE_STR("Failed to create string for field=src.");
+                       ret = -1;
+                       goto error;
+               }
+
+               status = bt_field_class_structure_append_member(
+                               debug_field_class, "bin", bin_field_class);
+               if (status != BT_FIELD_CLASS_STATUS_OK) {
+                       BT_LOGE_STR("Failed to add a field to debug_info "
+                                       "struct: field=bin.");
+                       ret = -1;
+                       goto error;
+               }
+               BT_FIELD_CLASS_PUT_REF_AND_RESET(bin_field_class);
+
+               status = bt_field_class_structure_append_member(
+                               debug_field_class, "func", func_field_class);
+               if (status != BT_FIELD_CLASS_STATUS_OK) {
+                       BT_LOGE_STR("Failed to add a field to debug_info "
+                                       "struct: field=func.");
+                       ret = -1;
+                       goto error;
+               }
+               BT_FIELD_CLASS_PUT_REF_AND_RESET(func_field_class);
+
+               status = bt_field_class_structure_append_member(
+                               debug_field_class, "src", src_field_class);
+               if (status != BT_FIELD_CLASS_STATUS_OK) {
+                       BT_LOGE_STR("Failed to add a field to debug_info "
+                                       "struct: field=src.");
+                       ret = -1;
+                       goto error;
+               }
+               BT_FIELD_CLASS_PUT_REF_AND_RESET(src_field_class);
+
+               /*Add the filled debug-info field class to the common context. */
+               status = bt_field_class_structure_append_member(out_field_class,
+                               debug_info_fc_name,
+                               debug_field_class);
+               if (status != BT_FIELD_CLASS_STATUS_OK) {
+                       BT_LOGE_STR("Failed to add debug_info field to "
+                                       "event common context.");
+                       ret = -1;
+                       goto error;
+               }
+               BT_FIELD_CLASS_PUT_REF_AND_RESET(debug_field_class);
+       }
+       BT_LOGD("Copied content of event common context field class: "
+               "in-fc-addr=%p, out-fc-addr=%p", in_field_class, out_field_class);
+       goto end;
+
+error:
+       if (debug_field_class) {
+               bt_field_class_put_ref(debug_field_class);
+       }
+       if (bin_field_class) {
+               bt_field_class_put_ref(bin_field_class);
+       }
+       if (func_field_class) {
+               bt_field_class_put_ref(func_field_class);
+       }
+       if (src_field_class) {
+               bt_field_class_put_ref(src_field_class);
+       }
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_field_class *create_field_class_copy(struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class)
+{
+       return create_field_class_copy_internal(md_maps, in_field_class);
+}
+
+BT_HIDDEN
+int copy_field_class_content(struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       return copy_field_class_content_internal(md_maps, in_field_class,
+                       out_field_class);
+}
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-copy.h
new file mode 100644 (file)
index 0000000..9330546
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H
+#define BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H
+
+/*
+ * Babeltrace - Trace IR metadata object copy
+ *
+ * Copyright (c) 2015 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "trace-ir-mapping.h"
+
+BT_HIDDEN
+int copy_trace_class_content(const bt_trace_class *in_trace_class,
+               bt_trace_class *out_trace_class);
+
+BT_HIDDEN
+int copy_stream_class_content(struct trace_ir_maps *trace_ir_maps,
+               const bt_stream_class *in_stream_class,
+               bt_stream_class *out_stream_class);
+
+BT_HIDDEN
+int copy_event_class_content(struct trace_ir_maps *trace_ir_maps,
+               const bt_event_class *in_event_class,
+               bt_event_class *out_event_class);
+
+BT_HIDDEN
+int copy_field_class_content(struct trace_ir_metadata_maps *trace_ir_metadata_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class);
+
+BT_HIDDEN
+int copy_event_common_context_field_class_content(
+               struct trace_ir_metadata_maps *trace_ir_metadata_maps,
+               const char *debug_info_field_class_name,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class);
+
+BT_HIDDEN
+bt_field_class *create_field_class_copy(
+               struct trace_ir_metadata_maps *trace_ir_metadata_maps,
+               const bt_field_class *in_field_class);
+
+#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_TRACE_METADATA_COPY_H */
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.c
new file mode 100644 (file)
index 0000000..70242d6
--- /dev/null
@@ -0,0 +1,765 @@
+/*
+ * Babeltrace - Trace IR field copy
+ *
+ * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2018 Philippe Proulx <pproulx@efficios.com>
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-LTTNG-UTILS-DEBUG-INFO-TRACE-IR-METADATA-FC-COPY"
+#include "logging.h"
+
+#include "common/assert.h"
+#include "common/common.h"
+#include "compat/compiler.h"
+#include <babeltrace2/babeltrace.h>
+
+#include "trace-ir-metadata-copy.h"
+#include "trace-ir-metadata-field-class-copy.h"
+
+/*
+ * This fonction walks througth the nested structures field class to resolve a
+ * field path object. A field path is made of indexes inside possibly nested
+ * structures ultimately leading to a field class.
+ */
+static
+const bt_field_class *walk_field_path(const bt_field_path *fp,
+               const bt_field_class *fc)
+{
+       uint64_t i, fp_item_count;
+       const bt_field_class *curr_fc;
+
+       BT_ASSERT(bt_field_class_get_type(fc) == BT_FIELD_CLASS_TYPE_STRUCTURE);
+       BT_LOGD("Walking field path on field class: fp-addr=%p, fc-addr=%p",
+                       fp, fc);
+
+       fp_item_count = bt_field_path_get_item_count(fp);
+       curr_fc = fc;
+       for (i = 0; i < fp_item_count; i++) {
+               bt_field_class_type fc_type = bt_field_class_get_type(curr_fc);
+               const bt_field_path_item *fp_item =
+                       bt_field_path_borrow_item_by_index_const(fp, i);
+
+               switch (fc_type) {
+               case BT_FIELD_CLASS_TYPE_STRUCTURE:
+               {
+                       const bt_field_class_structure_member *member;
+
+                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
+                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
+                       member = bt_field_class_structure_borrow_member_by_index_const(
+                               curr_fc,
+                               bt_field_path_item_index_get_index(fp_item));
+                       curr_fc = bt_field_class_structure_member_borrow_field_class_const(
+                               member);
+                       break;
+               }
+               case BT_FIELD_CLASS_TYPE_VARIANT:
+               {
+                       const bt_field_class_variant_option *option;
+
+                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
+                               BT_FIELD_PATH_ITEM_TYPE_INDEX);
+                       option = bt_field_class_variant_borrow_option_by_index_const(
+                               curr_fc,
+                               bt_field_path_item_index_get_index(fp_item));
+                       curr_fc = bt_field_class_variant_option_borrow_field_class_const(
+                               option);
+                       break;
+               }
+               case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+               case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+               {
+                       BT_ASSERT(bt_field_path_item_get_type(fp_item) ==
+                               BT_FIELD_PATH_ITEM_TYPE_CURRENT_ARRAY_ELEMENT);
+                       curr_fc = bt_field_class_array_borrow_element_field_class_const(
+                               curr_fc);
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+
+       return curr_fc;
+}
+
+static
+const bt_field_class *resolve_field_path_to_field_class(const bt_field_path *fp,
+               struct trace_ir_metadata_maps *md_maps)
+{
+       struct field_class_resolving_context *fc_resolving_ctx;
+       const bt_field_class *fc;
+       bt_scope fp_scope;
+
+       BT_LOGD("Resolving field path: fp-addr=%p", fp);
+
+       fc_resolving_ctx = md_maps->fc_resolving_ctx;
+       fp_scope = bt_field_path_get_root_scope(fp);
+
+       switch (fp_scope) {
+       case BT_SCOPE_PACKET_CONTEXT:
+               fc = walk_field_path(fp, fc_resolving_ctx->packet_context);
+               break;
+       case BT_SCOPE_EVENT_COMMON_CONTEXT:
+               fc = walk_field_path(fp, fc_resolving_ctx->event_common_context);
+               break;
+       case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
+               fc = walk_field_path(fp, fc_resolving_ctx->event_specific_context);
+               break;
+       case BT_SCOPE_EVENT_PAYLOAD:
+               fc = walk_field_path(fp, fc_resolving_ctx->event_payload);
+               break;
+       default:
+               abort();
+       }
+
+       return fc;
+}
+
+static inline
+void field_class_integer_set_props(const bt_field_class *input_fc,
+               bt_field_class *output_fc)
+{
+       bt_field_class_integer_set_preferred_display_base(output_fc,
+                       bt_field_class_integer_get_preferred_display_base(input_fc));
+       bt_field_class_integer_set_field_value_range(output_fc,
+                       bt_field_class_integer_get_field_value_range(input_fc));
+}
+
+static inline
+int field_class_unsigned_integer_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       BT_LOGD("Copying content of unsigned integer field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+       field_class_integer_set_props(in_field_class, out_field_class);
+
+       BT_LOGD("Copied content of unsigned integer field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+       return 0;
+}
+
+static inline
+int field_class_signed_integer_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       BT_LOGD("Copying content of signed integer field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+       field_class_integer_set_props(in_field_class, out_field_class);
+
+       BT_LOGD("Copied content of signed integer field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+       return 0;
+}
+
+BT_HIDDEN
+int field_class_unsigned_enumeration_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       uint64_t i, enum_mapping_count;
+       int ret = 0;
+
+       BT_LOGD("Copying content of unsigned enumeration field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+       /* Copy properties of the inner integer. */
+       field_class_integer_set_props(in_field_class, out_field_class);
+
+       /* Copy all enumeration entries. */
+       enum_mapping_count = bt_field_class_enumeration_get_mapping_count(in_field_class);
+       for (i = 0; i < enum_mapping_count; i++) {
+               const char *label;
+               const bt_field_class_unsigned_enumeration_mapping *u_mapping;
+               const bt_field_class_enumeration_mapping *mapping;
+               uint64_t range_index, range_count;
+
+               /* Get the ranges and the range count. */
+               u_mapping = bt_field_class_unsigned_enumeration_borrow_mapping_by_index_const(
+                               in_field_class, i);
+               mapping = bt_field_class_unsigned_enumeration_mapping_as_mapping_const(
+                       u_mapping);
+               range_count =
+                       bt_field_class_enumeration_mapping_get_range_count(
+                               mapping);
+               label = bt_field_class_enumeration_mapping_get_label(
+                       mapping);
+
+               /*
+                * Iterate over all the ranges to add them to copied field
+                * class.
+                */
+               for (range_index = 0; range_index < range_count; range_index++) {
+                       uint64_t lower, upper;
+                       bt_field_class_status status;
+                       bt_field_class_unsigned_enumeration_mapping_get_range_by_index(
+                                       u_mapping, range_index, &lower, &upper);
+
+                       BT_LOGD("Copying range in enumeration field class: "
+                                       "label=%s, lower=%"PRId64", upper=%"PRId64,
+                                       label, lower, upper);
+
+                       /* Add the label and its range to the copy field class. */
+                       status = bt_field_class_unsigned_enumeration_map_range(
+                                       out_field_class, label, lower, upper);
+
+                       if (status != BT_FIELD_CLASS_STATUS_OK) {
+                               BT_LOGE_STR("Failed to add range to unsigned "
+                                               "enumeration.");
+                               BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class);
+                               ret = -1;
+                               goto error;
+                       }
+               }
+       }
+
+       BT_LOGD("Copied content of unsigned enumeration field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+error:
+       return ret;
+}
+
+static inline
+int field_class_signed_enumeration_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       uint64_t i, enum_mapping_count;
+       int ret = 0;
+
+       BT_LOGD("Copying content of signed enumeration field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+       /* Copy properties of the inner integer. */
+       field_class_integer_set_props(in_field_class, out_field_class);
+
+       /* Copy all enumeration entries. */
+       enum_mapping_count =
+               bt_field_class_enumeration_get_mapping_count(in_field_class);
+       for (i = 0; i < enum_mapping_count; i++) {
+               const char *label;
+               const bt_field_class_signed_enumeration_mapping *i_mapping;
+               const bt_field_class_enumeration_mapping *mapping;
+               uint64_t range_index, range_count;
+
+               /* Get the ranges and the range count. */
+               i_mapping = bt_field_class_signed_enumeration_borrow_mapping_by_index_const(
+                               in_field_class, i);
+               mapping = bt_field_class_signed_enumeration_mapping_as_mapping_const(
+                       i_mapping);
+               range_count =
+                       bt_field_class_enumeration_mapping_get_range_count(
+                               mapping);
+               label = bt_field_class_enumeration_mapping_get_label(
+                       mapping);
+
+               /*
+                * Iterate over all the ranges to add them to copied field
+                * class.
+                */
+               for (range_index = 0; range_index < range_count; range_index++) {
+                       int64_t lower, upper;
+                       bt_field_class_status status;
+                       bt_field_class_signed_enumeration_mapping_get_range_by_index(
+                                       i_mapping, range_index, &lower, &upper);
+
+                       BT_LOGD("Copying range in enumeration field class: "
+                                       "label=%s, lower=%"PRId64", upper=%"PRId64,
+                                       label, lower, upper);
+
+                       /* Add the label and its range to the copy field class. */
+                       status = bt_field_class_signed_enumeration_map_range(
+                                       out_field_class, label, lower, upper);
+                       if (status != BT_FIELD_CLASS_STATUS_OK) {
+                               BT_LOGE_STR("Failed to add range to signed "
+                                               "enumeration.");
+                               BT_FIELD_CLASS_PUT_REF_AND_RESET(out_field_class);
+                               ret = -1;
+                               goto error;
+                       }
+               }
+       }
+
+       BT_LOGD("Copied content of signed enumeration field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+error:
+       return ret;
+}
+
+static inline
+int field_class_real_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       BT_LOGD("Copying content of real field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+       bt_field_class_real_set_is_single_precision(out_field_class,
+                       bt_field_class_real_is_single_precision(in_field_class));
+
+       BT_LOGD("Copied content real field class: in-fc-addr=%p, "
+                       "out-fc-addr=%p", in_field_class, out_field_class);
+
+       return 0;
+}
+
+static inline
+int field_class_structure_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       uint64_t i, struct_member_count;
+       bt_field_class_status status;
+       int ret = 0;
+
+       BT_LOGD("Copying content of structure field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+       /* Get the number of member in that struct. */
+       struct_member_count =
+               bt_field_class_structure_get_member_count(in_field_class);
+
+       /* Iterate over all the members of the struct. */
+       for (i = 0; i < struct_member_count; i++) {
+               const bt_field_class_structure_member *member;
+               const char *member_name;
+               const bt_field_class *member_fc;
+               bt_field_class *out_member_field_class;
+
+               member = bt_field_class_structure_borrow_member_by_index_const(
+                       in_field_class, i);
+               member_fc = bt_field_class_structure_member_borrow_field_class_const(
+                       member);
+               member_name = bt_field_class_structure_member_get_name(member);
+               BT_LOGD("Copying structure field class's field: "
+                       "index=%" PRId64 ", "
+                       "member-fc-addr=%p, field-name=\"%s\"",
+                       i, member_fc, member_name);
+
+               out_member_field_class = create_field_class_copy(md_maps,
+                               member_fc);
+               if (!out_member_field_class) {
+                       BT_LOGE("Cannot copy structure field class's field: "
+                               "index=%" PRId64 ", "
+                               "field-fc-addr=%p, field-name=\"%s\"",
+                               i, member_fc, member_name);
+                       ret = -1;
+                       goto error;
+               }
+               ret = copy_field_class_content(md_maps, member_fc,
+                               out_member_field_class);
+               if (ret) {
+                       goto error;
+               }
+
+               status = bt_field_class_structure_append_member(out_field_class,
+                               member_name, out_member_field_class);
+               if (status != BT_FIELD_CLASS_STATUS_OK) {
+                       BT_LOGE("Cannot append structure field class's field: "
+                               "index=%" PRId64 ", "
+                               "field-fc-addr=%p, field-name=\"%s\"",
+                               i, member_fc, member_name);
+                       BT_FIELD_CLASS_PUT_REF_AND_RESET(out_member_field_class);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Copied structure field class: original-fc-addr=%p, copy-fc-addr=%p",
+               in_field_class, out_field_class);
+
+error:
+       return ret;
+}
+
+static inline
+int field_class_variant_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       bt_field_class *out_tag_field_class = NULL;
+       uint64_t i, variant_option_count;
+       const bt_field_path *tag_fp;
+       const bt_field_class *tag_fc;
+       int ret = 0;
+
+       BT_LOGD("Copying content of variant field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+       tag_fp = bt_field_class_variant_borrow_selector_field_path_const(
+                       in_field_class);
+       if (tag_fp) {
+               tag_fc = resolve_field_path_to_field_class(tag_fp,
+                               md_maps);
+
+               out_tag_field_class = g_hash_table_lookup(
+                               md_maps->field_class_map, tag_fc);
+               if (!out_tag_field_class) {
+                       BT_LOGE_STR("Cannot find the tag field class.");
+                       ret = -1;
+                       goto error;
+               }
+               bt_field_class_variant_set_selector_field_class(out_field_class,
+                               out_tag_field_class);
+       }
+
+       variant_option_count =
+               bt_field_class_variant_get_option_count(in_field_class);
+       for (i = 0; i < variant_option_count; i++) {
+               const bt_field_class *option_fc;
+               const char *option_name;
+               bt_field_class *out_option_field_class;
+               bt_field_class_status status;
+               const bt_field_class_variant_option *option;
+
+               option = bt_field_class_variant_borrow_option_by_index_const(
+                       in_field_class, i);
+               option_fc = bt_field_class_variant_option_borrow_field_class_const(
+                       option);
+               option_name = bt_field_class_variant_option_get_name(option);
+               out_option_field_class = create_field_class_copy_internal(
+                               md_maps, option_fc);
+               if (!out_option_field_class) {
+                       BT_LOGE_STR("Cannot copy field class.");
+                       ret = -1;
+                       goto error;
+               }
+               ret = copy_field_class_content_internal(md_maps, option_fc,
+                               out_option_field_class);
+               if (ret) {
+                       BT_LOGE_STR("Error copying content of option variant "
+                                       "field class'");
+                       goto error;
+               }
+
+               status = bt_field_class_variant_append_option(
+                               out_field_class, option_name,
+                               out_option_field_class);
+               if (status != BT_FIELD_CLASS_STATUS_OK) {
+                       BT_LOGE_STR("Cannot append option to variant field class'");
+                       BT_FIELD_CLASS_PUT_REF_AND_RESET(out_tag_field_class);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Copied content of variant field class: in-fc-addr=%p, "
+               "out-fc-addr=%p", in_field_class, out_field_class);
+
+error:
+       return ret;
+}
+
+static inline
+int field_class_static_array_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       BT_LOGD("Copying content of static array field class: in-fc-addr=%p, "
+                       "out-fc-addr=%p", in_field_class, out_field_class);
+       /*
+        * There is no content to copy. Keep this function call anyway for
+        * logging purposes.
+        */
+       BT_LOGD("Copied content of static array field class: in-fc-addr=%p, "
+                       "out-fc-addr=%p", in_field_class, out_field_class);
+
+       return 0;
+}
+
+static inline
+int field_class_dynamic_array_copy(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       const bt_field_class *len_fc;
+       const bt_field_path *len_fp;
+       bt_field_class_status status;
+       bt_field_class *out_len_field_class;
+       int ret = 0;
+
+       BT_LOGD("Copying content of dynamic array field class: "
+                       "in-fc-addr=%p, out-fc-addr=%p",
+                       in_field_class, out_field_class);
+
+       len_fp = bt_field_class_dynamic_array_borrow_length_field_path_const(
+                       in_field_class);
+
+       if (len_fp) {
+               BT_LOGD("Copying dynamic array length field class using "
+                               "field path: in-len-fp=%p", len_fp);
+               len_fc = resolve_field_path_to_field_class(
+                               len_fp, md_maps);
+               out_len_field_class = g_hash_table_lookup(
+                               md_maps->field_class_map, len_fc);
+               if (!out_len_field_class) {
+                       BT_LOGE_STR("Cannot find the output matching length"
+                                       "field class.");
+                       ret = -1;
+                       goto error;
+               }
+
+               status = bt_field_class_dynamic_array_set_length_field_class(
+                               out_field_class, out_len_field_class);
+               if (status != BT_FIELD_CLASS_STATUS_OK) {
+                       BT_LOGE_STR("Cannot set dynamic array field class' "
+                                       "length field class.");
+                       BT_FIELD_CLASS_PUT_REF_AND_RESET(out_len_field_class);
+                       ret = -1;
+                       goto error;
+               }
+       }
+
+       BT_LOGD("Copied dynamic array field class: in-fc-addr=%p, "
+                       "out-fc-addr=%p", in_field_class, out_field_class);
+
+error:
+       return ret;
+}
+
+static inline
+int field_class_string_copy(struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       BT_LOGD("Copying content of string field class: in-fc-addr=%p, "
+                       "out-fc-addr=%p", in_field_class, out_field_class);
+       /*
+        * There is no content to copy. Keep this function call anyway for
+        * logging purposes.
+        */
+       BT_LOGD("Copied content of string field class: in-fc-addr=%p, "
+                       "out-fc-addr=%p", in_field_class, out_field_class);
+
+       return 0;
+}
+
+static
+bt_field_class *copy_field_class_array_element(struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_elem_fc)
+{
+       int ret;
+       bt_field_class *out_elem_fc =
+               create_field_class_copy_internal(md_maps, in_elem_fc);
+       if (!out_elem_fc) {
+               BT_LOGE("Error creating output elem field class "
+                               "from input elem field class for static array: "
+                               "in-fc-addr=%p", in_elem_fc);
+               goto error;
+       }
+
+       ret = copy_field_class_content_internal(md_maps, in_elem_fc, out_elem_fc);
+       if (ret) {
+               BT_LOGE("Error creating output elem field class "
+                               "from input elem field class for static array: "
+                               "in-fc-addr=%p", in_elem_fc);
+               BT_FIELD_CLASS_PUT_REF_AND_RESET(out_elem_fc);
+               goto error;
+       }
+
+error:
+       return out_elem_fc;
+}
+
+BT_HIDDEN
+bt_field_class *create_field_class_copy_internal(struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class)
+{
+       bt_field_class *out_field_class = NULL;
+
+       BT_LOGD("Creating bare field class based on field class: in-fc-addr=%p",
+                       in_field_class);
+
+       switch(bt_field_class_get_type(in_field_class)) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
+               out_field_class = bt_field_class_unsigned_integer_create(
+                               md_maps->output_trace_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
+               out_field_class = bt_field_class_signed_integer_create(
+                               md_maps->output_trace_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+               out_field_class = bt_field_class_unsigned_enumeration_create(
+                               md_maps->output_trace_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+               out_field_class = bt_field_class_signed_enumeration_create(
+                               md_maps->output_trace_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_REAL:
+               out_field_class = bt_field_class_real_create(
+                               md_maps->output_trace_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_STRING:
+               out_field_class = bt_field_class_string_create(
+                               md_maps->output_trace_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+               out_field_class = bt_field_class_structure_create(
+                               md_maps->output_trace_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+       {
+               const bt_field_class *in_elem_fc =
+                       bt_field_class_array_borrow_element_field_class_const(
+                                       in_field_class);
+               uint64_t array_len =
+                       bt_field_class_static_array_get_length(in_field_class);
+
+               bt_field_class *out_elem_fc = copy_field_class_array_element(
+                               md_maps, in_elem_fc);
+               if (!out_elem_fc) {
+                       out_field_class = NULL;
+                       goto error;
+               }
+
+               out_field_class = bt_field_class_static_array_create(
+                               md_maps->output_trace_class,
+                               out_elem_fc, array_len);
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+       {
+               const bt_field_class *in_elem_fc =
+                       bt_field_class_array_borrow_element_field_class_const(
+                                       in_field_class);
+
+               bt_field_class *out_elem_fc = copy_field_class_array_element(
+                               md_maps, in_elem_fc);
+               if (!out_elem_fc) {
+                       out_field_class = NULL;
+                       goto error;
+               }
+
+               out_field_class = bt_field_class_dynamic_array_create(
+                               md_maps->output_trace_class,
+                               out_elem_fc);
+               break;
+       }
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+               out_field_class = bt_field_class_variant_create(
+                               md_maps->output_trace_class);
+               break;
+       default:
+               abort();
+       }
+
+       /*
+        * Add mapping from in_field_class to out_field_class. This simplifies
+        * the resolution of field paths in variant and dynamic array field
+        * classes.
+        */
+       g_hash_table_insert(md_maps->field_class_map,
+                       (gpointer) in_field_class, out_field_class);
+
+error:
+       if(out_field_class){
+               BT_LOGD("Created bare field class based on field class: in-fc-addr=%p, "
+                               "out-fc-addr=%p", in_field_class, out_field_class);
+       } else {
+               BT_LOGE("Error creating output field class from input field "
+                       "class: in-fc-addr=%p", in_field_class);
+       }
+
+       return out_field_class;
+}
+
+BT_HIDDEN
+int copy_field_class_content_internal(
+               struct trace_ir_metadata_maps *md_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class)
+{
+       int ret = 0;
+       switch(bt_field_class_get_type(in_field_class)) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
+               ret = field_class_unsigned_integer_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
+               ret = field_class_signed_integer_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+               ret = field_class_unsigned_enumeration_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+               ret = field_class_signed_enumeration_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_REAL:
+               ret = field_class_real_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_STRING:
+               ret = field_class_string_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+               ret = field_class_structure_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+               ret = field_class_static_array_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+               ret = field_class_dynamic_array_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+               ret = field_class_variant_copy(md_maps,
+                               in_field_class, out_field_class);
+               break;
+       default:
+               abort();
+       }
+
+       return ret;
+}
diff --git a/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h b/src/plugins/lttng-utils/debug-info/trace-ir-metadata-field-class-copy.h
new file mode 100644 (file)
index 0000000..3bd5b80
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H
+#define BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H
+
+/*
+ * Babeltrace - Trace IR metadata field class copy
+ *
+ * Copyright (c) 2015-2019 EfficiOS Inc. and Linux Foundation
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "trace-ir-mapping.h"
+
+BT_HIDDEN
+int copy_field_class_content_internal(struct trace_ir_metadata_maps *trace_ir_metadata_maps,
+               const bt_field_class *in_field_class,
+               bt_field_class *out_field_class);
+
+BT_HIDDEN
+bt_field_class *create_field_class_copy_internal(
+               struct trace_ir_metadata_maps *trace_ir_metadata_maps,
+               const bt_field_class *in_field_class);
+
+#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_FIELD_CLASS_COPY_H */
diff --git a/src/plugins/lttng-utils/debug-info/utils.c b/src/plugins/lttng-utils/debug-info/utils.c
new file mode 100644 (file)
index 0000000..8f1bdde
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Babeltrace - Debug info utilities
+ *
+ * Copyright (c) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "utils.h"
+
+BT_HIDDEN
+const char *get_filename_from_path(const char *path)
+{
+       size_t i = strlen(path);
+
+       if (i == 0) {
+               goto end;
+       }
+
+       if (path[i - 1] == '/') {
+               /*
+                * Path ends with a trailing slash, no filename to return.
+                * Return the original path.
+                */
+               goto end;
+       }
+
+       while (i-- > 0) {
+               if (path[i] == '/') {
+                       path = &path[i + 1];
+                       goto end;
+               }
+       }
+end:
+       return path;
+}
+
+BT_HIDDEN
+bt_bool is_event_common_ctx_dbg_info_compatible(const bt_field_class *in_field_class,
+               const char *debug_info_field_class_name)
+{
+       const bt_field_class_structure_member *member;
+       const bt_field_class *ip_fc, *vpid_fc;
+       bt_bool match = BT_FALSE;
+
+       /*
+        * If the debug info field is already present in the event common
+        * context. Do not try to add it.
+        */
+       member =
+               bt_field_class_structure_borrow_member_by_name_const(
+                       in_field_class, debug_info_field_class_name);
+       if (member) {
+               goto end;
+       }
+
+       /*
+        * Verify that the ip and vpid field are present and of the right field
+        * class.
+        */
+       member = bt_field_class_structure_borrow_member_by_name_const(
+                       in_field_class, IP_FIELD_NAME);
+       if (!member) {
+               goto end;
+       }
+
+       ip_fc = bt_field_class_structure_member_borrow_field_class_const(
+               member);
+       if (bt_field_class_get_type(ip_fc) !=
+                       BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER) {
+               match = BT_FALSE;
+               goto end;
+       }
+
+       member = bt_field_class_structure_borrow_member_by_name_const(
+                       in_field_class, VPID_FIELD_NAME);
+       if (!member) {
+               goto end;
+       }
+
+       vpid_fc = bt_field_class_structure_member_borrow_field_class_const(
+               member);
+
+       if (bt_field_class_get_type(vpid_fc) !=
+                       BT_FIELD_CLASS_TYPE_SIGNED_INTEGER) {
+               goto end;
+       }
+
+       if (bt_field_class_integer_get_field_value_range(vpid_fc) != 32) {
+               goto end;
+       }
+
+       match = BT_TRUE;
+
+end:
+       return match;
+}
diff --git a/src/plugins/lttng-utils/debug-info/utils.h b/src/plugins/lttng-utils/debug-info/utils.h
new file mode 100644 (file)
index 0000000..393f34e
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H
+#define BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H
+/*
+ * Babeltrace - Debug Info Utilities
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/babeltrace.h"
+#include "trace-ir-mapping.h"
+
+/*
+ * Return the location of a path's file (the last element of the path).
+ * Returns the original path on error.
+ */
+BT_HIDDEN
+const char *get_filename_from_path(const char *path);
+
+BT_HIDDEN
+bt_bool is_event_common_ctx_dbg_info_compatible(
+               const bt_field_class *in_field_class,
+               const char *debug_info_field_class_name);
+
+#endif /* BABELTRACE_PLUGIN_DEBUG_INFO_UTILS_H */
diff --git a/src/plugins/lttng-utils/plugin.c b/src/plugins/lttng-utils/plugin.c
new file mode 100644 (file)
index 0000000..8d50b0e
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * plugin.c
+ *
+ * Babeltrace Debug Info Plug-in
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "debug-info/debug-info.h"
+
+#ifndef BT_BUILT_IN_PLUGINS
+BT_PLUGIN_MODULE();
+#endif
+
+/* Initialize plug-in entry points. */
+BT_PLUGIN_WITH_ID(lttng_utils, "lttng-utils");
+BT_PLUGIN_DESCRIPTION_WITH_ID(lttng_utils, "LTTng utilities");
+BT_PLUGIN_AUTHOR_WITH_ID(lttng_utils, "Julien Desfossez");
+BT_PLUGIN_LICENSE_WITH_ID(lttng_utils, "MIT");
+
+BT_PLUGIN_FILTER_COMPONENT_CLASS_WITH_ID(lttng_utils, debug_info, "debug-info",
+       debug_info_msg_iter_next);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION_WITH_ID(lttng_utils, debug_info,
+       "Augment compatible events with debugging information.");
+BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD_WITH_ID(lttng_utils,
+       debug_info, debug_info_comp_init);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD_WITH_ID(lttng_utils,
+       debug_info, debug_info_comp_finalize);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD_WITH_ID(
+       lttng_utils, debug_info, debug_info_msg_iter_init);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD_WITH_ID(
+       lttng_utils, debug_info, debug_info_msg_iter_seek_beginning);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CAN_SEEK_BEGINNING_METHOD_WITH_ID(
+       lttng_utils, debug_info, debug_info_msg_iter_can_seek_beginning);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD_WITH_ID(
+       lttng_utils, debug_info, debug_info_msg_iter_finalize);
diff --git a/src/plugins/plugins-common.h b/src/plugins/plugins-common.h
new file mode 100644 (file)
index 0000000..c7377bf
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef PLUGINS_COMMON_H
+#define PLUGINS_COMMON_H
+
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * UNUSED_VAR: tag a variable or parameter as explicitly unused so that
+ *             the compiler does not warn.
+ */
+#define UNUSED_VAR __attribute__((unused))
+
+#endif /* PLUGINS_COMMON_H */
diff --git a/src/plugins/text/Makefile.am b/src/plugins/text/Makefile.am
new file mode 100644 (file)
index 0000000..f717910
--- /dev/null
@@ -0,0 +1,21 @@
+SUBDIRS = pretty dmesg
+
+plugindir = "$(PLUGINSDIR)"
+plugin_LTLIBRARIES = babeltrace-plugin-text.la
+
+babeltrace_plugin_text_la_SOURCES = plugin.c
+babeltrace_plugin_text_la_LDFLAGS = \
+       $(LT_NO_UNDEFINED) \
+       -avoid-version -module
+
+babeltrace_plugin_text_la_LIBADD = \
+       pretty/libbabeltrace2-plugin-text-pretty-cc.la \
+       dmesg/libbabeltrace2-plugin-text-dmesg-cc.la
+
+if !ENABLE_BUILT_IN_PLUGINS
+babeltrace_plugin_text_la_LIBADD += \
+       $(top_builddir)/src/lib/libbabeltrace2.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(top_builddir)/src/compat/libcompat.la
+endif
diff --git a/src/plugins/text/dmesg/Makefile.am b/src/plugins/text/dmesg/Makefile.am
new file mode 100644 (file)
index 0000000..6f168b3
--- /dev/null
@@ -0,0 +1,8 @@
+noinst_LTLIBRARIES = libbabeltrace2-plugin-text-dmesg-cc.la
+
+# ctf-text plugin
+libbabeltrace2_plugin_text_dmesg_cc_la_SOURCES = \
+       dmesg.c \
+       dmesg.h \
+       logging.h \
+       logging.c
diff --git a/src/plugins/text/dmesg/dmesg.c b/src/plugins/text/dmesg/dmesg.c
new file mode 100644 (file)
index 0000000..7ed01cd
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+ * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-TEXT-DMESG-SRC"
+#include "logging.h"
+
+#include <stdbool.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include "common/assert.h"
+#include "common/common.h"
+#include <babeltrace2/babeltrace.h>
+#include "lib/value.h"
+#include "compat/utc.h"
+#include "compat/stdio.h"
+#include <glib.h>
+
+#define NSEC_PER_USEC 1000UL
+#define NSEC_PER_MSEC 1000000UL
+#define NSEC_PER_SEC 1000000000ULL
+#define USEC_PER_SEC 1000000UL
+
+struct dmesg_component;
+
+struct dmesg_msg_iter {
+       struct dmesg_component *dmesg_comp;
+       bt_self_message_iterator *pc_msg_iter; /* Weak */
+       char *linebuf;
+       size_t linebuf_len;
+       FILE *fp;
+       bt_message *tmp_event_msg;
+       uint64_t last_clock_value;
+
+       enum {
+               STATE_EMIT_STREAM_BEGINNING,
+               STATE_EMIT_STREAM_ACTIVITY_BEGINNING,
+               STATE_EMIT_PACKET_BEGINNING,
+               STATE_EMIT_EVENT,
+               STATE_EMIT_PACKET_END,
+               STATE_EMIT_STREAM_ACTIVITY_END,
+               STATE_EMIT_STREAM_END,
+               STATE_DONE,
+       } state;
+};
+
+struct dmesg_component {
+       struct {
+               GString *path;
+               bt_bool read_from_stdin;
+               bt_bool no_timestamp;
+       } params;
+
+       bt_self_component_source *self_comp;
+       bt_trace_class *trace_class;
+       bt_stream_class *stream_class;
+       bt_event_class *event_class;
+       bt_trace *trace;
+       bt_stream *stream;
+       bt_packet *packet;
+       bt_clock_class *clock_class;
+};
+
+static
+bt_field_class *create_event_payload_fc(bt_trace_class *trace_class)
+{
+       bt_field_class *root_fc = NULL;
+       bt_field_class *fc = NULL;
+       int ret;
+
+       root_fc = bt_field_class_structure_create(trace_class);
+       if (!root_fc) {
+               BT_LOGE_STR("Cannot create an empty structure field class object.");
+               goto error;
+       }
+
+       fc = bt_field_class_string_create(trace_class);
+       if (!fc) {
+               BT_LOGE_STR("Cannot create a string field class object.");
+               goto error;
+       }
+
+       ret = bt_field_class_structure_append_member(root_fc,
+               "str", fc);
+       if (ret) {
+               BT_LOGE("Cannot add `str` member to structure field class: "
+                       "ret=%d", ret);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_FIELD_CLASS_PUT_REF_AND_RESET(root_fc);
+
+end:
+       bt_field_class_put_ref(fc);
+       return root_fc;
+}
+
+static
+int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
+{
+       bt_field_class *fc = NULL;
+       int ret = 0;
+
+       dmesg_comp->trace_class = bt_trace_class_create(
+               bt_self_component_source_as_self_component(
+                       dmesg_comp->self_comp));
+       if (!dmesg_comp->trace_class) {
+               BT_LOGE_STR("Cannot create an empty trace class object.");
+               goto error;
+       }
+
+       dmesg_comp->stream_class = bt_stream_class_create(
+               dmesg_comp->trace_class);
+       if (!dmesg_comp->stream_class) {
+               BT_LOGE_STR("Cannot create a stream class object.");
+               goto error;
+       }
+
+       if (has_ts) {
+               dmesg_comp->clock_class = bt_clock_class_create(
+                               bt_self_component_source_as_self_component(
+                                       dmesg_comp->self_comp));
+               if (!dmesg_comp->clock_class) {
+                       BT_LOGE_STR("Cannot create clock class.");
+                       goto error;
+               }
+
+               /*
+                * The `dmesg` timestamp's origin is not the Unix epoch,
+                * it's the boot time.
+                */
+               bt_clock_class_set_origin_is_unix_epoch(dmesg_comp->clock_class,
+                       BT_FALSE);
+
+               ret = bt_stream_class_set_default_clock_class(
+                       dmesg_comp->stream_class, dmesg_comp->clock_class);
+               if (ret) {
+                       BT_LOGE_STR("Cannot set stream class's default clock class.");
+                       goto error;
+               }
+
+               bt_stream_class_set_packets_have_beginning_default_clock_snapshot(
+                       dmesg_comp->stream_class, BT_TRUE);
+               bt_stream_class_set_packets_have_end_default_clock_snapshot(
+                       dmesg_comp->stream_class, BT_TRUE);
+       }
+
+       dmesg_comp->event_class = bt_event_class_create(
+               dmesg_comp->stream_class);
+       if (!dmesg_comp->event_class) {
+               BT_LOGE_STR("Cannot create an event class object.");
+               goto error;
+       }
+
+       ret = bt_event_class_set_name(dmesg_comp->event_class, "string");
+       if (ret) {
+               BT_LOGE_STR("Cannot set event class's name.");
+               goto error;
+       }
+
+       fc = create_event_payload_fc(dmesg_comp->trace_class);
+       if (!fc) {
+               BT_LOGE_STR("Cannot create event payload field class.");
+               goto error;
+       }
+
+       ret = bt_event_class_set_payload_field_class(dmesg_comp->event_class, fc);
+       if (ret) {
+               BT_LOGE_STR("Cannot set event class's event payload field class.");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       bt_field_class_put_ref(fc);
+       return ret;
+}
+
+static
+int handle_params(struct dmesg_component *dmesg_comp,
+               const bt_value *params)
+{
+       const bt_value *no_timestamp = NULL;
+       const bt_value *path = NULL;
+       const char *path_str;
+       int ret = 0;
+
+       no_timestamp = bt_value_map_borrow_entry_value_const(params,
+               "no-extract-timestamp");
+       if (no_timestamp) {
+               if (!bt_value_is_bool(no_timestamp)) {
+                       BT_LOGE("Expecting a boolean value for the `no-extract-timestamp` parameter: "
+                               "type=%s",
+                               bt_common_value_type_string(
+                                       bt_value_get_type(no_timestamp)));
+                       goto error;
+               }
+
+               dmesg_comp->params.no_timestamp =
+                       bt_value_bool_get(no_timestamp);
+       }
+
+       path = bt_value_map_borrow_entry_value_const(params, "path");
+       if (path) {
+               if (dmesg_comp->params.read_from_stdin) {
+                       BT_LOGE_STR("Cannot specify both `read-from-stdin` and `path` parameters.");
+                       goto error;
+               }
+
+               if (!bt_value_is_string(path)) {
+                       BT_LOGE("Expecting a string value for the `path` parameter: "
+                               "type=%s",
+                               bt_common_value_type_string(
+                                       bt_value_get_type(path)));
+                       goto error;
+               }
+
+               path_str = bt_value_string_get(path);
+               g_string_assign(dmesg_comp->params.path, path_str);
+       } else {
+               dmesg_comp->params.read_from_stdin = true;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int create_packet_and_stream_and_trace(struct dmesg_component *dmesg_comp)
+{
+       int ret = 0;
+       const char *trace_name = NULL;
+       gchar *basename = NULL;
+
+       dmesg_comp->trace = bt_trace_create(dmesg_comp->trace_class);
+       if (!dmesg_comp->trace) {
+               BT_LOGE_STR("Cannot create trace object.");
+               goto error;
+       }
+
+       if (dmesg_comp->params.read_from_stdin) {
+               trace_name = "STDIN";
+       } else {
+               basename = g_path_get_basename(dmesg_comp->params.path->str);
+               BT_ASSERT(basename);
+
+               if (strcmp(basename, G_DIR_SEPARATOR_S) != 0 &&
+                               strcmp(basename, ".") != 0) {
+                       trace_name = basename;
+               }
+       }
+
+       if (trace_name) {
+               ret = bt_trace_set_name(dmesg_comp->trace, trace_name);
+               if (ret) {
+                       BT_LOGE("Cannot set trace's name: name=\"%s\"",
+                               trace_name);
+                       goto error;
+               }
+       }
+
+       dmesg_comp->stream = bt_stream_create(dmesg_comp->stream_class,
+               dmesg_comp->trace);
+       if (!dmesg_comp->stream) {
+               BT_LOGE_STR("Cannot create stream object.");
+               goto error;
+       }
+
+       dmesg_comp->packet = bt_packet_create(dmesg_comp->stream);
+       if (!dmesg_comp->packet) {
+               BT_LOGE_STR("Cannot create packet object.");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       if (basename) {
+               g_free(basename);
+       }
+
+       return ret;
+}
+
+static
+int try_create_meta_stream_packet(struct dmesg_component *dmesg_comp,
+               bool has_ts)
+{
+       int ret = 0;
+
+       if (dmesg_comp->trace) {
+               /* Already created */
+               goto end;
+       }
+
+       ret = create_meta(dmesg_comp, has_ts);
+       if (ret) {
+               BT_LOGE("Cannot create metadata objects: dmesg-comp-addr=%p",
+                       dmesg_comp);
+               goto error;
+       }
+
+       ret = create_packet_and_stream_and_trace(dmesg_comp);
+       if (ret) {
+               BT_LOGE("Cannot create packet and stream objects: "
+                       "dmesg-comp-addr=%p", dmesg_comp);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+void destroy_dmesg_component(struct dmesg_component *dmesg_comp)
+{
+       if (!dmesg_comp) {
+               return;
+       }
+
+       if (dmesg_comp->params.path) {
+               g_string_free(dmesg_comp->params.path, TRUE);
+       }
+
+       bt_packet_put_ref(dmesg_comp->packet);
+       bt_trace_put_ref(dmesg_comp->trace);
+       bt_stream_class_put_ref(dmesg_comp->stream_class);
+       bt_event_class_put_ref(dmesg_comp->event_class);
+       bt_stream_put_ref(dmesg_comp->stream);
+       bt_clock_class_put_ref(dmesg_comp->clock_class);
+       bt_trace_class_put_ref(dmesg_comp->trace_class);
+       g_free(dmesg_comp);
+}
+
+static
+bt_self_component_status create_port(
+               bt_self_component_source *self_comp)
+{
+       return bt_self_component_source_add_output_port(self_comp,
+               "out", NULL, NULL);
+}
+
+BT_HIDDEN
+bt_self_component_status dmesg_init(
+               bt_self_component_source *self_comp,
+               bt_value *params, void *init_method_data)
+{
+       int ret = 0;
+       struct dmesg_component *dmesg_comp = g_new0(struct dmesg_component, 1);
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+
+       if (!dmesg_comp) {
+               BT_LOGE_STR("Failed to allocate one dmesg component structure.");
+               goto error;
+       }
+
+       dmesg_comp->self_comp = self_comp;
+       dmesg_comp->params.path = g_string_new(NULL);
+       if (!dmesg_comp->params.path) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               goto error;
+       }
+
+       ret = handle_params(dmesg_comp, params);
+       if (ret) {
+               BT_LOGE("Invalid parameters: comp-addr=%p", self_comp);
+               goto error;
+       }
+
+       if (!dmesg_comp->params.read_from_stdin &&
+                       !g_file_test(dmesg_comp->params.path->str,
+                       G_FILE_TEST_IS_REGULAR)) {
+               BT_LOGE("Input path is not a regular file: "
+                       "comp-addr=%p, path=\"%s\"", self_comp,
+                       dmesg_comp->params.path->str);
+               goto error;
+       }
+
+       status = create_port(self_comp);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto error;
+       }
+
+       bt_self_component_set_data(
+               bt_self_component_source_as_self_component(self_comp),
+               dmesg_comp);
+       goto end;
+
+error:
+       destroy_dmesg_component(dmesg_comp);
+       bt_self_component_set_data(
+               bt_self_component_source_as_self_component(self_comp),
+               NULL);
+
+       if (status >= 0) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+       }
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+void dmesg_finalize(bt_self_component_source *self_comp)
+{
+       destroy_dmesg_component(bt_self_component_get_data(
+               bt_self_component_source_as_self_component(self_comp)));
+}
+
+static
+bt_message *create_init_event_msg_from_line(
+               struct dmesg_msg_iter *msg_iter,
+               const char *line, const char **new_start)
+{
+       bt_event *event;
+       bt_message *msg = NULL;
+       bool has_timestamp = false;
+       unsigned long sec, usec, msec;
+       unsigned int year, mon, mday, hour, min;
+       uint64_t ts = 0;
+       int ret = 0;
+       struct dmesg_component *dmesg_comp = msg_iter->dmesg_comp;
+
+       *new_start = line;
+
+       if (dmesg_comp->params.no_timestamp) {
+               goto skip_ts;
+       }
+
+       /* Extract time from input line */
+       if (sscanf(line, "[%lu.%lu] ", &sec, &usec) == 2) {
+               ts = (uint64_t) sec * USEC_PER_SEC + (uint64_t) usec;
+
+               /*
+                * The clock class we use has a 1 GHz frequency: convert
+                * from µs to ns.
+                */
+               ts *= NSEC_PER_USEC;
+               has_timestamp = true;
+       } else if (sscanf(line, "[%u-%u-%u %u:%u:%lu.%lu] ",
+                       &year, &mon, &mday, &hour, &min,
+                       &sec, &msec) == 7) {
+               time_t ep_sec;
+               struct tm ti;
+
+               memset(&ti, 0, sizeof(ti));
+               ti.tm_year = year - 1900;       /* From 1900 */
+               ti.tm_mon = mon - 1;            /* 0 to 11 */
+               ti.tm_mday = mday;
+               ti.tm_hour = hour;
+               ti.tm_min = min;
+               ti.tm_sec = sec;
+
+               ep_sec = bt_timegm(&ti);
+               if (ep_sec != (time_t) -1) {
+                       ts = (uint64_t) ep_sec * NSEC_PER_SEC
+                               + (uint64_t) msec * NSEC_PER_MSEC;
+               }
+
+               has_timestamp = true;
+       }
+
+       if (has_timestamp) {
+               /* Set new start for the message portion of the line */
+               *new_start = strchr(line, ']');
+               BT_ASSERT(*new_start);
+               (*new_start)++;
+
+               if ((*new_start)[0] == ' ') {
+                       (*new_start)++;
+               }
+       }
+
+skip_ts:
+       /*
+        * At this point, we know if the stream class's event header
+        * field class should have a timestamp or not, so we can lazily
+        * create the metadata, stream, and packet objects.
+        */
+       ret = try_create_meta_stream_packet(dmesg_comp, has_timestamp);
+       if (ret) {
+               /* try_create_meta_stream_packet() logs errors */
+               goto error;
+       }
+
+       if (dmesg_comp->clock_class) {
+               msg = bt_message_event_create_with_default_clock_snapshot(
+                       msg_iter->pc_msg_iter,
+                       dmesg_comp->event_class, dmesg_comp->packet, ts);
+               msg_iter->last_clock_value = ts;
+       } else {
+               msg = bt_message_event_create(msg_iter->pc_msg_iter,
+                       dmesg_comp->event_class, dmesg_comp->packet);
+       }
+
+       if (!msg) {
+               BT_LOGE_STR("Cannot create event message.");
+               goto error;
+       }
+
+       event = bt_message_event_borrow_event(msg);
+       BT_ASSERT(event);
+       goto end;
+
+error:
+       BT_MESSAGE_PUT_REF_AND_RESET(msg);
+
+end:
+       return msg;
+}
+
+static
+int fill_event_payload_from_line(const char *line,
+               bt_event *event)
+{
+       bt_field *ep_field = NULL;
+       bt_field *str_field = NULL;
+       size_t len;
+       int ret;
+
+       ep_field = bt_event_borrow_payload_field(event);
+       BT_ASSERT(ep_field);
+       str_field = bt_field_structure_borrow_member_field_by_index(
+               ep_field, 0);
+       if (!str_field) {
+               BT_LOGE_STR("Cannot borrow `timestamp` field from event payload structure field.");
+               goto error;
+       }
+
+       len = strlen(line);
+       if (line[len - 1] == '\n') {
+               /* Do not include the newline character in the payload */
+               len--;
+       }
+
+       ret = bt_field_string_clear(str_field);
+       if (ret) {
+               BT_LOGE_STR("Cannot clear string field object.");
+               goto error;
+       }
+
+       ret = bt_field_string_append_with_length(str_field, line, len);
+       if (ret) {
+               BT_LOGE("Cannot append value to string field object: "
+                       "len=%zu", len);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+bt_message *create_msg_from_line(
+               struct dmesg_msg_iter *dmesg_msg_iter, const char *line)
+{
+       bt_event *event = NULL;
+       bt_message *msg = NULL;
+       const char *new_start;
+       int ret;
+
+       msg = create_init_event_msg_from_line(dmesg_msg_iter,
+               line, &new_start);
+       if (!msg) {
+               BT_LOGE_STR("Cannot create and initialize event message from line.");
+               goto error;
+       }
+
+       event = bt_message_event_borrow_event(msg);
+       BT_ASSERT(event);
+       ret = fill_event_payload_from_line(new_start, event);
+       if (ret) {
+               BT_LOGE("Cannot fill event payload field from line: "
+                       "ret=%d", ret);
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_MESSAGE_PUT_REF_AND_RESET(msg);
+
+end:
+       return msg;
+}
+
+static
+void destroy_dmesg_msg_iter(struct dmesg_msg_iter *dmesg_msg_iter)
+{
+       if (!dmesg_msg_iter) {
+               return;
+       }
+
+       if (dmesg_msg_iter->fp && dmesg_msg_iter->fp != stdin) {
+               if (fclose(dmesg_msg_iter->fp)) {
+                       BT_LOGE_ERRNO("Cannot close input file", ".");
+               }
+       }
+
+       bt_message_put_ref(dmesg_msg_iter->tmp_event_msg);
+       free(dmesg_msg_iter->linebuf);
+       g_free(dmesg_msg_iter);
+}
+
+
+
+BT_HIDDEN
+bt_self_message_iterator_status dmesg_msg_iter_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_source *self_comp,
+               bt_self_component_port_output *self_port)
+{
+       struct dmesg_component *dmesg_comp;
+       struct dmesg_msg_iter *dmesg_msg_iter =
+               g_new0(struct dmesg_msg_iter, 1);
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       if (!dmesg_msg_iter) {
+               BT_LOGE_STR("Failed to allocate on dmesg message iterator structure.");
+               goto error;
+       }
+
+       dmesg_comp = bt_self_component_get_data(
+               bt_self_component_source_as_self_component(self_comp));
+       BT_ASSERT(dmesg_comp);
+       dmesg_msg_iter->dmesg_comp = dmesg_comp;
+       dmesg_msg_iter->pc_msg_iter = self_msg_iter;
+
+       if (dmesg_comp->params.read_from_stdin) {
+               dmesg_msg_iter->fp = stdin;
+       } else {
+               dmesg_msg_iter->fp = fopen(dmesg_comp->params.path->str, "r");
+               if (!dmesg_msg_iter->fp) {
+                       BT_LOGE_ERRNO("Cannot open input file in read mode", ": path=\"%s\"",
+                               dmesg_comp->params.path->str);
+                       goto error;
+               }
+       }
+
+       bt_self_message_iterator_set_data(self_msg_iter,
+               dmesg_msg_iter);
+       goto end;
+
+error:
+       destroy_dmesg_msg_iter(dmesg_msg_iter);
+       bt_self_message_iterator_set_data(self_msg_iter, NULL);
+       if (status >= 0) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+       }
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+void dmesg_msg_iter_finalize(
+               bt_self_message_iterator *priv_msg_iter)
+{
+       destroy_dmesg_msg_iter(bt_self_message_iterator_get_data(
+               priv_msg_iter));
+}
+
+static
+bt_self_message_iterator_status dmesg_msg_iter_next_one(
+               struct dmesg_msg_iter *dmesg_msg_iter,
+               bt_message **msg)
+{
+       ssize_t len;
+       struct dmesg_component *dmesg_comp;
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_ASSERT(dmesg_msg_iter);
+       dmesg_comp = dmesg_msg_iter->dmesg_comp;
+       BT_ASSERT(dmesg_comp);
+
+       if (dmesg_msg_iter->state == STATE_DONE) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+               goto end;
+       }
+
+       if (dmesg_msg_iter->tmp_event_msg ||
+                       dmesg_msg_iter->state == STATE_EMIT_PACKET_END ||
+                       dmesg_msg_iter->state == STATE_EMIT_STREAM_ACTIVITY_END ||
+                       dmesg_msg_iter->state == STATE_EMIT_STREAM_END) {
+               goto handle_state;
+       }
+
+       while (true) {
+               const char *ch;
+               bool only_spaces = true;
+
+               len = bt_getline(&dmesg_msg_iter->linebuf,
+                       &dmesg_msg_iter->linebuf_len, dmesg_msg_iter->fp);
+               if (len < 0) {
+                       if (errno == EINVAL) {
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                       } else if (errno == ENOMEM) {
+                               status =
+                                       BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+                       } else {
+                               if (dmesg_msg_iter->state == STATE_EMIT_STREAM_BEGINNING) {
+                                       /* Stream did not even begin */
+                                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+                                       goto end;
+                               } else {
+                                       /* End current packet now */
+                                       dmesg_msg_iter->state =
+                                               STATE_EMIT_PACKET_END;
+                                       goto handle_state;
+                               }
+                       }
+
+                       goto end;
+               }
+
+               BT_ASSERT(dmesg_msg_iter->linebuf);
+
+               /* Ignore empty lines, once trimmed */
+               for (ch = dmesg_msg_iter->linebuf; *ch != '\0'; ch++) {
+                       if (!isspace(*ch)) {
+                               only_spaces = false;
+                               break;
+                       }
+               }
+
+               if (!only_spaces) {
+                       break;
+               }
+       }
+
+       dmesg_msg_iter->tmp_event_msg = create_msg_from_line(
+               dmesg_msg_iter, dmesg_msg_iter->linebuf);
+       if (!dmesg_msg_iter->tmp_event_msg) {
+               BT_LOGE("Cannot create event message from line: "
+                       "dmesg-comp-addr=%p, line=\"%s\"", dmesg_comp,
+                       dmesg_msg_iter->linebuf);
+               goto end;
+       }
+
+handle_state:
+       BT_ASSERT(dmesg_comp->trace);
+
+       switch (dmesg_msg_iter->state) {
+       case STATE_EMIT_STREAM_BEGINNING:
+               BT_ASSERT(dmesg_msg_iter->tmp_event_msg);
+               *msg = bt_message_stream_beginning_create(
+                       dmesg_msg_iter->pc_msg_iter, dmesg_comp->stream);
+               dmesg_msg_iter->state = STATE_EMIT_STREAM_ACTIVITY_BEGINNING;
+               break;
+       case STATE_EMIT_STREAM_ACTIVITY_BEGINNING:
+               BT_ASSERT(dmesg_msg_iter->tmp_event_msg);
+               *msg = bt_message_stream_activity_beginning_create(
+                       dmesg_msg_iter->pc_msg_iter, dmesg_comp->stream);
+               dmesg_msg_iter->state = STATE_EMIT_PACKET_BEGINNING;
+               break;
+       case STATE_EMIT_PACKET_BEGINNING:
+               BT_ASSERT(dmesg_msg_iter->tmp_event_msg);
+
+               if (dmesg_comp->clock_class) {
+                       *msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
+                               dmesg_msg_iter->pc_msg_iter, dmesg_comp->packet,
+                               dmesg_msg_iter->last_clock_value);
+               } else {
+                       *msg = bt_message_packet_beginning_create(
+                               dmesg_msg_iter->pc_msg_iter, dmesg_comp->packet);
+               }
+
+               dmesg_msg_iter->state = STATE_EMIT_EVENT;
+               break;
+       case STATE_EMIT_EVENT:
+               BT_ASSERT(dmesg_msg_iter->tmp_event_msg);
+               *msg = dmesg_msg_iter->tmp_event_msg;
+               dmesg_msg_iter->tmp_event_msg = NULL;
+               break;
+       case STATE_EMIT_PACKET_END:
+               if (dmesg_comp->clock_class) {
+                       *msg = bt_message_packet_end_create_with_default_clock_snapshot(
+                               dmesg_msg_iter->pc_msg_iter, dmesg_comp->packet,
+                               dmesg_msg_iter->last_clock_value);
+               } else {
+                       *msg = bt_message_packet_end_create(
+                               dmesg_msg_iter->pc_msg_iter, dmesg_comp->packet);
+               }
+
+               dmesg_msg_iter->state = STATE_EMIT_STREAM_ACTIVITY_END;
+               break;
+       case STATE_EMIT_STREAM_ACTIVITY_END:
+               *msg = bt_message_stream_activity_end_create(
+                       dmesg_msg_iter->pc_msg_iter, dmesg_comp->stream);
+               dmesg_msg_iter->state = STATE_EMIT_STREAM_END;
+               break;
+       case STATE_EMIT_STREAM_END:
+               *msg = bt_message_stream_end_create(
+                       dmesg_msg_iter->pc_msg_iter, dmesg_comp->stream);
+               dmesg_msg_iter->state = STATE_DONE;
+               break;
+       default:
+               break;
+       }
+
+       if (!*msg) {
+               BT_LOGE("Cannot create message: dmesg-comp-addr=%p",
+                       dmesg_comp);
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+       }
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status dmesg_msg_iter_next(
+               bt_self_message_iterator *self_msg_iter,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       struct dmesg_msg_iter *dmesg_msg_iter =
+               bt_self_message_iterator_get_data(
+                       self_msg_iter);
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       uint64_t i = 0;
+
+       while (i < capacity &&
+                       status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+               bt_message *priv_msg = NULL;
+
+               status = dmesg_msg_iter_next_one(dmesg_msg_iter,
+                       &priv_msg);
+               msgs[i] = priv_msg;
+               if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                       i++;
+               }
+       }
+
+       if (i > 0) {
+               /*
+                * Even if dmesg_msg_iter_next_one() returned
+                * something else than
+                * BT_SELF_MESSAGE_ITERATOR_STATUS_OK, we
+                * accumulated message objects in the output
+                * message array, so we need to return
+                * BT_SELF_MESSAGE_ITERATOR_STATUS_OK so that they
+                * are transfered to downstream. This other status
+                * occurs again the next time muxer_msg_iter_do_next()
+                * is called, possibly without any accumulated
+                * message, in which case we'll return it.
+                */
+               *count = i;
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+bt_bool dmesg_msg_iter_can_seek_beginning(
+               bt_self_message_iterator *self_msg_iter)
+{
+       struct dmesg_msg_iter *dmesg_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_iter);
+
+       /* Can't seek the beginning of the standard input stream */
+       return !dmesg_msg_iter->dmesg_comp->params.read_from_stdin;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status dmesg_msg_iter_seek_beginning(
+               bt_self_message_iterator *self_msg_iter)
+{
+       struct dmesg_msg_iter *dmesg_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_iter);
+
+       BT_ASSERT(!dmesg_msg_iter->dmesg_comp->params.read_from_stdin);
+
+       BT_MESSAGE_PUT_REF_AND_RESET(dmesg_msg_iter->tmp_event_msg);
+       dmesg_msg_iter->last_clock_value = 0;
+       dmesg_msg_iter->state = STATE_EMIT_STREAM_BEGINNING;
+       return BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+}
diff --git a/src/plugins/text/dmesg/dmesg.h b/src/plugins/text/dmesg/dmesg.h
new file mode 100644 (file)
index 0000000..6fc5dde
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H
+#define BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H
+
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+BT_HIDDEN
+bt_self_component_status dmesg_init(
+               bt_self_component_source *self_comp,
+               const bt_value *params, void *init_method_data);
+
+BT_HIDDEN
+void dmesg_finalize(bt_self_component_source *self_comp);
+
+BT_HIDDEN
+bt_self_message_iterator_status dmesg_msg_iter_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_source *self_comp,
+               bt_self_component_port_output *self_port);
+
+BT_HIDDEN
+void dmesg_msg_iter_finalize(
+               bt_self_message_iterator *self_msg_iter);
+
+BT_HIDDEN
+bt_self_message_iterator_status dmesg_msg_iter_next(
+               bt_self_message_iterator *self_msg_iter,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count);
+
+BT_HIDDEN
+bt_bool dmesg_msg_iter_can_seek_beginning(
+               bt_self_message_iterator *message_iterator);
+
+BT_HIDDEN
+bt_self_message_iterator_status dmesg_msg_iter_seek_beginning(
+               bt_self_message_iterator *message_iterator);
+
+#endif /* BABELTRACE_PLUGIN_TEXT_DMESG_DMESG_H */
diff --git a/src/plugins/text/dmesg/logging.c b/src/plugins/text/dmesg/logging.c
new file mode 100644 (file)
index 0000000..cf04250
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_text_dmesg_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_plugin_text_dmesg_log_level,
+       "BABELTRACE_SRC_TEXT_DMESG_LOG_LEVEL");
diff --git a/src/plugins/text/dmesg/logging.h b/src/plugins/text/dmesg/logging.h
new file mode 100644 (file)
index 0000000..1facad3
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef PLUGINS_TEXT_DMESG_LOG_LEVEL
+#define PLUGINS_TEXT_DMESG_LOG_LEVEL
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_text_dmesg_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_text_dmesg_log_level);
+
+#endif /* PLUGINS_TEXT_DMESG_LOG_LEVEL */
diff --git a/src/plugins/text/plugin.c b/src/plugins/text/plugin.c
new file mode 100644 (file)
index 0000000..17f814b
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "pretty/pretty.h"
+#include "dmesg/dmesg.h"
+
+#ifndef BT_BUILT_IN_PLUGINS
+BT_PLUGIN_MODULE();
+#endif
+
+BT_PLUGIN(text);
+BT_PLUGIN_DESCRIPTION("Plain text component classes");
+BT_PLUGIN_AUTHOR("Julien Desfossez, Mathieu Desnoyers, Philippe Proulx");
+BT_PLUGIN_LICENSE("MIT");
+
+/* pretty sink */
+BT_PLUGIN_SINK_COMPONENT_CLASS(pretty, pretty_consume);
+BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(pretty, pretty_init);
+BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(pretty, pretty_finalize);
+BT_PLUGIN_SINK_COMPONENT_CLASS_GRAPH_IS_CONFIGURED_METHOD(pretty,
+       pretty_graph_is_configured);
+BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(pretty,
+       "Pretty-print messages (`text` format of Babeltrace 1).");
+
+/* dmesg source */
+BT_PLUGIN_SOURCE_COMPONENT_CLASS(dmesg, dmesg_msg_iter_next);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_DESCRIPTION(dmesg,
+       "Read a dmesg output from a file or from standard input.");
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_INIT_METHOD(dmesg, dmesg_init);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_FINALIZE_METHOD(dmesg, dmesg_finalize);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD(dmesg,
+       dmesg_msg_iter_init);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD(dmesg,
+       dmesg_msg_iter_finalize);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD(dmesg,
+       dmesg_msg_iter_seek_beginning);
+BT_PLUGIN_SOURCE_COMPONENT_CLASS_MESSAGE_ITERATOR_CAN_SEEK_BEGINNING_METHOD(dmesg,
+       dmesg_msg_iter_can_seek_beginning);
diff --git a/src/plugins/text/pretty/Makefile.am b/src/plugins/text/pretty/Makefile.am
new file mode 100644 (file)
index 0000000..37000e1
--- /dev/null
@@ -0,0 +1,9 @@
+noinst_LTLIBRARIES = libbabeltrace2-plugin-text-pretty-cc.la
+
+# ctf-text plugin
+libbabeltrace2_plugin_text_pretty_cc_la_SOURCES = \
+       logging.c \
+       logging.h \
+       pretty.c \
+       pretty.h \
+       print.c
diff --git a/src/plugins/text/pretty/logging.c b/src/plugins/text/pretty/logging.c
new file mode 100644 (file)
index 0000000..03dd9c1
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_text_pretty_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_plugin_text_pretty_log_level,
+       "BABELTRACE_SINK_TEXT_PRETTY_LOG_LEVEL");
diff --git a/src/plugins/text/pretty/logging.h b/src/plugins/text/pretty/logging.h
new file mode 100644 (file)
index 0000000..61d4f2b
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef PLUGINS_TEXT_PRETTY_LOG_LEVEL
+#define PLUGINS_TEXT_PRETTY_LOG_LEVEL
+
+/*
+ * Copyright (c) 2019 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_text_pretty_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_text_pretty_log_level);
+
+#endif /* PLUGINS_TEXT_PRETTY_LOG_LEVEL */
diff --git a/src/plugins/text/pretty/pretty.c b/src/plugins/text/pretty/pretty.c
new file mode 100644 (file)
index 0000000..9db8770
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-TEXT-PRETTY-SINK"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "compat/compiler.h"
+#include "common/common.h"
+#include "plugins/plugins-common.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <glib.h>
+#include "common/assert.h"
+
+#include "pretty.h"
+
+GQuark stream_packet_context_quarks[STREAM_PACKET_CONTEXT_QUARKS_LEN];
+
+static
+const char *plugin_options[] = {
+       "color",
+       "path",
+       "no-delta",
+       "clock-cycles",
+       "clock-seconds",
+       "clock-date",
+       "clock-gmt",
+       "verbose",
+       "name-default",         /* show/hide */
+       "name-payload",
+       "name-context",
+       "name-scope",
+       "name-header",
+       "field-default",        /* show/hide */
+       "field-trace",
+       "field-trace:hostname",
+       "field-trace:domain",
+       "field-trace:procname",
+       "field-trace:vpid",
+       "field-loglevel",
+       "field-emf",
+       "field-callsite",
+};
+
+static
+const char * const in_port_name = "in";
+
+static
+void destroy_pretty_data(struct pretty_component *pretty)
+{
+       bt_self_component_port_input_message_iterator_put_ref(pretty->iterator);
+
+       if (pretty->string) {
+               (void) g_string_free(pretty->string, TRUE);
+       }
+
+       if (pretty->tmp_string) {
+               (void) g_string_free(pretty->tmp_string, TRUE);
+       }
+
+       if (pretty->out != stdout) {
+               int ret;
+
+               ret = fclose(pretty->out);
+               if (ret) {
+                       perror("close output file");
+               }
+       }
+       g_free(pretty->options.output_path);
+       g_free(pretty);
+}
+
+static
+struct pretty_component *create_pretty(void)
+{
+       struct pretty_component *pretty;
+
+       pretty = g_new0(struct pretty_component, 1);
+       if (!pretty) {
+               goto end;
+       }
+       pretty->string = g_string_new("");
+       if (!pretty->string) {
+               goto error;
+       }
+       pretty->tmp_string = g_string_new("");
+       if (!pretty->tmp_string) {
+               goto error;
+       }
+end:
+       return pretty;
+
+error:
+       g_free(pretty);
+       return NULL;
+}
+
+BT_HIDDEN
+void pretty_finalize(bt_self_component_sink *comp)
+{
+       destroy_pretty_data(
+               bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(comp)));
+}
+
+static
+bt_self_component_status handle_message(
+               struct pretty_component *pretty,
+               const bt_message *message)
+{
+       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
+
+       BT_ASSERT(pretty);
+
+       switch (bt_message_get_type(message)) {
+       case BT_MESSAGE_TYPE_EVENT:
+               if (pretty_print_event(pretty, message)) {
+                       ret = BT_SELF_COMPONENT_STATUS_ERROR;
+               }
+               break;
+       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+               BT_LOGD_STR("Message iterator inactivity message.");
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+               if (pretty_print_discarded_items(pretty, message)) {
+                       ret = BT_SELF_COMPONENT_STATUS_ERROR;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+bt_self_component_status pretty_graph_is_configured(
+               bt_self_component_sink *comp)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct pretty_component *pretty;
+
+       pretty = bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(comp));
+       BT_ASSERT(pretty);
+       BT_ASSERT(!pretty->iterator);
+       pretty->iterator = bt_self_component_port_input_message_iterator_create(
+               bt_self_component_sink_borrow_input_port_by_name(comp,
+                       in_port_name));
+       if (!pretty->iterator) {
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+bt_self_component_status pretty_consume(
+               bt_self_component_sink *comp)
+{
+       bt_self_component_status ret;
+       bt_message_array_const msgs;
+       bt_self_component_port_input_message_iterator *it;
+       struct pretty_component *pretty = bt_self_component_get_data(
+               bt_self_component_sink_as_self_component(comp));
+       bt_message_iterator_status it_ret;
+       uint64_t count = 0;
+       uint64_t i = 0;
+
+       it = pretty->iterator;
+       it_ret = bt_self_component_port_input_message_iterator_next(it,
+               &msgs, &count);
+
+       switch (it_ret) {
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               ret = BT_SELF_COMPONENT_STATUS_AGAIN;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_END:
+               ret = BT_SELF_COMPONENT_STATUS_END;
+               BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_PUT_REF_AND_RESET(
+                       pretty->iterator);
+               goto end;
+       default:
+               ret = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_ASSERT(it_ret == BT_MESSAGE_ITERATOR_STATUS_OK);
+
+       for (i = 0; i < count; i++) {
+               ret = handle_message(pretty, msgs[i]);
+               if (ret) {
+                       goto end;
+               }
+
+               bt_message_put_ref(msgs[i]);
+       }
+
+end:
+       for (; i < count; i++) {
+               bt_message_put_ref(msgs[i]);
+       }
+
+       return ret;
+}
+
+static
+int add_params_to_map(bt_value *plugin_opt_map)
+{
+       int ret = 0;
+       unsigned int i;
+
+       for (i = 0; i < BT_ARRAY_SIZE(plugin_options); i++) {
+               const char *key = plugin_options[i];
+               bt_value_status status;
+
+               status = bt_value_map_insert_entry(plugin_opt_map, key,
+                       bt_value_null);
+               switch (status) {
+               case BT_VALUE_STATUS_OK:
+                       break;
+               default:
+                       ret = -1;
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+static
+bt_bool check_param_exists(const char *key, const bt_value *object,
+               void *data)
+{
+       struct pretty_component *pretty = data;
+
+       if (!bt_value_map_has_entry(pretty->plugin_opt_map,
+                                   key)) {
+               fprintf(pretty->err,
+                       "[warning] Parameter \"%s\" unknown to \"text.pretty\" sink component\n", key);
+       }
+       return BT_TRUE;
+}
+
+static
+void apply_one_string(const char *key, const bt_value *params, char **option)
+{
+       const bt_value *value = NULL;
+       const char *str;
+
+       value = bt_value_map_borrow_entry_value_const(params, key);
+       if (!value) {
+               goto end;
+       }
+       if (bt_value_is_null(value)) {
+               goto end;
+       }
+       str = bt_value_string_get(value);
+       *option = g_strdup(str);
+
+end:
+       return;
+}
+
+static
+void apply_one_bool(const char *key, const bt_value *params, bool *option,
+               bool *found)
+{
+       const bt_value *value = NULL;
+       bt_bool bool_val;
+
+       value = bt_value_map_borrow_entry_value_const(params, key);
+       if (!value) {
+               goto end;
+       }
+       bool_val = bt_value_bool_get(value);
+       *option = (bool) bool_val;
+       if (found) {
+               *found = true;
+       }
+
+end:
+       return;
+}
+
+static
+void warn_wrong_color_param(struct pretty_component *pretty)
+{
+       fprintf(pretty->err,
+               "[warning] Accepted values for the \"color\" parameter are:\n    \"always\", \"auto\", \"never\"\n");
+}
+
+static
+int open_output_file(struct pretty_component *pretty)
+{
+       int ret = 0;
+
+       if (!pretty->options.output_path) {
+               goto end;
+       }
+
+       pretty->out = fopen(pretty->options.output_path, "w");
+       if (!pretty->out) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+int apply_params(struct pretty_component *pretty, const bt_value *params)
+{
+       int ret = 0;
+       bt_value_status status;
+       bool value, found;
+       char *str = NULL;
+
+       pretty->plugin_opt_map = bt_value_map_create();
+       if (!pretty->plugin_opt_map) {
+               ret = -1;
+               goto end;
+       }
+       ret = add_params_to_map(pretty->plugin_opt_map);
+       if (ret) {
+               goto end;
+       }
+       /* Report unknown parameters. */
+       status = bt_value_map_foreach_entry_const(params,
+               check_param_exists, pretty);
+       switch (status) {
+       case BT_VALUE_STATUS_OK:
+               break;
+       default:
+               ret = -1;
+               goto end;
+       }
+       /* Known parameters. */
+       pretty->options.color = PRETTY_COLOR_OPT_AUTO;
+       if (bt_value_map_has_entry(params, "color")) {
+               const bt_value *color_value;
+               const char *color;
+
+               color_value = bt_value_map_borrow_entry_value_const(params,
+                       "color");
+               if (!color_value) {
+                       goto end;
+               }
+
+               color = bt_value_string_get(color_value);
+
+               if (strcmp(color, "never") == 0) {
+                       pretty->options.color = PRETTY_COLOR_OPT_NEVER;
+               } else if (strcmp(color, "auto") == 0) {
+                       pretty->options.color = PRETTY_COLOR_OPT_AUTO;
+               } else if (strcmp(color, "always") == 0) {
+                       pretty->options.color = PRETTY_COLOR_OPT_ALWAYS;
+               } else {
+                       warn_wrong_color_param(pretty);
+               }
+       }
+
+       apply_one_string("path", params, &pretty->options.output_path);
+       ret = open_output_file(pretty);
+       if (ret) {
+               goto end;
+       }
+
+       value = false;          /* Default. */
+       apply_one_bool("no-delta", params, &value, NULL);
+       pretty->options.print_delta_field = !value;     /* Reverse logic. */
+
+       value = false;          /* Default. */
+       apply_one_bool("clock-cycles", params, &value, NULL);
+       pretty->options.print_timestamp_cycles = value;
+
+       value = false;          /* Default. */
+       apply_one_bool("clock-seconds", params, &value, NULL);
+       pretty->options.clock_seconds = value;
+
+       value = false;          /* Default. */
+       apply_one_bool("clock-date", params, &value, NULL);
+       pretty->options.clock_date = value;
+
+       value = false;          /* Default. */
+       apply_one_bool("clock-gmt", params, &value, NULL);
+       pretty->options.clock_gmt = value;
+
+       value = false;          /* Default. */
+       apply_one_bool("verbose", params, &value, NULL);
+       pretty->options.verbose = value;
+
+       /* Names. */
+       apply_one_string("name-default", params, &str);
+       if (!str) {
+               pretty->options.name_default = PRETTY_DEFAULT_UNSET;
+       } else if (!strcmp(str, "show")) {
+               pretty->options.name_default = PRETTY_DEFAULT_SHOW;
+       } else if (!strcmp(str, "hide")) {
+               pretty->options.name_default = PRETTY_DEFAULT_HIDE;
+       } else {
+               ret = -1;
+               goto end;
+       }
+       g_free(str);
+       str = NULL;
+
+       switch (pretty->options.name_default) {
+       case PRETTY_DEFAULT_UNSET:
+               pretty->options.print_payload_field_names = true;
+               pretty->options.print_context_field_names = true;
+               pretty->options.print_header_field_names = false;
+               pretty->options.print_scope_field_names = false;
+               break;
+       case PRETTY_DEFAULT_SHOW:
+               pretty->options.print_payload_field_names = true;
+               pretty->options.print_context_field_names = true;
+               pretty->options.print_header_field_names = true;
+               pretty->options.print_scope_field_names = true;
+               break;
+       case PRETTY_DEFAULT_HIDE:
+               pretty->options.print_payload_field_names = false;
+               pretty->options.print_context_field_names = false;
+               pretty->options.print_header_field_names = false;
+               pretty->options.print_scope_field_names = false;
+               break;
+       default:
+               ret = -1;
+               goto end;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("name-payload", params, &value, &found);
+       if (found) {
+               pretty->options.print_payload_field_names = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("name-context", params, &value, &found);
+       if (found) {
+               pretty->options.print_context_field_names = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("name-header", params, &value, &found);
+       if (found) {
+               pretty->options.print_header_field_names = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("name-scope", params, &value, &found);
+       if (found) {
+               pretty->options.print_scope_field_names = value;
+       }
+
+       /* Fields. */
+       apply_one_string("field-default", params, &str);
+       if (!str) {
+               pretty->options.field_default = PRETTY_DEFAULT_UNSET;
+       } else if (!strcmp(str, "show")) {
+               pretty->options.field_default = PRETTY_DEFAULT_SHOW;
+       } else if (!strcmp(str, "hide")) {
+               pretty->options.field_default = PRETTY_DEFAULT_HIDE;
+       } else {
+               ret = -1;
+               goto end;
+       }
+       g_free(str);
+       str = NULL;
+
+       switch (pretty->options.field_default) {
+       case PRETTY_DEFAULT_UNSET:
+               pretty->options.print_trace_field = false;
+               pretty->options.print_trace_hostname_field = true;
+               pretty->options.print_trace_domain_field = false;
+               pretty->options.print_trace_procname_field = true;
+               pretty->options.print_trace_vpid_field = true;
+               pretty->options.print_loglevel_field = false;
+               pretty->options.print_emf_field = false;
+               pretty->options.print_callsite_field = false;
+               break;
+       case PRETTY_DEFAULT_SHOW:
+               pretty->options.print_trace_field = true;
+               pretty->options.print_trace_hostname_field = true;
+               pretty->options.print_trace_domain_field = true;
+               pretty->options.print_trace_procname_field = true;
+               pretty->options.print_trace_vpid_field = true;
+               pretty->options.print_loglevel_field = true;
+               pretty->options.print_emf_field = true;
+               pretty->options.print_callsite_field = true;
+               break;
+       case PRETTY_DEFAULT_HIDE:
+               pretty->options.print_trace_field = false;
+               pretty->options.print_trace_hostname_field = false;
+               pretty->options.print_trace_domain_field = false;
+               pretty->options.print_trace_procname_field = false;
+               pretty->options.print_trace_vpid_field = false;
+               pretty->options.print_loglevel_field = false;
+               pretty->options.print_emf_field = false;
+               pretty->options.print_callsite_field = false;
+               break;
+       default:
+               ret = -1;
+               goto end;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("field-trace", params, &value, &found);
+       if (found) {
+               pretty->options.print_trace_field = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("field-trace:hostname", params, &value, &found);
+       if (found) {
+               pretty->options.print_trace_hostname_field = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("field-trace:domain", params, &value, &found);
+       if (found) {
+               pretty->options.print_trace_domain_field = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("field-trace:procname", params, &value, &found);
+       if (found) {
+               pretty->options.print_trace_procname_field = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("field-trace:vpid", params, &value, &found);
+       if (found) {
+               pretty->options.print_trace_vpid_field = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("field-loglevel", params, &value, &found);
+       if (found) {
+               pretty->options.print_loglevel_field = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("field-emf", params, &value, &found);
+       if (found) {
+               pretty->options.print_emf_field = value;
+       }
+
+       value = false;
+       found = false;
+       apply_one_bool("field-callsite", params, &value, &found);
+       if (found) {
+               pretty->options.print_callsite_field = value;
+       }
+
+end:
+       bt_value_put_ref(pretty->plugin_opt_map);
+       pretty->plugin_opt_map = NULL;
+       g_free(str);
+       return ret;
+}
+
+static
+void set_use_colors(struct pretty_component *pretty)
+{
+       switch (pretty->options.color) {
+       case PRETTY_COLOR_OPT_ALWAYS:
+               pretty->use_colors = true;
+               break;
+       case PRETTY_COLOR_OPT_AUTO:
+               pretty->use_colors = pretty->out == stdout &&
+                       bt_common_colors_supported();
+               break;
+       case PRETTY_COLOR_OPT_NEVER:
+               pretty->use_colors = false;
+               break;
+       }
+}
+
+static
+void init_stream_packet_context_quarks(void)
+{
+       stream_packet_context_quarks[Q_TIMESTAMP_BEGIN] =
+               g_quark_from_string("timestamp_begin");
+       stream_packet_context_quarks[Q_TIMESTAMP_BEGIN] =
+               g_quark_from_string("timestamp_begin");
+       stream_packet_context_quarks[Q_TIMESTAMP_END] =
+               g_quark_from_string("timestamp_end");
+       stream_packet_context_quarks[Q_EVENTS_DISCARDED] =
+               g_quark_from_string("events_discarded");
+       stream_packet_context_quarks[Q_CONTENT_SIZE] =
+               g_quark_from_string("content_size");
+       stream_packet_context_quarks[Q_PACKET_SIZE] =
+               g_quark_from_string("packet_size");
+       stream_packet_context_quarks[Q_PACKET_SEQ_NUM] =
+               g_quark_from_string("packet_seq_num");
+}
+
+BT_HIDDEN
+bt_self_component_status pretty_init(
+               bt_self_component_sink *comp,
+               const bt_value *params,
+               UNUSED_VAR void *init_method_data)
+{
+       bt_self_component_status ret;
+       struct pretty_component *pretty = create_pretty();
+
+       if (!pretty) {
+               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       ret = bt_self_component_sink_add_input_port(comp, in_port_name,
+               NULL, NULL);
+       if (ret != BT_SELF_COMPONENT_STATUS_OK) {
+               goto end;
+       }
+
+       pretty->out = stdout;
+       pretty->err = stderr;
+
+       pretty->delta_cycles = -1ULL;
+       pretty->last_cycles_timestamp = -1ULL;
+
+       pretty->delta_real_timestamp = -1ULL;
+       pretty->last_real_timestamp = -1ULL;
+
+       if (apply_params(pretty, params)) {
+               ret = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto error;
+       }
+
+       set_use_colors(pretty);
+       bt_self_component_set_data(
+               bt_self_component_sink_as_self_component(comp), pretty);
+       init_stream_packet_context_quarks();
+
+end:
+       return ret;
+
+error:
+       destroy_pretty_data(pretty);
+       return ret;
+}
diff --git a/src/plugins/text/pretty/pretty.h b/src/plugins/text/pretty/pretty.h
new file mode 100644 (file)
index 0000000..e3a2410
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef BABELTRACE_PLUGIN_TEXT_PRETTY_PRETTY_H
+#define BABELTRACE_PLUGIN_TEXT_PRETTY_PRETTY_H
+
+/*
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+enum pretty_default {
+       PRETTY_DEFAULT_UNSET,
+       PRETTY_DEFAULT_SHOW,
+       PRETTY_DEFAULT_HIDE,
+};
+
+enum pretty_color_option {
+       PRETTY_COLOR_OPT_NEVER,
+       PRETTY_COLOR_OPT_AUTO,
+       PRETTY_COLOR_OPT_ALWAYS,
+};
+
+struct pretty_options {
+       char *output_path;
+
+       enum pretty_default name_default;
+       enum pretty_default field_default;
+
+       bool print_scope_field_names;
+       bool print_header_field_names;
+       bool print_context_field_names;
+       bool print_payload_field_names;
+
+       bool print_delta_field;
+       bool print_loglevel_field;
+       bool print_emf_field;
+       bool print_callsite_field;
+       bool print_trace_field;
+       bool print_trace_domain_field;
+       bool print_trace_procname_field;
+       bool print_trace_vpid_field;
+       bool print_trace_hostname_field;
+
+       bool print_timestamp_cycles;
+       bool clock_seconds;
+       bool clock_date;
+       bool clock_gmt;
+       enum pretty_color_option color;
+       bool verbose;
+};
+
+struct pretty_component {
+       struct pretty_options options;
+       bt_self_component_port_input_message_iterator *iterator;
+       FILE *out, *err;
+       int depth;      /* nesting, used for tabulation alignment. */
+       bool start_line;
+       GString *string;
+       GString *tmp_string;
+       bt_value *plugin_opt_map; /* Temporary parameter map. */
+       bool use_colors;
+
+       uint64_t last_cycles_timestamp;
+       uint64_t delta_cycles;
+
+       uint64_t last_real_timestamp;
+       uint64_t delta_real_timestamp;
+
+       bool negative_timestamp_warning_done;
+};
+
+enum stream_packet_context_quarks_enum {
+       Q_TIMESTAMP_BEGIN,
+       Q_TIMESTAMP_END,
+       Q_EVENTS_DISCARDED,
+       Q_CONTENT_SIZE,
+       Q_PACKET_SIZE,
+       Q_PACKET_SEQ_NUM,
+       STREAM_PACKET_CONTEXT_QUARKS_LEN, /* Always the last one of this enum. */
+};
+
+extern
+GQuark stream_packet_context_quarks[STREAM_PACKET_CONTEXT_QUARKS_LEN];
+
+BT_HIDDEN
+bt_self_component_status pretty_init(
+               bt_self_component_sink *component,
+               const bt_value *params,
+               void *init_method_data);
+
+BT_HIDDEN
+bt_self_component_status pretty_consume(
+               bt_self_component_sink *component);
+
+BT_HIDDEN
+bt_self_component_status pretty_graph_is_configured(
+               bt_self_component_sink *component);
+
+BT_HIDDEN
+void pretty_finalize(bt_self_component_sink *component);
+
+BT_HIDDEN
+int pretty_print_event(struct pretty_component *pretty,
+               const bt_message *event_msg);
+
+BT_HIDDEN
+int pretty_print_discarded_items(struct pretty_component *pretty,
+               const bt_message *msg);
+
+#endif /* BABELTRACE_PLUGIN_TEXT_PRETTY_PRETTY_H */
diff --git a/src/plugins/text/pretty/print.c b/src/plugins/text/pretty/print.c
new file mode 100644 (file)
index 0000000..388a091
--- /dev/null
@@ -0,0 +1,1390 @@
+/*
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "compat/bitfield.h"
+#include "common/common.h"
+#include "compat/time.h"
+#include "common/assert.h"
+#include <inttypes.h>
+#include <ctype.h>
+#include "pretty.h"
+
+#define NSEC_PER_SEC 1000000000LL
+
+#define COLOR_NAME             BT_COMMON_COLOR_BOLD
+#define COLOR_FIELD_NAME       BT_COMMON_COLOR_FG_CYAN
+#define COLOR_RST              BT_COMMON_COLOR_RESET
+#define COLOR_STRING_VALUE     BT_COMMON_COLOR_BOLD
+#define COLOR_NUMBER_VALUE     BT_COMMON_COLOR_BOLD
+#define COLOR_ENUM_MAPPING_NAME        BT_COMMON_COLOR_BOLD
+#define COLOR_UNKNOWN          BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_RED
+#define COLOR_EVENT_NAME       BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_MAGENTA
+#define COLOR_TIMESTAMP                BT_COMMON_COLOR_BOLD BT_COMMON_COLOR_FG_YELLOW
+
+struct timestamp {
+       int64_t real_timestamp; /* Relative to UNIX epoch. */
+       uint64_t clock_snapshot;        /* In cycles. */
+};
+
+static
+int print_field(struct pretty_component *pretty,
+               const bt_field *field, bool print_names,
+               GQuark *filters_fields, int filter_array_len);
+
+static
+void print_name_equal(struct pretty_component *pretty, const char *name)
+{
+       if (pretty->use_colors) {
+               g_string_append_printf(pretty->string, "%s%s%s = ", COLOR_NAME,
+                       name, COLOR_RST);
+       } else {
+               g_string_append_printf(pretty->string, "%s = ", name);
+       }
+}
+
+static
+void print_field_name_equal(struct pretty_component *pretty, const char *name)
+{
+       if (pretty->use_colors) {
+               g_string_append_printf(pretty->string, "%s%s%s = ",
+                       COLOR_FIELD_NAME, name, COLOR_RST);
+       } else {
+               g_string_append_printf(pretty->string, "%s = ", name);
+       }
+}
+
+static
+void print_timestamp_cycles(struct pretty_component *pretty,
+               const bt_clock_snapshot *clock_snapshot, bool update_last)
+{
+       uint64_t cycles;
+
+       cycles = bt_clock_snapshot_get_value(clock_snapshot);
+       g_string_append_printf(pretty->string, "%020" PRIu64, cycles);
+
+       if (update_last) {
+               if (pretty->last_cycles_timestamp != -1ULL) {
+                       pretty->delta_cycles = cycles - pretty->last_cycles_timestamp;
+               }
+
+               pretty->last_cycles_timestamp = cycles;
+       }
+}
+
+static
+void print_timestamp_wall(struct pretty_component *pretty,
+               const bt_clock_snapshot *clock_snapshot, bool update_last)
+{
+       int ret;
+       int64_t ts_nsec = 0;    /* add configurable offset */
+       int64_t ts_sec = 0;     /* add configurable offset */
+       uint64_t ts_sec_abs, ts_nsec_abs;
+       bool is_negative;
+
+       if (!clock_snapshot) {
+               g_string_append(pretty->string, "??:??:??.?????????");
+               return;
+       }
+
+       ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot, &ts_nsec);
+       if (ret) {
+               // TODO: log, this is unexpected
+               g_string_append(pretty->string, "Error");
+               return;
+       }
+
+       if (update_last) {
+               if (pretty->last_real_timestamp != -1ULL) {
+                       pretty->delta_real_timestamp = ts_nsec - pretty->last_real_timestamp;
+               }
+
+               pretty->last_real_timestamp = ts_nsec;
+       }
+
+       ts_sec += ts_nsec / NSEC_PER_SEC;
+       ts_nsec = ts_nsec % NSEC_PER_SEC;
+
+       if (ts_sec >= 0 && ts_nsec >= 0) {
+               is_negative = false;
+               ts_sec_abs = ts_sec;
+               ts_nsec_abs = ts_nsec;
+       } else if (ts_sec > 0 && ts_nsec < 0) {
+               is_negative = false;
+               ts_sec_abs = ts_sec - 1;
+               ts_nsec_abs = NSEC_PER_SEC + ts_nsec;
+       } else if (ts_sec == 0 && ts_nsec < 0) {
+               is_negative = true;
+               ts_sec_abs = ts_sec;
+               ts_nsec_abs = -ts_nsec;
+       } else if (ts_sec < 0 && ts_nsec > 0) {
+               is_negative = true;
+               ts_sec_abs = -(ts_sec + 1);
+               ts_nsec_abs = NSEC_PER_SEC - ts_nsec;
+       } else if (ts_sec < 0 && ts_nsec == 0) {
+               is_negative = true;
+               ts_sec_abs = -ts_sec;
+               ts_nsec_abs = ts_nsec;
+       } else {        /* (ts_sec < 0 && ts_nsec < 0) */
+               is_negative = true;
+               ts_sec_abs = -ts_sec;
+               ts_nsec_abs = -ts_nsec;
+       }
+
+       if (!pretty->options.clock_seconds) {
+               struct tm tm;
+               time_t time_s = (time_t) ts_sec_abs;
+
+               if (is_negative && !pretty->negative_timestamp_warning_done) {
+                       // TODO: log instead
+                       fprintf(stderr, "[warning] Fallback to [sec.ns] to print negative time value. Use --clock-seconds.\n");
+                       pretty->negative_timestamp_warning_done = true;
+                       goto seconds;
+               }
+
+               if (!pretty->options.clock_gmt) {
+                       struct tm *res;
+
+                       res = bt_localtime_r(&time_s, &tm);
+                       if (!res) {
+                               // TODO: log instead
+                               fprintf(stderr, "[warning] Unable to get localtime.\n");
+                               goto seconds;
+                       }
+               } else {
+                       struct tm *res;
+
+                       res = bt_gmtime_r(&time_s, &tm);
+                       if (!res) {
+                               // TODO: log instead
+                               fprintf(stderr, "[warning] Unable to get gmtime.\n");
+                               goto seconds;
+                       }
+               }
+               if (pretty->options.clock_date) {
+                       char timestr[26];
+                       size_t res;
+
+                       /* Print date and time */
+                       res = strftime(timestr, sizeof(timestr),
+                                       "%Y-%m-%d ", &tm);
+                       if (!res) {
+                               // TODO: log instead
+                               fprintf(stderr, "[warning] Unable to print ascii time.\n");
+                               goto seconds;
+                       }
+
+                       g_string_append(pretty->string, timestr);
+               }
+
+               /* Print time in HH:MM:SS.ns */
+               g_string_append_printf(pretty->string,
+                       "%02d:%02d:%02d.%09" PRIu64, tm.tm_hour, tm.tm_min,
+                       tm.tm_sec, ts_nsec_abs);
+               goto end;
+       }
+seconds:
+       g_string_append_printf(pretty->string, "%s%" PRId64 ".%09" PRIu64,
+               is_negative ? "-" : "", ts_sec_abs, ts_nsec_abs);
+end:
+       return;
+}
+
+static
+int print_event_timestamp(struct pretty_component *pretty,
+               const bt_message *event_msg, bool *start_line)
+{
+       bool print_names = pretty->options.print_header_field_names;
+       int ret = 0;
+       const bt_clock_snapshot *clock_snapshot = NULL;
+
+       if (!bt_message_event_borrow_stream_class_default_clock_class_const(
+                       event_msg)) {
+               /* No default clock class: skip the timestamp without an error */
+               goto end;
+       }
+
+       clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(event_msg);
+
+       if (print_names) {
+               print_name_equal(pretty, "timestamp");
+       } else {
+               g_string_append(pretty->string, "[");
+       }
+       if (pretty->use_colors) {
+               g_string_append(pretty->string, COLOR_TIMESTAMP);
+       }
+       if (pretty->options.print_timestamp_cycles) {
+               print_timestamp_cycles(pretty, clock_snapshot, true);
+       } else {
+               print_timestamp_wall(pretty, clock_snapshot, true);
+       }
+       if (pretty->use_colors) {
+               g_string_append(pretty->string, COLOR_RST);
+       }
+
+       if (!print_names)
+               g_string_append(pretty->string, "] ");
+
+       if (pretty->options.print_delta_field) {
+               if (print_names) {
+                       g_string_append(pretty->string, ", ");
+                       print_name_equal(pretty, "delta");
+               } else {
+                       g_string_append(pretty->string, "(");
+               }
+               if (pretty->options.print_timestamp_cycles) {
+                       if (pretty->delta_cycles == -1ULL) {
+                               g_string_append(pretty->string,
+                                       "+??????????\?\?"); /* Not a trigraph. */
+                       } else {
+                               g_string_append_printf(pretty->string,
+                                       "+%012" PRIu64, pretty->delta_cycles);
+                       }
+               } else {
+                       if (pretty->delta_real_timestamp != -1ULL) {
+                               uint64_t delta_sec, delta_nsec, delta;
+
+                               delta = pretty->delta_real_timestamp;
+                               delta_sec = delta / NSEC_PER_SEC;
+                               delta_nsec = delta % NSEC_PER_SEC;
+                               g_string_append_printf(pretty->string,
+                                       "+%" PRIu64 ".%09" PRIu64,
+                                       delta_sec, delta_nsec);
+                       } else {
+                               g_string_append(pretty->string, "+?.?????????");
+                       }
+               }
+               if (!print_names) {
+                       g_string_append(pretty->string, ") ");
+               }
+       }
+       *start_line = !print_names;
+
+end:
+       return ret;
+}
+
+static
+int print_event_header(struct pretty_component *pretty,
+               const bt_message *event_msg)
+{
+       bool print_names = pretty->options.print_header_field_names;
+       int ret = 0;
+       const bt_event_class *event_class = NULL;
+       const bt_stream_class *stream_class = NULL;
+       const bt_trace_class *trace_class = NULL;
+       const bt_packet *packet = NULL;
+       const bt_stream *stream = NULL;
+       const bt_trace *trace = NULL;
+       const bt_event *event = bt_message_event_borrow_event_const(event_msg);
+       int dom_print = 0;
+       bt_property_availability prop_avail;
+
+       event_class = bt_event_borrow_class_const(event);
+       stream_class = bt_event_class_borrow_stream_class_const(event_class);
+       trace_class = bt_stream_class_borrow_trace_class_const(stream_class);
+       packet = bt_event_borrow_packet_const(event);
+       stream = bt_packet_borrow_stream_const(packet);
+       trace = bt_stream_borrow_trace_const(stream);
+       ret = print_event_timestamp(pretty, event_msg, &pretty->start_line);
+       if (ret) {
+               goto end;
+       }
+       if (pretty->options.print_trace_field) {
+               const char *name;
+
+               name = bt_trace_get_name(trace);
+               if (name) {
+                       if (!pretty->start_line) {
+                               g_string_append(pretty->string, ", ");
+                       }
+                       if (print_names) {
+                               print_name_equal(pretty, "trace");
+                       }
+
+                       g_string_append(pretty->string, name);
+
+                       if (print_names) {
+                               g_string_append(pretty->string, ", ");
+                       }
+               }
+       }
+       if (pretty->options.print_trace_hostname_field) {
+               const bt_value *hostname_str;
+
+               hostname_str = bt_trace_class_borrow_environment_entry_value_by_name_const(
+                       trace_class, "hostname");
+               if (hostname_str) {
+                       const char *str;
+
+                       if (!pretty->start_line) {
+                               g_string_append(pretty->string, ", ");
+                       }
+                       if (print_names) {
+                               print_name_equal(pretty, "trace:hostname");
+                       }
+                       str = bt_value_string_get(hostname_str);
+                       g_string_append(pretty->string, str);
+                       dom_print = 1;
+               }
+       }
+       if (pretty->options.print_trace_domain_field) {
+               const bt_value *domain_str;
+
+               domain_str = bt_trace_class_borrow_environment_entry_value_by_name_const(
+                       trace_class, "domain");
+               if (domain_str) {
+                       const char *str;
+
+                       if (!pretty->start_line) {
+                               g_string_append(pretty->string, ", ");
+                       }
+                       if (print_names) {
+                               print_name_equal(pretty, "trace:domain");
+                       } else if (dom_print) {
+                               g_string_append(pretty->string, ":");
+                       }
+                       str = bt_value_string_get(domain_str);
+                       g_string_append(pretty->string, str);
+                       dom_print = 1;
+               }
+       }
+       if (pretty->options.print_trace_procname_field) {
+               const bt_value *procname_str;
+
+               procname_str = bt_trace_class_borrow_environment_entry_value_by_name_const(
+                       trace_class, "procname");
+               if (procname_str) {
+                       const char *str;
+
+                       if (!pretty->start_line) {
+                               g_string_append(pretty->string, ", ");
+                       }
+                       if (print_names) {
+                               print_name_equal(pretty, "trace:procname");
+                       } else if (dom_print) {
+                               g_string_append(pretty->string, ":");
+                       }
+                       str = bt_value_string_get(procname_str);
+                       g_string_append(pretty->string, str);
+                       dom_print = 1;
+               }
+       }
+       if (pretty->options.print_trace_vpid_field) {
+               const bt_value *vpid_value;
+
+               vpid_value = bt_trace_class_borrow_environment_entry_value_by_name_const(
+                       trace_class, "vpid");
+               if (vpid_value) {
+                       int64_t value;
+
+                       if (!pretty->start_line) {
+                               g_string_append(pretty->string, ", ");
+                       }
+                       if (print_names) {
+                               print_name_equal(pretty, "trace:vpid");
+                       } else if (dom_print) {
+                               g_string_append(pretty->string, ":");
+                       }
+                       value = bt_value_signed_integer_get(vpid_value);
+                       g_string_append_printf(pretty->string,
+                               "(%" PRId64 ")", value);
+                       dom_print = 1;
+               }
+       }
+       if (pretty->options.print_loglevel_field) {
+               static const char *log_level_names[] = {
+                       [ BT_EVENT_CLASS_LOG_LEVEL_EMERGENCY ] = "TRACE_EMERG",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_ALERT ] = "TRACE_ALERT",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_CRITICAL ] = "TRACE_CRIT",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_ERROR ] = "TRACE_ERR",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_WARNING ] = "TRACE_WARNING",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_NOTICE ] = "TRACE_NOTICE",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_INFO ] = "TRACE_INFO",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_SYSTEM ] = "TRACE_DEBUG_SYSTEM",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROGRAM ] = "TRACE_DEBUG_PROGRAM",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_PROCESS ] = "TRACE_DEBUG_PROCESS",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_MODULE ] = "TRACE_DEBUG_MODULE",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_UNIT ] = "TRACE_DEBUG_UNIT",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_FUNCTION ] = "TRACE_DEBUG_FUNCTION",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG_LINE ] = "TRACE_DEBUG_LINE",
+                       [ BT_EVENT_CLASS_LOG_LEVEL_DEBUG ] = "TRACE_DEBUG",
+               };
+               bt_event_class_log_level log_level;
+               const char *log_level_str = NULL;
+
+               prop_avail = bt_event_class_get_log_level(event_class,
+                       &log_level);
+               if (prop_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
+                       log_level_str = log_level_names[log_level];
+                       BT_ASSERT(log_level_str);
+
+                       if (!pretty->start_line) {
+                               g_string_append(pretty->string, ", ");
+                       }
+                       if (print_names) {
+                               print_name_equal(pretty, "loglevel");
+                       } else if (dom_print) {
+                               g_string_append(pretty->string, ":");
+                       }
+
+                       g_string_append(pretty->string, log_level_str);
+                       g_string_append_printf(
+                               pretty->string, " (%d)", (int) log_level);
+                       dom_print = 1;
+               }
+       }
+       if (pretty->options.print_emf_field) {
+               const char *uri_str;
+
+               uri_str = bt_event_class_get_emf_uri(event_class);
+               if (uri_str) {
+                       if (!pretty->start_line) {
+                               g_string_append(pretty->string, ", ");
+                       }
+                       if (print_names) {
+                               print_name_equal(pretty, "model.emf.uri");
+                       } else if (dom_print) {
+                               g_string_append(pretty->string, ":");
+                       }
+
+                       g_string_append(pretty->string, uri_str);
+                       dom_print = 1;
+               }
+       }
+       if (dom_print && !print_names) {
+               g_string_append(pretty->string, " ");
+       }
+       if (!pretty->start_line) {
+               g_string_append(pretty->string, ", ");
+       }
+       pretty->start_line = true;
+       if (print_names) {
+               print_name_equal(pretty, "name");
+       }
+       if (pretty->use_colors) {
+               g_string_append(pretty->string, COLOR_EVENT_NAME);
+       }
+       g_string_append(pretty->string, bt_event_class_get_name(event_class));
+       if (pretty->use_colors) {
+               g_string_append(pretty->string, COLOR_RST);
+       }
+       if (!print_names) {
+               g_string_append(pretty->string, ": ");
+       } else {
+               g_string_append(pretty->string, ", ");
+       }
+
+end:
+       return ret;
+}
+
+static
+int print_integer(struct pretty_component *pretty,
+               const bt_field *field)
+{
+       int ret = 0;
+       bt_field_class_integer_preferred_display_base base;
+       const bt_field_class *int_fc;
+       union {
+               uint64_t u;
+               int64_t s;
+       } v;
+       bool rst_color = false;
+       bt_field_class_type ft_type;
+
+       int_fc = bt_field_borrow_class_const(field);
+       BT_ASSERT(int_fc);
+       ft_type = bt_field_get_class_type(field);
+       if (ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
+                       ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
+               v.u = bt_field_unsigned_integer_get_value(field);
+       } else {
+               v.s = bt_field_signed_integer_get_value(field);
+       }
+
+       if (pretty->use_colors) {
+               g_string_append(pretty->string, COLOR_NUMBER_VALUE);
+               rst_color = true;
+       }
+
+       base = bt_field_class_integer_get_preferred_display_base(int_fc);
+       switch (base) {
+       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_BINARY:
+       {
+               int bitnr, len;
+
+               len = bt_field_class_integer_get_field_value_range(int_fc);
+               g_string_append(pretty->string, "0b");
+               _bt_safe_lshift(v.u, 64 - len);
+               for (bitnr = 0; bitnr < len; bitnr++) {
+                       g_string_append_printf(pretty->string, "%u", (v.u & (1ULL << 63)) ? 1 : 0);
+                       _bt_safe_lshift(v.u, 1);
+               }
+               break;
+       }
+       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_OCTAL:
+       {
+               if (ft_type == BT_FIELD_CLASS_TYPE_SIGNED_INTEGER ||
+                               ft_type == BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION) {
+                       int len;
+
+                       len = bt_field_class_integer_get_field_value_range(
+                               int_fc);
+                       if (len < 64) {
+                               size_t rounded_len;
+
+                               BT_ASSERT(len != 0);
+                               /* Round length to the nearest 3-bit */
+                               rounded_len = (((len - 1) / 3) + 1) * 3;
+                               v.u &= ((uint64_t) 1 << rounded_len) - 1;
+                       }
+               }
+
+               g_string_append_printf(pretty->string, "0%" PRIo64, v.u);
+               break;
+       }
+       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_DECIMAL:
+               if (ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER ||
+                               ft_type == BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION) {
+                       g_string_append_printf(pretty->string, "%" PRIu64, v.u);
+               } else {
+                       g_string_append_printf(pretty->string, "%" PRId64, v.s);
+               }
+               break;
+       case BT_FIELD_CLASS_INTEGER_PREFERRED_DISPLAY_BASE_HEXADECIMAL:
+       {
+               int len;
+
+               len = bt_field_class_integer_get_field_value_range(int_fc);
+               if (len < 64) {
+                       /* Round length to the nearest nibble */
+                       uint8_t rounded_len = ((len + 3) & ~0x3);
+
+                       v.u &= ((uint64_t) 1 << rounded_len) - 1;
+               }
+
+               g_string_append_printf(pretty->string, "0x%" PRIX64, v.u);
+               break;
+       }
+       default:
+               ret = -1;
+               goto end;
+       }
+end:
+       if (rst_color) {
+               g_string_append(pretty->string, COLOR_RST);
+       }
+       return ret;
+}
+
+static
+void print_escape_string(struct pretty_component *pretty, const char *str)
+{
+       int i;
+
+       g_string_append_c(pretty->string, '"');
+
+       for (i = 0; i < strlen(str); i++) {
+               /* Escape sequences not recognized by iscntrl(). */
+               switch (str[i]) {
+               case '\\':
+                       g_string_append(pretty->string, "\\\\");
+                       continue;
+               case '\'':
+                       g_string_append(pretty->string, "\\\'");
+                       continue;
+               case '\"':
+                       g_string_append(pretty->string, "\\\"");
+                       continue;
+               case '\?':
+                       g_string_append(pretty->string, "\\\?");
+                       continue;
+               }
+
+               /* Standard characters. */
+               if (!iscntrl(str[i])) {
+                       g_string_append_c(pretty->string, str[i]);
+                       continue;
+               }
+
+               switch (str[i]) {
+               case '\0':
+                       g_string_append(pretty->string, "\\0");
+                       break;
+               case '\a':
+                       g_string_append(pretty->string, "\\a");
+                       break;
+               case '\b':
+                       g_string_append(pretty->string, "\\b");
+                       break;
+               case '\e':
+                       g_string_append(pretty->string, "\\e");
+                       break;
+               case '\f':
+                       g_string_append(pretty->string, "\\f");
+                       break;
+               case '\n':
+                       g_string_append(pretty->string, "\\n");
+                       break;
+               case '\r':
+                       g_string_append(pretty->string, "\\r");
+                       break;
+               case '\t':
+                       g_string_append(pretty->string, "\\t");
+                       break;
+               case '\v':
+                       g_string_append(pretty->string, "\\v");
+                       break;
+               default:
+                       /* Unhandled control-sequence, print as hex. */
+                       g_string_append_printf(pretty->string, "\\x%02x", str[i]);
+                       break;
+               }
+       }
+
+       g_string_append_c(pretty->string, '"');
+}
+
+static
+int print_enum(struct pretty_component *pretty,
+               const bt_field *field)
+{
+       int ret = 0;
+       const bt_field_class *enumeration_field_class = NULL;
+       bt_field_class_enumeration_mapping_label_array label_array;
+       uint64_t label_count;
+       uint64_t i;
+
+       enumeration_field_class = bt_field_borrow_class_const(field);
+       if (!enumeration_field_class) {
+               ret = -1;
+               goto end;
+       }
+
+       switch (bt_field_get_class_type(field)) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+               ret = bt_field_unsigned_enumeration_get_mapping_labels(field,
+                       &label_array, &label_count);
+               break;
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+               ret = bt_field_signed_enumeration_get_mapping_labels(field,
+                       &label_array, &label_count);
+               break;
+       default:
+               abort();
+       }
+
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       g_string_append(pretty->string, "( ");
+       if (label_count == 0) {
+               if (pretty->use_colors) {
+                       g_string_append(pretty->string, COLOR_UNKNOWN);
+               }
+               g_string_append(pretty->string, "<unknown>");
+               if (pretty->use_colors) {
+                       g_string_append(pretty->string, COLOR_RST);
+               }
+               goto skip_loop;
+       }
+       for (i = 0; i < label_count; i++) {
+               const char *mapping_name = label_array[i];
+
+               if (i != 0) {
+                       g_string_append(pretty->string, ", ");
+               }
+               if (pretty->use_colors) {
+                       g_string_append(pretty->string, COLOR_ENUM_MAPPING_NAME);
+               }
+               print_escape_string(pretty, mapping_name);
+               if (pretty->use_colors) {
+                       g_string_append(pretty->string, COLOR_RST);
+               }
+       }
+skip_loop:
+       g_string_append(pretty->string, " : container = ");
+       ret = print_integer(pretty, field);
+       if (ret != 0) {
+               goto end;
+       }
+       g_string_append(pretty->string, " )");
+end:
+       return ret;
+}
+
+static
+int filter_field_name(struct pretty_component *pretty, const char *field_name,
+               GQuark *filter_fields, int filter_array_len)
+{
+       int i;
+       GQuark field_quark = g_quark_try_string(field_name);
+
+       if (!field_quark || pretty->options.verbose) {
+               return 1;
+       }
+
+       for (i = 0; i < filter_array_len; i++) {
+               if (field_quark == filter_fields[i]) {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static
+int print_struct_field(struct pretty_component *pretty,
+               const bt_field *_struct,
+               const bt_field_class *struct_class,
+               uint64_t i, bool print_names, uint64_t *nr_printed_fields,
+               GQuark *filter_fields, int filter_array_len)
+{
+       int ret = 0;
+       const char *field_name;
+       const bt_field *field = NULL;
+       const bt_field_class_structure_member *member;
+
+       field = bt_field_structure_borrow_member_field_by_index_const(_struct, i);
+       if (!field) {
+               ret = -1;
+               goto end;
+       }
+
+       member = bt_field_class_structure_borrow_member_by_index_const(
+               struct_class, i);
+       field_name = bt_field_class_structure_member_get_name(member);
+
+       if (filter_fields && !filter_field_name(pretty, field_name,
+                               filter_fields, filter_array_len)) {
+               ret = 0;
+               goto end;
+       }
+
+       if (*nr_printed_fields > 0) {
+               g_string_append(pretty->string, ", ");
+       } else {
+               g_string_append(pretty->string, " ");
+       }
+       if (print_names) {
+               print_field_name_equal(pretty, field_name);
+       }
+       ret = print_field(pretty, field, print_names, NULL, 0);
+       *nr_printed_fields += 1;
+
+end:
+       return ret;
+}
+
+static
+int print_struct(struct pretty_component *pretty,
+               const bt_field *_struct, bool print_names,
+               GQuark *filter_fields, int filter_array_len)
+{
+       int ret = 0;
+       const bt_field_class *struct_class = NULL;
+       uint64_t nr_fields, i, nr_printed_fields;
+
+       struct_class = bt_field_borrow_class_const(_struct);
+       if (!struct_class) {
+               ret = -1;
+               goto end;
+       }
+
+       nr_fields = bt_field_class_structure_get_member_count(struct_class);
+
+       g_string_append(pretty->string, "{");
+       pretty->depth++;
+       nr_printed_fields = 0;
+       for (i = 0; i < nr_fields; i++) {
+               ret = print_struct_field(pretty, _struct, struct_class, i,
+                               print_names, &nr_printed_fields, filter_fields,
+                               filter_array_len);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+       pretty->depth--;
+       g_string_append(pretty->string, " }");
+
+end:
+       return ret;
+}
+
+static
+int print_array_field(struct pretty_component *pretty,
+               const bt_field *array, uint64_t i, bool print_names)
+{
+       const bt_field *field = NULL;
+
+       if (i != 0) {
+               g_string_append(pretty->string, ", ");
+       } else {
+               g_string_append(pretty->string, " ");
+       }
+       if (print_names) {
+               g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
+       }
+
+       field = bt_field_array_borrow_element_field_by_index_const(array, i);
+       BT_ASSERT(field);
+       return print_field(pretty, field, print_names, NULL, 0);
+}
+
+static
+int print_array(struct pretty_component *pretty,
+               const bt_field *array, bool print_names)
+{
+       int ret = 0;
+       const bt_field_class *array_class = NULL;
+       uint64_t len;
+       uint64_t i;
+
+       array_class = bt_field_borrow_class_const(array);
+       if (!array_class) {
+               ret = -1;
+               goto end;
+       }
+       len = bt_field_array_get_length(array);
+       g_string_append(pretty->string, "[");
+       pretty->depth++;
+       for (i = 0; i < len; i++) {
+               ret = print_array_field(pretty, array, i, print_names);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+       pretty->depth--;
+       g_string_append(pretty->string, " ]");
+
+end:
+       return ret;
+}
+
+static
+int print_sequence_field(struct pretty_component *pretty,
+               const bt_field *seq, uint64_t i, bool print_names)
+{
+       const bt_field *field = NULL;
+
+       if (i != 0) {
+               g_string_append(pretty->string, ", ");
+       } else {
+               g_string_append(pretty->string, " ");
+       }
+       if (print_names) {
+               g_string_append_printf(pretty->string, "[%" PRIu64 "] = ", i);
+       }
+
+       field = bt_field_array_borrow_element_field_by_index_const(seq, i);
+       BT_ASSERT(field);
+       return print_field(pretty, field, print_names, NULL, 0);
+}
+
+static
+int print_sequence(struct pretty_component *pretty,
+               const bt_field *seq, bool print_names)
+{
+       int ret = 0;
+       uint64_t len;
+       uint64_t i;
+
+       len = bt_field_array_get_length(seq);
+       g_string_append(pretty->string, "[");
+
+       pretty->depth++;
+       for (i = 0; i < len; i++) {
+               ret = print_sequence_field(pretty, seq, i, print_names);
+               if (ret != 0) {
+                       goto end;
+               }
+       }
+       pretty->depth--;
+       g_string_append(pretty->string, " ]");
+
+end:
+       return ret;
+}
+
+static
+int print_variant(struct pretty_component *pretty,
+               const bt_field *variant, bool print_names)
+{
+       int ret = 0;
+       const bt_field *field = NULL;
+
+       field = bt_field_variant_borrow_selected_option_field_const(variant);
+       BT_ASSERT(field);
+       g_string_append(pretty->string, "{ ");
+       pretty->depth++;
+       if (print_names) {
+               // TODO: find tag's name using field path
+               // print_field_name_equal(pretty, tag_choice);
+       }
+       ret = print_field(pretty, field, print_names, NULL, 0);
+       if (ret != 0) {
+               goto end;
+       }
+       pretty->depth--;
+       g_string_append(pretty->string, " }");
+
+end:
+       return ret;
+}
+
+static
+int print_field(struct pretty_component *pretty,
+               const bt_field *field, bool print_names,
+               GQuark *filter_fields, int filter_array_len)
+{
+       bt_field_class_type class_id;
+
+       class_id = bt_field_get_class_type(field);
+       switch (class_id) {
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_INTEGER:
+       case BT_FIELD_CLASS_TYPE_SIGNED_INTEGER:
+               return print_integer(pretty, field);
+       case BT_FIELD_CLASS_TYPE_REAL:
+       {
+               double v;
+
+               v = bt_field_real_get_value(field);
+               if (pretty->use_colors) {
+                       g_string_append(pretty->string, COLOR_NUMBER_VALUE);
+               }
+               g_string_append_printf(pretty->string, "%g", v);
+               if (pretty->use_colors) {
+                       g_string_append(pretty->string, COLOR_RST);
+               }
+               return 0;
+       }
+       case BT_FIELD_CLASS_TYPE_UNSIGNED_ENUMERATION:
+       case BT_FIELD_CLASS_TYPE_SIGNED_ENUMERATION:
+               return print_enum(pretty, field);
+       case BT_FIELD_CLASS_TYPE_STRING:
+       {
+               const char *str;
+
+               str = bt_field_string_get_value(field);
+               if (!str) {
+                       return -1;
+               }
+
+               if (pretty->use_colors) {
+                       g_string_append(pretty->string, COLOR_STRING_VALUE);
+               }
+               print_escape_string(pretty, str);
+               if (pretty->use_colors) {
+                       g_string_append(pretty->string, COLOR_RST);
+               }
+               return 0;
+       }
+       case BT_FIELD_CLASS_TYPE_STRUCTURE:
+               return print_struct(pretty, field, print_names, filter_fields,
+                               filter_array_len);
+       case BT_FIELD_CLASS_TYPE_VARIANT:
+               return print_variant(pretty, field, print_names);
+       case BT_FIELD_CLASS_TYPE_STATIC_ARRAY:
+               return print_array(pretty, field, print_names);
+       case BT_FIELD_CLASS_TYPE_DYNAMIC_ARRAY:
+               return print_sequence(pretty, field, print_names);
+       default:
+               // TODO: log instead
+               fprintf(pretty->err, "[error] Unknown type id: %d\n", (int) class_id);
+               return -1;
+       }
+}
+
+static
+int print_stream_packet_context(struct pretty_component *pretty,
+               const bt_event *event)
+{
+       int ret = 0;
+       const bt_packet *packet = NULL;
+       const bt_field *main_field = NULL;
+
+       packet = bt_event_borrow_packet_const(event);
+       if (!packet) {
+               ret = -1;
+               goto end;
+       }
+       main_field = bt_packet_borrow_context_field_const(packet);
+       if (!main_field) {
+               goto end;
+       }
+       if (!pretty->start_line) {
+               g_string_append(pretty->string, ", ");
+       }
+       pretty->start_line = false;
+       if (pretty->options.print_scope_field_names) {
+               print_name_equal(pretty, "stream.packet.context");
+       }
+       ret = print_field(pretty, main_field,
+                       pretty->options.print_context_field_names,
+                       stream_packet_context_quarks,
+                       STREAM_PACKET_CONTEXT_QUARKS_LEN);
+
+end:
+       return ret;
+}
+
+static
+int print_stream_event_context(struct pretty_component *pretty,
+               const bt_event *event)
+{
+       int ret = 0;
+       const bt_field *main_field = NULL;
+
+       main_field = bt_event_borrow_common_context_field_const(event);
+       if (!main_field) {
+               goto end;
+       }
+       if (!pretty->start_line) {
+               g_string_append(pretty->string, ", ");
+       }
+       pretty->start_line = false;
+       if (pretty->options.print_scope_field_names) {
+               print_name_equal(pretty, "stream.event.context");
+       }
+       ret = print_field(pretty, main_field,
+                       pretty->options.print_context_field_names, NULL, 0);
+
+end:
+       return ret;
+}
+
+static
+int print_event_context(struct pretty_component *pretty,
+               const bt_event *event)
+{
+       int ret = 0;
+       const bt_field *main_field = NULL;
+
+       main_field = bt_event_borrow_specific_context_field_const(event);
+       if (!main_field) {
+               goto end;
+       }
+       if (!pretty->start_line) {
+               g_string_append(pretty->string, ", ");
+       }
+       pretty->start_line = false;
+       if (pretty->options.print_scope_field_names) {
+               print_name_equal(pretty, "event.context");
+       }
+       ret = print_field(pretty, main_field,
+                       pretty->options.print_context_field_names, NULL, 0);
+
+end:
+       return ret;
+}
+
+static
+int print_event_payload(struct pretty_component *pretty,
+               const bt_event *event)
+{
+       int ret = 0;
+       const bt_field *main_field = NULL;
+
+       main_field = bt_event_borrow_payload_field_const(event);
+       if (!main_field) {
+               goto end;
+       }
+       if (!pretty->start_line) {
+               g_string_append(pretty->string, ", ");
+       }
+       pretty->start_line = false;
+       if (pretty->options.print_scope_field_names) {
+               print_name_equal(pretty, "event.fields");
+       }
+       ret = print_field(pretty, main_field,
+                       pretty->options.print_payload_field_names, NULL, 0);
+
+end:
+       return ret;
+}
+
+static
+int flush_buf(FILE *stream, struct pretty_component *pretty)
+{
+       int ret = 0;
+
+       if (pretty->string->len == 0) {
+               goto end;
+       }
+
+       if (fwrite(pretty->string->str, pretty->string->len, 1, stream) != 1) {
+               ret = -1;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+int pretty_print_event(struct pretty_component *pretty,
+               const bt_message *event_msg)
+{
+       int ret;
+       const bt_event *event =
+               bt_message_event_borrow_event_const(event_msg);
+
+       BT_ASSERT(event);
+       pretty->start_line = true;
+       g_string_assign(pretty->string, "");
+       ret = print_event_header(pretty, event_msg);
+       if (ret != 0) {
+               goto end;
+       }
+
+       ret = print_stream_packet_context(pretty, event);
+       if (ret != 0) {
+               goto end;
+       }
+
+       ret = print_stream_event_context(pretty, event);
+       if (ret != 0) {
+               goto end;
+       }
+
+       ret = print_event_context(pretty, event);
+       if (ret != 0) {
+               goto end;
+       }
+
+       ret = print_event_payload(pretty, event);
+       if (ret != 0) {
+               goto end;
+       }
+
+       g_string_append_c(pretty->string, '\n');
+       if (flush_buf(pretty->out, pretty)) {
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int print_discarded_elements_msg(struct pretty_component *pretty,
+               const bt_stream *stream,
+               const bt_clock_snapshot *begin_clock_snapshot,
+               const bt_clock_snapshot *end_clock_snapshot,
+               uint64_t count, const char *elem_type)
+{
+       int ret = 0;
+       const bt_stream_class *stream_class = NULL;
+       const bt_trace *trace = NULL;
+       const char *stream_name;
+       const char *trace_name;
+       bt_uuid trace_uuid;
+       int64_t stream_class_id;
+       int64_t stream_id;
+       const char *init_msg;
+
+       /* Stream name */
+       stream_name = bt_stream_get_name(stream);
+       if (!stream_name) {
+               stream_name = "(unknown)";
+       }
+
+       /* Stream class ID */
+       stream_class = bt_stream_borrow_class_const(stream);
+       BT_ASSERT(stream_class);
+       stream_class_id = bt_stream_class_get_id(stream_class);
+
+       /* Stream ID */
+       stream_id = bt_stream_get_id(stream);
+
+       /* Trace name */
+       trace = bt_stream_borrow_trace_const(stream);
+       BT_ASSERT(trace);
+       trace_name = bt_trace_get_name(trace);
+       if (!trace_name) {
+               trace_name = "(unknown)";
+       }
+
+       /* Trace UUID */
+       trace_uuid = bt_trace_class_get_uuid(
+               bt_trace_borrow_class_const(trace));
+
+       /* Format message */
+       g_string_assign(pretty->string, "");
+
+       if (count == UINT64_C(-1)) {
+               init_msg = "Tracer may have discarded";
+       } else {
+               init_msg = "Tracer discarded";
+       }
+
+       g_string_append_printf(pretty->string,
+               "%s%sWARNING%s%s: %s ",
+               bt_common_color_fg_yellow(),
+               bt_common_color_bold(),
+               bt_common_color_reset(),
+               bt_common_color_fg_yellow(), init_msg);
+
+       if (count == UINT64_C(-1)) {
+               g_string_append_printf(pretty->string, "%ss", elem_type);
+       } else {
+               g_string_append_printf(pretty->string,
+                       "%" PRIu64 " %s%s", count, elem_type,
+                       count == 1 ? "" : "s");
+       }
+
+       g_string_append_c(pretty->string, ' ');
+
+       if (begin_clock_snapshot && end_clock_snapshot) {
+               g_string_append(pretty->string, "between [");
+               print_timestamp_wall(pretty, begin_clock_snapshot, false);
+               g_string_append(pretty->string, "] and [");
+               print_timestamp_wall(pretty, end_clock_snapshot, false);
+               g_string_append(pretty->string, "]");
+       } else {
+               g_string_append(pretty->string, "(unknown time range)");
+       }
+
+       g_string_append_printf(pretty->string, " in trace \"%s\" ", trace_name);
+
+       if (trace_uuid) {
+               g_string_append_printf(pretty->string,
+                       "(UUID: %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x) ",
+                       trace_uuid[0],
+                       trace_uuid[1],
+                       trace_uuid[2],
+                       trace_uuid[3],
+                       trace_uuid[4],
+                       trace_uuid[5],
+                       trace_uuid[6],
+                       trace_uuid[7],
+                       trace_uuid[8],
+                       trace_uuid[9],
+                       trace_uuid[10],
+                       trace_uuid[11],
+                       trace_uuid[12],
+                       trace_uuid[13],
+                       trace_uuid[14],
+                       trace_uuid[15]);
+       } else {
+               g_string_append(pretty->string, "(no UUID) ");
+       }
+
+       g_string_append_printf(pretty->string,
+               "within stream \"%s\" (stream class ID: %" PRIu64 ", ",
+               stream_name, stream_class_id);
+
+       if (stream_id >= 0) {
+               g_string_append_printf(pretty->string,
+                       "stream ID: %" PRIu64, stream_id);
+       } else {
+               g_string_append(pretty->string, "no stream ID");
+       }
+
+       g_string_append_printf(pretty->string, ").%s\n",
+               bt_common_color_reset());
+
+       /*
+        * Print to standard error stream to remain backward compatible
+        * with Babeltrace 1.
+        */
+       if (flush_buf(stderr, pretty)) {
+               ret = -1;
+       }
+
+       return ret;
+}
+
+BT_HIDDEN
+int pretty_print_discarded_items(struct pretty_component *pretty,
+               const bt_message *msg)
+{
+       const bt_clock_snapshot *begin = NULL;
+       const bt_clock_snapshot *end = NULL;
+       const bt_stream *stream;
+       const bt_stream_class *stream_class;
+       uint64_t count = UINT64_C(-1);
+       const char *elem_type;
+
+       switch (bt_message_get_type(msg)) {
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+               stream = bt_message_discarded_events_borrow_stream_const(msg);
+
+               if (bt_message_discarded_events_get_count(msg, &count) ==
+                               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
+                       count = UINT64_C(-1);
+               }
+
+               elem_type = "event";
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+               stream = bt_message_discarded_packets_borrow_stream_const(msg);
+
+               if (bt_message_discarded_packets_get_count(msg, &count) ==
+                               BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) {
+                       count = UINT64_C(-1);
+               }
+
+               elem_type = "packet";
+               break;
+       default:
+               abort();
+       }
+
+       BT_ASSERT(stream);
+       stream_class = bt_stream_borrow_class_const(stream);
+
+       switch (bt_message_get_type(msg)) {
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+               if (bt_stream_class_discarded_events_have_default_clock_snapshots(
+                               stream_class)) {
+                       begin = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+                               msg);
+                       end = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
+                               msg);
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+               if (bt_stream_class_discarded_packets_have_default_clock_snapshots(
+                               stream_class)) {
+                       begin = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+                               msg);
+                       end = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
+                               msg);
+               }
+
+               break;
+       default:
+               abort();
+       }
+
+       print_discarded_elements_msg(pretty, stream, begin, end,
+               count, elem_type);
+       return 0;
+}
diff --git a/src/plugins/utils/Makefile.am b/src/plugins/utils/Makefile.am
new file mode 100644 (file)
index 0000000..67f34f2
--- /dev/null
@@ -0,0 +1,21 @@
+SUBDIRS = dummy muxer counter trimmer
+
+plugindir = "$(PLUGINSDIR)"
+plugin_LTLIBRARIES = babeltrace-plugin-utils.la
+
+babeltrace_plugin_utils_la_SOURCES = plugin.c
+babeltrace_plugin_utils_la_LDFLAGS = \
+       $(LT_NO_UNDEFINED) \
+       -avoid-version -module
+babeltrace_plugin_utils_la_LIBADD = \
+       dummy/libbabeltrace2-plugin-dummy-cc.la \
+       muxer/libbabeltrace2-plugin-muxer.la \
+       counter/libbabeltrace2-plugin-counter-cc.la \
+       trimmer/libbabeltrace2-plugin-trimmer.la
+
+if !ENABLE_BUILT_IN_PLUGINS
+babeltrace_plugin_utils_la_LIBADD += \
+       $(top_builddir)/src/lib/libbabeltrace2.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la
+endif
diff --git a/src/plugins/utils/counter/Makefile.am b/src/plugins/utils/counter/Makefile.am
new file mode 100644 (file)
index 0000000..ef060f1
--- /dev/null
@@ -0,0 +1,6 @@
+noinst_LTLIBRARIES = libbabeltrace2-plugin-counter-cc.la
+libbabeltrace2_plugin_counter_cc_la_SOURCES = \
+       counter.c \
+       counter.h \
+       logging.c \
+       logging.h
diff --git a/src/plugins/utils/counter/counter.c b/src/plugins/utils/counter/counter.c
new file mode 100644 (file)
index 0000000..37ddd03
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-UTILS-COUNTER-FLT"
+#include "logging.h"
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "common/common.h"
+#include "plugins/plugins-common.h"
+#include "common/assert.h"
+#include <inttypes.h>
+#include <stdint.h>
+
+#include "counter.h"
+
+#define PRINTF_COUNT(_what, _var, args...)                             \
+       do {                                                            \
+               if (counter->count._var != 0 || !counter->hide_zero) {  \
+                       printf("%15" PRIu64 " %s message%s\n",          \
+                               counter->count._var,                    \
+                               (_what),                                \
+                               counter->count._var == 1 ? "" : "s");   \
+               }                                                       \
+       } while (0)
+
+static
+const char * const in_port_name = "in";
+
+static
+uint64_t get_total_count(struct counter *counter)
+{
+       return counter->count.event +
+               counter->count.stream_begin +
+               counter->count.stream_end +
+               counter->count.stream_activity_begin +
+               counter->count.stream_activity_end +
+               counter->count.packet_begin +
+               counter->count.packet_end +
+               counter->count.disc_events +
+               counter->count.disc_packets +
+               counter->count.msg_iter_inactivity +
+               counter->count.other;
+}
+
+static
+void print_count(struct counter *counter)
+{
+       uint64_t total = get_total_count(counter);
+
+       PRINTF_COUNT("Event", event);
+       PRINTF_COUNT("Stream beginning", stream_begin);
+       PRINTF_COUNT("Stream end", stream_end);
+       PRINTF_COUNT("Stream activity beginning", stream_activity_begin);
+       PRINTF_COUNT("Stream activity end", stream_activity_end);
+       PRINTF_COUNT("Packet beginning", packet_begin);
+       PRINTF_COUNT("Packet end", packet_end);
+       PRINTF_COUNT("Discarded event", disc_events);
+       PRINTF_COUNT("Discarded packet", disc_packets);
+       PRINTF_COUNT("Message iterator inactivity", msg_iter_inactivity);
+
+       if (counter->count.other > 0) {
+               PRINTF_COUNT("Other (unknown)", other);
+       }
+
+       printf("%s%15" PRIu64 " message%s (TOTAL)%s\n",
+               bt_common_color_bold(), total, total == 1 ? "" : "s",
+               bt_common_color_reset());
+       counter->last_printed_total = total;
+}
+
+static
+void try_print_count(struct counter *counter, uint64_t msg_count)
+{
+       if (counter->step == 0) {
+               /* No update */
+               return;
+       }
+
+       counter->at += msg_count;
+
+       if (counter->at >= counter->step) {
+               counter->at = 0;
+               print_count(counter);
+               putchar('\n');
+       }
+}
+
+static
+void try_print_last(struct counter *counter)
+{
+       const uint64_t total = get_total_count(counter);
+
+       if (total != counter->last_printed_total) {
+               print_count(counter);
+       }
+}
+
+void destroy_private_counter_data(struct counter *counter)
+{
+       bt_self_component_port_input_message_iterator_put_ref(counter->msg_iter);
+       g_free(counter);
+}
+
+BT_HIDDEN
+void counter_finalize(bt_self_component_sink *comp)
+{
+       struct counter *counter;
+
+       BT_ASSERT(comp);
+       counter = bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(comp));
+       BT_ASSERT(counter);
+       try_print_last(counter);
+       bt_self_component_port_input_message_iterator_put_ref(counter->msg_iter);
+       g_free(counter);
+}
+
+BT_HIDDEN
+bt_self_component_status counter_init(
+               bt_self_component_sink *component,
+               const bt_value *params,
+               UNUSED_VAR void *init_method_data)
+{
+       bt_self_component_status ret;
+       struct counter *counter = g_new0(struct counter, 1);
+       const bt_value *step = NULL;
+       const bt_value *hide_zero = NULL;
+
+       if (!counter) {
+               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto error;
+       }
+
+       ret = bt_self_component_sink_add_input_port(component,
+               "in", NULL, NULL);
+       if (ret != BT_SELF_COMPONENT_STATUS_OK) {
+               goto error;
+       }
+
+       counter->last_printed_total = -1ULL;
+       counter->step = 10000;
+       step = bt_value_map_borrow_entry_value_const(params, "step");
+       if (step) {
+               if (!bt_value_is_unsigned_integer(step)) {
+                       BT_LOGE("`step` parameter: expecting an unsigned integer value: "
+                               "type=%s", bt_common_value_type_string(
+                                       bt_value_get_type(step)));
+                       goto error;
+               }
+
+               counter->step = bt_value_unsigned_integer_get(step);
+       }
+
+       hide_zero = bt_value_map_borrow_entry_value_const(params, "hide-zero");
+       if (hide_zero) {
+               if (!bt_value_is_bool(hide_zero)) {
+                       BT_LOGE("`hide-zero` parameter: expecting a boolean value: "
+                               "type=%s", bt_common_value_type_string(
+                                       bt_value_get_type(hide_zero)));
+                       goto error;
+               }
+
+               counter->hide_zero = (bool) bt_value_bool_get(hide_zero);
+       }
+
+       bt_self_component_set_data(
+               bt_self_component_sink_as_self_component(component),
+               counter);
+       goto end;
+
+error:
+       destroy_private_counter_data(counter);
+       ret = BT_SELF_COMPONENT_STATUS_ERROR;
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_self_component_status counter_graph_is_configured(
+               bt_self_component_sink *comp)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct counter *counter;
+       bt_self_component_port_input_message_iterator *iterator;
+
+       counter = bt_self_component_get_data(
+               bt_self_component_sink_as_self_component(comp));
+       BT_ASSERT(counter);
+       iterator = bt_self_component_port_input_message_iterator_create(
+               bt_self_component_sink_borrow_input_port_by_name(comp,
+                       in_port_name));
+       if (!iterator) {
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF(
+               counter->msg_iter, iterator);
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+bt_self_component_status counter_consume(
+               bt_self_component_sink *comp)
+{
+       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
+       struct counter *counter;
+       bt_message_iterator_status it_ret;
+       uint64_t msg_count;
+       bt_message_array_const msgs;
+
+       counter = bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(comp));
+       BT_ASSERT(counter);
+
+       if (unlikely(!counter->msg_iter)) {
+               try_print_last(counter);
+               ret = BT_SELF_COMPONENT_STATUS_END;
+               goto end;
+       }
+
+       /* Consume messages */
+       it_ret = bt_self_component_port_input_message_iterator_next(
+               counter->msg_iter, &msgs, &msg_count);
+       if (it_ret < 0) {
+               ret = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       }
+
+       switch (it_ret) {
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+       {
+               uint64_t i;
+
+               for (i = 0; i < msg_count; i++) {
+                       const bt_message *msg = msgs[i];
+
+                       BT_ASSERT(msg);
+                       switch (bt_message_get_type(msg)) {
+                       case BT_MESSAGE_TYPE_EVENT:
+                               counter->count.event++;
+                               break;
+                       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+                               counter->count.packet_begin++;
+                               break;
+                       case BT_MESSAGE_TYPE_PACKET_END:
+                               counter->count.packet_end++;
+                               break;
+                       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+                               counter->count.msg_iter_inactivity++;
+                               break;
+                       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
+                               counter->count.stream_begin++;
+                               break;
+                       case BT_MESSAGE_TYPE_STREAM_END:
+                               counter->count.stream_end++;
+                               break;
+                       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+                               counter->count.stream_activity_begin++;
+                               break;
+                       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+                               counter->count.stream_activity_end++;
+                               break;
+                       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+                               counter->count.disc_events++;
+                               break;
+                       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+                               counter->count.disc_packets++;
+                               break;
+                       default:
+                               counter->count.other++;
+                       }
+
+                       bt_message_put_ref(msg);
+               }
+
+               ret = BT_SELF_COMPONENT_STATUS_OK;
+               break;
+       }
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               ret = BT_SELF_COMPONENT_STATUS_AGAIN;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_END:
+               try_print_last(counter);
+               ret = BT_SELF_COMPONENT_STATUS_END;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       default:
+               break;
+       }
+
+       try_print_count(counter, msg_count);
+
+end:
+       return ret;
+}
diff --git a/src/plugins/utils/counter/counter.h b/src/plugins/utils/counter/counter.h
new file mode 100644 (file)
index 0000000..c29f0fd
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef BABELTRACE_PLUGINS_UTILS_COUNTER_H
+#define BABELTRACE_PLUGINS_UTILS_COUNTER_H
+
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include <babeltrace2/babeltrace.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+struct counter {
+       bt_self_component_port_input_message_iterator *msg_iter;
+       struct {
+               uint64_t event;
+               uint64_t stream_begin;
+               uint64_t stream_end;
+               uint64_t stream_activity_begin;
+               uint64_t stream_activity_end;
+               uint64_t packet_begin;
+               uint64_t packet_end;
+               uint64_t disc_events;
+               uint64_t disc_packets;
+               uint64_t msg_iter_inactivity;
+               uint64_t other;
+       } count;
+       uint64_t last_printed_total;
+       uint64_t at;
+       uint64_t step;
+       bool hide_zero;
+};
+
+BT_HIDDEN
+bt_self_component_status counter_init(
+               bt_self_component_sink *component,
+               const bt_value *params, void *init_method_data);
+
+BT_HIDDEN
+void counter_finalize(bt_self_component_sink *component);
+
+BT_HIDDEN
+bt_self_component_status counter_graph_is_configured(
+               bt_self_component_sink *component);
+
+BT_HIDDEN
+bt_self_component_status counter_consume(bt_self_component_sink *component);
+
+#endif /* BABELTRACE_PLUGINS_UTILS_COUNTER_H */
diff --git a/src/plugins/utils/counter/logging.c b/src/plugins/utils/counter/logging.c
new file mode 100644 (file)
index 0000000..6fc046e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_counter_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_plugin_utils_counter_log_level,
+       "BABELTRACE_FLT_UTILS_COUNTER_LOG_LEVEL");
diff --git a/src/plugins/utils/counter/logging.h b/src/plugins/utils/counter/logging.h
new file mode 100644 (file)
index 0000000..8319243
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef PLUGINS_UTILS_COUNTER_LOGGING_H
+#define PLUGINS_UTILS_COUNTER_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_counter_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_utils_counter_log_level);
+
+#endif /* PLUGINS_UTILS_COUNTER_LOGGING_H */
diff --git a/src/plugins/utils/dummy/Makefile.am b/src/plugins/utils/dummy/Makefile.am
new file mode 100644 (file)
index 0000000..c0eb371
--- /dev/null
@@ -0,0 +1,2 @@
+noinst_LTLIBRARIES = libbabeltrace2-plugin-dummy-cc.la
+libbabeltrace2_plugin_dummy_cc_la_SOURCES = dummy.c dummy.h
diff --git a/src/plugins/utils/dummy/dummy.c b/src/plugins/utils/dummy/dummy.c
new file mode 100644 (file)
index 0000000..5da07ea
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include "plugins/plugins-common.h"
+#include "common/assert.h"
+#include "dummy.h"
+
+static
+const char * const in_port_name = "in";
+
+void destroy_private_dummy_data(struct dummy *dummy)
+{
+       bt_self_component_port_input_message_iterator_put_ref(dummy->msg_iter);
+       g_free(dummy);
+
+}
+
+BT_HIDDEN
+void dummy_finalize(bt_self_component_sink *comp)
+{
+       struct dummy *dummy;
+
+       BT_ASSERT(comp);
+       dummy = bt_self_component_get_data(
+                       bt_self_component_sink_as_self_component(comp));
+       BT_ASSERT(dummy);
+       destroy_private_dummy_data(dummy);
+}
+
+BT_HIDDEN
+bt_self_component_status dummy_init(
+               bt_self_component_sink *component,
+               const bt_value *params,
+               UNUSED_VAR void *init_method_data)
+{
+       bt_self_component_status ret;
+       struct dummy *dummy = g_new0(struct dummy, 1);
+
+       if (!dummy) {
+               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       ret = bt_self_component_sink_add_input_port(component,
+               "in", NULL, NULL);
+       if (ret != BT_SELF_COMPONENT_STATUS_OK) {
+               goto error;
+       }
+
+       bt_self_component_set_data(
+               bt_self_component_sink_as_self_component(component), dummy);
+       goto end;
+
+error:
+       destroy_private_dummy_data(dummy);
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_self_component_status dummy_graph_is_configured(
+               bt_self_component_sink *comp)
+{
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct dummy *dummy;
+       bt_self_component_port_input_message_iterator *iterator;
+
+       dummy = bt_self_component_get_data(
+               bt_self_component_sink_as_self_component(comp));
+       BT_ASSERT(dummy);
+       iterator = bt_self_component_port_input_message_iterator_create(
+               bt_self_component_sink_borrow_input_port_by_name(comp,
+                       in_port_name));
+       if (!iterator) {
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       BT_SELF_COMPONENT_PORT_INPUT_MESSAGE_ITERATOR_MOVE_REF(
+               dummy->msg_iter, iterator);
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+bt_self_component_status dummy_consume(
+               bt_self_component_sink *component)
+{
+       bt_self_component_status ret = BT_SELF_COMPONENT_STATUS_OK;
+       bt_message_array_const msgs;
+       uint64_t count;
+       struct dummy *dummy;
+       bt_message_iterator_status it_ret;
+       uint64_t i;
+
+       dummy = bt_self_component_get_data(
+               bt_self_component_sink_as_self_component(component));
+       BT_ASSERT(dummy);
+
+       if (unlikely(!dummy->msg_iter)) {
+               ret = BT_SELF_COMPONENT_STATUS_END;
+               goto end;
+       }
+
+       /* Consume one message  */
+       it_ret = bt_self_component_port_input_message_iterator_next(
+               dummy->msg_iter, &msgs, &count);
+       switch (it_ret) {
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+               ret = BT_SELF_COMPONENT_STATUS_OK;
+
+               for (i = 0; i < count; i++) {
+                       bt_message_put_ref(msgs[i]);
+               }
+
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               ret = BT_SELF_COMPONENT_STATUS_AGAIN;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_END:
+               ret = BT_SELF_COMPONENT_STATUS_END;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_ERROR:
+               ret = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto end;
+       case BT_MESSAGE_ITERATOR_STATUS_NOMEM:
+               ret = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       default:
+               break;
+       }
+
+end:
+       return ret;
+}
diff --git a/src/plugins/utils/dummy/dummy.h b/src/plugins/utils/dummy/dummy.h
new file mode 100644 (file)
index 0000000..ea44ecb
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef BABELTRACE_PLUGINS_UTILS_DUMMY_H
+#define BABELTRACE_PLUGINS_UTILS_DUMMY_H
+
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+#include <stdbool.h>
+
+struct dummy {
+       bt_self_component_port_input_message_iterator *msg_iter;
+};
+
+BT_HIDDEN
+bt_self_component_status dummy_init(
+               bt_self_component_sink *component,
+               const bt_value *params, void *init_method_data);
+
+BT_HIDDEN
+void dummy_finalize(bt_self_component_sink *component);
+
+BT_HIDDEN
+bt_self_component_status dummy_graph_is_configured(
+               bt_self_component_sink *comp);
+
+BT_HIDDEN
+bt_self_component_status dummy_consume(
+               bt_self_component_sink *component);
+
+#endif /* BABELTRACE_PLUGINS_UTILS_DUMMY_H */
diff --git a/src/plugins/utils/muxer/Makefile.am b/src/plugins/utils/muxer/Makefile.am
new file mode 100644 (file)
index 0000000..3eeb008
--- /dev/null
@@ -0,0 +1,2 @@
+noinst_LTLIBRARIES = libbabeltrace2-plugin-muxer.la
+libbabeltrace2_plugin_muxer_la_SOURCES = muxer.c muxer.h logging.c logging.h
diff --git a/src/plugins/utils/muxer/logging.c b/src/plugins/utils/muxer/logging.c
new file mode 100644 (file)
index 0000000..1bf5383
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_muxer_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_plugin_utils_muxer_log_level,
+       "BABELTRACE_FLT_UTILS_MUXER_LOG_LEVEL");
diff --git a/src/plugins/utils/muxer/logging.h b/src/plugins/utils/muxer/logging.h
new file mode 100644 (file)
index 0000000..ebb3538
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef PLUGINS_UTILS_MUXER_LOGGING_H
+#define PLUGINS_UTILS_MUXER_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_muxer_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_utils_muxer_log_level);
+
+#endif /* PLUGINS_UTILS_MUXER_LOGGING_H */
diff --git a/src/plugins/utils/muxer/muxer.c b/src/plugins/utils/muxer/muxer.c
new file mode 100644 (file)
index 0000000..b575f96
--- /dev/null
@@ -0,0 +1,1534 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-UTILS-MUXER-FLT"
+#include "logging.h"
+
+#include "common/babeltrace.h"
+#include "compat/uuid.h"
+#include <babeltrace2/babeltrace.h>
+#include "lib/value.h"
+#include "lib/graph/component.h"
+#include "lib/graph/message/iterator.h"
+#include "lib/graph/connection.h"
+#include "plugins/plugins-common.h"
+#include <glib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include "common/assert.h"
+#include "common/common.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "muxer.h"
+
+#define ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME       "assume-absolute-clock-classes"
+
+struct muxer_comp {
+       /* Weak ref */
+       bt_self_component_filter *self_comp;
+
+       unsigned int next_port_num;
+       size_t available_input_ports;
+       bool initializing_muxer_msg_iter;
+       bool assume_absolute_clock_classes;
+};
+
+struct muxer_upstream_msg_iter {
+       /* Owned by this, NULL if ended */
+       bt_self_component_port_input_message_iterator *msg_iter;
+
+       /* Contains `const bt_message *`, owned by this */
+       GQueue *msgs;
+};
+
+enum muxer_msg_iter_clock_class_expectation {
+       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ANY = 0,
+       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NONE,
+       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE,
+       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID,
+       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID,
+};
+
+struct muxer_msg_iter {
+       /*
+        * Array of struct muxer_upstream_msg_iter * (owned by this).
+        *
+        * NOTE: This array is searched in linearly to find the youngest
+        * current message. Keep this until benchmarks confirm that
+        * another data structure is faster than this for our typical
+        * use cases.
+        */
+       GPtrArray *active_muxer_upstream_msg_iters;
+
+       /*
+        * Array of struct muxer_upstream_msg_iter * (owned by this).
+        *
+        * We move ended message iterators from
+        * `active_muxer_upstream_msg_iters` to this array so as to be
+        * able to restore them when seeking.
+        */
+       GPtrArray *ended_muxer_upstream_msg_iters;
+
+       /* Last time returned in a message */
+       int64_t last_returned_ts_ns;
+
+       /* Clock class expectation state */
+       enum muxer_msg_iter_clock_class_expectation clock_class_expectation;
+
+       /*
+        * Expected clock class UUID, only valid when
+        * clock_class_expectation is
+        * MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID.
+        */
+       unsigned char expected_clock_class_uuid[BABELTRACE_UUID_LEN];
+};
+
+static
+void empty_message_queue(struct muxer_upstream_msg_iter *upstream_msg_iter)
+{
+       const bt_message *msg;
+
+       while ((msg = g_queue_pop_head(upstream_msg_iter->msgs))) {
+               bt_message_put_ref(msg);
+       }
+}
+
+static
+void destroy_muxer_upstream_msg_iter(
+               struct muxer_upstream_msg_iter *muxer_upstream_msg_iter)
+{
+       if (!muxer_upstream_msg_iter) {
+               return;
+       }
+
+       BT_LOGD("Destroying muxer's upstream message iterator wrapper: "
+               "addr=%p, msg-iter-addr=%p, queue-len=%u",
+               muxer_upstream_msg_iter,
+               muxer_upstream_msg_iter->msg_iter,
+               muxer_upstream_msg_iter->msgs->length);
+       bt_self_component_port_input_message_iterator_put_ref(
+               muxer_upstream_msg_iter->msg_iter);
+
+       if (muxer_upstream_msg_iter->msgs) {
+               empty_message_queue(muxer_upstream_msg_iter);
+               g_queue_free(muxer_upstream_msg_iter->msgs);
+       }
+
+       g_free(muxer_upstream_msg_iter);
+}
+
+static
+int muxer_msg_iter_add_upstream_msg_iter(struct muxer_msg_iter *muxer_msg_iter,
+               bt_self_component_port_input_message_iterator *self_msg_iter)
+{
+       int ret = 0;
+       struct muxer_upstream_msg_iter *muxer_upstream_msg_iter =
+               g_new0(struct muxer_upstream_msg_iter, 1);
+
+       if (!muxer_upstream_msg_iter) {
+               BT_LOGE_STR("Failed to allocate one muxer's upstream message iterator wrapper.");
+               goto error;
+       }
+
+       muxer_upstream_msg_iter->msg_iter = self_msg_iter;
+       bt_self_component_port_input_message_iterator_get_ref(muxer_upstream_msg_iter->msg_iter);
+       muxer_upstream_msg_iter->msgs = g_queue_new();
+       if (!muxer_upstream_msg_iter->msgs) {
+               BT_LOGE_STR("Failed to allocate a GQueue.");
+               goto error;
+       }
+
+       g_ptr_array_add(muxer_msg_iter->active_muxer_upstream_msg_iters,
+               muxer_upstream_msg_iter);
+       BT_LOGD("Added muxer's upstream message iterator wrapper: "
+               "addr=%p, muxer-msg-iter-addr=%p, msg-iter-addr=%p",
+               muxer_upstream_msg_iter, muxer_msg_iter,
+               self_msg_iter);
+
+       goto end;
+
+error:
+       g_free(muxer_upstream_msg_iter);
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static
+bt_self_component_status add_available_input_port(
+               bt_self_component_filter *self_comp)
+{
+       struct muxer_comp *muxer_comp = bt_self_component_get_data(
+               bt_self_component_filter_as_self_component(self_comp));
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       GString *port_name = NULL;
+
+       BT_ASSERT(muxer_comp);
+       port_name = g_string_new("in");
+       if (!port_name) {
+               BT_LOGE_STR("Failed to allocate a GString.");
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto end;
+       }
+
+       g_string_append_printf(port_name, "%u", muxer_comp->next_port_num);
+       status = bt_self_component_filter_add_input_port(
+               self_comp, port_name->str, NULL, NULL);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               BT_LOGE("Cannot add input port to muxer component: "
+                       "port-name=\"%s\", comp-addr=%p, status=%s",
+                       port_name->str, self_comp,
+                       bt_self_component_status_string(status));
+               goto end;
+       }
+
+       muxer_comp->available_input_ports++;
+       muxer_comp->next_port_num++;
+       BT_LOGD("Added one input port to muxer component: "
+               "port-name=\"%s\", comp-addr=%p",
+               port_name->str, self_comp);
+
+end:
+       if (port_name) {
+               g_string_free(port_name, TRUE);
+       }
+
+       return status;
+}
+
+static
+bt_self_component_status create_output_port(
+               bt_self_component_filter *self_comp)
+{
+       return bt_self_component_filter_add_output_port(
+               self_comp, "out", NULL, NULL);
+}
+
+static
+void destroy_muxer_comp(struct muxer_comp *muxer_comp)
+{
+       if (!muxer_comp) {
+               return;
+       }
+
+       g_free(muxer_comp);
+}
+
+static
+bt_value *get_default_params(void)
+{
+       bt_value *params;
+       int ret;
+
+       params = bt_value_map_create();
+       if (!params) {
+               BT_LOGE_STR("Cannot create a map value object.");
+               goto error;
+       }
+
+       ret = bt_value_map_insert_bool_entry(params,
+               ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME, false);
+       if (ret) {
+               BT_LOGE_STR("Cannot add boolean value to map value object.");
+               goto error;
+       }
+
+       goto end;
+
+error:
+       BT_VALUE_PUT_REF_AND_RESET(params);
+
+end:
+       return params;
+}
+
+static
+int configure_muxer_comp(struct muxer_comp *muxer_comp,
+               const bt_value *params)
+{
+       bt_value *default_params = NULL;
+       bt_value *real_params = NULL;
+       const bt_value *assume_absolute_clock_classes = NULL;
+       int ret = 0;
+       bt_bool bool_val;
+
+       default_params = get_default_params();
+       if (!default_params) {
+               BT_LOGE("Cannot get default parameters: "
+                       "muxer-comp-addr=%p", muxer_comp);
+               goto error;
+       }
+
+       ret = bt_value_map_extend(default_params, params, &real_params);
+       if (ret) {
+               BT_LOGE("Cannot extend default parameters map value: "
+                       "muxer-comp-addr=%p, def-params-addr=%p, "
+                       "params-addr=%p", muxer_comp, default_params,
+                       params);
+               goto error;
+       }
+
+       assume_absolute_clock_classes = bt_value_map_borrow_entry_value(real_params,
+                                                                       ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME);
+       if (assume_absolute_clock_classes &&
+                       !bt_value_is_bool(assume_absolute_clock_classes)) {
+               BT_LOGE("Expecting a boolean value for the `%s` parameter: "
+                       "muxer-comp-addr=%p, value-type=%s",
+                       ASSUME_ABSOLUTE_CLOCK_CLASSES_PARAM_NAME, muxer_comp,
+                       bt_common_value_type_string(
+                               bt_value_get_type(assume_absolute_clock_classes)));
+               goto error;
+       }
+
+       bool_val = bt_value_bool_get(assume_absolute_clock_classes);
+       muxer_comp->assume_absolute_clock_classes = (bool) bool_val;
+       BT_LOGD("Configured muxer component: muxer-comp-addr=%p, "
+               "assume-absolute-clock-classes=%d",
+               muxer_comp, muxer_comp->assume_absolute_clock_classes);
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       bt_value_put_ref(default_params);
+       bt_value_put_ref(real_params);
+       return ret;
+}
+
+BT_HIDDEN
+bt_self_component_status muxer_init(
+               bt_self_component_filter *self_comp,
+               const bt_value *params, void *init_data)
+{
+       int ret;
+       bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
+       struct muxer_comp *muxer_comp = g_new0(struct muxer_comp, 1);
+
+       BT_LOGD("Initializing muxer component: "
+               "comp-addr=%p, params-addr=%p", self_comp, params);
+
+       if (!muxer_comp) {
+               BT_LOGE_STR("Failed to allocate one muxer component.");
+               goto error;
+       }
+
+       ret = configure_muxer_comp(muxer_comp, params);
+       if (ret) {
+               BT_LOGE("Cannot configure muxer component: "
+                       "muxer-comp-addr=%p, params-addr=%p",
+                       muxer_comp, params);
+               goto error;
+       }
+
+       muxer_comp->self_comp = self_comp;
+       bt_self_component_set_data(
+               bt_self_component_filter_as_self_component(self_comp),
+               muxer_comp);
+       status = add_available_input_port(self_comp);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               BT_LOGE("Cannot ensure that at least one muxer component's input port is available: "
+                       "muxer-comp-addr=%p, status=%s",
+                       muxer_comp,
+                       bt_self_component_status_string(status));
+               goto error;
+       }
+
+       status = create_output_port(self_comp);
+       if (status) {
+               BT_LOGE("Cannot create muxer component's output port: "
+                       "muxer-comp-addr=%p, status=%s",
+                       muxer_comp,
+                       bt_self_component_status_string(status));
+               goto error;
+       }
+
+       BT_LOGD("Initialized muxer component: "
+               "comp-addr=%p, params-addr=%p, muxer-comp-addr=%p",
+               self_comp, params, muxer_comp);
+
+       goto end;
+
+error:
+       destroy_muxer_comp(muxer_comp);
+       bt_self_component_set_data(
+               bt_self_component_filter_as_self_component(self_comp),
+               NULL);
+
+       if (status == BT_SELF_COMPONENT_STATUS_OK) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+       }
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+void muxer_finalize(bt_self_component_filter *self_comp)
+{
+       struct muxer_comp *muxer_comp = bt_self_component_get_data(
+               bt_self_component_filter_as_self_component(self_comp));
+
+       BT_LOGD("Finalizing muxer component: comp-addr=%p",
+               self_comp);
+       destroy_muxer_comp(muxer_comp);
+}
+
+static
+bt_self_component_port_input_message_iterator *
+create_msg_iter_on_input_port(bt_self_component_port_input *self_port)
+{
+       const bt_port *port = bt_self_component_port_as_port(
+               bt_self_component_port_input_as_self_component_port(
+                       self_port));
+       bt_self_component_port_input_message_iterator *msg_iter =
+               NULL;
+
+       BT_ASSERT(port);
+       BT_ASSERT(bt_port_is_connected(port));
+
+       // TODO: Advance the iterator to >= the time of the latest
+       //       returned message by the muxer message
+       //       iterator which creates it.
+       msg_iter = bt_self_component_port_input_message_iterator_create(
+               self_port);
+       if (!msg_iter) {
+               BT_LOGE("Cannot create upstream message iterator on input port: "
+                       "port-addr=%p, port-name=\"%s\"",
+                       port, bt_port_get_name(port));
+               goto end;
+       }
+
+       BT_LOGD("Created upstream message iterator on input port: "
+               "port-addr=%p, port-name=\"%s\", msg-iter-addr=%p",
+               port, bt_port_get_name(port), msg_iter);
+
+end:
+       return msg_iter;
+}
+
+static
+bt_self_message_iterator_status muxer_upstream_msg_iter_next(
+               struct muxer_upstream_msg_iter *muxer_upstream_msg_iter,
+               bool *is_ended)
+{
+       bt_self_message_iterator_status status;
+       bt_message_iterator_status input_port_iter_status;
+       bt_message_array_const msgs;
+       uint64_t i;
+       uint64_t count;
+
+       BT_LOGV("Calling upstream message iterator's \"next\" method: "
+               "muxer-upstream-msg-iter-wrap-addr=%p, msg-iter-addr=%p",
+               muxer_upstream_msg_iter,
+               muxer_upstream_msg_iter->msg_iter);
+       input_port_iter_status = bt_self_component_port_input_message_iterator_next(
+               muxer_upstream_msg_iter->msg_iter, &msgs, &count);
+       BT_LOGV("Upstream message iterator's \"next\" method returned: "
+               "status=%s", bt_message_iterator_status_string(input_port_iter_status));
+
+       switch (input_port_iter_status) {
+       case BT_MESSAGE_ITERATOR_STATUS_OK:
+               /*
+                * Message iterator's current message is
+                * valid: it must be considered for muxing operations.
+                */
+               BT_LOGV_STR("Validated upstream message iterator wrapper.");
+               BT_ASSERT(count > 0);
+
+               /* Move messages to our queue */
+               for (i = 0; i < count; i++) {
+                       /*
+                        * Push to tail in order; other side
+                        * (muxer_msg_iter_do_next_one()) consumes
+                        * from the head first.
+                        */
+                       g_queue_push_tail(muxer_upstream_msg_iter->msgs,
+                               (void *) msgs[i]);
+               }
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_AGAIN:
+               /*
+                * Message iterator's current message is not
+                * valid anymore. Return
+                * BT_MESSAGE_ITERATOR_STATUS_AGAIN immediately.
+                */
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_AGAIN;
+               break;
+       case BT_MESSAGE_ITERATOR_STATUS_END:    /* Fall-through. */
+               /*
+                * Message iterator reached the end: release it. It
+                * won't be considered again to find the youngest
+                * message.
+                */
+               *is_ended = true;
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+               break;
+       default:
+               /* Error or unsupported status code */
+               BT_LOGE("Error or unsupported status code: "
+                       "status-code=%d", input_port_iter_status);
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               break;
+       }
+
+       return status;
+}
+
+static
+int get_msg_ts_ns(struct muxer_comp *muxer_comp,
+               struct muxer_msg_iter *muxer_msg_iter,
+               const bt_message *msg, int64_t last_returned_ts_ns,
+               int64_t *ts_ns)
+{
+       const bt_clock_snapshot *clock_snapshot = NULL;
+       int ret = 0;
+       bt_message_stream_activity_clock_snapshot_state sa_cs_state;
+       const bt_stream_class *stream_class = NULL;
+       bt_message_type msg_type;
+
+       BT_ASSERT(msg);
+       BT_ASSERT(ts_ns);
+       BT_LOGV("Getting message's timestamp: "
+               "muxer-msg-iter-addr=%p, msg-addr=%p, "
+               "last-returned-ts=%" PRId64,
+               muxer_msg_iter, msg, last_returned_ts_ns);
+
+       if (unlikely(muxer_msg_iter->clock_class_expectation ==
+                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NONE)) {
+               *ts_ns = last_returned_ts_ns;
+               goto end;
+       }
+
+       msg_type = bt_message_get_type(msg);
+
+       if (unlikely(msg_type == BT_MESSAGE_TYPE_PACKET_BEGINNING)) {
+               stream_class = bt_stream_borrow_class_const(
+                       bt_packet_borrow_stream_const(
+                               bt_message_packet_beginning_borrow_packet_const(
+                                       msg)));
+       } else if (unlikely(msg_type == BT_MESSAGE_TYPE_PACKET_END)) {
+               stream_class = bt_stream_borrow_class_const(
+                       bt_packet_borrow_stream_const(
+                               bt_message_packet_end_borrow_packet_const(
+                                       msg)));
+       } else if (unlikely(msg_type == BT_MESSAGE_TYPE_DISCARDED_EVENTS)) {
+               stream_class = bt_stream_borrow_class_const(
+                       bt_message_discarded_events_borrow_stream_const(msg));
+       } else if (unlikely(msg_type == BT_MESSAGE_TYPE_DISCARDED_PACKETS)) {
+               stream_class = bt_stream_borrow_class_const(
+                       bt_message_discarded_packets_borrow_stream_const(msg));
+       }
+
+       switch (msg_type) {
+       case BT_MESSAGE_TYPE_EVENT:
+               BT_ASSERT(bt_message_event_borrow_stream_class_default_clock_class_const(
+                               msg));
+               clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+               if (bt_stream_class_packets_have_beginning_default_clock_snapshot(
+                               stream_class)) {
+                       clock_snapshot = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
+                               msg);
+               } else {
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_PACKET_END:
+               if (bt_stream_class_packets_have_end_default_clock_snapshot(
+                               stream_class)) {
+                       clock_snapshot = bt_message_packet_end_borrow_default_clock_snapshot_const(
+                               msg);
+               } else {
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+               if (bt_stream_class_discarded_events_have_default_clock_snapshots(
+                               stream_class)) {
+                       clock_snapshot = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+                               msg);
+               } else {
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+               if (bt_stream_class_discarded_packets_have_default_clock_snapshots(
+                               stream_class)) {
+                       clock_snapshot = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+                               msg);
+               } else {
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+               BT_ASSERT(bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
+                               msg));
+               sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
+                       msg, &clock_snapshot);
+               if (sa_cs_state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+               BT_ASSERT(bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
+                               msg));
+               sa_cs_state = bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
+                       msg, &clock_snapshot);
+               if (sa_cs_state != BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_KNOWN) {
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+               clock_snapshot = bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
+                       msg);
+               break;
+       default:
+               /* All the other messages have a higher priority */
+               BT_LOGV_STR("Message has no timestamp: using the last returned timestamp.");
+               *ts_ns = last_returned_ts_ns;
+               goto end;
+       }
+
+       ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot, ts_ns);
+       if (ret) {
+               BT_LOGE("Cannot get nanoseconds from Epoch of clock snapshot: "
+                       "clock-snapshot-addr=%p", clock_snapshot);
+               goto error;
+       }
+
+       goto end;
+
+no_clock_snapshot:
+       BT_LOGV_STR("Message's default clock snapshot is missing: "
+               "using the last returned timestamp.");
+       *ts_ns = last_returned_ts_ns;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       if (ret == 0) {
+               BT_LOGV("Found message's timestamp: "
+                       "muxer-msg-iter-addr=%p, msg-addr=%p, "
+                       "last-returned-ts=%" PRId64 ", ts=%" PRId64,
+                       muxer_msg_iter, msg, last_returned_ts_ns,
+                       *ts_ns);
+       }
+
+       return ret;
+}
+
+static inline
+int validate_clock_class(struct muxer_msg_iter *muxer_msg_iter,
+               struct muxer_comp *muxer_comp,
+               const bt_clock_class *clock_class)
+{
+       int ret = 0;
+       const unsigned char *cc_uuid;
+       const char *cc_name;
+
+       BT_ASSERT(clock_class);
+       cc_uuid = bt_clock_class_get_uuid(clock_class);
+       cc_name = bt_clock_class_get_name(clock_class);
+
+       if (muxer_msg_iter->clock_class_expectation ==
+                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ANY) {
+               /*
+                * This is the first clock class that this muxer
+                * message iterator encounters. Its properties
+                * determine what to expect for the whole lifetime of
+                * the iterator without a true
+                * `assume-absolute-clock-classes` parameter.
+                */
+               if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
+                       /* Expect absolute clock classes */
+                       muxer_msg_iter->clock_class_expectation =
+                               MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE;
+               } else {
+                       if (cc_uuid) {
+                               /*
+                                * Expect non-absolute clock classes
+                                * with a specific UUID.
+                                */
+                               muxer_msg_iter->clock_class_expectation =
+                                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID;
+                               memcpy(muxer_msg_iter->expected_clock_class_uuid,
+                                       cc_uuid, BABELTRACE_UUID_LEN);
+                       } else {
+                               /*
+                                * Expect non-absolute clock classes
+                                * with no UUID.
+                                */
+                               muxer_msg_iter->clock_class_expectation =
+                                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID;
+                       }
+               }
+       }
+
+       if (!muxer_comp->assume_absolute_clock_classes) {
+               switch (muxer_msg_iter->clock_class_expectation) {
+               case MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ABSOLUTE:
+                       if (!bt_clock_class_origin_is_unix_epoch(clock_class)) {
+                               BT_LOGE("Expecting an absolute clock class, "
+                                       "but got a non-absolute one: "
+                                       "clock-class-addr=%p, clock-class-name=\"%s\"",
+                                       clock_class, cc_name);
+                               goto error;
+                       }
+                       break;
+               case MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_NO_UUID:
+                       if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
+                               BT_LOGE("Expecting a non-absolute clock class with no UUID, "
+                                       "but got an absolute one: "
+                                       "clock-class-addr=%p, clock-class-name=\"%s\"",
+                                       clock_class, cc_name);
+                               goto error;
+                       }
+
+                       if (cc_uuid) {
+                               BT_LOGE("Expecting a non-absolute clock class with no UUID, "
+                                       "but got one with a UUID: "
+                                       "clock-class-addr=%p, clock-class-name=\"%s\", "
+                                       "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+                                       clock_class, cc_name,
+                                       (unsigned int) cc_uuid[0],
+                                       (unsigned int) cc_uuid[1],
+                                       (unsigned int) cc_uuid[2],
+                                       (unsigned int) cc_uuid[3],
+                                       (unsigned int) cc_uuid[4],
+                                       (unsigned int) cc_uuid[5],
+                                       (unsigned int) cc_uuid[6],
+                                       (unsigned int) cc_uuid[7],
+                                       (unsigned int) cc_uuid[8],
+                                       (unsigned int) cc_uuid[9],
+                                       (unsigned int) cc_uuid[10],
+                                       (unsigned int) cc_uuid[11],
+                                       (unsigned int) cc_uuid[12],
+                                       (unsigned int) cc_uuid[13],
+                                       (unsigned int) cc_uuid[14],
+                                       (unsigned int) cc_uuid[15]);
+                               goto error;
+                       }
+                       break;
+               case MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NOT_ABS_SPEC_UUID:
+                       if (bt_clock_class_origin_is_unix_epoch(clock_class)) {
+                               BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
+                                       "but got an absolute one: "
+                                       "clock-class-addr=%p, clock-class-name=\"%s\"",
+                                       clock_class, cc_name);
+                               goto error;
+                       }
+
+                       if (!cc_uuid) {
+                               BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
+                                       "but got one with no UUID: "
+                                       "clock-class-addr=%p, clock-class-name=\"%s\"",
+                                       clock_class, cc_name);
+                               goto error;
+                       }
+
+                       if (memcmp(muxer_msg_iter->expected_clock_class_uuid,
+                                       cc_uuid, BABELTRACE_UUID_LEN) != 0) {
+                               BT_LOGE("Expecting a non-absolute clock class with a specific UUID, "
+                                       "but got one with different UUID: "
+                                       "clock-class-addr=%p, clock-class-name=\"%s\", "
+                                       "expected-uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\", "
+                                       "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
+                                       clock_class, cc_name,
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[0],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[1],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[2],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[3],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[4],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[5],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[6],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[7],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[8],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[9],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[10],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[11],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[12],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[13],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[14],
+                                       (unsigned int) muxer_msg_iter->expected_clock_class_uuid[15],
+                                       (unsigned int) cc_uuid[0],
+                                       (unsigned int) cc_uuid[1],
+                                       (unsigned int) cc_uuid[2],
+                                       (unsigned int) cc_uuid[3],
+                                       (unsigned int) cc_uuid[4],
+                                       (unsigned int) cc_uuid[5],
+                                       (unsigned int) cc_uuid[6],
+                                       (unsigned int) cc_uuid[7],
+                                       (unsigned int) cc_uuid[8],
+                                       (unsigned int) cc_uuid[9],
+                                       (unsigned int) cc_uuid[10],
+                                       (unsigned int) cc_uuid[11],
+                                       (unsigned int) cc_uuid[12],
+                                       (unsigned int) cc_uuid[13],
+                                       (unsigned int) cc_uuid[14],
+                                       (unsigned int) cc_uuid[15]);
+                               goto error;
+                       }
+                       break;
+               case MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NONE:
+                       BT_LOGE("Expecting no clock class, but got one: "
+                               "clock-class-addr=%p, clock-class-name=\"%s\"",
+                               clock_class, cc_name);
+                       goto error;
+               default:
+                       /* Unexpected */
+                       BT_LOGF("Unexpected clock class expectation: "
+                               "expectation-code=%d",
+                               muxer_msg_iter->clock_class_expectation);
+                       abort();
+               }
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static inline
+int validate_new_stream_clock_class(struct muxer_msg_iter *muxer_msg_iter,
+               struct muxer_comp *muxer_comp, const bt_stream *stream)
+{
+       int ret = 0;
+       const bt_stream_class *stream_class =
+               bt_stream_borrow_class_const(stream);
+       const bt_clock_class *clock_class =
+               bt_stream_class_borrow_default_clock_class_const(stream_class);
+
+       if (!clock_class) {
+               if (muxer_msg_iter->clock_class_expectation ==
+                       MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ANY) {
+                       /* Expect no clock class */
+                       muxer_msg_iter->clock_class_expectation =
+                               MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_NONE;
+               } else {
+                       BT_LOGE("Expecting stream class with a default clock class: "
+                               "stream-class-addr=%p, stream-class-name=\"%s\", "
+                               "stream-class-id=%" PRIu64,
+                               stream_class, bt_stream_class_get_name(stream_class),
+                               bt_stream_class_get_id(stream_class));
+                       ret = -1;
+               }
+
+               goto end;
+       }
+
+       ret = validate_clock_class(muxer_msg_iter, muxer_comp, clock_class);
+
+end:
+       return ret;
+}
+
+/*
+ * This function finds the youngest available message amongst the
+ * non-ended upstream message iterators and returns the upstream
+ * message iterator which has it, or
+ * BT_MESSAGE_ITERATOR_STATUS_END if there's no available
+ * message.
+ *
+ * This function does NOT:
+ *
+ * * Update any upstream message iterator.
+ * * Check the upstream message iterators to retry.
+ *
+ * On sucess, this function sets *muxer_upstream_msg_iter to the
+ * upstream message iterator of which the current message is
+ * the youngest, and sets *ts_ns to its time.
+ */
+static
+bt_self_message_iterator_status
+muxer_msg_iter_youngest_upstream_msg_iter(
+               struct muxer_comp *muxer_comp,
+               struct muxer_msg_iter *muxer_msg_iter,
+               struct muxer_upstream_msg_iter **muxer_upstream_msg_iter,
+               int64_t *ts_ns)
+{
+       size_t i;
+       int ret;
+       int64_t youngest_ts_ns = INT64_MAX;
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_ASSERT(muxer_comp);
+       BT_ASSERT(muxer_msg_iter);
+       BT_ASSERT(muxer_upstream_msg_iter);
+       *muxer_upstream_msg_iter = NULL;
+
+       for (i = 0; i < muxer_msg_iter->active_muxer_upstream_msg_iters->len;
+                       i++) {
+               const bt_message *msg;
+               struct muxer_upstream_msg_iter *cur_muxer_upstream_msg_iter =
+                       g_ptr_array_index(
+                               muxer_msg_iter->active_muxer_upstream_msg_iters,
+                               i);
+               int64_t msg_ts_ns;
+
+               if (!cur_muxer_upstream_msg_iter->msg_iter) {
+                       /* This upstream message iterator is ended */
+                       BT_LOGV("Skipping ended upstream message iterator: "
+                               "muxer-upstream-msg-iter-wrap-addr=%p",
+                               cur_muxer_upstream_msg_iter);
+                       continue;
+               }
+
+               BT_ASSERT(cur_muxer_upstream_msg_iter->msgs->length > 0);
+               msg = g_queue_peek_head(cur_muxer_upstream_msg_iter->msgs);
+               BT_ASSERT(msg);
+
+               if (unlikely(bt_message_get_type(msg) ==
+                               BT_MESSAGE_TYPE_STREAM_BEGINNING)) {
+                       ret = validate_new_stream_clock_class(
+                               muxer_msg_iter, muxer_comp,
+                               bt_message_stream_beginning_borrow_stream_const(
+                                       msg));
+                       if (ret) {
+                               /*
+                                * validate_new_stream_clock_class() logs
+                                * errors.
+                                */
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+               } else if (unlikely(bt_message_get_type(msg) ==
+                               BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY)) {
+                       const bt_clock_snapshot *cs;
+
+                       cs = bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
+                               msg);
+                       ret = validate_clock_class(muxer_msg_iter, muxer_comp,
+                               bt_clock_snapshot_borrow_clock_class_const(cs));
+                       if (ret) {
+                               /* validate_clock_class() logs errors */
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+               }
+
+               ret = get_msg_ts_ns(muxer_comp, muxer_msg_iter, msg,
+                       muxer_msg_iter->last_returned_ts_ns, &msg_ts_ns);
+               if (ret) {
+                       /* get_msg_ts_ns() logs errors */
+                       *muxer_upstream_msg_iter = NULL;
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                       goto end;
+               }
+
+               if (msg_ts_ns <= youngest_ts_ns) {
+                       *muxer_upstream_msg_iter =
+                               cur_muxer_upstream_msg_iter;
+                       youngest_ts_ns = msg_ts_ns;
+                       *ts_ns = youngest_ts_ns;
+               }
+       }
+
+       if (!*muxer_upstream_msg_iter) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+               *ts_ns = INT64_MIN;
+       }
+
+end:
+       return status;
+}
+
+static
+bt_self_message_iterator_status validate_muxer_upstream_msg_iter(
+       struct muxer_upstream_msg_iter *muxer_upstream_msg_iter,
+       bool *is_ended)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_LOGV("Validating muxer's upstream message iterator wrapper: "
+               "muxer-upstream-msg-iter-wrap-addr=%p",
+               muxer_upstream_msg_iter);
+
+       if (muxer_upstream_msg_iter->msgs->length > 0 ||
+                       !muxer_upstream_msg_iter->msg_iter) {
+               BT_LOGV("Already valid or not considered: "
+                       "queue-len=%u, upstream-msg-iter-addr=%p",
+                       muxer_upstream_msg_iter->msgs->length,
+                       muxer_upstream_msg_iter->msg_iter);
+               goto end;
+       }
+
+       /* muxer_upstream_msg_iter_next() logs details/errors */
+       status = muxer_upstream_msg_iter_next(muxer_upstream_msg_iter,
+               is_ended);
+
+end:
+       return status;
+}
+
+static
+bt_self_message_iterator_status validate_muxer_upstream_msg_iters(
+               struct muxer_msg_iter *muxer_msg_iter)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       size_t i;
+
+       BT_LOGV("Validating muxer's upstream message iterator wrappers: "
+               "muxer-msg-iter-addr=%p", muxer_msg_iter);
+
+       for (i = 0; i < muxer_msg_iter->active_muxer_upstream_msg_iters->len;
+                       i++) {
+               bool is_ended = false;
+               struct muxer_upstream_msg_iter *muxer_upstream_msg_iter =
+                       g_ptr_array_index(
+                               muxer_msg_iter->active_muxer_upstream_msg_iters,
+                               i);
+
+               status = validate_muxer_upstream_msg_iter(
+                       muxer_upstream_msg_iter, &is_ended);
+               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                       if (status < 0) {
+                               BT_LOGE("Cannot validate muxer's upstream message iterator wrapper: "
+                                       "muxer-msg-iter-addr=%p, "
+                                       "muxer-upstream-msg-iter-wrap-addr=%p",
+                                       muxer_msg_iter,
+                                       muxer_upstream_msg_iter);
+                       } else {
+                               BT_LOGV("Cannot validate muxer's upstream message iterator wrapper: "
+                                       "muxer-msg-iter-addr=%p, "
+                                       "muxer-upstream-msg-iter-wrap-addr=%p",
+                                       muxer_msg_iter,
+                                       muxer_upstream_msg_iter);
+                       }
+
+                       goto end;
+               }
+
+               /*
+                * Move this muxer upstream message iterator to the
+                * array of ended iterators if it's ended.
+                */
+               if (unlikely(is_ended)) {
+                       BT_LOGV("Muxer's upstream message iterator wrapper: ended or canceled: "
+                               "muxer-msg-iter-addr=%p, "
+                               "muxer-upstream-msg-iter-wrap-addr=%p",
+                               muxer_msg_iter, muxer_upstream_msg_iter);
+                       g_ptr_array_add(
+                               muxer_msg_iter->ended_muxer_upstream_msg_iters,
+                               muxer_upstream_msg_iter);
+                       muxer_msg_iter->active_muxer_upstream_msg_iters->pdata[i] = NULL;
+
+                       /*
+                        * Use g_ptr_array_remove_fast() because the
+                        * order of those elements is not important.
+                        */
+                       g_ptr_array_remove_index_fast(
+                               muxer_msg_iter->active_muxer_upstream_msg_iters,
+                               i);
+                       i--;
+               }
+       }
+
+end:
+       return status;
+}
+
+static inline
+bt_self_message_iterator_status muxer_msg_iter_do_next_one(
+               struct muxer_comp *muxer_comp,
+               struct muxer_msg_iter *muxer_msg_iter,
+               const bt_message **msg)
+{
+       bt_self_message_iterator_status status;
+       struct muxer_upstream_msg_iter *muxer_upstream_msg_iter = NULL;
+       int64_t next_return_ts;
+
+       status = validate_muxer_upstream_msg_iters(muxer_msg_iter);
+       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+               /* validate_muxer_upstream_msg_iters() logs details */
+               goto end;
+       }
+
+       /*
+        * At this point we know that all the existing upstream
+        * message iterators are valid. We can find the one,
+        * amongst those, of which the current message is the
+        * youngest.
+        */
+       status = muxer_msg_iter_youngest_upstream_msg_iter(muxer_comp,
+                       muxer_msg_iter, &muxer_upstream_msg_iter,
+                       &next_return_ts);
+       if (status < 0 || status == BT_SELF_MESSAGE_ITERATOR_STATUS_END) {
+               if (status < 0) {
+                       BT_LOGE("Cannot find the youngest upstream message iterator wrapper: "
+                               "status=%s",
+                               bt_common_self_message_iterator_status_string(status));
+               } else {
+                       BT_LOGV("Cannot find the youngest upstream message iterator wrapper: "
+                               "status=%s",
+                               bt_common_self_message_iterator_status_string(status));
+               }
+
+               goto end;
+       }
+
+       if (next_return_ts < muxer_msg_iter->last_returned_ts_ns) {
+               BT_LOGE("Youngest upstream message iterator wrapper's timestamp is less than muxer's message iterator's last returned timestamp: "
+                       "muxer-msg-iter-addr=%p, ts=%" PRId64 ", "
+                       "last-returned-ts=%" PRId64,
+                       muxer_msg_iter, next_return_ts,
+                       muxer_msg_iter->last_returned_ts_ns);
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_LOGV("Found youngest upstream message iterator wrapper: "
+               "muxer-msg-iter-addr=%p, "
+               "muxer-upstream-msg-iter-wrap-addr=%p, "
+               "ts=%" PRId64,
+               muxer_msg_iter, muxer_upstream_msg_iter, next_return_ts);
+       BT_ASSERT(status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK);
+       BT_ASSERT(muxer_upstream_msg_iter);
+
+       /*
+        * Consume from the queue's head: other side
+        * (muxer_upstream_msg_iter_next()) writes to the tail.
+        */
+       *msg = g_queue_pop_head(muxer_upstream_msg_iter->msgs);
+       BT_ASSERT(*msg);
+       muxer_msg_iter->last_returned_ts_ns = next_return_ts;
+
+end:
+       return status;
+}
+
+static
+bt_self_message_iterator_status muxer_msg_iter_do_next(
+               struct muxer_comp *muxer_comp,
+               struct muxer_msg_iter *muxer_msg_iter,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       uint64_t i = 0;
+
+       while (i < capacity && status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+               status = muxer_msg_iter_do_next_one(muxer_comp,
+                       muxer_msg_iter, &msgs[i]);
+               if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                       i++;
+               }
+       }
+
+       if (i > 0) {
+               /*
+                * Even if muxer_msg_iter_do_next_one() returned
+                * something else than
+                * BT_MESSAGE_ITERATOR_STATUS_OK, we accumulated
+                * message objects in the output message
+                * array, so we need to return
+                * BT_MESSAGE_ITERATOR_STATUS_OK so that they are
+                * transfered to downstream. This other status occurs
+                * again the next time muxer_msg_iter_do_next() is
+                * called, possibly without any accumulated
+                * message, in which case we'll return it.
+                */
+               *count = i;
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       }
+
+       return status;
+}
+
+static
+void destroy_muxer_msg_iter(struct muxer_msg_iter *muxer_msg_iter)
+{
+       if (!muxer_msg_iter) {
+               return;
+       }
+
+       BT_LOGD("Destroying muxer component's message iterator: "
+               "muxer-msg-iter-addr=%p", muxer_msg_iter);
+
+       if (muxer_msg_iter->active_muxer_upstream_msg_iters) {
+               BT_LOGD_STR("Destroying muxer's active upstream message iterator wrappers.");
+               g_ptr_array_free(
+                       muxer_msg_iter->active_muxer_upstream_msg_iters, TRUE);
+       }
+
+       if (muxer_msg_iter->ended_muxer_upstream_msg_iters) {
+               BT_LOGD_STR("Destroying muxer's ended upstream message iterator wrappers.");
+               g_ptr_array_free(
+                       muxer_msg_iter->ended_muxer_upstream_msg_iters, TRUE);
+       }
+
+       g_free(muxer_msg_iter);
+}
+
+static
+int muxer_msg_iter_init_upstream_iterators(struct muxer_comp *muxer_comp,
+               struct muxer_msg_iter *muxer_msg_iter)
+{
+       int64_t count;
+       int64_t i;
+       int ret = 0;
+
+       count = bt_component_filter_get_input_port_count(
+               bt_self_component_filter_as_component_filter(
+                       muxer_comp->self_comp));
+       if (count < 0) {
+               BT_LOGD("No input port to initialize for muxer component's message iterator: "
+                       "muxer-comp-addr=%p, muxer-msg-iter-addr=%p",
+                       muxer_comp, muxer_msg_iter);
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               bt_self_component_port_input_message_iterator *upstream_msg_iter;
+               bt_self_component_port_input *self_port =
+                       bt_self_component_filter_borrow_input_port_by_index(
+                               muxer_comp->self_comp, i);
+               const bt_port *port;
+
+               BT_ASSERT(self_port);
+               port = bt_self_component_port_as_port(
+                       bt_self_component_port_input_as_self_component_port(
+                               self_port));
+               BT_ASSERT(port);
+
+               if (!bt_port_is_connected(port)) {
+                       /* Skip non-connected port */
+                       continue;
+               }
+
+               upstream_msg_iter = create_msg_iter_on_input_port(self_port);
+               if (!upstream_msg_iter) {
+                       /* create_msg_iter_on_input_port() logs errors */
+                       BT_ASSERT(!upstream_msg_iter);
+                       ret = -1;
+                       goto end;
+               }
+
+               ret = muxer_msg_iter_add_upstream_msg_iter(muxer_msg_iter,
+                       upstream_msg_iter);
+               bt_self_component_port_input_message_iterator_put_ref(
+                       upstream_msg_iter);
+               if (ret) {
+                       /* muxer_msg_iter_add_upstream_msg_iter() logs errors */
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status muxer_msg_iter_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_filter *self_comp,
+               bt_self_component_port_output *port)
+{
+       struct muxer_comp *muxer_comp = NULL;
+       struct muxer_msg_iter *muxer_msg_iter = NULL;
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       int ret;
+
+       muxer_comp = bt_self_component_get_data(
+               bt_self_component_filter_as_self_component(self_comp));
+       BT_ASSERT(muxer_comp);
+       BT_LOGD("Initializing muxer component's message iterator: "
+               "comp-addr=%p, muxer-comp-addr=%p, msg-iter-addr=%p",
+               self_comp, muxer_comp, self_msg_iter);
+
+       if (muxer_comp->initializing_muxer_msg_iter) {
+               /*
+                * Weird, unhandled situation detected: downstream
+                * creates a muxer message iterator while creating
+                * another muxer message iterator (same component).
+                */
+               BT_LOGE("Recursive initialization of muxer component's message iterator: "
+                       "comp-addr=%p, muxer-comp-addr=%p, msg-iter-addr=%p",
+                       self_comp, muxer_comp, self_msg_iter);
+               goto error;
+       }
+
+       muxer_comp->initializing_muxer_msg_iter = true;
+       muxer_msg_iter = g_new0(struct muxer_msg_iter, 1);
+       if (!muxer_msg_iter) {
+               BT_LOGE_STR("Failed to allocate one muxer component's message iterator.");
+               goto error;
+       }
+
+       muxer_msg_iter->last_returned_ts_ns = INT64_MIN;
+       muxer_msg_iter->active_muxer_upstream_msg_iters =
+               g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) destroy_muxer_upstream_msg_iter);
+       if (!muxer_msg_iter->active_muxer_upstream_msg_iters) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       muxer_msg_iter->ended_muxer_upstream_msg_iters =
+               g_ptr_array_new_with_free_func(
+                       (GDestroyNotify) destroy_muxer_upstream_msg_iter);
+       if (!muxer_msg_iter->ended_muxer_upstream_msg_iters) {
+               BT_LOGE_STR("Failed to allocate a GPtrArray.");
+               goto error;
+       }
+
+       ret = muxer_msg_iter_init_upstream_iterators(muxer_comp,
+               muxer_msg_iter);
+       if (ret) {
+               BT_LOGE("Cannot initialize connected input ports for muxer component's message iterator: "
+                       "comp-addr=%p, muxer-comp-addr=%p, "
+                       "muxer-msg-iter-addr=%p, msg-iter-addr=%p, ret=%d",
+                       self_comp, muxer_comp, muxer_msg_iter,
+                       self_msg_iter, ret);
+               goto error;
+       }
+
+       bt_self_message_iterator_set_data(self_msg_iter, muxer_msg_iter);
+       BT_LOGD("Initialized muxer component's message iterator: "
+               "comp-addr=%p, muxer-comp-addr=%p, muxer-msg-iter-addr=%p, "
+               "msg-iter-addr=%p",
+               self_comp, muxer_comp, muxer_msg_iter, self_msg_iter);
+       goto end;
+
+error:
+       destroy_muxer_msg_iter(muxer_msg_iter);
+       bt_self_message_iterator_set_data(self_msg_iter, NULL);
+       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+
+end:
+       muxer_comp->initializing_muxer_msg_iter = false;
+       return status;
+}
+
+BT_HIDDEN
+void muxer_msg_iter_finalize(bt_self_message_iterator *self_msg_iter)
+{
+       struct muxer_msg_iter *muxer_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_iter);
+       bt_self_component *self_comp = NULL;
+       struct muxer_comp *muxer_comp = NULL;
+
+       self_comp = bt_self_message_iterator_borrow_component(
+               self_msg_iter);
+       BT_ASSERT(self_comp);
+       muxer_comp = bt_self_component_get_data(self_comp);
+       BT_LOGD("Finalizing muxer component's message iterator: "
+               "comp-addr=%p, muxer-comp-addr=%p, muxer-msg-iter-addr=%p, "
+               "msg-iter-addr=%p",
+               self_comp, muxer_comp, muxer_msg_iter, self_msg_iter);
+
+       if (muxer_msg_iter) {
+               destroy_muxer_msg_iter(muxer_msg_iter);
+       }
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status muxer_msg_iter_next(
+               bt_self_message_iterator *self_msg_iter,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       bt_self_message_iterator_status status;
+       struct muxer_msg_iter *muxer_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_iter);
+       bt_self_component *self_comp = NULL;
+       struct muxer_comp *muxer_comp = NULL;
+
+       BT_ASSERT(muxer_msg_iter);
+       self_comp = bt_self_message_iterator_borrow_component(
+               self_msg_iter);
+       BT_ASSERT(self_comp);
+       muxer_comp = bt_self_component_get_data(self_comp);
+       BT_ASSERT(muxer_comp);
+       BT_LOGV("Muxer component's message iterator's \"next\" method called: "
+               "comp-addr=%p, muxer-comp-addr=%p, muxer-msg-iter-addr=%p, "
+               "msg-iter-addr=%p",
+               self_comp, muxer_comp, muxer_msg_iter, self_msg_iter);
+
+       status = muxer_msg_iter_do_next(muxer_comp, muxer_msg_iter,
+               msgs, capacity, count);
+       if (status < 0) {
+               BT_LOGE("Cannot get next message: "
+                       "comp-addr=%p, muxer-comp-addr=%p, muxer-msg-iter-addr=%p, "
+                       "msg-iter-addr=%p, status=%s",
+                       self_comp, muxer_comp, muxer_msg_iter, self_msg_iter,
+                       bt_common_self_message_iterator_status_string(status));
+       } else {
+               BT_LOGV("Returning from muxer component's message iterator's \"next\" method: "
+                       "status=%s",
+                       bt_common_self_message_iterator_status_string(status));
+       }
+
+       return status;
+}
+
+BT_HIDDEN
+bt_self_component_status muxer_input_port_connected(
+               bt_self_component_filter *self_comp,
+               bt_self_component_port_input *self_port,
+               const bt_port_output *other_port)
+{
+       bt_self_component_status status;
+
+       status = add_available_input_port(self_comp);
+       if (status) {
+               /*
+                * Only way to report an error later since this
+                * method does not return anything.
+                */
+               BT_LOGE("Cannot add one muxer component's input port: "
+                       "status=%s",
+                       bt_self_component_status_string(status));
+               goto end;
+       }
+
+end:
+       return status;
+}
+
+static inline
+bt_bool muxer_upstream_msg_iters_can_all_seek_beginning(
+               GPtrArray *muxer_upstream_msg_iters)
+{
+       uint64_t i;
+       bt_bool ret = BT_TRUE;
+
+       for (i = 0; i < muxer_upstream_msg_iters->len; i++) {
+               struct muxer_upstream_msg_iter *upstream_msg_iter =
+                       muxer_upstream_msg_iters->pdata[i];
+
+               if (!bt_self_component_port_input_message_iterator_can_seek_beginning(
+                               upstream_msg_iter->msg_iter)) {
+                       ret = BT_FALSE;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_bool muxer_msg_iter_can_seek_beginning(
+               bt_self_message_iterator *self_msg_iter)
+{
+       struct muxer_msg_iter *muxer_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_iter);
+       bt_bool ret = BT_TRUE;
+
+       if (!muxer_upstream_msg_iters_can_all_seek_beginning(
+                       muxer_msg_iter->active_muxer_upstream_msg_iters)) {
+               ret = BT_FALSE;
+               goto end;
+       }
+
+       if (!muxer_upstream_msg_iters_can_all_seek_beginning(
+                       muxer_msg_iter->ended_muxer_upstream_msg_iters)) {
+               ret = BT_FALSE;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status muxer_msg_iter_seek_beginning(
+               bt_self_message_iterator *self_msg_iter)
+{
+       struct muxer_msg_iter *muxer_msg_iter =
+               bt_self_message_iterator_get_data(self_msg_iter);
+       bt_message_iterator_status status = BT_MESSAGE_ITERATOR_STATUS_OK;
+       uint64_t i;
+
+       /* Seek all ended upstream iterators first */
+       for (i = 0; i < muxer_msg_iter->ended_muxer_upstream_msg_iters->len;
+                       i++) {
+               struct muxer_upstream_msg_iter *upstream_msg_iter =
+                       muxer_msg_iter->ended_muxer_upstream_msg_iters->pdata[i];
+
+               status = bt_self_component_port_input_message_iterator_seek_beginning(
+                       upstream_msg_iter->msg_iter);
+               if (status != BT_MESSAGE_ITERATOR_STATUS_OK) {
+                       goto end;
+               }
+
+               empty_message_queue(upstream_msg_iter);
+       }
+
+       /* Seek all previously active upstream iterators */
+       for (i = 0; i < muxer_msg_iter->active_muxer_upstream_msg_iters->len;
+                       i++) {
+               struct muxer_upstream_msg_iter *upstream_msg_iter =
+                       muxer_msg_iter->active_muxer_upstream_msg_iters->pdata[i];
+
+               status = bt_self_component_port_input_message_iterator_seek_beginning(
+                       upstream_msg_iter->msg_iter);
+               if (status != BT_MESSAGE_ITERATOR_STATUS_OK) {
+                       goto end;
+               }
+
+               empty_message_queue(upstream_msg_iter);
+       }
+
+       /* Make them all active */
+       for (i = 0; i < muxer_msg_iter->ended_muxer_upstream_msg_iters->len;
+                       i++) {
+               struct muxer_upstream_msg_iter *upstream_msg_iter =
+                       muxer_msg_iter->ended_muxer_upstream_msg_iters->pdata[i];
+
+               g_ptr_array_add(muxer_msg_iter->active_muxer_upstream_msg_iters,
+                       upstream_msg_iter);
+               muxer_msg_iter->ended_muxer_upstream_msg_iters->pdata[i] = NULL;
+       }
+
+       g_ptr_array_remove_range(muxer_msg_iter->ended_muxer_upstream_msg_iters,
+               0, muxer_msg_iter->ended_muxer_upstream_msg_iters->len);
+       muxer_msg_iter->last_returned_ts_ns = INT64_MIN;
+       muxer_msg_iter->clock_class_expectation =
+               MUXER_MSG_ITER_CLOCK_CLASS_EXPECTATION_ANY;
+
+end:
+       return (bt_self_message_iterator_status) status;
+}
diff --git a/src/plugins/utils/muxer/muxer.h b/src/plugins/utils/muxer/muxer.h
new file mode 100644 (file)
index 0000000..a383e4c
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef BABELTRACE_PLUGINS_UTILS_MUXER_H
+#define BABELTRACE_PLUGINS_UTILS_MUXER_H
+
+/*
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <babeltrace2/babeltrace.h>
+#include "common/babeltrace.h"
+
+BT_HIDDEN
+bt_self_component_status muxer_init(
+               bt_self_component_filter *self_comp,
+               const bt_value *params, void *init_data);
+
+BT_HIDDEN
+void muxer_finalize(bt_self_component_filter *self_comp);
+
+BT_HIDDEN
+bt_self_message_iterator_status muxer_msg_iter_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_filter *self_comp,
+               bt_self_component_port_output *self_port);
+
+BT_HIDDEN
+void muxer_msg_iter_finalize(
+               bt_self_message_iterator *self_msg_iter);
+
+BT_HIDDEN
+bt_self_message_iterator_status muxer_msg_iter_next(
+               bt_self_message_iterator *self_msg_iter,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count);
+
+BT_HIDDEN
+bt_self_component_status muxer_input_port_connected(
+               bt_self_component_filter *comp,
+               bt_self_component_port_input *self_port,
+               const bt_port_output *other_port);
+
+BT_HIDDEN
+bt_bool muxer_msg_iter_can_seek_beginning(
+               bt_self_message_iterator *message_iterator);
+
+BT_HIDDEN
+bt_self_message_iterator_status muxer_msg_iter_seek_beginning(
+               bt_self_message_iterator *message_iterator);
+
+#endif /* BABELTRACE_PLUGINS_UTILS_MUXER_H */
diff --git a/src/plugins/utils/plugin.c b/src/plugins/utils/plugin.c
new file mode 100644 (file)
index 0000000..d6b5b24
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/babeltrace.h>
+#include "dummy/dummy.h"
+#include "counter/counter.h"
+#include "muxer/muxer.h"
+#include "trimmer/trimmer.h"
+
+#ifndef BT_BUILT_IN_PLUGINS
+BT_PLUGIN_MODULE();
+#endif
+
+BT_PLUGIN(utils);
+BT_PLUGIN_DESCRIPTION("Graph utilities");
+BT_PLUGIN_AUTHOR("Julien Desfossez, Jérémie Galarneau, Philippe Proulx");
+BT_PLUGIN_LICENSE("MIT");
+
+/* sink.utils.dummy */
+BT_PLUGIN_SINK_COMPONENT_CLASS(dummy, dummy_consume);
+BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(dummy, dummy_init);
+BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(dummy, dummy_finalize);
+BT_PLUGIN_SINK_COMPONENT_CLASS_GRAPH_IS_CONFIGURED_METHOD(dummy,
+       dummy_graph_is_configured);
+BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(dummy,
+       "Consume messages and discard them.");
+
+/* sink.utils.counter */
+BT_PLUGIN_SINK_COMPONENT_CLASS(counter, counter_consume);
+BT_PLUGIN_SINK_COMPONENT_CLASS_INIT_METHOD(counter, counter_init);
+BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(counter, counter_finalize);
+BT_PLUGIN_SINK_COMPONENT_CLASS_GRAPH_IS_CONFIGURED_METHOD(counter,
+       counter_graph_is_configured);
+BT_PLUGIN_SINK_COMPONENT_CLASS_DESCRIPTION(counter,
+       "Count messages and print the results.");
+
+/* flt.utils.trimmer */
+BT_PLUGIN_FILTER_COMPONENT_CLASS(trimmer, trimmer_msg_iter_next);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(trimmer,
+       "Keep messages that occur within a specific time range.");
+BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD(trimmer, trimmer_init);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(trimmer, trimmer_finalize);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD(trimmer,
+       trimmer_msg_iter_init);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD(trimmer,
+       trimmer_msg_iter_finalize);
+
+/* flt.utils.muxer */
+BT_PLUGIN_FILTER_COMPONENT_CLASS(muxer, muxer_msg_iter_next);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_DESCRIPTION(muxer,
+       "Sort messages from multiple input ports to a single output port by time.");
+BT_PLUGIN_FILTER_COMPONENT_CLASS_INIT_METHOD(muxer, muxer_init);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(muxer, muxer_finalize);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_INPUT_PORT_CONNECTED_METHOD(muxer,
+       muxer_input_port_connected);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_INIT_METHOD(muxer,
+       muxer_msg_iter_init);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_FINALIZE_METHOD(muxer,
+       muxer_msg_iter_finalize);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_SEEK_BEGINNING_METHOD(muxer,
+       muxer_msg_iter_seek_beginning);
+BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CAN_SEEK_BEGINNING_METHOD(muxer,
+       muxer_msg_iter_can_seek_beginning);
diff --git a/src/plugins/utils/trimmer/Makefile.am b/src/plugins/utils/trimmer/Makefile.am
new file mode 100644 (file)
index 0000000..9ce4c9b
--- /dev/null
@@ -0,0 +1,6 @@
+noinst_LTLIBRARIES = libbabeltrace2-plugin-trimmer.la
+libbabeltrace2_plugin_trimmer_la_SOURCES = \
+       trimmer.c \
+       trimmer.h \
+       logging.c \
+       logging.h
diff --git a/src/plugins/utils/trimmer/logging.c b/src/plugins/utils/trimmer/logging.c
new file mode 100644 (file)
index 0000000..f672123
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_trimmer_log_level
+#include "logging/log.h"
+
+BT_LOG_INIT_LOG_LEVEL(bt_plugin_utils_trimmer_log_level,
+       "BABELTRACE_FLT_UTILS_TRIMMER_LOG_LEVEL");
diff --git a/src/plugins/utils/trimmer/logging.h b/src/plugins/utils/trimmer/logging.h
new file mode 100644 (file)
index 0000000..aba659b
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef PLUGINS_UTILS_TRIMMER_LOGGING_H
+#define PLUGINS_UTILS_TRIMMER_LOGGING_H
+
+/*
+ * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_OUTPUT_LEVEL bt_plugin_utils_trimmer_log_level
+#include "logging/log.h"
+
+BT_LOG_LEVEL_EXTERN_SYMBOL(bt_plugin_utils_trimmer_log_level);
+
+#endif /* PLUGINS_UTILS_TRIMMER_LOGGING_H */
diff --git a/src/plugins/utils/trimmer/trimmer.c b/src/plugins/utils/trimmer/trimmer.c
new file mode 100644 (file)
index 0000000..f2d2c43
--- /dev/null
@@ -0,0 +1,2049 @@
+/*
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright 2019 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-UTILS-TRIMMER-FLT"
+#include "logging.h"
+
+#include "compat/utc.h"
+#include "compat/time.h"
+#include <babeltrace2/babeltrace.h>
+#include "common/common.h"
+#include "plugins/plugins-common.h"
+#include "common/assert.h"
+#include <stdint.h>
+#include <inttypes.h>
+#include <glib.h>
+
+#include "trimmer.h"
+
+#define NS_PER_S       INT64_C(1000000000)
+
+static const char * const in_port_name = "in";
+
+struct trimmer_time {
+       unsigned int hour, minute, second, ns;
+};
+
+struct trimmer_bound {
+       /*
+        * Nanoseconds from origin, valid if `is_set` is set and
+        * `is_infinite` is false.
+        */
+       int64_t ns_from_origin;
+
+       /* True if this bound's full time (`ns_from_origin`) is set */
+       bool is_set;
+
+       /*
+        * True if this bound represents the infinity (negative or
+        * positive depending on which bound it is). If this is true,
+        * then we don't care about `ns_from_origin` above.
+        */
+       bool is_infinite;
+
+       /*
+        * This bound's time without the date; this time is used to set
+        * `ns_from_origin` once we know the date.
+        */
+       struct trimmer_time time;
+};
+
+struct trimmer_comp {
+       struct trimmer_bound begin, end;
+       bool is_gmt;
+};
+
+enum trimmer_iterator_state {
+       /*
+        * Find the first message's date and set the bounds's times
+        * accordingly.
+        */
+       TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN,
+
+       /*
+        * Initially seek to the trimming range's beginning time.
+        */
+       TRIMMER_ITERATOR_STATE_SEEK_INITIALLY,
+
+       /*
+        * Fill the output message queue for as long as received input
+        * messages are within the trimming time range.
+        */
+       TRIMMER_ITERATOR_STATE_TRIM,
+
+       /* Flush the remaining messages in the output message queue */
+       TRIMMER_ITERATOR_STATE_ENDING,
+
+       /* Trimming operation and message iterator is ended */
+       TRIMMER_ITERATOR_STATE_ENDED,
+};
+
+struct trimmer_iterator {
+       /* Weak */
+       struct trimmer_comp *trimmer_comp;
+
+       /* Weak */
+       bt_self_message_iterator *self_msg_iter;
+
+       enum trimmer_iterator_state state;
+
+       /* Owned by this */
+       bt_self_component_port_input_message_iterator *upstream_iter;
+       struct trimmer_bound begin, end;
+
+       /*
+        * Queue of `const bt_message *` (owned by the queue).
+        *
+        * This is where the trimming operation pushes the messages to
+        * output by this message iterator.
+        */
+       GQueue *output_messages;
+
+       /*
+        * Hash table of `bt_stream *` (weak) to
+        * `struct trimmer_iterator_stream_state *` (owned by the HT).
+        */
+       GHashTable *stream_states;
+};
+
+struct trimmer_iterator_stream_state {
+       /*
+        * True if both stream beginning and initial stream activity
+        * beginning messages were pushed for this stream.
+        */
+       bool inited;
+
+       /*
+        * True if the last pushed message for this stream was a stream
+        * activity end message.
+        */
+       bool last_msg_is_stream_activity_end;
+
+       /*
+        * Time to use for a generated stream end activity message when
+        * ending the stream.
+        */
+       int64_t stream_act_end_ns_from_origin;
+
+       /* Weak */
+       const bt_stream *stream;
+
+       /* Owned by this (`NULL` initially and between packets) */
+       const bt_packet *cur_packet;
+
+       /* Owned by this */
+       const bt_message *stream_beginning_msg;
+};
+
+static
+void destroy_trimmer_comp(struct trimmer_comp *trimmer_comp)
+{
+       BT_ASSERT(trimmer_comp);
+       g_free(trimmer_comp);
+}
+
+static
+struct trimmer_comp *create_trimmer_comp(void)
+{
+       return g_new0(struct trimmer_comp, 1);
+}
+
+BT_HIDDEN
+void trimmer_finalize(bt_self_component_filter *self_comp)
+{
+       struct trimmer_comp *trimmer_comp =
+               bt_self_component_get_data(
+                       bt_self_component_filter_as_self_component(self_comp));
+
+       if (trimmer_comp) {
+               destroy_trimmer_comp(trimmer_comp);
+       }
+}
+
+/*
+ * Sets the time (in ns from origin) of a trimmer bound from date and
+ * time components.
+ *
+ * Returns a negative value if anything goes wrong.
+ */
+static
+int set_bound_ns_from_origin(struct trimmer_bound *bound,
+               unsigned int year, unsigned int month, unsigned int day,
+               unsigned int hour, unsigned int minute, unsigned int second,
+               unsigned int ns, bool is_gmt)
+{
+       int ret = 0;
+       time_t result;
+       struct tm tm = {
+               .tm_sec = second,
+               .tm_min = minute,
+               .tm_hour = hour,
+               .tm_mday = day,
+               .tm_mon = month - 1,
+               .tm_year = year - 1900,
+               .tm_isdst = -1,
+       };
+
+       if (is_gmt) {
+               result = bt_timegm(&tm);
+       } else {
+               result = mktime(&tm);
+       }
+
+       if (result < 0) {
+               ret = -1;
+               goto end;
+       }
+
+       BT_ASSERT(bound);
+       bound->ns_from_origin = (int64_t) result;
+       bound->ns_from_origin *= NS_PER_S;
+       bound->ns_from_origin += ns;
+       bound->is_set = true;
+
+end:
+       return ret;
+}
+
+/*
+ * Parses a timestamp, figuring out its format.
+ *
+ * Returns a negative value if anything goes wrong.
+ *
+ * Expected formats:
+ *
+ *     YYYY-MM-DD hh:mm[:ss[.ns]]
+ *     [hh:mm:]ss[.ns]
+ *     [-]s[.ns]
+ *
+ * TODO: Check overflows.
+ */
+static
+int set_bound_from_str(const char *str, struct trimmer_bound *bound,
+               bool is_gmt)
+{
+       int ret = 0;
+       int s_ret;
+       unsigned int year, month, day, hour, minute, second, ns;
+       char dummy;
+
+       /* Try `YYYY-MM-DD hh:mm:ss.ns` format */
+       s_ret = sscanf(str, "%u-%u-%u %u:%u:%u.%u%c", &year, &month, &day,
+               &hour, &minute, &second, &ns, &dummy);
+       if (s_ret == 7) {
+               ret = set_bound_ns_from_origin(bound, year, month, day,
+                       hour, minute, second, ns, is_gmt);
+               goto end;
+       }
+
+       /* Try `YYYY-MM-DD hh:mm:ss` format */
+       s_ret = sscanf(str, "%u-%u-%u %u:%u:%u%c", &year, &month, &day,
+               &hour, &minute, &second, &dummy);
+       if (s_ret == 6) {
+               ret = set_bound_ns_from_origin(bound, year, month, day,
+                       hour, minute, second, 0, is_gmt);
+               goto end;
+       }
+
+       /* Try `YYYY-MM-DD hh:mm` format */
+       s_ret = sscanf(str, "%u-%u-%u %u:%u%c", &year, &month, &day,
+               &hour, &minute, &dummy);
+       if (s_ret == 5) {
+               ret = set_bound_ns_from_origin(bound, year, month, day,
+                       hour, minute, 0, 0, is_gmt);
+               goto end;
+       }
+
+       /* Try `YYYY-MM-DD` format */
+       s_ret = sscanf(str, "%u-%u-%u%c", &year, &month, &day, &dummy);
+       if (s_ret == 3) {
+               ret = set_bound_ns_from_origin(bound, year, month, day,
+                       0, 0, 0, 0, is_gmt);
+               goto end;
+       }
+
+       /* Try `hh:mm:ss.ns` format */
+       s_ret = sscanf(str, "%u:%u:%u.%u%c", &hour, &minute, &second, &ns,
+               &dummy);
+       if (s_ret == 4) {
+               bound->time.hour = hour;
+               bound->time.minute = minute;
+               bound->time.second = second;
+               bound->time.ns = ns;
+               goto end;
+       }
+
+       /* Try `hh:mm:ss` format */
+       s_ret = sscanf(str, "%u:%u:%u%c", &hour, &minute, &second, &dummy);
+       if (s_ret == 3) {
+               bound->time.hour = hour;
+               bound->time.minute = minute;
+               bound->time.second = second;
+               bound->time.ns = 0;
+               goto end;
+       }
+
+       /* Try `-s.ns` format */
+       s_ret = sscanf(str, "-%u.%u%c", &second, &ns, &dummy);
+       if (s_ret == 2) {
+               bound->ns_from_origin = -((int64_t) second) * NS_PER_S;
+               bound->ns_from_origin -= (int64_t) ns;
+               bound->is_set = true;
+               goto end;
+       }
+
+       /* Try `s.ns` format */
+       s_ret = sscanf(str, "%u.%u%c", &second, &ns, &dummy);
+       if (s_ret == 2) {
+               bound->ns_from_origin = ((int64_t) second) * NS_PER_S;
+               bound->ns_from_origin += (int64_t) ns;
+               bound->is_set = true;
+               goto end;
+       }
+
+       /* Try `-s` format */
+       s_ret = sscanf(str, "-%u%c", &second, &dummy);
+       if (s_ret == 1) {
+               bound->ns_from_origin = -((int64_t) second) * NS_PER_S;
+               bound->is_set = true;
+               goto end;
+       }
+
+       /* Try `s` format */
+       s_ret = sscanf(str, "%u%c", &second, &dummy);
+       if (s_ret == 1) {
+               bound->ns_from_origin = (int64_t) second * NS_PER_S;
+               bound->is_set = true;
+               goto end;
+       }
+
+       BT_LOGE("Invalid date/time format: param=\"%s\"", str);
+       ret = -1;
+
+end:
+       return ret;
+}
+
+/*
+ * Sets a trimmer bound's properties from a parameter string/integer
+ * value.
+ *
+ * Returns a negative value if anything goes wrong.
+ */
+static
+int set_bound_from_param(const char *param_name, const bt_value *param,
+               struct trimmer_bound *bound, bool is_gmt)
+{
+       int ret;
+       const char *arg;
+       char tmp_arg[64];
+
+       if (bt_value_is_signed_integer(param)) {
+               int64_t value = bt_value_signed_integer_get(param);
+
+               /*
+                * Just convert it to a temporary string to handle
+                * everything the same way.
+                */
+               sprintf(tmp_arg, "%" PRId64, value);
+               arg = tmp_arg;
+       } else if (bt_value_is_string(param)) {
+               arg = bt_value_string_get(param);
+       } else {
+               BT_LOGE("`%s` parameter must be an integer or a string value.",
+                       param_name);
+               ret = -1;
+               goto end;
+       }
+
+       ret = set_bound_from_str(arg, bound, is_gmt);
+
+end:
+       return ret;
+}
+
+static
+int validate_trimmer_bounds(struct trimmer_bound *begin,
+               struct trimmer_bound *end)
+{
+       int ret = 0;
+
+       BT_ASSERT(begin->is_set);
+       BT_ASSERT(end->is_set);
+
+       if (!begin->is_infinite && !end->is_infinite &&
+                       begin->ns_from_origin > end->ns_from_origin) {
+               BT_LOGE("Trimming time range's beginning time is greater than end time: "
+                       "begin-ns-from-origin=%" PRId64 ", "
+                       "end-ns-from-origin=%" PRId64,
+                       begin->ns_from_origin,
+                       end->ns_from_origin);
+               ret = -1;
+               goto end;
+       }
+
+       if (!begin->is_infinite && begin->ns_from_origin == INT64_MIN) {
+               BT_LOGE("Invalid trimming time range's beginning time: "
+                       "ns-from-origin=%" PRId64,
+                       begin->ns_from_origin);
+               ret = -1;
+               goto end;
+       }
+
+       if (!end->is_infinite && end->ns_from_origin == INT64_MIN) {
+               BT_LOGE("Invalid trimming time range's end time: "
+                       "ns-from-origin=%" PRId64,
+                       end->ns_from_origin);
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static
+int init_trimmer_comp_from_params(struct trimmer_comp *trimmer_comp,
+               const bt_value *params)
+{
+       const bt_value *value;
+       int ret = 0;
+
+       BT_ASSERT(params);
+        value = bt_value_map_borrow_entry_value_const(params, "gmt");
+       if (value) {
+               trimmer_comp->is_gmt = (bool) bt_value_bool_get(value);
+       }
+
+        value = bt_value_map_borrow_entry_value_const(params, "begin");
+       if (value) {
+               if (set_bound_from_param("begin", value,
+                               &trimmer_comp->begin, trimmer_comp->is_gmt)) {
+                       /* set_bound_from_param() logs errors */
+                       ret = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+       } else {
+               trimmer_comp->begin.is_infinite = true;
+               trimmer_comp->begin.is_set = true;
+       }
+
+        value = bt_value_map_borrow_entry_value_const(params, "end");
+       if (value) {
+               if (set_bound_from_param("end", value,
+                               &trimmer_comp->end, trimmer_comp->is_gmt)) {
+                       /* set_bound_from_param() logs errors */
+                       ret = BT_SELF_COMPONENT_STATUS_ERROR;
+                       goto end;
+               }
+       } else {
+               trimmer_comp->end.is_infinite = true;
+               trimmer_comp->end.is_set = true;
+       }
+
+end:
+       if (trimmer_comp->begin.is_set && trimmer_comp->end.is_set) {
+               /* validate_trimmer_bounds() logs errors */
+               ret = validate_trimmer_bounds(&trimmer_comp->begin,
+                       &trimmer_comp->end);
+       }
+
+       return ret;
+}
+
+bt_self_component_status trimmer_init(bt_self_component_filter *self_comp,
+               const bt_value *params, void *init_data)
+{
+       int ret;
+       bt_self_component_status status;
+       struct trimmer_comp *trimmer_comp = create_trimmer_comp();
+
+       if (!trimmer_comp) {
+               status = BT_SELF_COMPONENT_STATUS_NOMEM;
+               goto error;
+       }
+
+       status = bt_self_component_filter_add_input_port(
+               self_comp, in_port_name, NULL, NULL);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto error;
+       }
+
+       status = bt_self_component_filter_add_output_port(
+               self_comp, "out", NULL, NULL);
+       if (status != BT_SELF_COMPONENT_STATUS_OK) {
+               goto error;
+       }
+
+       ret = init_trimmer_comp_from_params(trimmer_comp, params);
+       if (ret) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+               goto error;
+       }
+
+       bt_self_component_set_data(
+               bt_self_component_filter_as_self_component(self_comp),
+               trimmer_comp);
+       goto end;
+
+error:
+       if (status == BT_SELF_COMPONENT_STATUS_OK) {
+               status = BT_SELF_COMPONENT_STATUS_ERROR;
+       }
+
+       if (trimmer_comp) {
+               destroy_trimmer_comp(trimmer_comp);
+       }
+
+end:
+       return status;
+}
+
+static
+void destroy_trimmer_iterator(struct trimmer_iterator *trimmer_it)
+{
+       BT_ASSERT(trimmer_it);
+       bt_self_component_port_input_message_iterator_put_ref(
+               trimmer_it->upstream_iter);
+
+       if (trimmer_it->output_messages) {
+               g_queue_free(trimmer_it->output_messages);
+       }
+
+       if (trimmer_it->stream_states) {
+               g_hash_table_destroy(trimmer_it->stream_states);
+       }
+
+       g_free(trimmer_it);
+}
+
+static
+void destroy_trimmer_iterator_stream_state(
+               struct trimmer_iterator_stream_state *sstate)
+{
+       BT_ASSERT(sstate);
+       BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
+       BT_MESSAGE_PUT_REF_AND_RESET(sstate->stream_beginning_msg);
+       g_free(sstate);
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status trimmer_msg_iter_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_filter *self_comp,
+               bt_self_component_port_output *port)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       struct trimmer_iterator *trimmer_it;
+
+       trimmer_it = g_new0(struct trimmer_iterator, 1);
+       if (!trimmer_it) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto end;
+       }
+
+       trimmer_it->trimmer_comp = bt_self_component_get_data(
+               bt_self_component_filter_as_self_component(self_comp));
+       BT_ASSERT(trimmer_it->trimmer_comp);
+
+       if (trimmer_it->trimmer_comp->begin.is_set &&
+                       trimmer_it->trimmer_comp->end.is_set) {
+               /*
+                * Both trimming time range's bounds are set, so skip
+                * the
+                * `TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN`
+                * phase.
+                */
+               trimmer_it->state = TRIMMER_ITERATOR_STATE_SEEK_INITIALLY;
+       }
+
+       trimmer_it->begin = trimmer_it->trimmer_comp->begin;
+       trimmer_it->end = trimmer_it->trimmer_comp->end;
+       trimmer_it->upstream_iter =
+               bt_self_component_port_input_message_iterator_create(
+                       bt_self_component_filter_borrow_input_port_by_name(
+                               self_comp, in_port_name));
+       if (!trimmer_it->upstream_iter) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       trimmer_it->output_messages = g_queue_new();
+       if (!trimmer_it->output_messages) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto end;
+       }
+
+       trimmer_it->stream_states = g_hash_table_new_full(g_direct_hash,
+               g_direct_equal, NULL,
+               (GDestroyNotify) destroy_trimmer_iterator_stream_state);
+       if (!trimmer_it->stream_states) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto end;
+       }
+
+       trimmer_it->self_msg_iter = self_msg_iter;
+       bt_self_message_iterator_set_data(self_msg_iter, trimmer_it);
+
+end:
+       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK && trimmer_it) {
+               destroy_trimmer_iterator(trimmer_it);
+       }
+
+       return status;
+}
+
+static inline
+int get_msg_ns_from_origin(const bt_message *msg, int64_t *ns_from_origin,
+               bool *skip)
+{
+       const bt_clock_class *clock_class = NULL;
+       const bt_clock_snapshot *clock_snapshot = NULL;
+       bt_message_stream_activity_clock_snapshot_state sa_cs_state;
+       int ret = 0;
+
+       BT_ASSERT(msg);
+       BT_ASSERT(ns_from_origin);
+       BT_ASSERT(skip);
+
+       switch (bt_message_get_type(msg)) {
+       case BT_MESSAGE_TYPE_EVENT:
+               clock_class =
+                       bt_message_event_borrow_stream_class_default_clock_class_const(
+                               msg);
+               if (unlikely(!clock_class)) {
+                       goto error;
+               }
+
+               clock_snapshot = bt_message_event_borrow_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+               clock_class =
+                       bt_message_packet_beginning_borrow_stream_class_default_clock_class_const(
+                               msg);
+               if (unlikely(!clock_class)) {
+                       goto error;
+               }
+
+               clock_snapshot = bt_message_packet_beginning_borrow_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_PACKET_END:
+               clock_class =
+                       bt_message_packet_end_borrow_stream_class_default_clock_class_const(
+                               msg);
+               if (unlikely(!clock_class)) {
+                       goto error;
+               }
+
+               clock_snapshot = bt_message_packet_end_borrow_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+               clock_class =
+                       bt_message_discarded_events_borrow_stream_class_default_clock_class_const(
+                               msg);
+               if (unlikely(!clock_class)) {
+                       goto error;
+               }
+
+               clock_snapshot = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+               clock_class =
+                       bt_message_discarded_packets_borrow_stream_class_default_clock_class_const(
+                               msg);
+               if (unlikely(!clock_class)) {
+                       goto error;
+               }
+
+               clock_snapshot = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+                       msg);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+               clock_class =
+                       bt_message_stream_activity_beginning_borrow_stream_class_default_clock_class_const(
+                               msg);
+               if (unlikely(!clock_class)) {
+                       goto error;
+               }
+
+               sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
+                       msg, &clock_snapshot);
+               if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN ||
+                               sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE) {
+                       /* Lowest possible time to always include them */
+                       *ns_from_origin = INT64_MIN;
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+               clock_class =
+                       bt_message_stream_activity_end_borrow_stream_class_default_clock_class_const(
+                               msg);
+               if (unlikely(!clock_class)) {
+                       goto error;
+               }
+
+               sa_cs_state = bt_message_stream_activity_end_borrow_default_clock_snapshot_const(
+                       msg, &clock_snapshot);
+               if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_UNKNOWN) {
+                       /* Lowest time to always include it */
+                       *ns_from_origin = INT64_MIN;
+                       goto no_clock_snapshot;
+               } else if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE) {
+                       /* Greatest time to always exclude it */
+                       *ns_from_origin = INT64_MAX;
+                       goto no_clock_snapshot;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
+               clock_snapshot =
+                       bt_message_message_iterator_inactivity_borrow_default_clock_snapshot_const(
+                               msg);
+               break;
+       default:
+               goto no_clock_snapshot;
+       }
+
+       ret = bt_clock_snapshot_get_ns_from_origin(clock_snapshot,
+               ns_from_origin);
+       if (unlikely(ret)) {
+               goto error;
+       }
+
+       goto end;
+
+no_clock_snapshot:
+       *skip = true;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static inline
+void put_messages(bt_message_array_const msgs, uint64_t count)
+{
+       uint64_t i;
+
+       for (i = 0; i < count; i++) {
+               BT_MESSAGE_PUT_REF_AND_RESET(msgs[i]);
+       }
+}
+
+static inline
+int set_trimmer_iterator_bound(struct trimmer_bound *bound,
+               int64_t ns_from_origin, bool is_gmt)
+{
+       struct tm tm;
+       time_t time_seconds = (time_t) (ns_from_origin / NS_PER_S);
+       int ret = 0;
+
+       BT_ASSERT(!bound->is_set);
+       errno = 0;
+
+       /* We only need to extract the date from this time */
+       if (is_gmt) {
+               bt_gmtime_r(&time_seconds, &tm);
+       } else {
+               bt_localtime_r(&time_seconds, &tm);
+       }
+
+       if (errno) {
+               BT_LOGE_ERRNO("Cannot convert timestamp to date and time",
+                       "ts=%" PRId64, (int64_t) time_seconds);
+               ret = -1;
+               goto end;
+       }
+
+       ret = set_bound_ns_from_origin(bound, tm.tm_year + 1900, tm.tm_mon + 1,
+               tm.tm_mday, bound->time.hour, bound->time.minute,
+               bound->time.second, bound->time.ns, is_gmt);
+
+end:
+       return ret;
+}
+
+static
+bt_self_message_iterator_status state_set_trimmer_iterator_bounds(
+               struct trimmer_iterator *trimmer_it)
+{
+       bt_message_iterator_status upstream_iter_status =
+               BT_MESSAGE_ITERATOR_STATUS_OK;
+       struct trimmer_comp *trimmer_comp = trimmer_it->trimmer_comp;
+       bt_message_array_const msgs;
+       uint64_t count = 0;
+       int64_t ns_from_origin = INT64_MIN;
+       uint64_t i;
+       int ret;
+
+       BT_ASSERT(!trimmer_it->begin.is_set ||
+               !trimmer_it->end.is_set);
+
+       while (true) {
+               upstream_iter_status =
+                       bt_self_component_port_input_message_iterator_next(
+                               trimmer_it->upstream_iter, &msgs, &count);
+               if (upstream_iter_status != BT_MESSAGE_ITERATOR_STATUS_OK) {
+                       goto end;
+               }
+
+               for (i = 0; i < count; i++) {
+                       const bt_message *msg = msgs[i];
+                       bool skip = false;
+                       int ret;
+
+                       ret = get_msg_ns_from_origin(msg, &ns_from_origin,
+                               &skip);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (skip) {
+                               continue;
+                       }
+
+                       BT_ASSERT(ns_from_origin != INT64_MIN &&
+                               ns_from_origin != INT64_MAX);
+                       put_messages(msgs, count);
+                       goto found;
+               }
+
+               put_messages(msgs, count);
+       }
+
+found:
+       if (!trimmer_it->begin.is_set) {
+               BT_ASSERT(!trimmer_it->begin.is_infinite);
+               ret = set_trimmer_iterator_bound(&trimmer_it->begin,
+                       ns_from_origin, trimmer_comp->is_gmt);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       if (!trimmer_it->end.is_set) {
+               BT_ASSERT(!trimmer_it->end.is_infinite);
+               ret = set_trimmer_iterator_bound(&trimmer_it->end,
+                       ns_from_origin, trimmer_comp->is_gmt);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       ret = validate_trimmer_bounds(&trimmer_it->begin,
+               &trimmer_it->end);
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       put_messages(msgs, count);
+       upstream_iter_status = BT_MESSAGE_ITERATOR_STATUS_ERROR;
+
+end:
+       return (int) upstream_iter_status;
+}
+
+static
+bt_self_message_iterator_status state_seek_initially(
+               struct trimmer_iterator *trimmer_it)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_ASSERT(trimmer_it->begin.is_set);
+
+       if (trimmer_it->begin.is_infinite) {
+               if (!bt_self_component_port_input_message_iterator_can_seek_beginning(
+                               trimmer_it->upstream_iter)) {
+                       BT_LOGE_STR("Cannot make upstream message iterator initially seek its beginning.");
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                       goto end;
+               }
+
+               status = (int) bt_self_component_port_input_message_iterator_seek_beginning(
+                       trimmer_it->upstream_iter);
+       } else {
+               if (!bt_self_component_port_input_message_iterator_can_seek_ns_from_origin(
+                               trimmer_it->upstream_iter,
+                               trimmer_it->begin.ns_from_origin)) {
+                       BT_LOGE("Cannot make upstream message iterator initially seek: "
+                               "seek-ns-from-origin=%" PRId64,
+                               trimmer_it->begin.ns_from_origin);
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                       goto end;
+               }
+
+               status = (int) bt_self_component_port_input_message_iterator_seek_ns_from_origin(
+                       trimmer_it->upstream_iter, trimmer_it->begin.ns_from_origin);
+       }
+
+       if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+               trimmer_it->state = TRIMMER_ITERATOR_STATE_TRIM;
+       }
+
+end:
+       return status;
+}
+
+static inline
+void push_message(struct trimmer_iterator *trimmer_it, const bt_message *msg)
+{
+       g_queue_push_head(trimmer_it->output_messages, (void *) msg);
+}
+
+static inline
+const bt_message *pop_message(struct trimmer_iterator *trimmer_it)
+{
+       return g_queue_pop_tail(trimmer_it->output_messages);
+}
+
+static inline
+int clock_raw_value_from_ns_from_origin(const bt_clock_class *clock_class,
+               int64_t ns_from_origin, uint64_t *raw_value)
+{
+
+       int64_t cc_offset_s;
+       uint64_t cc_offset_cycles;
+       uint64_t cc_freq;
+
+       bt_clock_class_get_offset(clock_class, &cc_offset_s, &cc_offset_cycles);
+       cc_freq = bt_clock_class_get_frequency(clock_class);
+       return bt_common_clock_value_from_ns_from_origin(cc_offset_s,
+               cc_offset_cycles, cc_freq, ns_from_origin, raw_value);
+}
+
+static inline
+bt_self_message_iterator_status end_stream(struct trimmer_iterator *trimmer_it,
+               struct trimmer_iterator_stream_state *sstate)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       uint64_t raw_value;
+       const bt_clock_class *clock_class;
+       int ret;
+       bt_message *msg = NULL;
+
+       BT_ASSERT(!trimmer_it->end.is_infinite);
+
+       if (!sstate->stream) {
+               goto end;
+       }
+
+       if (sstate->cur_packet) {
+               /*
+                * The last message could not have been a stream
+                * activity end message if we have a current packet.
+                */
+               BT_ASSERT(!sstate->last_msg_is_stream_activity_end);
+
+               /*
+                * Create and push a packet end message, making its time
+                * the trimming range's end time.
+                */
+               clock_class = bt_stream_class_borrow_default_clock_class_const(
+                       bt_stream_borrow_class_const(sstate->stream));
+               BT_ASSERT(clock_class);
+               ret = clock_raw_value_from_ns_from_origin(clock_class,
+                       trimmer_it->end.ns_from_origin, &raw_value);
+               if (ret) {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                       goto end;
+               }
+
+               msg = bt_message_packet_end_create_with_default_clock_snapshot(
+                       trimmer_it->self_msg_iter, sstate->cur_packet,
+                       raw_value);
+               if (!msg) {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+                       goto end;
+               }
+
+               push_message(trimmer_it, msg);
+               msg = NULL;
+               BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
+
+               /*
+                * Because we generated a packet end message, set the
+                * stream activity end message's time to use to the
+                * trimming range's end time (this packet end message's
+                * time).
+                */
+               sstate->stream_act_end_ns_from_origin =
+                       trimmer_it->end.ns_from_origin;
+       }
+
+       if (!sstate->last_msg_is_stream_activity_end) {
+               /* Create and push a stream activity end message */
+               msg = bt_message_stream_activity_end_create(
+                       trimmer_it->self_msg_iter, sstate->stream);
+               if (!msg) {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+                       goto end;
+               }
+
+               clock_class = bt_stream_class_borrow_default_clock_class_const(
+                       bt_stream_borrow_class_const(sstate->stream));
+               BT_ASSERT(clock_class);
+
+               if (sstate->stream_act_end_ns_from_origin == INT64_MIN) {
+                       /*
+                        * We received at least what is necessary to
+                        * have a stream state (stream beginning and
+                        * stream activity beginning messages), but
+                        * nothing else: use the trimmer range's end
+                        * time.
+                        */
+                       sstate->stream_act_end_ns_from_origin =
+                               trimmer_it->end.ns_from_origin;
+               }
+
+               ret = clock_raw_value_from_ns_from_origin(clock_class,
+                       sstate->stream_act_end_ns_from_origin, &raw_value);
+               if (ret) {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                       goto end;
+               }
+
+               bt_message_stream_activity_end_set_default_clock_snapshot(
+                       msg, raw_value);
+               push_message(trimmer_it, msg);
+               msg = NULL;
+       }
+
+       /* Create and push a stream end message */
+       msg = bt_message_stream_end_create(trimmer_it->self_msg_iter,
+               sstate->stream);
+       if (!msg) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto end;
+       }
+
+       push_message(trimmer_it, msg);
+       msg = NULL;
+
+       /*
+        * Just to make sure that we don't use this stream state again
+        * in the future without an obvious error.
+        */
+       sstate->stream = NULL;
+
+end:
+       bt_message_put_ref(msg);
+       return status;
+}
+
+static inline
+bt_self_message_iterator_status end_iterator_streams(
+               struct trimmer_iterator *trimmer_it)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       GHashTableIter iter;
+       gpointer key, sstate;
+
+       if (trimmer_it->end.is_infinite) {
+               /*
+                * An infinite trimming range's end time guarantees that
+                * we received (and pushed) all the appropriate end
+                * messages.
+                */
+               goto remove_all;
+       }
+
+       /*
+        * End each stream and then remove them from the hash table of
+        * stream states to release unneeded references.
+        */
+       g_hash_table_iter_init(&iter, trimmer_it->stream_states);
+
+       while (g_hash_table_iter_next(&iter, &key, &sstate)) {
+               status = end_stream(trimmer_it, sstate);
+               if (status) {
+                       goto end;
+               }
+       }
+
+remove_all:
+       g_hash_table_remove_all(trimmer_it->stream_states);
+
+end:
+       return status;
+}
+
+static inline
+bt_self_message_iterator_status create_stream_beginning_activity_message(
+               struct trimmer_iterator *trimmer_it,
+               const bt_stream *stream,
+               const bt_clock_class *clock_class, bt_message **msg)
+{
+       bt_message *local_msg;
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_ASSERT(msg);
+       BT_ASSERT(!trimmer_it->begin.is_infinite);
+
+       local_msg = bt_message_stream_activity_beginning_create(
+               trimmer_it->self_msg_iter, stream);
+       if (!local_msg) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto end;
+       }
+
+       if (clock_class) {
+               int ret;
+               uint64_t raw_value;
+
+               ret = clock_raw_value_from_ns_from_origin(clock_class,
+                       trimmer_it->begin.ns_from_origin, &raw_value);
+               if (ret) {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                       bt_message_put_ref(local_msg);
+                       goto end;
+               }
+
+               bt_message_stream_activity_beginning_set_default_clock_snapshot(
+                       local_msg, raw_value);
+       }
+
+       BT_MESSAGE_MOVE_REF(*msg, local_msg);
+
+end:
+       return status;
+}
+
+/*
+ * Makes sure to initialize a stream state, pushing the appropriate
+ * initial messages.
+ *
+ * `stream_act_beginning_msg` is an initial stream activity beginning
+ * message to potentially use, depending on its clock snapshot state.
+ * This function consumes `stream_act_beginning_msg` unconditionally.
+ */
+static inline
+bt_self_message_iterator_status ensure_stream_state_is_inited(
+               struct trimmer_iterator *trimmer_it,
+               struct trimmer_iterator_stream_state *sstate,
+               const bt_message *stream_act_beginning_msg)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       bt_message *new_msg = NULL;
+       const bt_clock_class *clock_class =
+               bt_stream_class_borrow_default_clock_class_const(
+                       bt_stream_borrow_class_const(sstate->stream));
+
+       BT_ASSERT(!sstate->inited);
+
+       if (!sstate->stream_beginning_msg) {
+               /* No initial stream beginning message: create one */
+               sstate->stream_beginning_msg =
+                       bt_message_stream_beginning_create(
+                               trimmer_it->self_msg_iter, sstate->stream);
+               if (!sstate->stream_beginning_msg) {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+                       goto end;
+               }
+       }
+
+       /* Push initial stream beginning message */
+       BT_ASSERT(sstate->stream_beginning_msg);
+       push_message(trimmer_it, sstate->stream_beginning_msg);
+       sstate->stream_beginning_msg = NULL;
+
+       if (stream_act_beginning_msg) {
+               /*
+                * Initial stream activity beginning message exists: if
+                * its time is -inf, then create and push a new one
+                * having the trimming range's beginning time. Otherwise
+                * push it as is (known and unknown).
+                */
+               const bt_clock_snapshot *cs;
+               bt_message_stream_activity_clock_snapshot_state sa_cs_state;
+
+               sa_cs_state = bt_message_stream_activity_beginning_borrow_default_clock_snapshot_const(
+                       stream_act_beginning_msg, &cs);
+               if (sa_cs_state == BT_MESSAGE_STREAM_ACTIVITY_CLOCK_SNAPSHOT_STATE_INFINITE &&
+                               !trimmer_it->begin.is_infinite) {
+                       /*
+                        * -inf time: use trimming range's beginning
+                        * time (which is not -inf).
+                        */
+                       status = create_stream_beginning_activity_message(
+                               trimmer_it, sstate->stream, clock_class,
+                               &new_msg);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       push_message(trimmer_it, new_msg);
+                       new_msg = NULL;
+               } else {
+                       /* Known/unknown: push as is */
+                       push_message(trimmer_it, stream_act_beginning_msg);
+                       stream_act_beginning_msg = NULL;
+               }
+       } else {
+               BT_ASSERT(!trimmer_it->begin.is_infinite);
+
+               /*
+                * No stream beginning activity message: create and push
+                * a new message.
+                */
+               status = create_stream_beginning_activity_message(
+                       trimmer_it, sstate->stream, clock_class, &new_msg);
+               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                       goto end;
+               }
+
+               push_message(trimmer_it, new_msg);
+               new_msg = NULL;
+       }
+
+       sstate->inited = true;
+
+end:
+       bt_message_put_ref(new_msg);
+       bt_message_put_ref(stream_act_beginning_msg);
+       return status;
+}
+
+static inline
+bt_self_message_iterator_status ensure_cur_packet_exists(
+       struct trimmer_iterator *trimmer_it,
+       struct trimmer_iterator_stream_state *sstate,
+       const bt_packet *packet)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       int ret;
+       const bt_clock_class *clock_class =
+               bt_stream_class_borrow_default_clock_class_const(
+                       bt_stream_borrow_class_const(sstate->stream));
+       bt_message *msg = NULL;
+       uint64_t raw_value;
+
+       BT_ASSERT(!trimmer_it->begin.is_infinite);
+       BT_ASSERT(!sstate->cur_packet);
+
+       /*
+        * Create and push an initial packet beginning message,
+        * making its time the trimming range's beginning time.
+        */
+       ret = clock_raw_value_from_ns_from_origin(clock_class,
+               trimmer_it->begin.ns_from_origin, &raw_value);
+       if (ret) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       msg = bt_message_packet_beginning_create_with_default_clock_snapshot(
+               trimmer_it->self_msg_iter, packet, raw_value);
+       if (!msg) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+               goto end;
+       }
+
+       push_message(trimmer_it, msg);
+       msg = NULL;
+
+       /* Set packet as this stream's current packet */
+       sstate->cur_packet = packet;
+       bt_packet_get_ref(sstate->cur_packet);
+
+end:
+       bt_message_put_ref(msg);
+       return status;
+}
+
+/*
+ * Handles a message which is associated to a given stream state. This
+ * _could_ make the iterator's output message queue grow; this could
+ * also consume the message without pushing anything to this queue, only
+ * modifying the stream state.
+ *
+ * This function consumes the `msg` reference, _whatever the outcome_.
+ *
+ * `ns_from_origin` is the message's time, as given by
+ * get_msg_ns_from_origin().
+ *
+ * This function sets `reached_end` if handling this message made the
+ * iterator reach the end of the trimming range. Note that the output
+ * message queue could contain messages even if this function sets
+ * `reached_end`.
+ */
+static inline
+bt_self_message_iterator_status handle_message_with_stream_state(
+               struct trimmer_iterator *trimmer_it, const bt_message *msg,
+               struct trimmer_iterator_stream_state *sstate,
+               int64_t ns_from_origin, bool *reached_end)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       bt_message_type msg_type = bt_message_get_type(msg);
+       int ret;
+
+       switch (msg_type) {
+       case BT_MESSAGE_TYPE_EVENT:
+               if (unlikely(!trimmer_it->end.is_infinite &&
+                               ns_from_origin > trimmer_it->end.ns_from_origin)) {
+                       status = end_iterator_streams(trimmer_it);
+                       *reached_end = true;
+                       break;
+               }
+
+               if (unlikely(!sstate->inited)) {
+                       status = ensure_stream_state_is_inited(trimmer_it,
+                               sstate, NULL);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+               }
+
+               if (unlikely(!sstate->cur_packet)) {
+                       const bt_event *event =
+                               bt_message_event_borrow_event_const(msg);
+                       const bt_packet *packet = bt_event_borrow_packet_const(
+                               event);
+
+                       status = ensure_cur_packet_exists(trimmer_it, sstate,
+                               packet);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(sstate->cur_packet);
+               push_message(trimmer_it, msg);
+               msg = NULL;
+               break;
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+               if (unlikely(!trimmer_it->end.is_infinite &&
+                               ns_from_origin > trimmer_it->end.ns_from_origin)) {
+                       status = end_iterator_streams(trimmer_it);
+                       *reached_end = true;
+                       break;
+               }
+
+               if (unlikely(!sstate->inited)) {
+                       status = ensure_stream_state_is_inited(trimmer_it,
+                               sstate, NULL);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(!sstate->cur_packet);
+               sstate->cur_packet =
+                       bt_message_packet_beginning_borrow_packet_const(msg);
+               bt_packet_get_ref(sstate->cur_packet);
+               push_message(trimmer_it, msg);
+               msg = NULL;
+               break;
+       case BT_MESSAGE_TYPE_PACKET_END:
+               sstate->stream_act_end_ns_from_origin = ns_from_origin;
+
+               if (unlikely(!trimmer_it->end.is_infinite &&
+                               ns_from_origin > trimmer_it->end.ns_from_origin)) {
+                       status = end_iterator_streams(trimmer_it);
+                       *reached_end = true;
+                       break;
+               }
+
+               if (unlikely(!sstate->inited)) {
+                       status = ensure_stream_state_is_inited(trimmer_it,
+                               sstate, NULL);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+               }
+
+               if (unlikely(!sstate->cur_packet)) {
+                       const bt_packet *packet =
+                               bt_message_packet_end_borrow_packet_const(msg);
+
+                       status = ensure_cur_packet_exists(trimmer_it, sstate,
+                               packet);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+               }
+
+               BT_ASSERT(sstate->cur_packet);
+               BT_PACKET_PUT_REF_AND_RESET(sstate->cur_packet);
+               push_message(trimmer_it, msg);
+               msg = NULL;
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+       {
+               /*
+                * `ns_from_origin` is the message's time range's
+                * beginning time here.
+                */
+               int64_t end_ns_from_origin;
+               const bt_clock_snapshot *end_cs;
+
+               if (bt_message_get_type(msg) ==
+                               BT_MESSAGE_TYPE_DISCARDED_EVENTS) {
+                       /*
+                        * Safe to ignore the return value because we
+                        * know there's a default clock and it's always
+                        * known.
+                        */
+                       end_cs = bt_message_discarded_events_borrow_end_default_clock_snapshot_const(
+                               msg);
+               } else {
+                       /*
+                        * Safe to ignore the return value because we
+                        * know there's a default clock and it's always
+                        * known.
+                        */
+                       end_cs = bt_message_discarded_packets_borrow_end_default_clock_snapshot_const(
+                               msg);
+               }
+
+               if (bt_clock_snapshot_get_ns_from_origin(end_cs,
+                               &end_ns_from_origin)) {
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                       goto end;
+               }
+
+               sstate->stream_act_end_ns_from_origin = end_ns_from_origin;
+
+               if (!trimmer_it->end.is_infinite &&
+                               ns_from_origin > trimmer_it->end.ns_from_origin) {
+                       status = end_iterator_streams(trimmer_it);
+                       *reached_end = true;
+                       break;
+               }
+
+               if (!trimmer_it->end.is_infinite &&
+                               end_ns_from_origin > trimmer_it->end.ns_from_origin) {
+                       /*
+                        * This message's end time is outside the
+                        * trimming time range: replace it with a new
+                        * message having an end time equal to the
+                        * trimming time range's end and without a
+                        * count.
+                        */
+                       const bt_clock_class *clock_class =
+                               bt_clock_snapshot_borrow_clock_class_const(
+                                       end_cs);
+                       const bt_clock_snapshot *begin_cs;
+                       bt_message *new_msg;
+                       uint64_t end_raw_value;
+
+                       ret = clock_raw_value_from_ns_from_origin(clock_class,
+                               trimmer_it->end.ns_from_origin, &end_raw_value);
+                       if (ret) {
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       if (msg_type == BT_MESSAGE_TYPE_DISCARDED_EVENTS) {
+                               begin_cs = bt_message_discarded_events_borrow_beginning_default_clock_snapshot_const(
+                                       msg);
+                               new_msg = bt_message_discarded_events_create_with_default_clock_snapshots(
+                                       trimmer_it->self_msg_iter,
+                                       sstate->stream,
+                                       bt_clock_snapshot_get_value(begin_cs),
+                                       end_raw_value);
+                       } else {
+                               begin_cs = bt_message_discarded_packets_borrow_beginning_default_clock_snapshot_const(
+                                       msg);
+                               new_msg = bt_message_discarded_packets_create_with_default_clock_snapshots(
+                                       trimmer_it->self_msg_iter,
+                                       sstate->stream,
+                                       bt_clock_snapshot_get_value(begin_cs),
+                                       end_raw_value);
+                       }
+
+                       if (!new_msg) {
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+                               goto end;
+                       }
+
+                       /* Replace the original message */
+                       BT_MESSAGE_MOVE_REF(msg, new_msg);
+               }
+
+               if (unlikely(!sstate->inited)) {
+                       status = ensure_stream_state_is_inited(trimmer_it,
+                               sstate, NULL);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+               }
+
+               push_message(trimmer_it, msg);
+               msg = NULL;
+               break;
+       }
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+               if (!trimmer_it->end.is_infinite &&
+                               ns_from_origin > trimmer_it->end.ns_from_origin) {
+                       /*
+                        * This only happens when the message's time is
+                        * known and is greater than the trimming
+                        * range's end time. Unknown and -inf times are
+                        * always less than
+                        * `trimmer_it->end.ns_from_origin`.
+                        */
+                       status = end_iterator_streams(trimmer_it);
+                       *reached_end = true;
+                       break;
+               }
+
+               if (!sstate->inited) {
+                       status = ensure_stream_state_is_inited(trimmer_it,
+                               sstate, msg);
+                       msg = NULL;
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+               } else {
+                       push_message(trimmer_it, msg);
+                       msg = NULL;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+               if (trimmer_it->end.is_infinite) {
+                       push_message(trimmer_it, msg);
+                       msg = NULL;
+                       break;
+               }
+
+               if (ns_from_origin == INT64_MIN) {
+                       /* Unknown: push as is if stream state is inited */
+                       if (sstate->inited) {
+                               push_message(trimmer_it, msg);
+                               msg = NULL;
+                               sstate->last_msg_is_stream_activity_end = true;
+                       }
+               } else if (ns_from_origin == INT64_MAX) {
+                       /* Infinite: use trimming range's end time */
+                       sstate->stream_act_end_ns_from_origin =
+                               trimmer_it->end.ns_from_origin;
+               } else {
+                       /* Known: check if outside of trimming range */
+                       if (ns_from_origin > trimmer_it->end.ns_from_origin) {
+                               sstate->stream_act_end_ns_from_origin =
+                                       trimmer_it->end.ns_from_origin;
+                               status = end_iterator_streams(trimmer_it);
+                               *reached_end = true;
+                               break;
+                       }
+
+                       if (!sstate->inited) {
+                               /*
+                                * First message for this stream is a
+                                * stream activity end: we can't deduce
+                                * anything about the stream activity
+                                * beginning's time, and using this
+                                * message's time would make a useless
+                                * pair of stream activity beginning/end
+                                * with the same time. Just skip this
+                                * message and wait for something
+                                * useful.
+                                */
+                               break;
+                       }
+
+                       push_message(trimmer_it, msg);
+                       msg = NULL;
+                       sstate->last_msg_is_stream_activity_end = true;
+                       sstate->stream_act_end_ns_from_origin = ns_from_origin;
+               }
+
+               break;
+       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
+               /*
+                * We don't know what follows at this point, so just
+                * keep this message until we know what to do with it
+                * (it will be used in ensure_stream_state_is_inited()).
+                */
+               BT_ASSERT(!sstate->inited);
+               BT_MESSAGE_MOVE_REF(sstate->stream_beginning_msg, msg);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_END:
+               if (sstate->inited) {
+                       /*
+                        * This is the end of an inited stream: end this
+                        * stream if its stream activity end message
+                        * time is not the trimming range's end time
+                        * (which means the final stream activity end
+                        * message had an infinite time). end_stream()
+                        * will generate its own stream end message.
+                        */
+                       if (trimmer_it->end.is_infinite) {
+                               push_message(trimmer_it, msg);
+                               msg = NULL;
+                               g_hash_table_remove(trimmer_it->stream_states,
+                                       sstate->stream);
+                       } else if (sstate->stream_act_end_ns_from_origin <
+                                       trimmer_it->end.ns_from_origin) {
+                               status = end_stream(trimmer_it, sstate);
+                               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                                       goto end;
+                               }
+
+                               /* We won't need this stream state again */
+                               g_hash_table_remove(trimmer_it->stream_states,
+                                       sstate->stream);
+                       }
+               } else {
+                       /* We dont't need this stream state anymore */
+                       g_hash_table_remove(trimmer_it->stream_states, sstate->stream);
+               }
+
+               break;
+       default:
+               break;
+       }
+
+end:
+       /* We release the message's reference whatever the outcome */
+       bt_message_put_ref(msg);
+       return BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+}
+
+/*
+ * Handles an input message. This _could_ make the iterator's output
+ * message queue grow; this could also consume the message without
+ * pushing anything to this queue, only modifying the stream state.
+ *
+ * This function consumes the `msg` reference, _whatever the outcome_.
+ *
+ * This function sets `reached_end` if handling this message made the
+ * iterator reach the end of the trimming range. Note that the output
+ * message queue could contain messages even if this function sets
+ * `reached_end`.
+ */
+static inline
+bt_self_message_iterator_status handle_message(
+               struct trimmer_iterator *trimmer_it, const bt_message *msg,
+               bool *reached_end)
+{
+       bt_self_message_iterator_status status;
+       const bt_stream *stream = NULL;
+       int64_t ns_from_origin = INT64_MIN;
+       bool skip;
+       int ret;
+       struct trimmer_iterator_stream_state *sstate = NULL;
+
+       /* Find message's associated stream */
+       switch (bt_message_get_type(msg)) {
+       case BT_MESSAGE_TYPE_EVENT:
+               stream = bt_event_borrow_stream_const(
+                       bt_message_event_borrow_event_const(msg));
+               break;
+       case BT_MESSAGE_TYPE_PACKET_BEGINNING:
+               stream = bt_packet_borrow_stream_const(
+                       bt_message_packet_beginning_borrow_packet_const(msg));
+               break;
+       case BT_MESSAGE_TYPE_PACKET_END:
+               stream = bt_packet_borrow_stream_const(
+                       bt_message_packet_end_borrow_packet_const(msg));
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
+               stream = bt_message_discarded_events_borrow_stream_const(msg);
+               break;
+       case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
+               stream = bt_message_discarded_packets_borrow_stream_const(msg);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_BEGINNING:
+               stream = bt_message_stream_activity_beginning_borrow_stream_const(msg);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_ACTIVITY_END:
+               stream = bt_message_stream_activity_end_borrow_stream_const(msg);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_BEGINNING:
+               stream = bt_message_stream_beginning_borrow_stream_const(msg);
+               break;
+       case BT_MESSAGE_TYPE_STREAM_END:
+               stream = bt_message_stream_end_borrow_stream_const(msg);
+               break;
+       default:
+               break;
+       }
+
+       if (likely(stream)) {
+               /* Find stream state */
+               sstate = g_hash_table_lookup(trimmer_it->stream_states,
+                       stream);
+               if (unlikely(!sstate)) {
+                       /* No stream state yet: create one now */
+                       const bt_stream_class *sc;
+
+                       /*
+                        * Validate right now that the stream's class
+                        * has a registered default clock class so that
+                        * an existing stream state guarantees existing
+                        * default clock snapshots for its associated
+                        * messages.
+                        *
+                        * Also check that clock snapshots are always
+                        * known.
+                        */
+                       sc = bt_stream_borrow_class_const(stream);
+                       if (!bt_stream_class_borrow_default_clock_class_const(sc)) {
+                               BT_LOGE("Unsupported stream: stream class does "
+                                       "not have a default clock class: "
+                                       "stream-addr=%p, "
+                                       "stream-id=%" PRIu64 ", "
+                                       "stream-name=\"%s\"",
+                                       stream, bt_stream_get_id(stream),
+                                       bt_stream_get_name(stream));
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       /*
+                        * Temporary: make sure packet beginning, packet
+                        * end, discarded events, and discarded packets
+                        * messages have default clock snapshots until
+                        * the support for not having them is
+                        * implemented.
+                        */
+                       if (!bt_stream_class_packets_have_beginning_default_clock_snapshot(
+                                       sc)) {
+                               BT_LOGE("Unsupported stream: packets have "
+                                       "no beginning clock snapshot: "
+                                       "stream-addr=%p, "
+                                       "stream-id=%" PRIu64 ", "
+                                       "stream-name=\"%s\"",
+                                       stream, bt_stream_get_id(stream),
+                                       bt_stream_get_name(stream));
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       if (!bt_stream_class_packets_have_end_default_clock_snapshot(
+                                       sc)) {
+                               BT_LOGE("Unsupported stream: packets have "
+                                       "no end clock snapshot: "
+                                       "stream-addr=%p, "
+                                       "stream-id=%" PRIu64 ", "
+                                       "stream-name=\"%s\"",
+                                       stream, bt_stream_get_id(stream),
+                                       bt_stream_get_name(stream));
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       if (bt_stream_class_supports_discarded_events(sc) &&
+                                       !bt_stream_class_discarded_events_have_default_clock_snapshots(sc)) {
+                               BT_LOGE("Unsupported stream: discarded events "
+                                       "have no clock snapshots: "
+                                       "stream-addr=%p, "
+                                       "stream-id=%" PRIu64 ", "
+                                       "stream-name=\"%s\"",
+                                       stream, bt_stream_get_id(stream),
+                                       bt_stream_get_name(stream));
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       if (bt_stream_class_supports_discarded_packets(sc) &&
+                                       !bt_stream_class_discarded_packets_have_default_clock_snapshots(sc)) {
+                               BT_LOGE("Unsupported stream: discarded packets "
+                                       "have no clock snapshots: "
+                                       "stream-addr=%p, "
+                                       "stream-id=%" PRIu64 ", "
+                                       "stream-name=\"%s\"",
+                                       stream, bt_stream_get_id(stream),
+                                       bt_stream_get_name(stream));
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+                               goto end;
+                       }
+
+                       sstate = g_new0(struct trimmer_iterator_stream_state,
+                               1);
+                       if (!sstate) {
+                               status = BT_SELF_MESSAGE_ITERATOR_STATUS_NOMEM;
+                               goto end;
+                       }
+
+                       sstate->stream = stream;
+                       sstate->stream_act_end_ns_from_origin = INT64_MIN;
+                       g_hash_table_insert(trimmer_it->stream_states,
+                               (void *) stream, sstate);
+               }
+       }
+
+       /* Retrieve the message's time */
+       ret = get_msg_ns_from_origin(msg, &ns_from_origin, &skip);
+       if (unlikely(ret)) {
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       if (likely(sstate)) {
+               /* Message associated to a stream */
+               status = handle_message_with_stream_state(trimmer_it, msg,
+                       sstate, ns_from_origin, reached_end);
+
+               /*
+                * handle_message_with_stream_state() unconditionally
+                * consumes `msg`.
+                */
+               msg = NULL;
+       } else {
+               /*
+                * Message not associated to a stream (message iterator
+                * inactivity).
+                */
+               if (unlikely(ns_from_origin > trimmer_it->end.ns_from_origin)) {
+                       BT_MESSAGE_PUT_REF_AND_RESET(msg);
+                       status = end_iterator_streams(trimmer_it);
+                       *reached_end = true;
+               } else {
+                       push_message(trimmer_it, msg);
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+                       msg = NULL;
+               }
+       }
+
+end:
+       /* We release the message's reference whatever the outcome */
+       bt_message_put_ref(msg);
+       return status;
+}
+
+static inline
+void fill_message_array_from_output_messages(
+               struct trimmer_iterator *trimmer_it,
+               bt_message_array_const msgs, uint64_t capacity, uint64_t *count)
+{
+       *count = 0;
+
+       /*
+        * Move auto-seek messages to the output array (which is this
+        * iterator's base message array).
+        */
+       while (capacity > 0 && !g_queue_is_empty(trimmer_it->output_messages)) {
+               msgs[*count] = pop_message(trimmer_it);
+               capacity--;
+               (*count)++;
+       }
+
+       BT_ASSERT(*count > 0);
+}
+
+static inline
+bt_self_message_iterator_status state_ending(
+               struct trimmer_iterator *trimmer_it,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       if (g_queue_is_empty(trimmer_it->output_messages)) {
+               trimmer_it->state = TRIMMER_ITERATOR_STATE_ENDED;
+               status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+               goto end;
+       }
+
+       fill_message_array_from_output_messages(trimmer_it, msgs,
+               capacity, count);
+
+end:
+       return status;
+}
+
+static inline
+bt_self_message_iterator_status state_trim(struct trimmer_iterator *trimmer_it,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+       bt_message_array_const my_msgs;
+       uint64_t my_count;
+       uint64_t i;
+       bool reached_end = false;
+
+       while (g_queue_is_empty(trimmer_it->output_messages)) {
+               status = (int) bt_self_component_port_input_message_iterator_next(
+                       trimmer_it->upstream_iter, &my_msgs, &my_count);
+               if (unlikely(status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK)) {
+                       if (status == BT_SELF_MESSAGE_ITERATOR_STATUS_END) {
+                               status = end_iterator_streams(trimmer_it);
+                               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                                       goto end;
+                               }
+
+                               trimmer_it->state =
+                                       TRIMMER_ITERATOR_STATE_ENDING;
+                               status = state_ending(trimmer_it, msgs,
+                                       capacity, count);
+                       }
+
+                       goto end;
+               }
+
+               BT_ASSERT(my_count > 0);
+
+               for (i = 0; i < my_count; i++) {
+                       status = handle_message(trimmer_it, my_msgs[i],
+                               &reached_end);
+
+                       /*
+                        * handle_message() unconditionally consumes the
+                        * message reference.
+                        */
+                       my_msgs[i] = NULL;
+
+                       if (unlikely(status !=
+                                       BT_SELF_MESSAGE_ITERATOR_STATUS_OK)) {
+                               put_messages(my_msgs, my_count);
+                               goto end;
+                       }
+
+                       if (unlikely(reached_end)) {
+                               /*
+                                * This message's time was passed the
+                                * trimming time range's end time: we
+                                * are done. Their might still be
+                                * messages in the output message queue,
+                                * so move to the "ending" state and
+                                * apply it immediately since
+                                * state_trim() is called within the
+                                * "next" method.
+                                */
+                               put_messages(my_msgs, my_count);
+                               trimmer_it->state =
+                                       TRIMMER_ITERATOR_STATE_ENDING;
+                               status = state_ending(trimmer_it, msgs,
+                                       capacity, count);
+                               goto end;
+                       }
+               }
+       }
+
+       /*
+        * There's at least one message in the output message queue:
+        * move the messages to the output message array.
+        */
+       BT_ASSERT(!g_queue_is_empty(trimmer_it->output_messages));
+       fill_message_array_from_output_messages(trimmer_it, msgs,
+               capacity, count);
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+bt_self_message_iterator_status trimmer_msg_iter_next(
+               bt_self_message_iterator *self_msg_iter,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count)
+{
+       struct trimmer_iterator *trimmer_it =
+               bt_self_message_iterator_get_data(self_msg_iter);
+       bt_self_message_iterator_status status =
+               BT_SELF_MESSAGE_ITERATOR_STATUS_OK;
+
+       BT_ASSERT(trimmer_it);
+
+       if (likely(trimmer_it->state == TRIMMER_ITERATOR_STATE_TRIM)) {
+               status = state_trim(trimmer_it, msgs, capacity, count);
+               if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                       goto end;
+               }
+       } else {
+               switch (trimmer_it->state) {
+               case TRIMMER_ITERATOR_STATE_SET_BOUNDS_NS_FROM_ORIGIN:
+                       status = state_set_trimmer_iterator_bounds(trimmer_it);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       status = state_seek_initially(trimmer_it);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       status = state_trim(trimmer_it, msgs, capacity, count);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       break;
+               case TRIMMER_ITERATOR_STATE_SEEK_INITIALLY:
+                       status = state_seek_initially(trimmer_it);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       status = state_trim(trimmer_it, msgs, capacity, count);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       break;
+               case TRIMMER_ITERATOR_STATE_ENDING:
+                       status = state_ending(trimmer_it, msgs, capacity,
+                               count);
+                       if (status != BT_SELF_MESSAGE_ITERATOR_STATUS_OK) {
+                               goto end;
+                       }
+
+                       break;
+               case TRIMMER_ITERATOR_STATE_ENDED:
+                       status = BT_SELF_MESSAGE_ITERATOR_STATUS_END;
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+end:
+       return status;
+}
+
+BT_HIDDEN
+void trimmer_msg_iter_finalize(bt_self_message_iterator *self_msg_iter)
+{
+       struct trimmer_iterator *trimmer_it =
+               bt_self_message_iterator_get_data(self_msg_iter);
+
+       BT_ASSERT(trimmer_it);
+       destroy_trimmer_iterator(trimmer_it);
+}
diff --git a/src/plugins/utils/trimmer/trimmer.h b/src/plugins/utils/trimmer/trimmer.h
new file mode 100644 (file)
index 0000000..27f2329
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef BABELTRACE_PLUGINS_UTILS_TRIMMER_H
+#define BABELTRACE_PLUGINS_UTILS_TRIMMER_H
+
+/*
+ * BabelTrace - Trace Trimmer Plug-in
+ *
+ * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include "common/babeltrace.h"
+#include <babeltrace2/babeltrace.h>
+
+BT_HIDDEN
+void trimmer_finalize(bt_self_component_filter *self_comp);
+
+BT_HIDDEN
+bt_self_component_status trimmer_init(bt_self_component_filter *self_comp,
+               const bt_value *params, void *init_data);
+
+BT_HIDDEN
+bt_self_message_iterator_status trimmer_msg_iter_init(
+               bt_self_message_iterator *self_msg_iter,
+               bt_self_component_filter *self_comp,
+               bt_self_component_port_output *port);
+
+BT_HIDDEN
+bt_self_message_iterator_status trimmer_msg_iter_next(
+               bt_self_message_iterator *self_msg_iter,
+               bt_message_array_const msgs, uint64_t capacity,
+               uint64_t *count);
+
+BT_HIDDEN
+void trimmer_msg_iter_finalize(bt_self_message_iterator *self_msg_iter);
+
+#endif /* BABELTRACE_PLUGINS_UTILS_TRIMMER_H */
diff --git a/src/python-plugin-provider/Makefile.am b/src/python-plugin-provider/Makefile.am
new file mode 100644 (file)
index 0000000..e388406
--- /dev/null
@@ -0,0 +1,25 @@
+if ENABLE_PYTHON_PLUGINS
+AM_CPPFLAGS += $(PYTHON_INCLUDE)
+
+lib_LTLIBRARIES = libbabeltrace2-python-plugin-provider.la
+
+libbabeltrace2_python_plugin_provider_la_SOURCES = \
+       python-plugin-provider.c \
+       python-plugin-provider.h
+
+libbabeltrace2_python_plugin_provider_la_LDFLAGS = \
+       $(LT_NO_UNDEFINED) \
+       -version-info $(BABELTRACE_LIBRARY_VERSION) \
+       $(PYTHON_LIBS)
+
+libbabeltrace2_python_plugin_provider_la_LIBADD =
+
+# Link the Python plugin provider library with libbabeltrace2
+# when it's not built-in the babeltrace2 executable.
+if !ENABLE_BUILT_IN_PLUGINS
+libbabeltrace2_python_plugin_provider_la_LIBADD += \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/lib/libbabeltrace2.la
+endif
+endif # ENABLE_PYTHON_PLUGINS
diff --git a/src/python-plugin-provider/python-plugin-provider.c b/src/python-plugin-provider/python-plugin-provider.c
new file mode 100644 (file)
index 0000000..35f8755
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * python-plugin-provider.c
+ *
+ * Babeltrace Python plugin provider
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BT_LOG_TAG "PLUGIN-PY"
+
+#include "common/babeltrace.h"
+#include "compat/compiler.h"
+#include <babeltrace2/plugin/plugin-const.h>
+#include "lib/plugin/plugin.h"
+#include <babeltrace2/graph/component-class.h>
+#include "lib/graph/component-class.h"
+#include <stdlib.h>
+#include <signal.h>
+#include <Python.h>
+#include <glib.h>
+#include <gmodule.h>
+
+#define PYTHON_PLUGIN_FILE_PREFIX      "bt_plugin_"
+#define PYTHON_PLUGIN_FILE_PREFIX_LEN  (sizeof(PYTHON_PLUGIN_FILE_PREFIX) - 1)
+#define PYTHON_PLUGIN_FILE_EXT         ".py"
+#define PYTHON_PLUGIN_FILE_EXT_LEN     (sizeof(PYTHON_PLUGIN_FILE_EXT) - 1)
+
+enum python_state {
+       /* init_python() not called yet */
+       PYTHON_STATE_NOT_INITED,
+
+       /* init_python() called once with success */
+       PYTHON_STATE_FULLY_INITIALIZED,
+
+       /* init_python() called once without success */
+       PYTHON_STATE_CANNOT_INITIALIZE,
+} python_state = PYTHON_STATE_NOT_INITED;
+
+static PyObject *py_try_load_plugin_module_func = NULL;
+static bool python_was_initialized_by_us;
+
+static
+void print_python_traceback_warn(void)
+{
+       if (BT_LOG_ON_WARN && Py_IsInitialized() && PyErr_Occurred()) {
+               BT_LOGW_STR("Exception occured: traceback: ");
+               PyErr_Print();
+       }
+}
+
+static
+void pyerr_clear(void)
+{
+       if (Py_IsInitialized()) {
+               PyErr_Clear();
+       }
+}
+
+static
+void init_python(void)
+{
+       PyObject *py_bt2_py_plugin_mod = NULL;
+       const char *dis_python_env;
+#ifndef __MINGW32__
+       sighandler_t old_sigint = signal(SIGINT, SIG_DFL);
+#endif
+
+       if (python_state != PYTHON_STATE_NOT_INITED) {
+               goto end;
+       }
+
+       /*
+        * User can disable Python plugin support with the
+        * BABELTRACE_DISABLE_PYTHON_PLUGINS environment variable set to
+        * 1.
+        */
+       dis_python_env = getenv("BABELTRACE_DISABLE_PYTHON_PLUGINS");
+       if (dis_python_env && strcmp(dis_python_env, "1") == 0) {
+               BT_LOGI_STR("Python plugin support is disabled because `BABELTRACE_DISABLE_PYTHON_PLUGINS=1`.");
+               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
+               goto end;
+       }
+
+       if (!Py_IsInitialized()) {
+               BT_LOGI_STR("Python interpreter is not initialized: initializing Python interpreter.");
+               Py_InitializeEx(0);
+               python_was_initialized_by_us = true;
+               BT_LOGI("Initialized Python interpreter: version=\"%s\"",
+                       Py_GetVersion());
+       } else {
+               BT_LOGI("Python interpreter is already initialized: version=\"%s\"",
+                       Py_GetVersion());
+       }
+
+       py_bt2_py_plugin_mod = PyImport_ImportModule("bt2.py_plugin");
+       if (!py_bt2_py_plugin_mod) {
+               BT_LOGI_STR("Cannot import bt2.py_plugin Python module: Python plugin support is disabled.");
+               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
+               goto end;
+       }
+
+       py_try_load_plugin_module_func =
+               PyObject_GetAttrString(py_bt2_py_plugin_mod, "_try_load_plugin_module");
+       if (!py_try_load_plugin_module_func) {
+               BT_LOGI_STR("Cannot get _try_load_plugin_module attribute from bt2.py_plugin Python module: Python plugin support is disabled.");
+               python_state = PYTHON_STATE_CANNOT_INITIALIZE;
+               goto end;
+       }
+
+       python_state = PYTHON_STATE_FULLY_INITIALIZED;
+
+end:
+#ifndef __MINGW32__
+       if (old_sigint != SIG_ERR) {
+               (void) signal(SIGINT, old_sigint);
+       }
+#endif
+
+       print_python_traceback_warn();
+       pyerr_clear();
+       Py_XDECREF(py_bt2_py_plugin_mod);
+       return;
+}
+
+__attribute__((destructor)) static
+void fini_python(void) {
+       if (Py_IsInitialized() && python_was_initialized_by_us) {
+               if (py_try_load_plugin_module_func) {
+                       Py_DECREF(py_try_load_plugin_module_func);
+                       py_try_load_plugin_module_func = NULL;
+               }
+
+               Py_Finalize();
+               BT_LOGI_STR("Finalized Python interpreter.");
+       }
+
+       python_state = PYTHON_STATE_NOT_INITED;
+}
+
+static
+bt_plugin *bt_plugin_from_python_plugin_info(PyObject *plugin_info)
+{
+       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;
+
+       BT_ASSERT(plugin_info);
+       BT_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);
+
+                       BT_ASSERT(py_major);
+                       BT_ASSERT(py_minor);
+                       BT_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);
+
+                       BT_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++) {
+                       bt_component_class *comp_class;
+                       PyObject *py_comp_class_addr;
+
+                       py_comp_class_addr =
+                               PyList_GetItem(py_comp_class_addrs, i);
+                       BT_ASSERT(py_comp_class_addr);
+                       if (PyLong_Check(py_comp_class_addr)) {
+                               comp_class = PyLong_AsVoidPtr(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;
+                       }
+               }
+       }
+
+       goto end;
+
+error:
+       print_python_traceback_warn();
+       pyerr_clear();
+       BT_OBJECT_PUT_REF_AND_RESET(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;
+}
+
+G_MODULE_EXPORT
+bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path)
+{
+       bt_plugin_set *plugin_set = NULL;
+       bt_plugin *plugin = NULL;
+       PyObject *py_plugin_info = NULL;
+       gchar *basename = NULL;
+       size_t path_len;
+
+       BT_ASSERT(path);
+
+       if (python_state == PYTHON_STATE_CANNOT_INITIALIZE) {
+               /*
+                * We do not even care about the rest of the function
+                * here because we already know Python cannot be fully
+                * initialized.
+                */
+               goto error;
+       }
+
+       BT_LOGD("Creating all Python plugins from file: path=\"%s\"", path);
+       path_len = strlen(path);
+
+       /* File name ends with `.py` */
+       if (strncmp(path + path_len - PYTHON_PLUGIN_FILE_EXT_LEN,
+                       PYTHON_PLUGIN_FILE_EXT,
+                       PYTHON_PLUGIN_FILE_EXT_LEN) != 0) {
+               BT_LOGD("Skipping non-Python file: path=\"%s\"", path);
+               goto error;
+       }
+
+       /* File name starts with `bt_plugin_` */
+       basename = g_path_get_basename(path);
+       if (!basename) {
+               BT_LOGW("Cannot get path's basename: path=\"%s\"", path);
+               goto error;
+       }
+
+       if (strncmp(basename, PYTHON_PLUGIN_FILE_PREFIX,
+                       PYTHON_PLUGIN_FILE_PREFIX_LEN) != 0) {
+               BT_LOGD("Skipping Python file not starting with `%s`: "
+                       "path=\"%s\"", PYTHON_PLUGIN_FILE_PREFIX, path);
+               goto error;
+       }
+
+       /*
+        * Initialize Python now.
+        *
+        * This is not done in the library contructor because the
+        * interpreter is somewhat slow to initialize. If you don't
+        * have any potential Python plugins, you don't need to endure
+        * this waiting time everytime you load the library.
+        */
+       init_python();
+       if (python_state != PYTHON_STATE_FULLY_INITIALIZED) {
+               /*
+                * For some reason we cannot initialize Python,
+                * import the required modules, and get the required
+                * attributes from them.
+                */
+               BT_LOGI("Failed to initialize Python interpreter.");
+               goto error;
+       }
+
+       /*
+        * Call bt2.py_plugin._try_load_plugin_module() with this path
+        * to get plugin info if the plugin is loadable and complete.
+        * This function returns None when there's an error, but just in
+        * case we also manually clear the last Python error state.
+        */
+       BT_LOGD_STR("Getting Python plugin info object from Python module.");
+       py_plugin_info = PyObject_CallFunction(py_try_load_plugin_module_func,
+               "(s)", path);
+       if (!py_plugin_info || py_plugin_info == Py_None) {
+               BT_LOGW("Cannot load Python plugin: path=\"%s\"", path);
+               print_python_traceback_warn();
+               PyErr_Clear();
+               goto error;
+       }
+
+       /*
+        * Get bt_plugin from plugin info object.
+        */
+       plugin = bt_plugin_from_python_plugin_info(py_plugin_info);
+       if (!plugin) {
+               BT_LOGW("Cannot create plugin object from Python plugin info object: "
+                       "path=\"%s\", py-plugin-info-addr=%p",
+                       path, py_plugin_info);
+               goto error;
+       }
+
+       bt_plugin_set_path(plugin, path);
+       plugin_set = bt_plugin_set_create();
+       if (!plugin_set) {
+               BT_LOGE_STR("Cannot create empty plugin set.");
+               goto error;
+       }
+
+       bt_plugin_set_add_plugin(plugin_set, plugin);
+       BT_LOGD("Created all Python plugins from file: path=\"%s\", "
+               "plugin-addr=%p, plugin-name=\"%s\"",
+               path, plugin, bt_plugin_get_name(plugin));
+       goto end;
+
+error:
+       BT_OBJECT_PUT_REF_AND_RESET(plugin_set);
+
+end:
+       bt_plugin_put_ref(plugin);
+       Py_XDECREF(py_plugin_info);
+       g_free(basename);
+       return plugin_set;
+}
diff --git a/src/python-plugin-provider/python-plugin-provider.h b/src/python-plugin-provider/python-plugin-provider.h
new file mode 100644 (file)
index 0000000..1d7aa2c
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H
+#define BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H
+
+/*
+ * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace2/plugin/plugin-const.h>
+
+extern
+struct bt_plugin_set *bt_plugin_python_create_all_from_file(const char *path);
+
+#endif /* BABELTRACE_PLUGIN_PYTHON_PLUGIN_PROVIDER_INTERNAL_H */
index d627714fecd96ceeb5fa6d3b067e3b01e53e9630..e9941018d2fcbff695949940787ec9e9e9e3c8c5 100644 (file)
@@ -25,18 +25,18 @@ check_coverage() {
 }
 
 export BABELTRACE_PYTHON_BT2_NO_TRACEBACK=1
 }
 
 export BABELTRACE_PYTHON_BT2_NO_TRACEBACK=1
-export TEST_PLUGIN_PLUGINS_PATH="${BT_BUILD_PATH}/plugins"
-export BABELTRACE_PLUGIN_PATH="${BT_BUILD_PATH}/plugins/ctf:${BT_BUILD_PATH}/plugins/utils:${BT_BUILD_PATH}/plugins/text"
+export TEST_PLUGIN_PLUGINS_PATH="${BT_BUILD_PATH}/src/plugins"
+export BABELTRACE_PLUGIN_PATH="${BT_BUILD_PATH}/src/plugins/ctf:${BT_BUILD_PATH}/src/plugins/utils:${BT_BUILD_PATH}/src/plugins/text"
 export TEST_CTF_TRACES_PATH="${BT_SRC_PATH}/tests/ctf-traces"
 export TEST_CTF_TRACES_PATH="${BT_SRC_PATH}/tests/ctf-traces"
-PYTHON_BUILD_DIR="${BT_BUILD_PATH}/bindings/python/bt2/build/build_lib"
+PYTHON_BUILD_DIR="${BT_BUILD_PATH}/src/bindings/python/bt2/build/build_lib"
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 TESTRUNNER_PY="${BT_SRC_PATH}/tests/utils/python/testrunner.py"
 THIS_DIR="${BT_SRC_PATH}/tests/bindings/python/bt2"
 
 if [ "x${MSYSTEM}" != "x" ]; then
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 TESTRUNNER_PY="${BT_SRC_PATH}/tests/utils/python/testrunner.py"
 THIS_DIR="${BT_SRC_PATH}/tests/bindings/python/bt2"
 
 if [ "x${MSYSTEM}" != "x" ]; then
-       export PATH="${BT_BUILD_PATH}/lib/.libs:${PATH}"
+       export PATH="${BT_BUILD_PATH}/src/lib/.libs:${PATH}"
 else
 else
-       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/lib/.libs:${LD_LIBRARY_PATH}"
+       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/src/lib/.libs:${LD_LIBRARY_PATH}"
 fi
 
 if test "x${TESTALL_COVERAGE}" = "x1"; then
 fi
 
 if test "x${TESTALL_COVERAGE}" = "x1"; then
index 9cb75b00039ca013824433d2346beca064e8475b..679fda2b148e4104776756ccca0fbd0736c3ec78 100644 (file)
@@ -13,17 +13,17 @@ test_bitfield_LDADD = $(LIBTAP) $(builddir)/libtestcommon.la
 
 test_ctf_writer_LDADD = \
        $(COMMON_TEST_LDADD) \
 
 test_ctf_writer_LDADD = \
        $(COMMON_TEST_LDADD) \
-       $(top_builddir)/ctf-writer/libbabeltrace2-ctf-writer.la
+       $(top_builddir)/src/ctf-writer/libbabeltrace2-ctf-writer.la
 
 test_bt_values_LDADD = $(COMMON_TEST_LDADD) \
 
 test_bt_values_LDADD = $(COMMON_TEST_LDADD) \
-       $(top_builddir)/lib/libbabeltrace2.la
+       $(top_builddir)/src/lib/libbabeltrace2.la
 
 test_trace_ir_ref_LDADD = $(COMMON_TEST_LDADD) \
 
 test_trace_ir_ref_LDADD = $(COMMON_TEST_LDADD) \
-       $(top_builddir)/lib/libbabeltrace2.la \
-       $(top_builddir)/ctf-writer/libbabeltrace2-ctf-writer.la
+       $(top_builddir)/src/lib/libbabeltrace2.la \
+       $(top_builddir)/src/ctf-writer/libbabeltrace2-ctf-writer.la
 
 test_graph_topo_LDADD = $(COMMON_TEST_LDADD) \
 
 test_graph_topo_LDADD = $(COMMON_TEST_LDADD) \
-       $(top_builddir)/lib/libbabeltrace2.la
+       $(top_builddir)/src/lib/libbabeltrace2.la
 
 noinst_PROGRAMS = test_bitfield test_ctf_writer test_bt_values \
        test_trace_ir_ref test_graph_topo
 
 noinst_PROGRAMS = test_bitfield test_ctf_writer test_bt_values \
        test_trace_ir_ref test_graph_topo
@@ -37,7 +37,7 @@ test_graph_topo_SOURCES = test_graph_topo.c
 if !ENABLE_BUILT_IN_PLUGINS
 noinst_PROGRAMS += test_plugin
 test_plugin_LDADD = $(COMMON_TEST_LDADD) \
 if !ENABLE_BUILT_IN_PLUGINS
 noinst_PROGRAMS += test_plugin
 test_plugin_LDADD = $(COMMON_TEST_LDADD) \
-       $(top_builddir)/lib/libbabeltrace2.la
+       $(top_builddir)/src/lib/libbabeltrace2.la
 test_plugin_SOURCES = test_plugin.c
 SUBDIRS += test-plugin-plugins
 endif
 test_plugin_SOURCES = test_plugin.c
 SUBDIRS += test-plugin-plugins
 endif
index 3a185b27fea80273faff1daee74e4cf0ef4cd0a8..c852655d2ae57956f5e9d589091a55469e3dba3d 100644 (file)
@@ -6,7 +6,7 @@ plugin_minimal_la_LDFLAGS = \
        $(LT_NO_UNDEFINED) \
        -rpath / -avoid-version -module
 plugin_minimal_la_LIBADD = \
        $(LT_NO_UNDEFINED) \
        -rpath / -avoid-version -module
 plugin_minimal_la_LIBADD = \
-       $(top_builddir)/lib/libbabeltrace2.la
+       $(top_builddir)/src/lib/libbabeltrace2.la
 
 # source/filter/sink plugin
 plugin_sfs_la_SOURCES = sfs.c
 
 # source/filter/sink plugin
 plugin_sfs_la_SOURCES = sfs.c
@@ -14,4 +14,4 @@ plugin_sfs_la_LDFLAGS = \
        $(LT_NO_UNDEFINED) \
        -rpath / -avoid-version -module
 plugin_sfs_la_LIBADD = \
        $(LT_NO_UNDEFINED) \
        -rpath / -avoid-version -module
 plugin_sfs_la_LIBADD = \
-       $(top_builddir)/lib/libbabeltrace2.la
+       $(top_builddir)/src/lib/libbabeltrace2.la
index d746afae10356890c6c2f4f213db7f2b5f503ac2..4431abc0a87b09b9919225241b3b5b4be6b6b2fb 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #include <babeltrace2/babeltrace.h>
  */
 
 #include <babeltrace2/babeltrace.h>
-#include <babeltrace2/assert-internal.h>
+#include "common/assert.h"
 
 static bt_self_component_status sink_consume(
                bt_self_component_sink *self_comp)
 
 static bt_self_component_status sink_consume(
                bt_self_component_sink *self_comp)
index 848d4bd31cf81d2b69022e2eeb1b0e5e0e8ac68a..b9bd6d40a60bb093209ff67307b66aaca4277e4a 100644 (file)
@@ -19,7 +19,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <babeltrace2/bitfield-internal.h>
+#include "compat/bitfield.h"
 #include <time.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <time.h>
 #include <stdlib.h>
 #include <stdio.h>
index f9526379ca2ed5c907f28e075d756c370549c113..d16c67a5b213244d2f7c6b09cf061669ed65e465 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 #include <babeltrace2/babeltrace.h>
  */
 
 #include <babeltrace2/babeltrace.h>
-#include <babeltrace2/assert-internal.h>
+#include "common/assert.h"
 #include <string.h>
 #include "tap/tap.h"
 
 #include <string.h>
 #include "tap/tap.h"
 
index 75b914ce32a764aa1d913f5cba7bef7c0d5aba11..1ed4cc6737d764f730c1b8d2b7e00215b1be392e 100644 (file)
 #include <babeltrace2/value.h>
 #include <glib.h>
 #include <unistd.h>
 #include <babeltrace2/value.h>
 #include <glib.h>
 #include <unistd.h>
-#include <babeltrace2/compat/stdlib-internal.h>
+#include "compat/stdlib.h"
 #include <stdio.h>
 #include <stdio.h>
-#include <babeltrace2/compat/limits-internal.h>
-#include <babeltrace2/compat/stdio-internal.h>
+#include "compat/limits.h"
+#include "compat/stdio.h"
 #include <string.h>
 #include <string.h>
-#include <babeltrace2/assert-internal.h>
+#include "common/assert.h"
 #include <fcntl.h>
 #include "tap/tap.h"
 #include <math.h>
 #include <fcntl.h>
 #include "tap/tap.h"
 #include <math.h>
index b0409d49ce297986fc2ed96ba616bccd0201c05d..7a85f511cfa4584718cb036e7365670d52dfc52f 100644 (file)
@@ -18,7 +18,7 @@
  */
 
 #include <babeltrace2/babeltrace.h>
  */
 
 #include <babeltrace2/babeltrace.h>
-#include <babeltrace2/assert-internal.h>
+#include "common/assert.h"
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
index 852b26fbf26039b04f76a67c6b16855e886c228e..39b054e53ee3ddac324839284d9fa04fc12fce2f 100644 (file)
@@ -19,7 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-#include <babeltrace2/assert-internal.h>
+#include "common/assert.h"
 #include <glib.h>
 #include "tap/tap.h"
 #include "common.h"
 #include <glib.h>
 #include "tap/tap.h"
 #include "common.h"
index 99a1d3749a6afbb3e8b17424734391158437d841..10916fba59294c1040dfe7fee074c5a3de93fd97 100644 (file)
@@ -21,9 +21,9 @@
 
 #include "tap/tap.h"
 #include <babeltrace2/babeltrace.h>
 
 #include "tap/tap.h"
 #include <babeltrace2/babeltrace.h>
-#include <babeltrace2/object-internal.h>
-#include <babeltrace2/compat/stdlib-internal.h>
-#include <babeltrace2/assert-internal.h>
+#include "lib/object.h"
+#include "compat/stdlib.h"
+#include "common/assert.h"
 #include <babeltrace2/ctf-writer/writer.h>
 #include <babeltrace2/ctf-writer/clock.h>
 #include <babeltrace2/ctf-writer/clock-class.h>
 #include <babeltrace2/ctf-writer/writer.h>
 #include <babeltrace2/ctf-writer/clock.h>
 #include <babeltrace2/ctf-writer/clock-class.h>
index e78b34458310359906c04be9486f3d3d683c7c0c..b4d49dc6bbe47fade860145869263fbf95104fe7 100644 (file)
 NO_SH_TAP=1
 . "@abs_top_builddir@/tests/utils/common.sh"
 
 NO_SH_TAP=1
 . "@abs_top_builddir@/tests/utils/common.sh"
 
-PYTHON_BUILD_DIR="${BT_BUILD_PATH}/bindings/python/bt2/build/build_lib"
+PYTHON_BUILD_DIR="${BT_BUILD_PATH}/src/bindings/python/bt2/build/build_lib"
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 TESTRUNNER_PY="${BT_SRC_PATH}/tests/utils/python/testrunner.py"
 THIS_DIR="${BT_SRC_PATH}/tests/lib/trace-ir"
 
 if [ "x${MSYSTEM}" != "x" ]; then
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 TESTRUNNER_PY="${BT_SRC_PATH}/tests/utils/python/testrunner.py"
 THIS_DIR="${BT_SRC_PATH}/tests/lib/trace-ir"
 
 if [ "x${MSYSTEM}" != "x" ]; then
-       export PATH="${BT_BUILD_PATH}/lib/.libs:${PATH}"
+       export PATH="${BT_BUILD_PATH}/src/lib/.libs:${PATH}"
 else
 else
-       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/lib/.libs:${LD_LIBRARY_PATH}"
+       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/src/lib/.libs:${LD_LIBRARY_PATH}"
 fi
 
 PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}" \
 fi
 
 PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}" \
index b5d584b72f2ebcadc8f7196bf370b01895d44afe..015f775fbf82736a7ea106d74d4c97e21edacccd 100644 (file)
@@ -1,4 +1,4 @@
-AM_CPPFLAGS += -I$(top_srcdir)/tests/utils -I$(top_srcdir)/plugins
+AM_CPPFLAGS += -I$(top_srcdir)/tests/utils -I$(top_srcdir)/src/plugins
 
 LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
 
 
 LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la
 
@@ -16,19 +16,19 @@ if ENABLE_DEBUG_INFO
 noinst_PROGRAMS += test_dwarf test_bin_info
 
 test_dwarf_LDADD = \
 noinst_PROGRAMS += test_dwarf test_bin_info
 
 test_dwarf_LDADD = \
-       $(top_builddir)/plugins/lttng-utils/debug-info/libdebug-info.la \
-       $(top_builddir)/fd-cache/libbabeltrace2-fd-cache.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/plugins/lttng-utils/debug-info/libdebug-info.la \
+       $(top_builddir)/src/fd-cache/libbabeltrace2-fd-cache.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
        $(ELFUTILS_LIBS) \
        $(LIBTAP)
 test_dwarf_SOURCES = test_dwarf.c
 
 test_bin_info_LDADD = \
        $(ELFUTILS_LIBS) \
        $(LIBTAP)
 test_dwarf_SOURCES = test_dwarf.c
 
 test_bin_info_LDADD = \
-       $(top_builddir)/plugins/lttng-utils/debug-info/libdebug-info.la \
-       $(top_builddir)/fd-cache/libbabeltrace2-fd-cache.la \
-       $(top_builddir)/logging/libbabeltrace2-logging.la \
-       $(top_builddir)/common/libbabeltrace2-common.la \
+       $(top_builddir)/src/plugins/lttng-utils/debug-info/libdebug-info.la \
+       $(top_builddir)/src/fd-cache/libbabeltrace2-fd-cache.la \
+       $(top_builddir)/src/logging/libbabeltrace2-logging.la \
+       $(top_builddir)/src/common/libbabeltrace2-common.la \
        $(ELFUTILS_LIBS) \
        $(LIBTAP)
 test_bin_info_SOURCES = test_bin_info.c
        $(ELFUTILS_LIBS) \
        $(LIBTAP)
 test_bin_info_SOURCES = test_bin_info.c
index 7f873b36eb27d9f05815cde3ef02048328dbad54..a4c95d051d46594d2bf041cb97a0b53857f2d125 100644 (file)
@@ -27,8 +27,8 @@
 #include <inttypes.h>
 #include <glib.h>
 
 #include <inttypes.h>
 #include <glib.h>
 
-#include <babeltrace2/babeltrace-internal.h>
-#include <babeltrace2/assert-internal.h>
+#include "common/babeltrace.h"
+#include "common/assert.h"
 #include <lttng-utils/debug-info/bin-info.h>
 
 #include "tap/tap.h"
 #include <lttng-utils/debug-info/bin-info.h>
 
 #include "tap/tap.h"
index bb6b2d339eb0597fae3b107f38a7a35ef1b0e54b..5d02aaee1136ae057cc5bd3ca7adf0f25b7afa3d 100644 (file)
 NO_SH_TAP=1
 . "@abs_top_builddir@/tests/utils/common.sh"
 
 NO_SH_TAP=1
 . "@abs_top_builddir@/tests/utils/common.sh"
 
-PYTHON_BUILD_DIR="${BT_BUILD_PATH}/bindings/python/bt2/build/build_lib"
+PYTHON_BUILD_DIR="${BT_BUILD_PATH}/src/bindings/python/bt2/build/build_lib"
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 TESTRUNNER_PY="${BT_SRC_PATH}/tests/utils/python/testrunner.py"
 THIS_DIR="${BT_SRC_PATH}/tests/plugins"
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 TESTRUNNER_PY="${BT_SRC_PATH}/tests/utils/python/testrunner.py"
 THIS_DIR="${BT_SRC_PATH}/tests/plugins"
-export BABELTRACE_PLUGIN_PATH="${BT_BUILD_PATH}/plugins/utils:${BT_BUILD_PATH}/plugins/ctf:${BT_BUILD_PATH}/plugins/lttng-utils"
+export BABELTRACE_PLUGIN_PATH="${BT_BUILD_PATH}/src/plugins/utils:${BT_BUILD_PATH}/src/plugins/ctf:${BT_BUILD_PATH}/src/plugins/lttng-utils"
 export DEBUG_INFO_DATA_DIR="${BT_SRC_PATH}/tests/debug-info-data"
 
 if [ "x${MSYSTEM}" != "x" ]; then
 export DEBUG_INFO_DATA_DIR="${BT_SRC_PATH}/tests/debug-info-data"
 
 if [ "x${MSYSTEM}" != "x" ]; then
-       export PATH="${BT_BUILD_PATH}/lib/.libs:${PATH}"
+       export PATH="${BT_BUILD_PATH}/src/lib/.libs:${PATH}"
 else
 else
-       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/lib/.libs:${LD_LIBRARY_PATH}"
+       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/src/lib/.libs:${LD_LIBRARY_PATH}"
 fi
 
 PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}" \
 fi
 
 PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}" \
index 6f80f98428c2a0f7d2875dceb3df6d599d6e5992..b6fc05a3925861083726e65e2f7df0662444525e 100644 (file)
@@ -22,15 +22,15 @@ NO_SH_TAP=1
 
 export PYTHON_PLUGIN_PROVIDER_TEST_PLUGIN_PATH="${BT_SRC_PATH}/tests/python-plugin-provider/bt_plugin_test_python_plugin_provider.py"
 
 
 export PYTHON_PLUGIN_PROVIDER_TEST_PLUGIN_PATH="${BT_SRC_PATH}/tests/python-plugin-provider/bt_plugin_test_python_plugin_provider.py"
 
-PYTHON_BUILD_DIR="${BT_BUILD_PATH}/bindings/python/bt2/build/build_lib"
+PYTHON_BUILD_DIR="${BT_BUILD_PATH}/src/bindings/python/bt2/build/build_lib"
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 TESTRUNNER_PY="${BT_SRC_PATH}/tests/utils/python/testrunner.py"
 THIS_DIR="${BT_SRC_PATH}/tests/python-plugin-provider"
 
 if [ "x${MSYSTEM}" != "x" ]; then
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 TESTRUNNER_PY="${BT_SRC_PATH}/tests/utils/python/testrunner.py"
 THIS_DIR="${BT_SRC_PATH}/tests/python-plugin-provider"
 
 if [ "x${MSYSTEM}" != "x" ]; then
-       export PATH="${BT_BUILD_PATH}/lib/.libs:${BT_BUILD_PATH}/python-plugin-provider/.libs:${PATH}"
+       export PATH="${BT_BUILD_PATH}/src/lib/.libs:${BT_BUILD_PATH}/src/python-plugin-provider/.libs:${PATH}"
 else
 else
-       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/lib/.libs:${BT_BUILD_PATH}/python-plugin-provider/.libs:${LD_LIBRARY_PATH}"
+       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/src/lib/.libs:${BT_BUILD_PATH}/src/python-plugin-provider/.libs:${LD_LIBRARY_PATH}"
 fi
 
 PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}" \
 fi
 
 PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}" \
index 84307786fd6c3e3d190636d25176894e1fa1eb8d..4d585f051c600542f8c35fcd5ad4a4acb6d07196 100644 (file)
 
 export PYTHON_PLUGIN_PROVIDER_TEST_PLUGIN_PATH="${BT_SRC_PATH}/tests/python-plugin-provider/bt_plugin_test_python_plugin_provider.py"
 
 
 export PYTHON_PLUGIN_PROVIDER_TEST_PLUGIN_PATH="${BT_SRC_PATH}/tests/python-plugin-provider/bt_plugin_test_python_plugin_provider.py"
 
-PYTHON_BUILD_DIR="${BT_BUILD_PATH}/bindings/python/bt2/build/build_lib"
+PYTHON_BUILD_DIR="${BT_BUILD_PATH}/src/bindings/python/bt2/build/build_lib"
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 export PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}"
 
 if [ "x${MSYSTEM}" != "x" ]; then
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 export PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}"
 
 if [ "x${MSYSTEM}" != "x" ]; then
-       export PATH="${BT_BUILD_PATH}/lib/.libs:${BT_BUILD_PATH}/python-plugin-provider/.libs:${PATH}"
+       export PATH="${BT_BUILD_PATH}/src/lib/.libs:${BT_BUILD_PATH}/src/python-plugin-provider/.libs:${PATH}"
 else
 else
-       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/lib/.libs:${BT_BUILD_PATH}/python-plugin-provider/.libs:${LD_LIBRARY_PATH}"
+       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/src/lib/.libs:${BT_BUILD_PATH}/src/python-plugin-provider/.libs:${LD_LIBRARY_PATH}"
 fi
 
 exec "$*"
 fi
 
 exec "$*"
index 13de3679e52bd5a16ecafb1eac9b1de288ebab21..976ef70e2bf97b31b4f111b277955cb0788e346a 100644 (file)
@@ -3,7 +3,7 @@
 BT_SRC_PATH="@abs_top_srcdir@"
 BT_BUILD_PATH="@abs_top_builddir@"
 
 BT_SRC_PATH="@abs_top_srcdir@"
 BT_BUILD_PATH="@abs_top_builddir@"
 
-BT_BIN="${BT_BUILD_PATH}/cli/babeltrace2@EXEEXT@"
+BT_BIN="${BT_BUILD_PATH}/src/cli/babeltrace2@EXEEXT@"
 BT_CTF_TRACES="${BT_SRC_PATH}/tests/ctf-traces"
 
 if [ "x${NO_SH_TAP}" = x ]; then
 BT_CTF_TRACES="${BT_SRC_PATH}/tests/ctf-traces"
 
 if [ "x${NO_SH_TAP}" = x ]; then
index 03ac2522e1a8faa37fd8ad869fe1d0b0bc8654bf..d8e46b54a33b6206b42e00883bf4bd50ee207711 100644 (file)
@@ -28,17 +28,17 @@ NO_SH_TAP=1
 . "@abs_top_builddir@/tests/utils/common.sh"
 
 export BABELTRACE_PYTHON_BT2_NO_TRACEBACK=1
 . "@abs_top_builddir@/tests/utils/common.sh"
 
 export BABELTRACE_PYTHON_BT2_NO_TRACEBACK=1
-export TEST_PLUGIN_PLUGINS_PATH="${BT_BUILD_PATH}/plugins"
-export BABELTRACE_PLUGIN_PATH="${BT_BUILD_PATH}/plugins/ctf:${BT_BUILD_PATH}/plugins/utils:${BT_BUILD_PATH}/plugins/text"
+export TEST_PLUGIN_PLUGINS_PATH="${BT_BUILD_PATH}/src/plugins"
+export BABELTRACE_PLUGIN_PATH="${BT_BUILD_PATH}/src/plugins/ctf:${BT_BUILD_PATH}/src/plugins/utils:${BT_BUILD_PATH}/src/plugins/text"
 export TEST_CTF_TRACES_PATH="${BT_SRC_PATH}/tests/ctf-traces"
 export TEST_CTF_TRACES_PATH="${BT_SRC_PATH}/tests/ctf-traces"
-PYTHON_BUILD_DIR="${BT_BUILD_PATH}/bindings/python/bt2/build/build_lib"
+PYTHON_BUILD_DIR="${BT_BUILD_PATH}/src/bindings/python/bt2/build/build_lib"
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 export PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}"
 
 if [ "x${MSYSTEM}" != "x" ]; then
 TESTS_UTILS_PYTHON_DIR="${BT_SRC_PATH}/tests/utils/python"
 export PYTHONPATH="${PYTHON_BUILD_DIR}:${TESTS_UTILS_PYTHON_DIR}"
 
 if [ "x${MSYSTEM}" != "x" ]; then
-       export PATH="${BT_BUILD_PATH}/lib/.libs:${PATH}"
+       export PATH="${BT_BUILD_PATH}/src/lib/.libs:${PATH}"
 else
 else
-       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/lib/.libs:${LD_LIBRARY_PATH}"
+       export LD_LIBRARY_PATH="${BT_BUILD_PATH}/src/lib/.libs:${LD_LIBRARY_PATH}"
 fi
 
 exec "$@"
 fi
 
 exec "$@"
This page took 2.775388 seconds and 4 git commands to generate.